Browse Source

Add string::join(). Reorder models how they are ordered in plugin's manifest. Use list instead of vector for models and tags in plugin::Plugin/Model.

tags/v2.0.0
Andrew Belt 4 years ago
parent
commit
2b9efc1401
8 changed files with 79 additions and 38 deletions
  1. +4
    -3
      include/plugin/Model.hpp
  2. +10
    -6
      include/plugin/Plugin.hpp
  3. +15
    -0
      include/string.hpp
  4. +7
    -8
      src/app/ModuleBrowser.cpp
  5. +2
    -2
      src/app/ModuleWidget.cpp
  6. +6
    -6
      src/plugin.cpp
  7. +4
    -4
      src/plugin/Model.cpp
  8. +31
    -9
      src/plugin/Plugin.cpp

+ 4
- 3
include/plugin/Model.hpp View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <common.hpp>
#include <plugin/Plugin.hpp>


#include <jansson.h> #include <jansson.h>


#include <common.hpp>
#include <plugin/Plugin.hpp>
#include <list>




namespace rack { namespace rack {
@@ -34,7 +35,7 @@ struct Model {
/** List of tag IDs representing the function(s) of the module. /** List of tag IDs representing the function(s) of the module.
Tag IDs are not part of the ABI and may change at any time. Tag IDs are not part of the ABI and may change at any time.
*/ */
std::vector<int> tags;
std::list<int> tagIds;
/** A one-line summary of the module's purpose */ /** A one-line summary of the module's purpose */
std::string description; std::string description;
/** The manual of the module. HTML, PDF, or GitHub readme/wiki are fine. /** The manual of the module. HTML, PDF, or GitHub readme/wiki are fine.


+ 10
- 6
include/plugin/Plugin.hpp View File

@@ -1,9 +1,9 @@
#pragma once #pragma once
#include <vector>
#include <common.hpp>


#include <jansson.h> #include <jansson.h>


#include <common.hpp>
#include <list>




namespace rack { namespace rack {
@@ -15,11 +15,15 @@ struct Model;


// Subclass this and return a pointer to a new one when init() is called // Subclass this and return a pointer to a new one when init() is called
struct Plugin { struct Plugin {
/** A list of the models available by this plugin, add with addModel() */
std::vector<Model*> models;
/** The file path to the plugin's directory */
/** List of models contained in this plugin.
Add with addModel().
*/
std::list<Model*> models;
/** The file path to the plugin's directory.
*/
std::string path; std::string path;
/** OS-dependent library handle */
/** OS-dependent library handle.
*/
void* handle = NULL; void* handle = NULL;


/** Must be unique. Used for saving patches. Never change this after releasing your plugin. /** Must be unique. Used for saving patches. Never change this after releasing your plugin.


+ 15
- 0
include/string.hpp View File

@@ -52,6 +52,21 @@ struct CaseInsensitiveCompare {
bool operator()(const std::string& a, const std::string& b) const; bool operator()(const std::string& a, const std::string& b) const;
}; };


/** Joins an container (vector, list, etc) of std::strings with an optional separator string.
*/
template <typename TContainer>
std::string join(const TContainer& container, std::string seperator = "") {
std::string s;
bool first = true;
for (const auto& c : container) {
if (!first)
s += seperator;
first = false;
s += c;
}
return s;
}



#if defined ARCH_WIN #if defined ARCH_WIN
/** Performs a Unicode string conversion from UTF-16 to UTF-8. /** Performs a Unicode string conversion from UTF-16 to UTF-8.


+ 7
- 8
src/app/ModuleBrowser.cpp View File

@@ -54,7 +54,7 @@ static void modelDbInit() {
for (plugin::Model* model : plugin->models) { for (plugin::Model* model : plugin->models) {
// Get search fields for model // Get search fields for model
std::string tagStr; std::string tagStr;
for (int tagId : model->tags) {
for (int tagId : model->tagIds) {
// Add all aliases of a tag // Add all aliases of a tag
for (const std::string& tagAlias : tag::tagAliases[tagId]) { for (const std::string& tagAlias : tag::tagAliases[tagId]) {
tagStr += tagAlias; tagStr += tagAlias;
@@ -249,12 +249,11 @@ struct ModelBox : widget::OpaqueWidget {
} }
// Tags // Tags
text += "\n\nTags: "; text += "\n\nTags: ";
for (size_t i = 0; i < model->tags.size(); i++) {
if (i > 0)
text += ", ";
int tagId = model->tags[i];
text += tag::getTag(tagId);
std::vector<std::string> tags;
for (int tagId : model->tagIds) {
tags.push_back(tag::getTag(tagId));
} }
text += string::join(tags, ", ");
ui::Tooltip* tooltip = new ui::Tooltip; ui::Tooltip* tooltip = new ui::Tooltip;
tooltip->text = text; tooltip->text = text;
return tooltip; return tooltip;
@@ -585,8 +584,8 @@ struct ModuleBrowser : widget::OpaqueWidget {


// Filter tag // Filter tag
for (int tagId : tagIds) { for (int tagId : tagIds) {
auto it = std::find(model->tags.begin(), model->tags.end(), tagId);
if (it == model->tags.end())
auto it = std::find(model->tagIds.begin(), model->tagIds.end(), tagId);
if (it == model->tagIds.end())
return false; return false;
} }




+ 2
- 2
src/app/ModuleWidget.cpp View File

@@ -85,11 +85,11 @@ struct ModuleInfoItem : ui::MenuItem {
} }


// tags // tags
if (!model->tags.empty()) {
if (!model->tagIds.empty()) {
ui::MenuLabel* tagsLabel = new ui::MenuLabel; ui::MenuLabel* tagsLabel = new ui::MenuLabel;
tagsLabel->text = "Tags:"; tagsLabel->text = "Tags:";
menu->addChild(tagsLabel); menu->addChild(tagsLabel);
for (int tagId : model->tags) {
for (int tagId : model->tagIds) {
ui::MenuLabel* tagLabel = new ui::MenuLabel; ui::MenuLabel* tagLabel = new ui::MenuLabel;
tagLabel->text = "• " + tag::getTag(tagId); tagLabel->text = "• " + tag::getTag(tagId);
menu->addChild(tagLabel); menu->addChild(tagLabel);


+ 6
- 6
src/plugin.cpp View File

@@ -148,18 +148,18 @@ static Plugin* loadPlugin(std::string path) {
plugin->fromJson(rootJ); plugin->fromJson(rootJ);


// Reject plugin if slug already exists // Reject plugin if slug already exists
Plugin* oldPlugin = getPlugin(plugin->slug);
if (oldPlugin)
Plugin* existingPlugin = getPlugin(plugin->slug);
if (existingPlugin)
throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str()); throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str());

plugins.push_back(plugin);
INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), plugin->path.c_str());
} }
catch (Exception& e) { catch (Exception& e) {
WARN("Could not load plugin %s: %s", path.c_str(), e.what()); WARN("Could not load plugin %s: %s", path.c_str(), e.what());
delete plugin; delete plugin;
plugin = NULL;
return NULL;
} }

plugins.push_back(plugin);
INFO("Loaded plugin %s v%s from %s", plugin->slug.c_str(), plugin->version.c_str(), plugin->path.c_str());
return plugin; return plugin;
} }




+ 4
- 4
src/plugin/Model.cpp View File

@@ -26,7 +26,7 @@ void Model::fromJson(json_t* rootJ) {
description = json_string_value(descriptionJ); description = json_string_value(descriptionJ);


// Tags // Tags
tags.clear();
tagIds.clear();
json_t* tagsJ = json_object_get(rootJ, "tags"); json_t* tagsJ = json_object_get(rootJ, "tags");
if (tagsJ) { if (tagsJ) {
size_t i; size_t i;
@@ -36,12 +36,12 @@ void Model::fromJson(json_t* rootJ) {
int tagId = tag::findId(tag); int tagId = tag::findId(tag);


// Omit duplicates // Omit duplicates
auto it = std::find(tags.begin(), tags.end(), tagId);
if (it != tags.end())
auto it = std::find(tagIds.begin(), tagIds.end(), tagId);
if (it != tagIds.end())
continue; continue;


if (tagId >= 0) if (tagId >= 0)
tags.push_back(tagId);
tagIds.push_back(tagId);
} }
} }




+ 31
- 9
src/plugin/Plugin.cpp View File

@@ -4,6 +4,8 @@
#include <string.hpp> #include <string.hpp>
#include <app/common.hpp> #include <app/common.hpp>


#include <algorithm>



namespace rack { namespace rack {
namespace plugin { namespace plugin {
@@ -24,12 +26,12 @@ void Plugin::addModel(Model* model) {
} }


Model* Plugin::getModel(const std::string& slug) { Model* Plugin::getModel(const std::string& slug) {
for (Model* model : models) {
if (model->slug == slug) {
return model;
}
}
return NULL;
auto it = std::find_if(models.begin(), models.end(), [&](Model* m) {
return m->slug == slug;
});
if (it == models.end())
return NULL;
return *it;
} }


void Plugin::fromJson(json_t* rootJ) { void Plugin::fromJson(json_t* rootJ) {
@@ -106,6 +108,9 @@ void Plugin::fromJson(json_t* rootJ) {
if (changelogUrlJ) if (changelogUrlJ)
changelogUrl = json_string_value(changelogUrlJ); changelogUrl = json_string_value(changelogUrlJ);


// Reordered models vector
std::list<Model*> newModels;

json_t* modulesJ = json_object_get(rootJ, "modules"); json_t* modulesJ = json_object_get(rootJ, "modules");
if (modulesJ && json_array_size(modulesJ) > 0) { if (modulesJ && json_array_size(modulesJ) > 0) {
size_t moduleId; size_t moduleId;
@@ -131,11 +136,17 @@ void Plugin::fromJson(json_t* rootJ) {
} }


// Get model // Get model
Model* model = getModel(modelSlug);
if (!model) {
throw Exception("Manifest contains module %s but it is not defined in the plugin", modelSlug.c_str());
auto it = std::find_if(models.begin(), models.end(), [&](Model* m) {
return m->slug == modelSlug;
});
if (it == models.end()) {
throw Exception("Manifest contains module %s but it is not defined in plugin", modelSlug.c_str());
} }


Model* model = *it;
models.erase(it);
newModels.push_back(model);

model->fromJson(moduleJ); model->fromJson(moduleJ);
} }
} }
@@ -143,6 +154,17 @@ void Plugin::fromJson(json_t* rootJ) {
WARN("No modules in plugin manifest %s", slug.c_str()); WARN("No modules in plugin manifest %s", slug.c_str());
} }


if (!models.empty()) {
std::vector<std::string> slugs;
for (Model* model : models) {
slugs.push_back(model->slug);
delete model;
}
throw Exception("Plugin defines module %s but it is not defined in manifest", string::join(slugs, ", ").c_str());
}

models = newModels;

// Remove models without names // Remove models without names
// This is a hacky way of matching JSON models with C++ models. // This is a hacky way of matching JSON models with C++ models.
for (auto it = models.begin(); it != models.end();) { for (auto it = models.begin(); it != models.end();) {


Loading…
Cancel
Save