From 186db21a3de70806bfb2615d882ee81bdb17139b Mon Sep 17 00:00:00 2001 From: alandefreitas Date: Thu, 30 Nov 2023 21:33:06 -0300 Subject: [PATCH] feat: template context includes config --- include/mrdocs/Config.hpp | 14 ++++-- src/lib/Gen/adoc/Builder.cpp | 98 ++++++++++++++++++++++++++++++++++++ src/lib/Lib/ConfigImpl.cpp | 38 +++++++++----- src/lib/Lib/ConfigImpl.hpp | 79 ++++++++++++++--------------- 4 files changed, 172 insertions(+), 57 deletions(-) diff --git a/include/mrdocs/Config.hpp b/include/mrdocs/Config.hpp index 3bd5aa9a8..0ea57aaa1 100644 --- a/include/mrdocs/Config.hpp +++ b/include/mrdocs/Config.hpp @@ -34,6 +34,10 @@ class ThreadPool; A configuration is always connected to a particular directory from which absolute paths are calculated from relative paths. + + The Config class is an abstract interface + whose concrete implementation includes + . */ class MRDOCS_DECL Config @@ -42,7 +46,8 @@ class MRDOCS_DECL Config() noexcept; public: - + /** Settings values used to generate the Corpus and Docs + */ struct Settings { /** Selected documentation generator. @@ -115,13 +120,16 @@ class MRDOCS_DECL ThreadPool& threadPool() const noexcept = 0; + /** Return the settings used to generate the Corpus and Docs. + */ + virtual Settings const& settings() const noexcept = 0; + + /// @copydoc settings() constexpr Settings const* operator->() const noexcept { return &settings(); } - - virtual Settings const& settings() const noexcept = 0; }; } // mrdocs diff --git a/src/lib/Gen/adoc/Builder.cpp b/src/lib/Gen/adoc/Builder.cpp index a4d17798f..f544b0de8 100644 --- a/src/lib/Gen/adoc/Builder.cpp +++ b/src/lib/Gen/adoc/Builder.cpp @@ -10,6 +10,7 @@ #include "Builder.hpp" #include "lib/Support/Radix.hpp" +#include #include #include #include @@ -178,6 +179,101 @@ getRelPrefix(std::size_t depth) return rel_prefix; } +class ConfigObjectImpl : public dom::ObjectImpl +{ + Config const* config_; + +public: + ~ConfigObjectImpl() override = default; + + ConfigObjectImpl(Config const& config) + : config_(&config) + {} + + char const* type_key() const noexcept override + { + return "ConfigObject"; + } + + dom::Value get(std::string_view key) const override + { + if (key == "multiPage") return (*config_)->multiPage; + if (key == "generate") return (*config_)->generate; + if (key == "workingDir") return (*config_)->workingDir; + auto* config_impl = dynamic_cast(config_); + if (config_impl) + { + if (key == "inaccessibleBases") return (*config_impl)->inaccessibleBases; + if (key == "inaccessibleMembers") return (*config_impl)->inaccessibleMembers; + if (key == "anonymousNamespaces") return (*config_impl)->anonymousNamespaces; + if (key == "ignoreFailures") return (*config_impl)->ignoreFailures; + if (key == "defines") { + dom::Array defines; + for (auto& define: (*config_impl)->defines) + { + defines.emplace_back(define); + } + return defines; + } + } + return {}; + } + + void set(dom::String key, dom::Value value) override + { + // Cannot set values in the config object from templates + } + + bool + visit(std::function fn) const override + { + if (!fn("multiPage", (*config_)->multiPage)) { return false; }; + if (!fn("generate", (*config_)->generate)) { return false; }; + if (!fn("workingDir", (*config_)->workingDir)) { return false; }; + auto* config_impl = dynamic_cast(config_); + if (config_impl) + { + if (!fn("inaccessibleBases", (*config_impl)->inaccessibleBases)) { return false; }; + if (!fn("inaccessibleMembers", (*config_impl)->inaccessibleMembers)) { return false; }; + if (!fn("anonymousNamespaces", (*config_impl)->anonymousNamespaces)) { return false; }; + if (!fn("ignoreFailures", (*config_impl)->ignoreFailures)) { return false; }; + dom::Array defines; + for (auto& define: (*config_impl)->defines) + { + defines.emplace_back(define); + } + if (!fn("defines", defines)) { return false; }; + } + return true; + } + + /** Return the number of properties in the object. + */ + std::size_t size() const override { + return 8; + }; + + /** Determine if a key exists. + */ + bool exists(std::string_view key) const override + { + if (key == "multiPage") return true; + if (key == "generate") return true; + if (key == "workingDir") return true; + auto* config_impl = dynamic_cast(config_); + if (config_impl) + { + if (key == "inaccessibleBases") return true; + if (key == "inaccessibleMembers") return true; + if (key == "anonymousNamespaces") return true; + if (key == "ignoreFailures") return true; + if (key == "defines") return true; + } + return false; + } +}; + + dom::Value Builder:: createContext( @@ -188,6 +284,8 @@ createContext( domCorpus.get(I.id)); props.emplace_back("relfileprefix", getRelPrefix(I.Namespace.size())); + props.emplace_back("config", + dom::newObject(domCorpus->config)); return dom::Object(std::move(props)); } diff --git a/src/lib/Lib/ConfigImpl.cpp b/src/lib/Lib/ConfigImpl.cpp index 17f0383fb..997ce20b2 100644 --- a/src/lib/Lib/ConfigImpl.cpp +++ b/src/lib/Lib/ConfigImpl.cpp @@ -156,8 +156,11 @@ ConfigImpl( namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; - if(! files::isAbsolute(workingDir)) + // Check working dir + if (!files::isAbsolute(workingDir)) + { formatError("working path \"{}\" is not absolute", workingDir).Throw(); + } settings_.workingDir = files::makeDirsy(files::normalizePath(workingDir)); // Addons directory @@ -167,14 +170,17 @@ ConfigImpl( MRDOCS_ASSERT(files::isDirsy(settings_.addonsDir)); } + // Config strings settings_.configYaml = configYaml; settings_.extraYaml = extraYaml; // Parse the YAML strings YamlReporter reporter; { - llvm::yaml::Input yin(settings_.configYaml, - &reporter, reporter); + llvm::yaml::Input yin( + settings_.configYaml, + &reporter, + reporter); yin.setAllowUnknownKeys(true); yin >> settings_; Error(yin.error()).maybeThrow(); @@ -187,20 +193,26 @@ ConfigImpl( Error(yin.error()).maybeThrow(); } - // This has to be forward slash style + // Source root has to be forward slash style settings_.sourceRoot = files::makePosixStyle(files::makeDirsy( files::makeAbsolute(settings_.sourceRoot, settings_.workingDir))); - // adjust input files + // Adjust input files for(auto& name : inputFileIncludes_) + { name = files::makePosixStyle( files::makeAbsolute(name, settings_.workingDir)); + } - // Parse the symbol filters + // Parse the filters for(std::string_view pattern : settings_.filters.symbols.exclude) + { parseSymbolFilter(settings_.symbolFilter, pattern, true); + } for(std::string_view pattern : settings_.filters.symbols.include) + { parseSymbolFilter(settings_.symbolFilter, pattern, false); + } settings_.symbolFilter.finalize(false, false, false); } @@ -277,16 +289,16 @@ loadConfig( namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; - auto temp = files::normalizePath(filePath); + std::string normFilePath = files::normalizePath(filePath); - // load the config file into a string - MRDOCS_TRY(auto absPath, files::makeAbsolute(temp)); - MRDOCS_TRY(auto configYaml, files::getFileText(absPath)); + // Load the config file into a string + MRDOCS_TRY(auto absConfigPath, files::makeAbsolute(normFilePath)); + MRDOCS_TRY(auto configYaml, files::getFileText(absConfigPath)); - // calculate the working directory - auto workingDir = files::getParentDir(absPath); + // Calculate the working directory + auto workingDir = files::getParentDir(absConfigPath); - // attempt to create the config + // Attempt to create the config try { return std::make_shared( diff --git a/src/lib/Lib/ConfigImpl.hpp b/src/lib/Lib/ConfigImpl.hpp index 5d81ae800..9d2e23c85 100644 --- a/src/lib/Lib/ConfigImpl.hpp +++ b/src/lib/Lib/ConfigImpl.hpp @@ -31,26 +31,18 @@ class ConfigImpl public: struct SettingsImpl : Settings { - struct FileFilter - { - std::vector include; - }; + /** Extraction policy for declarations. - struct Filters - { - struct Category - { - std::vector include; - std::vector exclude; - }; - - Category symbols; - }; + This determines how declarations are extracted. + */ enum class ExtractPolicy { + /// Always extract the declaration. Always, + /// Extract the declaration if it is referenced. Dependency, + /// Never extract the declaration. Never }; @@ -58,40 +50,19 @@ class ConfigImpl This determines how declarations which are referenced by explicitly extracted declarations are extracted. - - Given a function parameter of type `std::string`, `std::string` - would be extracted if this option is set to `Policy::Always`. - */ + */ ExtractPolicy referencedDeclarations = ExtractPolicy::Dependency; /** Extraction policy for anonymous namespace. - - @li `ExtractPolicy::Always`: anonymous namespaces and their - members will always be extracted. - - @li `ExtractPolicy::Dependency`: members of anonymous namespaces will only - be extracted via dependency. - - @li `ExtractPolicy::Never`: members of anonymous namespace will - never be extracted, regardless of how they are referenced. - */ + */ ExtractPolicy anonymousNamespaces = ExtractPolicy::Always; /** Extraction policy for inaccessible members. - - @li `ExtractPolicy::Always`: all `private` and `protected` members - will be extracted. - - @li `ExtractPolicy::Dependency`: `private` and `protected` members will only - be extracted via dependency. - - @li `ExtractPolicy::Never`: `private` and `protected` will never be extracted. - */ + */ ExtractPolicy inaccessibleMembers = ExtractPolicy::Always; ExtractPolicy inaccessibleBases = ExtractPolicy::Always; - /** Additional defines passed to the compiler. */ std::vector defines; @@ -111,8 +82,34 @@ class ConfigImpl */ std::string sourceRoot; + /** Specifies files that should be filtered + */ + struct FileFilter + { + /// Directories to include + std::vector include; + }; + + /// @copydoc FileFilter FileFilter input; + /** Specifies filters for various kinds of symbols. + */ + struct Filters + { + /** Specifies inclusion and exclusion patterns + */ + struct Category + { + std::vector include; + std::vector exclude; + }; + + /// Specifies filter patterns for symbols + Category symbols; + }; + + /// @copydoc Filters Filters filters; /** Symbol filter root node. @@ -125,20 +122,20 @@ class ConfigImpl }; + /// @copydoc Config::settings() Settings const& - settings()const noexcept override + settings() const noexcept override { return settings_; } + /// @copydoc Config::settings() constexpr SettingsImpl const* operator->() const noexcept { return &settings_; } - //-------------------------------------------- - private: SettingsImpl settings_; ThreadPool& threadPool_;