aboutsummaryrefslogtreecommitdiff
path: root/lib/configuration
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2019-11-03 00:18:10 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2019-11-03 00:20:41 +0200
commitf3a4607d6a722a862af0eb9747a15dcdf624b6fb (patch)
tree9885709cdff55a865be6c03c591a9757680b0396 /lib/configuration
parentChange spdlog from makedepends to depends (diff)
downloadsmolbote-f3a4607d6a722a862af0eb9747a15dcdf624b6fb.tar.xz
Drop boost dependency
- wrote not-invented-here config file parser and conf class - spent obscene amount of time plugging in said conf class
Diffstat (limited to 'lib/configuration')
-rw-r--r--lib/configuration/Kconfig131
-rw-r--r--lib/configuration/configuration.cpp205
-rw-r--r--lib/configuration/configuration.h136
-rw-r--r--lib/configuration/meson.build14
4 files changed, 127 insertions, 359 deletions
diff --git a/lib/configuration/Kconfig b/lib/configuration/Kconfig
deleted file mode 100644
index b165093..0000000
--- a/lib/configuration/Kconfig
+++ /dev/null
@@ -1,131 +0,0 @@
-menu "Configuration defaults"
- config PATH_CONFIG
- string "Configuration location"
- default "~/.config/smolbote/smolbote.cfg"
- config PATH_FILTER
- string "Host filter path"
- default "~/.config/smolbote/hosts.d"
- config PATH_PLUGINS
- string "Plugin load location"
- default "~/.config/smolbote/plugins.d"
- config PATH_PROFILES
- string "Profile load location"
- default "~/.config/smolbote/profiles.d"
- config PATH_BOOKMARKS
- string "Bookmarks location"
- default "~/.config/smolbote/bookmarks.xbel"
- config PATH_DOWNLOADS
- string "Downloads location"
- default "~/Downloads"
- config PATH_SESSION
- string "Session location"
- default "~/.config/smolbote/session.d"
-endmenu
-
-menu "Keyboard shortcuts"
- comment "Main Window shortcuts"
- config SHORTCUT_WINDOW_NEWGROUP
- string "New Group shortcut"
- default "Ctrl+G"
- config SHORTCUT_WINDOW_NEWWINDOW
- string "New Window shortcut"
- default "Ctrl+N"
- config SHORTCUT_WINDOW_ABOUT
- string "Show About Dialog"
- default "Ctrl+H"
- config SHORTCUT_WINDOW_QUIT
- string "Quit shortcut"
- default "Ctrl+Q"
-
- config SHORTCUT_WINDOW_SEARCH
- string "Show or hide search box"
- default "F3"
-
- config SHORTCUT_WINDOW_BOOKMARKS
- string "Show bookmarks dialog in this window"
- default "Ctrl+B"
- config SHORTCUT_WINDOW_DOWNLOADS
- string "Show downloads dialog in this window"
- default "Ctrl+D"
-
- comment "Navigation Bar shortcuts"
- config SHORTCUT_NAVIGATION_BACK
- string "Go back in history"
- default "Ctrl+Left"
- config SHORTCUT_NAVIGATION_BACKMENU
- string "Show Back history menu"
- default "Ctrl+Down"
- config SHORTCUT_NAVIGATION_FORWARD
- string "Go forward in history"
- default "Ctrl+Right"
- config SHORTCUT_NAVIGATION_FORWARDMENU
- string "Show Forward history menu"
- default "Ctrl+Up"
- config SHORTCUT_NAVIGATION_REFRESH
- string "Refresh the page"
- default "F5"
- config SHORTCUT_NAVIGATION_RELOAD
- string "Reload the page"
- default "Ctrl+F5"
- config SHORTCUT_NAVIGATION_HOME
- string "Load homepage"
- default "Ctrl+Home"
-
- comment "Address Bar shortcuts"
- config SHORTCUT_ADDRESS_FOCUS
- string "Focus the Address Bar"
- default "F4"
- config SHORTCUT_ADDRESS_MENU
- string "Show Address Bar menu"
- default "F2"
-
- comment "Subwindow shortcuts"
- config SHORTCUT_SUBWINDOW_MENU
- string "Subwindow context menu"
- default "F1"
- config SHORTCUT_SUBWINDOW_TILE
- string "Tile subwindows"
- default "F9"
- config SHORTCUT_SUBWINDOW_CASCADE
- string "Cascade subwindow"
- default "F10"
- config SHORTCUT_SUBWINDOW_FULLSCREEN
- string "Make current subwindow fullscreen"
- default "F11"
-
- config SHORTCUT_SUBWINDOW_NEWTAB
- string "Create new tab"
- default "Ctrl+T"
- config SHORTCUT_SUBWINDOW_CLOSETAB
- string "Close current tab"
- default "Ctrl+X"
- config SHORTCUT_SUBWINDOW_TABLEFT
- string "Switch to the tab on the left"
- default "Ctrl+O"
- config SHORTCUT_SUBWINDOW_MOVETABLEFT
- string "Move tab to the left"
- default "Ctrl+Shift+O"
- config SHORTCUT_SUBWINDOW_TABRIGHT
- string "Switch to the tab on the right"
- default "Ctrl+P"
- config SHORTCUT_SUBWINDOW_MOVETABRIGHT
- string "Move tab to the right"
- default "Ctrl+Shift+P"
-
-endmenu
-
-menu "Profile defaults"
- config PROFILE_DEFAULT
- string "Default profile"
- default ""
- config PROFILE_DEFAULT_SEARCH
- string "Search engine"
- default "https://duckduckgo.com/?q=%1&ia=web"
- config PROFILE_DEFAULT_HOMEPAGE
- string "Homepage"
- default "about:blank"
- config PROFILE_DEFAULT_NEWTAB
- string "New tab page"
- default "about:blank"
-endmenu
-
diff --git a/lib/configuration/configuration.cpp b/lib/configuration/configuration.cpp
index 952f4b2..bd7700c 100644
--- a/lib/configuration/configuration.cpp
+++ b/lib/configuration/configuration.cpp
@@ -7,146 +7,97 @@
*/
#include "configuration.h"
-#include <QStandardPaths>
-#include <fstream>
-#include <boost/algorithm/string/predicate.hpp>
+#include <sstream>
+#include <algorithm>
+#include <stdexcept>
#include <iostream>
-#include <QCoreApplication>
-#include "config.h"
+#include <QStandardPaths>
-namespace po = boost::program_options;
+static std::unique_ptr<Configuration> s_conf;
-inline std::string defaultUserConfigLocation()
+inline void strip(std::string &value)
{
-#ifdef CONFIG_PATH_CONFIG
- return CONFIG_PATH_CONFIG;
-#else
- // try to locate an existing config
- QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg");
+ value.erase(value.begin(), std::find_if(value.begin(), value.end(), std::bind1st(std::not_equal_to<char>(), ' ')));
+ value.erase(std::find_if(value.rbegin(), value.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), value.end());
+}
- // it's possible there is no config, so set the path properly
- if(path.isEmpty())
- path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smolbote/smolbote.cfg";
- return path.toStdString();
-#endif
+Configuration::Configuration()
+ : use_global(true)
+{
+ if(!s_conf)
+ throw new std::runtime_error("Trying to use default Configuration, but none has been set!");
}
-Configuration::Configuration(int argc, char **argv, const std::string &path, QObject *parent)
- : QObject(parent)
- , m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
+Configuration::Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept
+ : m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
{
- configuration_desc.add_options()
- ("browser.stylesheet", po::value<std::string>())
- ("browser.iconTheme", po::value<std::string>(), "Icon theme")
- ("browser.locale", po::value<std::string>(), "Set Qt localization.")
- ("browser.translation", po::value<std::string>(), "Set application localization.")
-
- // sessions
- ("browser.session.path", po::value<std::string>()->default_value(CONFIG_PATH_SESSION))
-
-#ifdef CONFIG_USEBREAKPAD
- ("browser.crash.path", po::value<std::string>()->default_value(CONFIG_PATH_CRASHDUMP))
- ("browser.crash.handler", po::value<std::string>()->default_value(CONFIG_PATH_CRASHHANDLER))
-#endif
-
- // main window ui
- ("mainwindow.height", po::value<int>()->default_value(720))
- ("mainwindow.width", po::value<int>()->default_value(1280))
- ("mainwindow.maximized", po::value<bool>()->default_value(true))
- ("mainwindow.title", po::value<std::string>()->default_value(CONFIG_POI_NAME))
-
- // main window shortcuts
- ("mainwindow.shortcuts.saveSession", po::value<std::string>()->default_value("Ctrl+S,S"))
- ("mainwindow.shortcuts.openSession", po::value<std::string>()->default_value("Ctrl+S,O"))
-
- ("mainwindow.shortcuts.newGroup", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_NEWGROUP))
- ("mainwindow.shortcuts.newWindow", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_NEWWINDOW))
-
- ("mainwindow.shortcuts.about", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_ABOUT))
- ("mainwindow.shortcuts.quit", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_QUIT))
-
- ("mainwindow.shortcuts.search", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_SEARCH))
- ("mainwindow.shortcuts.tileWindows", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TILE))
- ("mainwindow.shortcuts.cascadeWindows", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_CASCADE))
-
- // navigation
- ("navigation.movable", po::value<bool>()->default_value(false))
- ("navigation.shortcuts.back", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_BACK))
- ("navigation.shortcuts.backMenu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_BACKMENU))
- ("navigation.shortcuts.forward", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_FORWARD))
- ("navigation.shortcuts.forwardMenu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_FORWARDMENU))
- ("navigation.shortcuts.refresh", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_REFRESH))
- ("navigation.shortcuts.reload", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_RELOAD))
- ("navigation.shortcuts.home", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_HOME))
-
- // address bar
- ("addressbar.shortcuts.focus", po::value<std::string>()->default_value(CONFIG_SHORTCUT_ADDRESS_FOCUS))
- ("addressbar.shortcuts.menu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_ADDRESS_MENU))
-
- // subwindow
- ("subwindow.shortcuts.menu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MENU))
- ("subwindow.shortcuts.new", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_NEWTAB))
- ("subwindow.shortcuts.close", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_CLOSETAB))
- ("subwindow.shortcuts.restoreTab", po::value<std::string>()->default_value("Ctrl+Shift+T"))
- ("subwindow.shortcuts.left", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TABLEFT))
- ("subwindow.shortcuts.moveLeft", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MOVETABLEFT))
- ("subwindow.shortcuts.right", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TABRIGHT))
- ("subwindow.shortcuts.moveRight", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MOVETABRIGHT))
- ("subwindow.shortcuts.fullscreen", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_FULLSCREEN))
-
- // Filter settings
- ("filter.hosts", po::value<std::string>()->default_value(CONFIG_PATH_FILTER))
- ("filter.adblock", po::value<std::string>())
- ("filter.header", po::value<std::vector<std::string>>())
-// ("filter.cookies.block.all", po::value<bool>()->default_value(false))
-// ("filter.cookies.block.thirdParty", po::value<bool>()->default_value(true))
-// ("filter.cookies.path", po::value<std::string>()->default_value("~/.config/smolbote/cookies.d"))
-
- // Plugin settings
- ("plugins.path", po::value<std::string>()->default_value(CONFIG_PATH_PLUGINS))
-
- // Profile settings
- // default profile name the browser should use; "" is off-the-record
- ("profile.default", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT))
- ("profile.path", po::value<std::string>()->default_value(CONFIG_PATH_PROFILES))
- ("profile.search", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_SEARCH))
- ("profile.homepage", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_HOMEPAGE))
- ("profile.newtab", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_NEWTAB))
-
- // Bookmark settings
- ("bookmarks.path", po::value<std::string>()->default_value(CONFIG_PATH_BOOKMARKS))
- ("bookmarks.shortcut", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_BOOKMARKS))
-
- // Downloads settings
- ("downloads.path", po::value<std::string>()->default_value(CONFIG_PATH_DOWNLOADS))
- ("downloads.shortcut", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_DOWNLOADS))
- ;
-
- // po::store will only overwrite values that are default, so:
- // 1. parse command line
- {
- auto cmd = po::command_line_parser(argc, argv);
- cmd.allow_unregistered();
- cmd.options(configuration_desc);
- po::store(cmd.run(), vm);
- }
- // 2. parse config file
- {
- std::ifstream f(path, std::ifstream::in);
- // parse_config_file(file, options_description, allow_unregistered)
- po::store(po::parse_config_file(f, configuration_desc, true), vm);
- }
+ for(const auto &i : l) {
+ insert_or_assign(i.first, i.second);
+ }
}
-QHash<QString, QString> Configuration::section(const std::string &prefix) const
+void Configuration::read(std::basic_istream<char> &input)
{
- QHash<QString, QString> v;
- for(auto &s : configuration_desc.options()) {
- if(boost::starts_with(s->long_name(), prefix)) {
- v[s->long_name().c_str()] = QString::fromStdString(value<std::string>(s->long_name().c_str()).value());
+ std::string line, key, value;
+ std::istringstream is_line;
+
+ while(std::getline(input, line)) {
+ if(line[0] == '#' || line.length() == 0)
+ continue;
+
+ is_line.clear();
+ is_line.str(line);
+
+ if(std::getline(is_line, key, '=')) {
+ is_line >> value;
+
+ strip(key);
+ strip(value);
+
+ if(this->count(key) == 0) {
+ // no type has been specified for this key, assuming std::string
+ insert(std::make_pair(key, value));
+ continue;
+ }
+
+ auto v = at(key);
+ if(std::holds_alternative<std::string>(v)) {
+ at(key) = value;
+ } else if(std::holds_alternative<int>(v)) {
+ at(key) = std::stoi(value);
+ } else if(std::holds_alternative<bool>(v)) {
+ at(key) = (value == "true");
+ }
+
}
}
+}
+
- return v;
+void Configuration::move_global(std::unique_ptr<Configuration> &&conf)
+{
+ s_conf = std::move(conf);
+}
+
+Configuration* Configuration::instance()
+{
+ return s_conf.get();
+}
+
+void setShortcut(QAction *action, const char *name)
+{
+ if(!s_conf)
+ throw new std::runtime_error("Trying to set a shortcut, but no configuration has been set!");
+
+ if(const auto shortcutText = s_conf->value<QString>(name)) {
+ const QString tooltip = action->toolTip();
+ action->setShortcut(QKeySequence::fromString(shortcutText.value()));
+ action->setToolTip(QString("%1 (%2)").arg(tooltip, shortcutText.value()));
+ }
+#ifdef QT_DEBUG
+ else {
+ std::cout << "fixme: setShortcut called for " << name << ", but no such value exists!" << std::endl;
+ }
+#endif
}
diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h
index 40da50e..bc8f52e 100644
--- a/lib/configuration/configuration.h
+++ b/lib/configuration/configuration.h
@@ -9,121 +9,77 @@
#ifndef SMOLBOTE_CONFIGURATION_H
#define SMOLBOTE_CONFIGURATION_H
-#include <QAction>
-#include <QString>
-#include <QStringList>
-#include <QVariant>
-#include <boost/program_options.hpp>
#include <optional>
#include <string>
#include <vector>
+#include <unordered_map>
+#include <variant>
+#include <initializer_list>
+#include <memory>
+#include <QAction>
+#include <QString>
-class Configuration : public QObject
+typedef std::variant<std::string, int, bool> conf_value_t;
+
+class [[clang::consumable(unconsumed)]] Configuration : private std::unordered_map<std::string, conf_value_t>
{
- Q_OBJECT
public:
- explicit Configuration(int argc, char** argv, const std::string &path, QObject *parent = nullptr);
+ [[clang::return_typestate(unconsumed)]]
+ explicit Configuration();
+
+ [[clang::return_typestate(unconsumed)]]
+ explicit Configuration(std::initializer_list<std::pair<std::string, conf_value_t>> l) noexcept;
+
+ explicit Configuration(Configuration &&other [[clang::param_typestate(unconsumed)]]) = default;
+
~Configuration() = default;
- bool exists(const char *path)
- {
- return vm.count(path) ? true : false;
- }
+ [[clang::callable_when(unconsumed)]]
+ void read(std::basic_istream<char> &input);
template <typename T>
- std::optional<T> value(const char *path) const
+ [[clang::callable_when(unconsumed)]] std::optional<T> value(const char *path) const
{
- // if setting doesn't exist, we crash
- // in debug builds, check if setting exists
-
- if(vm.count(path) == 0) {
+ if(use_global)
+ return instance()->value<T>(path);
+
+ if(this->count(path) == 0) {
return std::nullopt;
}
- // path is guaranteed to exist, so using vm[path] is safe
-
- if constexpr(std::is_same_v<T, QStringList>) {
- QStringList r;
- for(const std::string &item : vm[path].as<std::vector<std::string>>()) {
- r.append(QString::fromStdString(item));
- }
- return std::optional<QStringList>(r);
-
- } else if constexpr(std::is_same_v<T, std::string> || std::is_same_v<T, QString>) {
-
- if(vm[path].value().type() == typeid(int)) {
- if constexpr(std::is_same_v<T, std::string>)
- return std::optional<std::string>(std::to_string(vm[path].as<int>()));
- else if constexpr(std::is_same_v<T, QString>)
- return std::optional<QString>(QString::number(vm[path].as<int>()));
- }
-
- if(vm[path].value().type() == typeid(bool)) {
- return std::optional<T>(vm[path].as<bool>() ? "true" : "false");
- }
-
- std::string r = vm[path].as<std::string>();
+ // path is guaranteed to exist
+ const auto value = at(path);
- // check if it's a path
- if(r.front() == '~') {
+ if constexpr(std::is_same_v<T, QString> || std::is_same_v<T, std::string>) {
+ auto r = std::get<std::string>(value);
+ if(r.front() == '~')
r.replace(0, 1, m_homePath);
- }
- if constexpr(std::is_same_v<T, std::string>)
- return std::optional<std::string>(r);
- else if constexpr(std::is_same_v<T, QString>)
- return std::optional<QString>(QString::fromStdString(r));
+ if constexpr(std::is_same_v<T, QString>)
+ return std::make_optional(QString::fromStdString(r));
+ else
+ return std::make_optional(r);
- } else
- return std::optional<T>(vm[path].as<T>());
- }
-
- template <typename T>
- void setValue(const char *path, const T &value)
- {
- if(vm.count(path) == 0) {
- qWarning("value(%s) does not exist", path);
- }
-
- vm.at(path).value() = value;
-
- emit settingChanged(path, value);
- }
+ } else if constexpr(std::is_same_v<T, QStringList>) {
+ return std::make_optional(QString::fromStdString(std::get<std::string>(value)).split(';'));
- void setShortcut(QAction *action, const char *name) const
- {
- Q_CHECK_PTR(action);
-
- const auto shortcutText = this->value<QString>(name);
- if(shortcutText) {
- const QString tooltip = action->toolTip();
- action->setShortcut(QKeySequence::fromString(shortcutText.value()));
- action->setToolTip(QString("%1 (%2)").arg(tooltip, shortcutText.value()));
-
- connect(this, &Configuration::settingChanged, action, [=](const std::string &path, const QString &value) {
- if(path == name) {
- action->setShortcut(QKeySequence::fromString(value));
- action->setToolTip(QString("%1 (%2)").arg(tooltip, value));
- }
- });
- }
- }
-
- QHash<QString, QString> section(const std::string &prefix) const;
- const boost::program_options::options_description& description() const
- {
- return configuration_desc;
- }
+ } 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
-signals:
- void settingChanged(const std::string &path, const QString &value);
+ static void move_global(std::unique_ptr<Configuration> &&conf);
private:
- boost::program_options::options_description configuration_desc;
- boost::program_options::variables_map vm;
+ static Configuration *instance();
const std::string m_homePath;
+ const bool use_global = false;
};
+void setShortcut(QAction *action, const char *name);
+
#endif // SMOLBOTE_CONFIGURATION_H
diff --git a/lib/configuration/meson.build b/lib/configuration/meson.build
index 19f57f4..939a493 100644
--- a/lib/configuration/meson.build
+++ b/lib/configuration/meson.build
@@ -1,13 +1,5 @@
-configuration_moc = mod_qt5.preprocess(
- moc_headers: ['configuration.h'],
- dependencies: dep_qt5
-)
-
-configuration_lib = static_library('configuration', ['configuration.cpp', configuration_moc],
- dependencies: [dep_boost, dep_qt5, autogen_config]
-)
-
dep_configuration = declare_dependency(
- include_directories: include_directories('.'),
- link_with: configuration_lib
+ include_directories: include_directories('.'),
+ link_with: static_library('configuration', ['configuration.cpp'], dependencies: dep_qt5)
)
+