aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2019-11-09 21:05:07 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2019-11-09 21:05:07 +0200
commiteb311838538b80fb3280aa9ab5b57abc22925926 (patch)
tree71a705fb9594fd4b169aea175047f91287b1ba18
parentFix manpages not disabled when disabled by meson (diff)
downloadsmolbote-eb311838538b80fb3280aa9ab5b57abc22925926.tar.xz
Add configuration subcommand
--dump: Write current configuration to stdout and exit
-rw-r--r--lib/configuration/configuration.cpp44
-rw-r--r--lib/configuration/configuration.h51
-rw-r--r--meson.build3
-rw-r--r--src/builtins.cpp41
-rw-r--r--src/builtins.h7
-rw-r--r--src/main.cpp61
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;