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 3 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
#include <common.hpp>
#include <plugin/Plugin.hpp>

#include <jansson.h>

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


namespace rack {
@@ -34,7 +35,7 @@ struct Model {
/** 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.
*/
std::vector<int> tags;
std::list<int> tagIds;
/** A one-line summary of the module's purpose */
std::string description;
/** 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
#include <vector>
#include <common.hpp>

#include <jansson.h>

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


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

// Subclass this and return a pointer to a new one when init() is called
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;
/** OS-dependent library handle */
/** OS-dependent library handle.
*/
void* handle = NULL;

/** 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;
};

/** 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
/** 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) {
// Get search fields for model
std::string tagStr;
for (int tagId : model->tags) {
for (int tagId : model->tagIds) {
// Add all aliases of a tag
for (const std::string& tagAlias : tag::tagAliases[tagId]) {
tagStr += tagAlias;
@@ -249,12 +249,11 @@ struct ModelBox : widget::OpaqueWidget {
}
// Tags
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;
tooltip->text = text;
return tooltip;
@@ -585,8 +584,8 @@ struct ModuleBrowser : widget::OpaqueWidget {

// Filter tag
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;
}



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

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

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


+ 6
- 6
src/plugin.cpp View File

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

// 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());

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) {
WARN("Could not load plugin %s: %s", path.c_str(), e.what());
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;
}



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

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

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

// 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;

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 <app/common.hpp>

#include <algorithm>


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

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) {
@@ -106,6 +108,9 @@ void Plugin::fromJson(json_t* rootJ) {
if (changelogUrlJ)
changelogUrl = json_string_value(changelogUrlJ);

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

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

// 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);
}
}
@@ -143,6 +154,17 @@ void Plugin::fromJson(json_t* rootJ) {
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
// This is a hacky way of matching JSON models with C++ models.
for (auto it = models.begin(); it != models.end();) {


Loading…
Cancel
Save