diff options
author | Aqua-sama <aqua@iserlohn-fortress.net> | 2019-11-09 21:05:07 +0200 |
---|---|---|
committer | Aqua-sama <aqua@iserlohn-fortress.net> | 2019-11-09 21:05:07 +0200 |
commit | eb311838538b80fb3280aa9ab5b57abc22925926 (patch) | |
tree | 71a705fb9594fd4b169aea175047f91287b1ba18 | |
parent | Fix manpages not disabled when disabled by meson (diff) | |
download | smolbote-eb311838538b80fb3280aa9ab5b57abc22925926.tar.xz |
Add configuration subcommand
--dump: Write current configuration to stdout and exit
-rw-r--r-- | lib/configuration/configuration.cpp | 44 | ||||
-rw-r--r-- | lib/configuration/configuration.h | 51 | ||||
-rw-r--r-- | meson.build | 3 | ||||
-rw-r--r-- | src/builtins.cpp | 41 | ||||
-rw-r--r-- | src/builtins.h | 7 | ||||
-rw-r--r-- | src/main.cpp | 61 |
6 files changed, 139 insertions, 68 deletions
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp index bd7700c..34e84af 100644 --- a/lib/configuration/configuration.cpp +++ b/lib/configuration/configuration.cpp @@ -7,11 +7,11 @@ */ #include "configuration.h" -#include <sstream> +#include <QStandardPaths> #include <algorithm> -#include <stdexcept> #include <iostream> -#include <QStandardPaths> +#include <sstream> +#include <stdexcept> static std::unique_ptr<Configuration> s_conf; @@ -21,7 +21,6 @@ inline void strip(std::string &value) value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end()); } - Configuration::Configuration() : use_global(true) { @@ -32,9 +31,9 @@ Configuration::Configuration() Configuration::Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept : m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()) { - for(const auto &i : l) { - insert_or_assign(i.first, i.second); - } + for(const auto &i : l) { + insert_or_assign(i.first, i.second); + } } void Configuration::read(std::basic_istream<char> &input) @@ -69,18 +68,16 @@ void Configuration::read(std::basic_istream<char> &input) } else if(std::holds_alternative<bool>(v)) { at(key) = (value == "true"); } - } } } - void Configuration::move_global(std::unique_ptr<Configuration> &&conf) { s_conf = std::move(conf); } -Configuration* Configuration::instance() +Configuration *Configuration::instance() { return s_conf.get(); } @@ -101,3 +98,30 @@ void setShortcut(QAction *action, const char *name) } #endif } + +std::ostream &operator<<(std::ostream &out, const Configuration &obj) +{ + // unordered_map is, well, unordered, so grab the keys and sort them before printing them + std::vector<std::string> keys; + + if(obj.use_global) { + if(!s_conf) + throw new std::runtime_error("Trying to use default Configuration, but none has been set!"); + + for(const auto &pair : *s_conf) + keys.emplace_back(pair.first); + } else { + for(const auto &pair : obj) + out << pair.first << "\n"; + } + std::sort(keys.begin(), keys.end()); + + for(const auto &key : keys) { + if(obj.use_global) + out << key << "=" << s_conf->value<std::string>(key.c_str()).value() << "\n"; + else + out << key << "=" << obj.value<std::string>(key.c_str()).value() << "\n"; + } + + return out; +} diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index b77685a..4459dd0 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -9,21 +9,21 @@ #ifndef SMOLBOTE_CONFIGURATION_H #define SMOLBOTE_CONFIGURATION_H +#include <QAction> +#include <QString> +#include <initializer_list> +#include <memory> #include <optional> #include <string> -#include <vector> #include <unordered_map> #include <variant> -#include <initializer_list> -#include <memory> -#include <QAction> -#include <QString> +#include <vector> -#if defined (__clang__) -#define consumable(X) [[clang::consumable(X)]] -#define return_typestate(X) [[clang::return_typestate(X)]] -#define callable_when(X) [[clang::callable_when(X)]] -#define param_typestate(X) [[clang::param_typestate(X)]] +#if defined(__clang__) +#define consumable(X) [[clang::consumable(X)]] +#define return_typestate(X) [[clang::return_typestate(X)]] +#define callable_when(X) [[clang::callable_when(X)]] +#define param_typestate(X) [[clang::param_typestate(X)]] #else #define consumable(X) #define return_typestate(X) @@ -35,27 +35,25 @@ typedef std::variant<std::string, int, bool> conf_value_t; class consumable(unconsumed) Configuration : private std::unordered_map<std::string, conf_value_t> { + friend std::ostream &operator<<(std::ostream &out, const Configuration &obj); public: - return_typestate(unconsumed) - explicit Configuration(); + return_typestate(unconsumed) explicit Configuration(); - return_typestate(unconsumed) - explicit Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept; + return_typestate(unconsumed) explicit Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept; - explicit Configuration(Configuration &&other param_typestate(unconsumed)) = default; + explicit Configuration(Configuration && other param_typestate(unconsumed)) = default; ~Configuration() = default; - callable_when(unconsumed) - void read(std::basic_istream<char> &input); + callable_when(unconsumed) void read(std::basic_istream<char> & input); template <typename T> callable_when(unconsumed) std::optional<T> value(const char *path) const { if(use_global) return instance()->value<T>(path); - + if(this->count(path) == 0) { return std::nullopt; } @@ -64,7 +62,15 @@ public: const auto value = at(path); if constexpr(std::is_same_v<T, QString> || std::is_same_v<T, std::string>) { - auto r = std::get<std::string>(value); + auto r = [&value]() { + if(std::holds_alternative<std::string>(value)) + return std::get<std::string>(value); + else if(std::holds_alternative<int>(value)) + return std::to_string(std::get<int>(value)); + else + return std::get<bool>(value) ? std::string("true") : std::string("false"); + }(); + if(r.front() == '~') r.replace(0, 1, m_homePath); @@ -76,14 +82,14 @@ public: } else if constexpr(std::is_same_v<T, QStringList>) { return std::make_optional(QString::fromStdString(std::get<std::string>(value)).split(';')); - } else if (std::holds_alternative<T>(value)) { + } else if(std::holds_alternative<T>(value)) { return std::optional<T>(std::get<T>(value)); } else return std::nullopt; - + } // std::optional<T> value(path) const - static void move_global(std::unique_ptr<Configuration> &&conf); + static void move_global(std::unique_ptr<Configuration> && conf); private: static Configuration *instance(); @@ -93,5 +99,6 @@ private: }; void setShortcut(QAction *action, const char *name); +std::ostream &operator<<(std::ostream &out, const Configuration &obj); #endif // SMOLBOTE_CONFIGURATION_H diff --git a/meson.build b/meson.build index 50e239d..35541c5 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,8 @@ add_project_arguments(cxx.get_supported_arguments([ '-mspeculative-load-hardening', # Spectre v1 mitigation - '-Wconsumed', + '-Wconsumed', # (clang) use-after-move warnings + '-Wdate-time', # Warn when using __TIME__ and __DATE__ macros '-Wimplicit-fallthrough', ]), language: 'cpp') diff --git a/src/builtins.cpp b/src/builtins.cpp index 1af2dc8..ab5942c 100644 --- a/src/builtins.cpp +++ b/src/builtins.cpp @@ -7,20 +7,11 @@ */ #include "builtins.h" +#include "configuration.h" +#include "version.h" #include <QObject> #include <QVersionNumber> #include <iostream> -#include "version.h" -#include <QTranslator> - -inline const char* tr(const QTranslator *translator, const char *text) -{ - const auto t = translator->translate("builtins", text); - if(t.isEmpty()) - return text; - else - return qUtf8Printable(t); -} int builtins::version() { @@ -34,3 +25,31 @@ int builtins::build() std::cout << poi_Version << std::endl; return 0; } + +int builtins::configuration(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs) +{ + args::ArgumentParser parser("configuration"); + parser.Prog(progname); + + args::HelpFlag help(parser, "help", "Display this help message and exit.", { 'h', "help" }); + args::Flag dump(parser, "dump", "Dump currently used configuration and exit", { "dump" }); + + try { + parser.ParseArgs(beginargs, endargs); + } catch(args::Help &e) { + std::cout << parser; + return 0; + } catch(args::Error &e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return -1; + } + + if(dump) { + Configuration conf; + std::cout << conf << std::endl; + return 0; + } + + return 0; +} diff --git a/src/builtins.h b/src/builtins.h index a3b9b07..088aa23 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -9,13 +9,18 @@ #ifndef SMOLBOTE_BUILTINS_H #define SMOLBOTE_BUILTINS_H -#include <boost/program_options.hpp> +#include <args.hxx> #include <plugininterface.h> +typedef std::function<int(const std::string &, std::vector<std::string>::const_iterator, std::vector<std::string>::const_iterator)> subcommand_func; +typedef std::unordered_map<std::string, subcommand_func> command_map; + namespace builtins { int version(); int build(); + +int configuration(const std::string &progname, std::vector<std::string>::const_iterator beginargs, std::vector<std::string>::const_iterator endargs); } #endif diff --git a/src/main.cpp b/src/main.cpp index 4d4fa8d..7889c08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,16 +18,12 @@ #include <QFile> #include <QPluginLoader> #include <QStandardPaths> -#include <args.hxx> #include <iostream> #include <memory> #include <plugininterface.h> #include <pluginloader.h> #include <spdlog/spdlog.h> -typedef std::function<void(const std::string &, std::vector<std::string>::const_iterator, std::vector<std::string>::const_iterator)> subcommand_func; -typedef std::unordered_map<std::string, subcommand_func> command_map; - // a helper function to join the keys of a command_map into a string inline std::string join_keys(const command_map &map, const std::string sep = ", ") { @@ -59,9 +55,19 @@ int main(int argc, char **argv) #endif const std::vector<std::string> args(argv + 1, argv + argc); - args::ArgumentParser parser("smolbote: yet another no-frills browser", "For more information on usage, refer to the manual page."); + args::ArgumentParser parser("smolbote: yet another no-frills browser", +#ifdef Q_OS_UNIX + "For more information on usage, refer to the manual page." +#else + "For more information on usage, refer to the manual." +#endif + ); parser.Prog(argv[0]); + const command_map commands{ + { "configuration", builtins::configuration } + }; + args::HelpFlag cmd_help(parser, "help", "Display this help message.", { 'h', "help" }); args::Flag cmd_version(parser, "version", "Display version information.", { 'v', "version" }); args::Flag cmd_build(parser, "build", "Display build commit.", { 'b', "build" }); @@ -74,19 +80,44 @@ int main(int argc, char **argv) args::ValueFlag<std::string> cmd_session(parser, "session", "Open the specified session.", { 's', "session" }); args::PositionalList<std::string> cmd_args(parser, "URL(s)", "List of URLs to open"); + cmd_args.KickOut(true); try { - /*auto next = */ parser.ParseArgs(args); + auto next = parser.ParseArgs(args); if(cmd_version) return builtins::version(); if(cmd_build) return builtins::build(); + // create and load configuration + const std::string config_path = [&]() { + std::string path; + if(cmd_config) + path = args::get(cmd_config); + else + path = std::string(CONFIG_POI_CFG_PATH); + + if(path.front() == '~') + path.replace(0, 1, QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()); + + return path; + }(); + spdlog::debug("Opening config file {}", config_path); + init_conf(config_path); + + if(cmd_args) { + const auto front = args::get(cmd_args).front(); + const auto cmd = commands.find(front); + if(cmd != commands.end()) { + return cmd->second(argv[0], next, std::end(args)); + } + } + } catch(args::Help &e) { std::cout << parser; Q_UNUSED(e); - //std::cout << "Available subcommands: " << command_keys << std::endl; + std::cout << "Available subcommands: " << join_keys(commands) << std::endl; return 0; } catch(args::Error &e) { @@ -102,22 +133,6 @@ int main(int argc, char **argv) qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromiumFlags + " --disable-in-process-stack-traces"); } - // create and load configuration - const std::string config_path = [&]() { - std::string path; - if(cmd_config) - path = args::get(cmd_config); - else - path = std::string(CONFIG_POI_CFG_PATH); - - if(path.front() == '~') - path.replace(0, 1, QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString()); - - return path; - }(); - spdlog::debug("Opening config file {}", config_path); - init_conf(config_path); - QVector<QPluginLoader *> plugins; CommandHash_t pluginCommands; |