Merge pull request #2604 from OpenSpace/feature/documentation-overhaul

Feature/documentation overhaul
This commit is contained in:
Ylva Selling
2023-04-14 18:42:44 -04:00
committed by GitHub
27 changed files with 541 additions and 240 deletions

3
.gitmodules vendored
View File

@@ -32,3 +32,6 @@
[submodule "support/coding/codegen"]
path = support/coding/codegen
url = https://github.com/OpenSpace/codegen
[submodule "documentation"]
path = documentation
url = https://github.com/OpenSpace/OpenSpace-Documentation-Dist.git

1
documentation Submodule

Submodule documentation added at e5320f7802

View File

@@ -28,6 +28,7 @@
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <ghoul/misc/exception.h>
namespace openspace::documentation {
@@ -109,6 +110,8 @@ public:
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
private:
/// The list of all Documentation%s that are stored by the DocumentationEngine

View File

@@ -56,6 +56,7 @@ public:
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
const std::multimap<KeyWithModifier, std::string>& keyBindings() const;

View File

@@ -27,6 +27,7 @@
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <map>
#include <string>
#include <vector>
@@ -99,6 +100,13 @@ public:
*/
const std::string& identifier() const;
/**
* Returns the type of this PropertyOwner.
*
* \return The type of this PropertyOwner
*/
const std::string& type() const;
/**
* Sets the user-facing name of this PropertyOwner. This name does not have to be
* unique, but it is recommended to be.
@@ -291,6 +299,8 @@ public:
// Generate JSON for documentation
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
protected:
/// The unique identifier of this PropertyOwner
std::string _identifier;
@@ -298,6 +308,8 @@ protected:
std::string _guiName;
/// The description for this PropertyOwner
std::string _description;
/// The type for this PropertyOwner
std::string _type;
/// The owner of this PropertyOwner
PropertyOwner* _owner = nullptr;

View File

@@ -27,6 +27,7 @@
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <vector>
namespace openspace {
@@ -35,6 +36,7 @@ class SceneLicenseWriter : public DocumentationGenerator {
public:
SceneLicenseWriter();
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
};
} // namespace openspace

View File

@@ -27,8 +27,8 @@
#include <openspace/util/syncable.h>
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/json.h>
#include <ghoul/lua/luastate.h>
#include <ghoul/misc/boolean.h>
#include <filesystem>
@@ -96,6 +96,7 @@ public:
std::vector<std::string> allLuaFunctions() const;
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
private:
BooleanType(Replace);

View File

@@ -27,6 +27,7 @@
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <ghoul/misc/exception.h>
#include <ghoul/misc/templatefactory.h>
#include <memory>
@@ -109,6 +110,7 @@ public:
ghoul::TemplateFactory<T>* factory() const;
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
private:
/// Singleton member for the Factory Manager

View File

@@ -83,6 +83,7 @@ StaticRotation::StaticRotation()
_matrixIsDirty = true;
requireUpdate();
});
_type = "StaticRotation";
}
StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRotation() {
@@ -101,6 +102,7 @@ StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRota
_eulerRotation = rotationMatrixToEulerAngles(std::get<glm::dmat3>(p.rotation));
}
_matrixIsDirty = true;
_type = "StaticRotation";
}
glm::dmat3 StaticRotation::matrix(const UpdateData&) const {

View File

@@ -58,11 +58,13 @@ StaticScale::StaticScale() : _scaleValue(ScaleInfo, 1.f, 0.1f, 100.f) {
_scaleValue.onChange([this]() {
requireUpdate();
});
_type = "StaticScale";
}
StaticScale::StaticScale(const ghoul::Dictionary& dictionary) : StaticScale() {
const Parameters p = codegen::bake<Parameters>(dictionary);
_scaleValue = p.scale;
_type = "StaticScale";
}
} // namespace openspace

View File

@@ -60,6 +60,7 @@ StaticTranslation::StaticTranslation()
requireUpdate();
notifyObservers();
});
_type = "StaticTranslation";
}
StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary)
@@ -67,6 +68,7 @@ StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
_position = p.position;
_type = "StaticTranslation";
}
glm::dvec3 StaticTranslation::position(const UpdateData&) const {

View File

@@ -27,6 +27,7 @@
#include <openspace/openspace.h>
#include <openspace/documentation/core_registration.h>
#include <openspace/documentation/verifier.h>
#include <openspace/json.h>
#include <openspace/util/json_helper.h>
#include <ghoul/fmt.h>
#include <ghoul/filesystem/filesystem.h>
@@ -87,19 +88,20 @@ DocumentationEngine& DocumentationEngine::ref() {
return *_instance;
}
std::string generateJsonDocumentation(const Documentation& d) {
std::stringstream result;
result << "{";
nlohmann::json generateJsonDocumentation(const Documentation& d) {
nlohmann::json json;
json["name"] = d.name;
json["id"] = d.id;
json["properties"] = nlohmann::json::array();
result << R"("name": ")" << d.name << "\",";
result << R"("id": ")" << d.id << "\",";
result << R"("entries": [)";
for (const DocumentationEntry& p : d.entries) {
result << '{';
result << R"("key": ")" << p.key << "\",";
result << R"("optional": )" << (p.optional ? "true" : "false") << ',';
result << R"("type": ")" << p.verifier->type() << "\",";
result << R"("documentation": ")" << escapedJson(p.documentation) << "\",";
nlohmann::json entry;
entry["key"] = p.key;
entry["optional"] = p.optional ? true : false;
entry["type"] = p.verifier->type();
entry["documentation"] = p.documentation;
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast<ReferencingVerifier*>(p.verifier.get());
@@ -112,53 +114,52 @@ std::string generateJsonDocumentation(const Documentation& d) {
);
if (it == documentations.end()) {
result << R"("reference": { "found": false })";
entry["reference"]["found"] = false;
}
else {
result << R"("reference": {)"
<< R"("found": true,)"
<< R"("name": ")" << it->name << "\","
<< R"("identifier": ")" << rv->identifier << '\"'
<< '}';
nlohmann::json reference;
reference["found"] = true;
reference["name"] = it->name;
reference["identifier"] = rv->identifier;
entry["reference"] = reference;
}
}
else if (tv) {
std::string json = generateJsonDocumentation({ "", "", tv->documentations });
nlohmann::json json = generateJsonDocumentation(tv->documentations);
// We have a TableVerifier, so we need to recurse
result << R"("restrictions": )" << json;
entry["restrictions"] = json;
}
else {
result << R"("description": ")" << p.verifier->documentation() << '\"';
entry["description"] = p.verifier->documentation();
}
result << '}';
if (&p != &d.entries.back()) {
result << ", ";
}
json["properties"].push_back(entry);
}
result << ']';
result << '}';
return result.str();
return json;
}
std::string DocumentationEngine::generateJson() const {
std::stringstream json;
json << "[";
nlohmann::json json;
for (const Documentation& d : _documentations) {
json << generateJsonDocumentation(d);
if (&d != &_documentations.back()) {
json << ", ";
}
json["data"].push_back(generateJsonDocumentation(d));
}
json << "]";
return json.str();
return json.dump();
}
nlohmann::json DocumentationEngine::generateJsonJson() const {
nlohmann::json json;
for (const Documentation& d : _documentations) {
json.push_back(generateJsonDocumentation(d));
}
return json;
}
void DocumentationEngine::addDocumentation(Documentation documentation) {
if (documentation.id.empty()) {
_documentations.push_back(std::move(documentation));

View File

@@ -41,6 +41,7 @@
#include <openspace/interaction/interactionmonitor.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/json.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/navigation/orbitalnavigator.h>
#include <openspace/network/parallelpeer.h>
@@ -1029,13 +1030,13 @@ void OpenSpaceEngine::writeDocumentation() {
path = absPath(path).string() + '/';
// Start the async requests as soon as possible so they are finished when we need them
std::future<std::string> root = std::async(
&properties::PropertyOwner::generateJson,
std::future<nlohmann::json> settings = std::async(
&properties::PropertyOwner::generateJsonJson,
global::rootPropertyOwner
);
std::future<std::string> scene = std::async(
&properties::PropertyOwner::generateJson,
std::future<nlohmann::json> scene = std::async(
&properties::PropertyOwner::generateJsonJson,
_scene.get()
);
@@ -1044,56 +1045,41 @@ void OpenSpaceEngine::writeDocumentation() {
DocEng.addHandlebarTemplates(FactoryManager::ref().templatesToRegister());
DocEng.addHandlebarTemplates(DocEng.templatesToRegister());
std::string json = "{\"documentation\":[";
nlohmann::json scripting;
scripting["Name"] = "Scripting API";
scripting["Data"] = global::scriptEngine->generateJsonJson();
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Scripting",
global::scriptEngine->jsonName(),
global::scriptEngine->generateJson()
);
nlohmann::json factory;
factory["Name"] = "Asset Types";
factory["Data"] = FactoryManager::ref().generateJsonJson();
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Top Level", DocEng.jsonName(), DocEng.generateJson()
);
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Factory", FactoryManager::ref().jsonName(), FactoryManager::ref().generateJson()
);
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Keybindings",
global::keybindingManager->jsonName(),
global::keybindingManager->generateJson()
);
nlohmann::json keybindings;
keybindings["Name"] = "Keybindings";
keybindings["Keybindings"] = global::keybindingManager->generateJsonJson();
SceneLicenseWriter writer;
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Scene License Information", writer.jsonName(), writer.generateJson()
);
nlohmann::json license;
license["Name"] = "Licenses";
license["Data"] = writer.generateJsonJson();
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}},)",
"Scene Properties", "propertylist", root.get()
);
nlohmann::json sceneProperties;
sceneProperties["Name"] = "Settings";
sceneProperties["Data"] = settings.get();
json += fmt::format(
R"({{"name":"{}","identifier":"{}","data":{}}})",
"Scene Graph Information", "propertylist", scene.get()
);
nlohmann::json sceneGraph;
sceneGraph["Name"] = "Scene";
sceneGraph["Data"] = scene.get();
json += "]}";
nlohmann::json documentation = {
sceneGraph, sceneProperties, keybindings, license, scripting, factory
};
// Add templates for the JSONs we just registered
DocEng.addHandlebarTemplates(global::keybindingManager->templatesToRegister());
DocEng.addHandlebarTemplates(writer.templatesToRegister());
DocEng.addHandlebarTemplates(global::rootPropertyOwner->templatesToRegister());
nlohmann::json result;
result["documentation"] = documentation;
DocEng.writeDocumentationHtml(path, json);
std::ofstream out(absPath("${DOCUMENTATION}/documentationData.js"));
out << "var data = " << result.dump();
out.close();
}
void OpenSpaceEngine::preSynchronization() {

View File

@@ -38,6 +38,30 @@
namespace openspace::interaction {
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
KeybindingManager::KeybindingManager()
: DocumentationGenerator(
"Keybindings",
@@ -140,6 +164,22 @@ std::string KeybindingManager::generateJson() const {
return json.str();
}
nlohmann::json KeybindingManager::generateJsonJson() const {
ZoneScoped;
nlohmann::json json;
for (const std::pair<const KeyWithModifier, std::string>& p : _keyLua) {
nlohmann::json keybind;
keybind["Name"] = ghoul::to_string(p.first);
keybind["Action"] = p.second;
json.push_back(std::move(keybind));
}
sortJson(json);
return json;
}
scripting::LuaLibrary KeybindingManager::luaLibrary() {
return {
"",

View File

@@ -27,6 +27,7 @@
#include <openspace/engine/globals.h>
#include <openspace/events/event.h>
#include <openspace/events/eventengine.h>
#include <openspace/json.h>
#include <openspace/properties/property.h>
#include <openspace/scene/scene.h>
#include <openspace/util/json_helper.h>
@@ -40,66 +41,64 @@
namespace {
constexpr std::string_view _loggerCat = "PropertyOwner";
void createJson(openspace::properties::PropertyOwner* owner, std::vector<char>& buf) {
ZoneScoped;
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json createJson(openspace::properties::PropertyOwner* owner) {
ZoneScoped
using namespace openspace;
nlohmann::json json;
json["Name"] = owner->identifier();
constexpr std::string_view replStr = R"("{}": "{}")";
json["Description"] = owner->description();
json["Properties"] = nlohmann::json::array();
json["PropertyOwners"] = nlohmann::json::array();
json["Type"] = owner->type();
json["Tags"] = owner->tags();
buf.push_back('{');
fmt::format_to(std::back_inserter(buf), replStr, "name", owner->identifier());
buf.push_back(',');
constexpr std::string_view propertiesText = "\"properties\": [";
buf.insert(buf.end(), propertiesText.begin(), propertiesText.end());
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
//json << "{";
buf.push_back('{');
//json << fmt::format(replStr, "id", p->identifier()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "id", p->identifier());
buf.push_back(',');
//json << fmt::format(replStr, "type", p->className()) << ",";
fmt::format_to(std::back_inserter(buf), replStr, "type", p->className());
buf.push_back(',');
nlohmann::json propertyJson;
propertyJson["Name"] = p->identifier();
propertyJson["Type"] = p->className();
propertyJson["URI"] = p->fullyQualifiedIdentifier();
propertyJson["Gui Name"] = p->guiName();
propertyJson["Description"] = p->description();
fmt::format_to(
std::back_inserter(buf),
replStr, "fullyQualifiedId", p->fullyQualifiedIdentifier()
);
buf.push_back(',');
fmt::format_to(std::back_inserter(buf), replStr, "guiName", p->guiName());
buf.push_back(',');
fmt::format_to(
std::back_inserter(buf),
replStr, "description", escapedJson(p->description())
);
buf.push_back('}');
if (p != properties.back()) {
buf.push_back(',');
}
json["Properties"].push_back(propertyJson);
}
buf.push_back(']');
buf.push_back(',');
sortJson(json["Properties"]);
constexpr std::string_view propertyOwnersText = "\"propertyOwners\": [";
buf.insert(
buf.end(),
propertyOwnersText.begin(),
propertyOwnersText.end()
);
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
createJson(o, buf);
if (o != propertyOwners.back()) {
buf.push_back(',');
}
nlohmann::json propertyOwner;
json["PropertyOwners"].push_back(createJson(o));
}
buf.push_back(']');
buf.push_back('}');
sortJson(json["PropertyOwners"]);
return json;
}
} // namespace
@@ -387,6 +386,10 @@ const std::string& PropertyOwner::identifier() const {
return _identifier;
}
const std::string& PropertyOwner::type() const {
return _type;
}
void PropertyOwner::setGuiName(std::string guiName) {
_guiName = std::move(guiName);
}
@@ -418,17 +421,28 @@ void PropertyOwner::removeTag(const std::string& tag) {
std::string PropertyOwner::generateJson() const {
ZoneScoped;
std::vector<char> res;
res.reserve(5 * 51024 * 1024); // 5 MB
res.push_back('[');
nlohmann::json json;
std::vector<PropertyOwner*> subOwners = propertySubOwners();
for (PropertyOwner* owner : subOwners) {
createJson(owner, res);
res.push_back(',');
json["Data"].push_back(createJson(owner));
}
res.back() = ']';
return std::string(res.begin(), res.end());
return json.dump();
}
nlohmann::json PropertyOwner::generateJsonJson() const {
ZoneScoped
nlohmann::json json;
std::vector<PropertyOwner*> subOwners = propertySubOwners();
for (PropertyOwner* owner : subOwners) {
if (owner->identifier() != "Scene") {
json.push_back(createJson(owner));
}
}
sortJson(json);
return json;
}
} // namespace openspace::properties

View File

@@ -68,6 +68,8 @@ std::unique_ptr<DashboardItem> DashboardItem::createFromDictionary(
const std::string& dashboardType = dictionary.value<std::string>(KeyType);
DashboardItem* item = factory->create(dashboardType, std::move(dictionary));
item->_type = dashboardType;
return std::unique_ptr<DashboardItem>(item);
}

View File

@@ -130,6 +130,7 @@ ghoul::mm_unique_ptr<Renderable> Renderable::createFromDictionary(
dictionary,
&global::memoryManager->PersistentMemory
);
result->_type = renderableType;
return ghoul::mm_unique_ptr<Renderable>(result);
}

View File

@@ -217,6 +217,7 @@ std::unique_ptr<ScreenSpaceRenderable> ScreenSpaceRenderable::createFromDictiona
p.type,
dictionary
);
ssr->_type = p.type;
return std::unique_ptr<ScreenSpaceRenderable>(ssr);
}

View File

@@ -76,6 +76,7 @@ std::unique_ptr<LightSource> LightSource::createFromDictionary(
LightSource* source = factory->create(p.type, dictionary);
source->setIdentifier(p.identifier);
source->_type = p.type;
return std::unique_ptr<LightSource>(source);
}

View File

@@ -61,6 +61,7 @@ ghoul::mm_unique_ptr<Rotation> Rotation::createFromDictionary(
dictionary,
&global::memoryManager->PersistentMemory
);
result->_type = p.type;
return ghoul::mm_unique_ptr<Rotation>(result);
}

View File

@@ -61,6 +61,8 @@ ghoul::mm_unique_ptr<Scale> Scale::createFromDictionary(
&global::memoryManager->PersistentMemory
);
result->setIdentifier("Scale");
result->_type = p.type;
return ghoul::mm_unique_ptr<Scale>(result);
}

View File

@@ -491,6 +491,7 @@ ghoul::mm_unique_ptr<SceneGraphNode> SceneGraphNode::createFromDictionary(
LDEBUG(fmt::format("Successfully created SceneGraphNode '{}'", result->identifier()));
result->_lastScreenSpaceUpdateTime = std::chrono::high_resolution_clock::now();
result->_type = "SceneGraphNode";
return result;
}

View File

@@ -46,6 +46,107 @@ SceneLicenseWriter::SceneLicenseWriter()
)
{}
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json SceneLicenseWriter::generateJsonJson() const {
nlohmann::json json;
std::vector<const Asset*> assets =
global::openSpaceEngine->assetManager().allAssets();
int metaTotal = 0;
int metaCount = 0;
for (const Asset* asset : assets) {
std::optional<Asset::MetaInformation> meta = asset->metaInformation();
if (!meta.has_value()) {
continue;
}
metaTotal++;
}
if (global::profile->meta.has_value()) {
metaTotal++;
nlohmann::json metaJson;
metaJson["Name"] = "Profile";
metaJson["ProfileName"] = global::profile->meta->name.value_or("");
metaJson["Version"] = global::profile->meta->version.value_or("");
metaJson["Description"] = global::profile->meta->description.value_or("");
metaJson["Author"] = global::profile->meta->author.value_or("");
metaJson["Url"] = global::profile->meta->url.value_or("");
metaJson["License"] = global::profile->meta->license.value_or("");
metaJson["Type"] = "license";
json.push_back(std::move(metaJson));
}
std::map<std::string, nlohmann::json> assetLicenses;
for (const Asset* asset : assets) {
std::optional<Asset::MetaInformation> meta = asset->metaInformation();
nlohmann::json assetJson;
if (!meta.has_value()) {
assetJson["Name"] = "";
assetJson["Version"] = "";
assetJson["Description"] = "";
assetJson["Author"] = "";
assetJson["Url"] = "";
assetJson["License"] = "No license";
assetJson["Identifiers"] = "";
assetJson["Path"] = asset->path().string();
assetLicenses["No license"].push_back(assetJson);
}
else {
std::string license = meta->license == "" ? "No license" : meta->license;
assetJson["Name"] = meta->name;
assetJson["Version"] = meta->version;
assetJson["Description"] = meta->description;
assetJson["Author"] = meta->author;
assetJson["Url"] = meta->url;
assetJson["License"] = license;
assetJson["Identifiers"] = meta->identifiers;
assetJson["Path"] = asset->path().string();
assetLicenses[license].push_back(assetJson);
}
}
nlohmann::json assetsJson;
assetsJson["Name"] = "Assets";
assetsJson["Type"] = "Licenses";
for (const std::pair<std::string, nlohmann::json>& assetLicense : assetLicenses) {
nlohmann::json entry;
entry["Name"] = assetLicense.first;
entry["Assets"] = assetLicense.second;
sortJson(entry["Assets"]);
assetsJson["Licenses"].push_back(entry);
}
json.push_back(assetsJson);
return json;
}
std::string SceneLicenseWriter::generateJson() const {
ZoneScoped;

View File

@@ -57,6 +57,8 @@ ghoul::mm_unique_ptr<TimeFrame> TimeFrame::createFromDictionary(
TimeFrame* result = FactoryManager::ref().factory<TimeFrame>()->create(p.type, dict);
result->setIdentifier("TimeFrame");
result->_type = p.type;
return ghoul::mm_unique_ptr<TimeFrame>(result);
}

View File

@@ -59,6 +59,7 @@ ghoul::mm_unique_ptr<Translation> Translation::createFromDictionary(
dictionary,
&global::memoryManager->PersistentMemory
);
result->_type = p.type;
return ghoul::mm_unique_ptr<Translation>(result);
}

View File

@@ -39,7 +39,6 @@
#include <ghoul/ext/assimp/contrib/zip/src/zip.h>
#include <filesystem>
#include <fstream>
#include "scriptengine_lua.inl"
namespace {
@@ -82,85 +81,50 @@ namespace {
return result;
}
void toJson(const openspace::scripting::LuaLibrary& library, std::stringstream& json)
{
constexpr std::string_view replStr = R"("{}": "{}", )";
constexpr std::string_view replStr2 = R"("{}": "{}")";
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json toJson(const openspace::scripting::LuaLibrary::Function& f) {
using namespace openspace;
using namespace openspace::scripting;
nlohmann::json function;
function["Name"] = f.name;
nlohmann::json arguments = nlohmann::json::array();
json << "{";
json << fmt::format(replStr, "library", library.name);
json << "\"functions\": [";
for (const LuaLibrary::Function& f : library.functions) {
json << "{";
json << fmt::format(replStr, "name", f.name);
json << "\"arguments\": [";
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
json << "{";
json << fmt::format(replStr, "name", escapedJson(arg.name));
json << fmt::format(replStr, "type", escapedJson(arg.type));
json << fmt::format(
replStr2, "defaultValue", escapedJson(arg.defaultValue.value_or(""))
);
json << "}";
if (&arg != &f.arguments.back()) {
json << ",";
}
}
json << "],";
json << fmt::format(replStr, "returnType", escapedJson(f.returnType));
json << fmt::format(replStr, "help", escapedJson(f.helpText));
json << fmt::format(
"\"sourceLocation\": {{ \"file\": \"{}\", \"line\": {} }}",
escapedJson(f.sourceLocation.file), f.sourceLocation.line
);
json << "}";
if (&f != &library.functions.back() || !library.documentations.empty()) {
json << ",";
}
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
nlohmann::json argument;
argument["Name"] = arg.name;
argument["Type"] = arg.type;
argument["Default Value"] = arg.defaultValue.value_or("");
arguments.push_back(argument);
}
function["Arguments"] = arguments;
function["Return Type"] = f.returnType;
function["Help"] = f.helpText;
for (const LuaLibrary::Function& f : library.documentations) {
json << "{";
json << fmt::format(replStr, "name", f.name);
json << "\"arguments\": [";
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
json << "{";
json << fmt::format(replStr, "name", escapedJson(arg.name));
json << fmt::format(replStr, "type", escapedJson(arg.type));
json << fmt::format(
replStr2, "defaultValue", escapedJson(arg.defaultValue.value_or(""))
);
json << "}";
if (&arg != &f.arguments.back()) {
json << ",";
}
}
json << "],";
json << fmt::format(replStr, "returnType", escapedJson(f.returnType));
json << fmt::format(replStr2, "help", escapedJson(f.helpText));
json << "}";
if (&f != &library.documentations.back()) {
json << ",";
}
}
json << "],";
json << "\"subLibraries\": [";
for (const LuaLibrary& sl : library.subLibraries) {
toJson(sl, json);
if (&sl != &library.subLibraries.back()) {
json << ",";
}
}
json << "]}";
return function;
}
#include "scriptengine_codegen.cpp"
@@ -510,24 +474,35 @@ std::vector<std::string> ScriptEngine::allLuaFunctions() const {
}
std::string ScriptEngine::generateJson() const {
ZoneScoped;
return "";
}
// Create JSON
std::stringstream json;
json << "[";
nlohmann::json ScriptEngine::generateJsonJson() const {
ZoneScoped
nlohmann::json json;
bool first = true;
for (const LuaLibrary& l : _registeredLibraries) {
if (!first) {
json << ",";
using namespace openspace;
using namespace openspace::scripting;
nlohmann::json library;
std::string libraryName = l.name.empty() ? "openspace" : "openspace." + l.name;
library["Name"] = libraryName;
for (const LuaLibrary::Function& f : l.functions) {
library["Functions"].push_back(toJson(f));
}
first = false;
toJson(l, json);
for (const LuaLibrary::Function& f : l.documentations) {
library["Functions"].push_back(toJson(f));
}
sortJson(library["Functions"]);
json.push_back(library);
sortJson(json);
}
json << "]";
return json.str();
return json;
}
void ScriptEngine::writeLog(const std::string& script) {

View File

@@ -24,6 +24,9 @@
#include <openspace/util/factorymanager.h>
#include <openspace/documentation/documentationengine.h>
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <openspace/rendering/dashboarditem.h>
#include <openspace/rendering/renderable.h>
#include <openspace/scene/lightsource.h>
@@ -35,6 +38,87 @@
#include <openspace/util/task.h>
#include <sstream>
namespace {
using namespace openspace;
using namespace openspace::documentation;
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json generateJsonDocumentation(const Documentation& d) {
nlohmann::json json;
json["Name"] = d.name;
json["Identifier"] = d.id;
json["Members"] = nlohmann::json::array();
for (const DocumentationEntry& p : d.entries) {
nlohmann::json entry;
entry["Name"] = p.key;
entry["Optional"] = p.optional.value;
entry["Type"] = p.verifier->type();
entry["Documentation"] = p.documentation;
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast<ReferencingVerifier*>(p.verifier.get());
if (rv) {
const std::vector<Documentation>& documentations = DocEng.documentations();
auto it = std::find_if(
documentations.begin(),
documentations.end(),
[rv](const Documentation& doc) { return doc.id == rv->identifier; }
);
if (it == documentations.end()) {
entry["Reference"]["Found"] = false;
}
else {
nlohmann::json reference;
reference["Found"] = true;
reference["Name"] = it->name;
reference["Identifier"] = rv->identifier;
entry["Reference"] = reference;
}
}
else if (tv) {
nlohmann::json json = generateJsonDocumentation(tv->documentations);
// We have a TableVerifier, so we need to recurse
entry["Restrictions"] = json;
}
else {
entry["Description"] = p.verifier->documentation();
}
json["Members"].push_back(entry);
}
sortJson(json["Members"]);
return json;
}
}
namespace openspace {
FactoryManager* FactoryManager::_manager = nullptr;
@@ -89,33 +173,90 @@ FactoryManager& FactoryManager::ref() {
}
std::string FactoryManager::generateJson() const {
std::stringstream json;
nlohmann::json json;
json << "[";
for (const FactoryInfo& factoryInfo : _factories) {
json << "{";
json << "\"name\": \"" << factoryInfo.name << "\",";
json << "\"classes\": [";
nlohmann::json factory;
factory["Name"] = factoryInfo.name;
ghoul::TemplateFactoryBase* f = factoryInfo.factory.get();
const std::vector<std::string>& registeredClasses = f->registeredClasses();
for (const std::string& c : registeredClasses) {
json << "\"" << c << "\"";
if (&c != &registeredClasses.back()) {
json << ",";
}
}
json << "]}";
if (&factoryInfo != &_factories.back()) {
json << ",";
json["Classes"].push_back(c);
}
json["Data"].push_back(factory);
}
json << "]";
return json.dump();
}
nlohmann::json FactoryManager::generateJsonJson() const {
nlohmann::json json;
std::vector<Documentation> docs = DocEng.documentations();
for (const FactoryInfo& factoryInfo : _factories) {
nlohmann::json factory;
factory["Name"] = factoryInfo.name;
factory["Identifier"] = "category" + factoryInfo.name;
ghoul::TemplateFactoryBase* f = factoryInfo.factory.get();
// Add documentation about base class
auto factoryDoc = std::find_if(
docs.begin(),
docs.end(),
[&factoryInfo](const Documentation& d) {
return d.name == factoryInfo.name;
});
if (factoryDoc != docs.end()) {
nlohmann::json documentation = generateJsonDocumentation(*factoryDoc);
factory["Classes"].push_back(documentation);
// Remove documentation from list check at the end if all docs got put in
docs.erase(factoryDoc);
}
else {
nlohmann::json documentation;
documentation["Name"] = factoryInfo.name;
documentation["Identifier"] = factoryInfo.name;
factory["Classes"].push_back(documentation);
}
// Add documentation about derived classes
const std::vector<std::string>& registeredClasses = f->registeredClasses();
for (const std::string& c : registeredClasses) {
auto found = std::find_if(
docs.begin(),
docs.end(),
[&c](const Documentation& d) {
return d.name == c;
});
if (found != docs.end()) {
nlohmann::json documentation = generateJsonDocumentation(*found);
factory["Classes"].push_back(documentation);
docs.erase(found);
}
else {
nlohmann::json documentation;
documentation["Name"] = c;
documentation["Identifier"] = c;
factory["Classes"].push_back(documentation);
}
}
sortJson(factory["Classes"]);
json.push_back(factory);
}
// Add all leftover docs
nlohmann::json leftovers;
leftovers["Name"] = "Other";
leftovers["Identifier"] = "other";
for (const Documentation& doc : docs) {
leftovers["Classes"].push_back(generateJsonDocumentation(doc));
}
sortJson(leftovers["Classes"]);
json.push_back(leftovers);
sortJson(json);
// I did not check the output of this for correctness ---abock
return json.str();
return json;
}
} // namespace openspace