commit facf79a5f51684ec8a1d20ecd72be2d77e4daf1c
parent 16ace30d78acfa34dd6ffc49dfaa746fb4b9cfd3
Author: cfillion <cfillion@users.noreply.github.com>
Date: Wed, 5 Oct 2016 01:41:12 -0400
support multiple action list sections for scripts
Diffstat:
13 files changed, 169 insertions(+), 43 deletions(-)
diff --git a/src/about.cpp b/src/about.cpp
@@ -323,7 +323,7 @@ void AboutIndexDelegate::initInstalledFiles()
for(const Registry::File &file : allFiles) {
stream << file.path.join();
- if(file.main)
+ if(file.sections) // is this file registered in the action list?
stream << '*';
stream << "\r\n";
}
@@ -493,7 +493,7 @@ void AboutPackageDelegate::updateList(const int index)
for(const Source *src : ver->sources()) {
string actionList;
- if(src->isMain() && src->type() == Package::ScriptType)
+ if(src->sections() && src->type() == Package::ScriptType)
actionList = "Yes";
else
actionList = "No";
diff --git a/src/index_v1.cpp b/src/index_v1.cpp
@@ -19,6 +19,7 @@
#include "errors.hpp"
+#include <sstream>
#include <WDL/tinyxml/tinyxml.h>
using namespace std;
@@ -175,6 +176,9 @@ void LoadSourceV1(TiXmlElement *node, Version *ver)
const char *file = node->Attribute("file");
if(!file) file = "";
+ const char *main = node->Attribute("main");
+ if(!main) main = "";
+
const char *url = node->GetText();
if(!url) url = "";
@@ -184,8 +188,12 @@ void LoadSourceV1(TiXmlElement *node, Version *ver)
src->setPlatform(platform);
src->setTypeOverride(Package::getType(type));
- if(node->Attribute("main"))
- src->setMain(true);
+ int sections = 0;
+ string section;
+ istringstream mainStream(main);
+ while(getline(mainStream, section, '\x20'))
+ sections |= Source::getSection(section.c_str());
+ src->setSections(sections);
if(ver->addSource(src))
ptr.release();
diff --git a/src/registry.cpp b/src/registry.cpp
@@ -178,7 +178,7 @@ auto Registry::push(const Version *ver, vector<Path> *conflicts) -> Entry
m_insertFile->bind(1, entryId);
m_insertFile->bind(2, path.join('/'));
- m_insertFile->bind(3, src->isMain());
+ m_insertFile->bind(3, src->sections());
m_insertFile->bind(4, src->typeOverride());
try {
@@ -259,7 +259,7 @@ auto Registry::getFiles(const Entry &entry) const -> vector<File>
m_getFiles->bind(1, entry.id);
m_getFiles->exec([&] {
File file{m_getFiles->stringColumn(0)};
- file.main = m_getFiles->boolColumn(1);
+ file.sections = m_getFiles->intColumn(1);
file.type = static_cast<Package::Type>(m_getFiles->intColumn(2));
if(!file.type) // < v1.0rc2
@@ -281,7 +281,7 @@ auto Registry::getMainFiles(const Entry &entry) const -> vector<File>
vector<File> mainFiles;
copy_if(allFiles.begin(), allFiles.end(),
- back_inserter(mainFiles), [&](const File &f) { return f.main; });
+ back_inserter(mainFiles), [&](const File &f) { return f.sections; });
return mainFiles;
}
diff --git a/src/registry.hpp b/src/registry.hpp
@@ -44,7 +44,7 @@ public:
struct File {
Path path;
- bool main;
+ int sections;
Package::Type type;
bool operator<(const File &o) const { return path < o.path; }
diff --git a/src/source.cpp b/src/source.cpp
@@ -20,10 +20,24 @@
#include "errors.hpp"
#include "index.hpp"
+#include <boost/algorithm/string.hpp>
+
using namespace std;
+auto Source::getSection(const char *name) -> Section
+{
+ if(!strcmp(name, "main"))
+ return MainSection;
+ else if(!strcmp(name, "midi_editor"))
+ return MIDIEditorSection;
+ else if(!strcmp(name, "true"))
+ return ImplicitSection;
+ else
+ return UnknownSection;
+}
+
Source::Source(const string &file, const string &url, const Version *ver)
- : m_type(Package::UnknownType), m_file(file), m_url(url), m_main(false),
+ : m_type(Package::UnknownType), m_file(file), m_url(url), m_sections(0),
m_version(ver)
{
if(m_url.empty())
@@ -56,6 +70,28 @@ const string &Source::file() const
throw reapack_error("empty source file name and no package");
}
+void Source::setSections(int sections)
+{
+ if(sections == ImplicitSection) {
+ // for compatibility with v1.0
+
+ const Package *pkg = package();
+ const Category *cat = pkg ? pkg->category() : nullptr;
+ if(!cat)
+ throw reapack_error("cannot resolve implicit section: category is unset");
+
+ string category = Path(cat->name()).first();
+ boost::algorithm::to_lower(category);
+
+ if(category == "midi editor")
+ sections = MIDIEditorSection;
+ else
+ sections = MainSection;
+ }
+
+ m_sections = sections;
+}
+
string Source::fullName() const
{
if(!m_version)
diff --git a/src/source.hpp b/src/source.hpp
@@ -27,6 +27,16 @@ class Version;
class Source {
public:
+ enum Section {
+ UnknownSection = 0,
+ MainSection = 1<<0,
+ MIDIEditorSection = 1<<1,
+
+ ImplicitSection = -1, // for compatibility with v1.0
+ };
+
+ static Section getSection(const char *);
+
Source(const std::string &file, const std::string &url,
const Version * = nullptr);
@@ -38,8 +48,8 @@ public:
Package::Type type() const;
const std::string &file() const;
const std::string &url() const { return m_url; }
- void setMain(bool main) { m_main = main; }
- bool isMain() const { return m_main; }
+ void setSections(int);
+ int sections() const { return m_sections; }
const Version *version() const { return m_version; }
const Package *package() const;
@@ -52,7 +62,7 @@ private:
Package::Type m_type;
std::string m_file;
std::string m_url;
- bool m_main;
+ int m_sections;
const Version *m_version;
};
diff --git a/src/task.cpp b/src/task.cpp
@@ -121,8 +121,7 @@ void InstallTask::commit()
if(FS::remove(file.path))
tx()->receipt()->addRemoval(file.path);
- if(file.main)
- tx()->registerFile({false, m_oldEntry, file});
+ tx()->registerFile({false, m_oldEntry, file});
}
InstallTicket::Type type;
@@ -179,8 +178,7 @@ void UninstallTask::commit()
else
tx()->receipt()->addError({FS::lastError(), file.path.join()});
- if(file.main)
- tx()->registerFile({false, m_entry, file});
+ tx()->registerFile({false, m_entry, file});
}
tx()->registry()->forget(m_entry);
diff --git a/src/transaction.cpp b/src/transaction.cpp
@@ -25,8 +25,6 @@
#include "remote.hpp"
#include "task.hpp"
-#include <boost/algorithm/string.hpp>
-
#include <reaper_plugin_functions.h>
using namespace std;
@@ -308,26 +306,45 @@ void Transaction::registerQueued()
}
}
-void Transaction::registerScript(const HostTicket ®, const bool isLast)
+void Transaction::registerScript(const HostTicket ®, const bool isLastCall)
{
- enum Section { MainSection = 0, MidiEditorSection = 32060 };
+ static const map<Source::Section, int> sectionMap{
+ {Source::MainSection, 0},
+ {Source::MIDIEditorSection, 32060},
+ };
- if(!AddRemoveReaScript)
- return; // do nothing if REAPER < v5.12
+ if(!AddRemoveReaScript || !reg.file.sections)
+ return; // do nothing if REAPER < v5.12 and skip non-main files
- Section section;
- string category = Path(reg.entry.category).first();
- boost::algorithm::to_lower(category);
+ const string &fullPath = Path::prefixRoot(reg.file.path).join();
- if(category == "midi editor")
- section = MidiEditorSection;
- else
- section = MainSection;
+ vector<int> sections;
- const string &fullPath = Path::prefixRoot(reg.file.path).join();
- if(!AddRemoveReaScript(reg.add, section, fullPath.c_str(), isLast) && reg.add) {
- m_receipt.addError({"This script could not be registered in REAPER.",
- reg.file.path.join()});
+ for(const auto &pair : sectionMap) {
+ if(reg.file.sections & pair.first)
+ sections.push_back(pair.second);
+ }
+
+ assert(!sections.empty()); // is a section missing in sectionMap?
+
+ bool enableError = reg.add;
+ auto it = sections.begin();
+
+ while(true) {
+ const int section = *it++;
+ const bool isLastSection = it == sections.end();
+
+ int id = AddRemoveReaScript(reg.add, section, fullPath.c_str(),
+ isLastCall && isLastSection);
+
+ if(!id && enableError) {
+ m_receipt.addError({"This script could not be registered in REAPER.",
+ reg.file.path.join()});
+ enableError = false;
+ }
+
+ if(isLastSection)
+ break;
}
}
diff --git a/test/index_v1.cpp b/test/index_v1.cpp
@@ -174,13 +174,13 @@ TEST_CASE("full index", M) {
const Source *source1 = ver->source(0);
REQUIRE(source1->platform() == Platform::GenericPlatform);
REQUIRE(source1->file() == "test.lua");
- REQUIRE(source1->isMain());
+ REQUIRE(source1->sections() == Source::MainSection);
REQUIRE(source1->url() == "https://google.com/");
const Source *source2 = ver->source(1);
REQUIRE(source2->platform() == Platform::GenericPlatform);
REQUIRE(source2->file() == "background.png");
- REQUIRE_FALSE(source2->isMain());
+ REQUIRE_FALSE(source2->sections() == Source::MainSection);
REQUIRE(source2->url() == "http://cfillion.tk/");
}
@@ -293,3 +293,13 @@ TEST_CASE("read package description", M) {
CHECK(ri->packages().size() == 1);
REQUIRE(ri->category(0)->package(0)->description() == "From the New World");
}
+
+TEST_CASE("read multiple sections", M) {
+ UseRootPath root(RIPATH);
+
+ IndexPtr ri = Index::load("explicit_sections");
+
+ CHECK(ri->packages().size() == 1);
+ REQUIRE(ri->category(0)->package(0)->version(0)->source(0)->sections()
+ == (Source::MainSection | Source::MIDIEditorSection));
+}
diff --git a/test/indexes/v1/ReaPack/cache/explicit_sections.xml b/test/indexes/v1/ReaPack/cache/explicit_sections.xml
@@ -0,0 +1,9 @@
+<index version="1">
+ <category name="MIDI Editor">
+ <reapack name="packname" type="script">
+ <version name="1.0">
+ <source main=" main midi_editor HELLO ">https://google.com/</source>
+ </version>
+ </reapack>
+ </category>
+</index>
diff --git a/test/indexes/v1/ReaPack/cache/valid_index.xml b/test/indexes/v1/ReaPack/cache/valid_index.xml
@@ -2,7 +2,7 @@
<category name="Category Name">
<reapack name="Hello World.lua" type="script">
<version name="1.0">
- <source platform="all" file="test.lua" main="true">https://google.com/</source>
+ <source platform="all" file="test.lua" main="main">https://google.com/</source>
<source platform="all" file="background.png">http://cfillion.tk/</source>
<changelog>Fixed a division by zero error.</changelog>
</version>
diff --git a/test/registry.cpp b/test/registry.cpp
@@ -92,7 +92,7 @@ TEST_CASE("get file list", M) {
const vector<Registry::File> &files = reg.getFiles(reg.getEntry(&pkg));
REQUIRE(files.size() == 1);
REQUIRE(files[0].path == src->targetPath());
- REQUIRE(files[0].main == false);
+ REQUIRE(files[0].sections == 0);
REQUIRE(files[0].type == pkg.type());
}
@@ -170,12 +170,12 @@ TEST_CASE("get main files", M) {
REQUIRE((reg.getMainFiles({})).empty());
Source *main1 = new Source({}, "url", &ver);
- main1->setMain(true);
+ main1->setSections(Source::MIDIEditorSection);
main1->setTypeOverride(Package::EffectType);
ver.addSource(main1);
Source *main2 = new Source({}, "url", &ver); // duplicate file ignored
- main2->setMain(true);
+ main2->setSections(Source::MainSection);
main2->setTypeOverride(Package::EffectType);
ver.addSource(main2);
@@ -184,7 +184,7 @@ TEST_CASE("get main files", M) {
const vector<Registry::File> ¤t = reg.getMainFiles(entry);
REQUIRE(current.size() == 1);
REQUIRE(current[0].path == main1->targetPath());
- REQUIRE(current[0].main == true);
+ REQUIRE(current[0].sections == Source::MIDIEditorSection);
REQUIRE(current[0].type == Package::EffectType);
}
diff --git a/test/source.cpp b/test/source.cpp
@@ -55,12 +55,50 @@ TEST_CASE("empty source file name and no package", M) {
}
}
+TEST_CASE("parse file section", M) {
+ REQUIRE(-1 == Source::getSection("true"));
+ REQUIRE(0 == Source::getSection("hello"));
+ REQUIRE(Source::MainSection == Source::getSection("main"));
+ REQUIRE(Source::MIDIEditorSection == Source::getSection("midi_editor"));
+}
+
TEST_CASE("main source", M) {
Source source("filename", "url");
- REQUIRE_FALSE(source.isMain());
+ REQUIRE(source.sections() == 0);
+
+ source.setSections(Source::MainSection | Source::MIDIEditorSection);
+ REQUIRE(source.sections() == (Source::MainSection | Source::MIDIEditorSection));
+}
+
+TEST_CASE("implicit source section") {
+ SECTION("main") {
+ Category cat("Category Name");
+ Package pack(Package::UnknownType, "package name", &cat);
+ Version ver("1.0", &pack);
+
+ Source source("filename", "url", &ver);
+ source.setSections(Source::ImplicitSection);
+ REQUIRE(source.sections() == Source::MainSection);
+ }
- source.setMain(true);
- REQUIRE(source.isMain());
+ SECTION("midi editor") {
+ Category cat("midi Editor/somthing else");
+ Package pack(Package::UnknownType, "package name", &cat);
+ Version ver("1.0", &pack);
+
+ Source source("filename", "url", &ver);
+ source.setSections(Source::ImplicitSection);
+ REQUIRE(source.sections() == Source::MIDIEditorSection);
+ }
+
+ SECTION("no category") {
+ Source source("filename", "url");
+ try {
+ source.setSections(Source::ImplicitSection);
+ FAIL(); // should throw (or crash if buggy, but not do nothing)
+ }
+ catch(const reapack_error &) {}
+ }
}
TEST_CASE("empty source url", M) {