aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/poi.cfg5
-rw-r--r--lib/settings/configuration.cpp177
-rw-r--r--lib/settings/configuration.h97
-rw-r--r--lib/settings/settingsdialog.cpp7
-rw-r--r--src/main.cpp89
5 files changed, 93 insertions, 282 deletions
diff --git a/data/poi.cfg b/data/poi.cfg
index 2cf50d6..f6b2d2c 100644
--- a/data/poi.cfg
+++ b/data/poi.cfg
@@ -4,9 +4,6 @@
// Browser default settings
browser = {
- // true to generate user settings when run
- firstRun = true;
-
// default profile name the browser should use; "" is off-the-record
profile = "";
@@ -62,7 +59,7 @@ plugins = {
// Profile settings
profile = {
- path = "~/.config/smolbote/Profiles";
+ path = "~/.config/smolbote/profiles.d";
search = "https://duckduckgo.com/?q=$term&ia=web"
homepage = "about:blank";
newtab = "about:blank";
diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp
index 64e8b38..10c284c 100644
--- a/lib/settings/configuration.cpp
+++ b/lib/settings/configuration.cpp
@@ -8,6 +8,7 @@
#include "configuration.h"
#include <QtCore/QStandardPaths>
+#include <QFile>
#include <sstream>
using namespace libconfig;
@@ -16,40 +17,36 @@ Configuration::Configuration(const std::string &path, const std::string &home)
{
m_userCfg = new Config();
// prettier output
- m_userCfg->setOptions(Config::OptionSemicolonSeparators | Config::OptionOpenBraceOnSeparateLine);
+ m_userCfg->setOption(Config::OptionSemicolonSeparators, true);
+ m_userCfg->setOption(Config::OptionColonAssignmentForGroups, false);
+ m_userCfg->setOption(Config::OptionColonAssignmentForNonGroups, false);
+ m_userCfg->setOption(Config::OptionOpenBraceOnSeparateLine, false);
m_userCfg->setOption(Config::OptionFsync, true);
m_userCfgPath = path;
m_homePath = home;
-
- m_defaultCfg = new Config();
}
Configuration::~Configuration()
{
delete m_userCfg;
- delete m_defaultCfg;
}
-bool Configuration::read()
+bool Configuration::read(const QString &path)
{
- try {
- m_userCfg->readFile(m_userCfgPath.c_str());
- } catch(const FileIOException &e) {
- return false;
- } catch(const ParseException &e) {
+ QFile conf(path);
+
+ if(!conf.open(QIODevice::ReadOnly)) {
return false;
}
- return true;
-}
-bool Configuration::parse(const std::string &contents)
-{
try {
- m_userCfg->readString(contents);
+ m_userCfg->readString(conf.readAll().toStdString());
+ conf.close();
} catch(const ParseException &e) {
return false;
}
+
return true;
}
@@ -71,16 +68,6 @@ bool Configuration::writeIfNeeded(const std::string &path)
return true;
}
-bool Configuration::parseDefaultConfiguration(const std::string &contents)
-{
- try {
- m_defaultCfg->readString(contents);
- } catch(const ParseException &e) {
- return false;
- }
- return true;
-}
-
std::vector<std::string> Configuration::childrenSettings(const char *name)
{
std::vector<std::string> groupNames;
@@ -110,77 +97,6 @@ std::vector<std::string> Configuration::childrenGroups(const char *name)
return groupNames;
}
-void Configuration::resetValue(const char *path)
-{
- if(!m_userCfg->exists(path) && m_defaultCfg->exists(path)) {
- // entry doesn't exist, create path to it
- // split path into array of items, sep=.
- std::string s(path);
- std::vector<std::string> pathTokens;
- std::string::size_type prev_pos = 0, pos = 0;
- while((pos = s.find('.', pos)) != std::string::npos) {
- std::string substring(s.substr(prev_pos, pos - prev_pos));
- pathTokens.push_back(substring);
- prev_pos = ++pos;
- }
- pathTokens.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
-
- s.clear();
- // iterate through items, creating the path along the way
- for(const std::string &t : pathTokens) {
- Setting &v = m_userCfg->lookup(s);
- Setting &d = m_defaultCfg->lookup(s).lookup(t);
-
- if(!v.exists(t)) {
- v.add(t, d.getType());
- }
-
- if(s.empty())
- s.append(t);
- else
- s.append('.' + t);
- }
- }
-
- // if the path doesn't exist in the defaultCfg, this will crash
-
- // entry exists, reset it
- Setting &v = m_userCfg->lookup(path);
- switch(v.getType()) {
- case Setting::TypeNone:
- break;
- case Setting::TypeInt:
- v = static_cast<int>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeInt64:
- v = static_cast<long>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeFloat:
- v = static_cast<double>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeString:
- v = static_cast<const char *>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeBoolean:
- v = static_cast<bool>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeGroup:
- break;
- case Setting::TypeArray:
- break;
- case Setting::TypeList:
- break;
- }
-
- // if it's a string, it may contain a path
- if(v.getType() == Setting::TypeString) {
- std::string val(static_cast<const char *>(v));
- v = patchHome(val, m_homePath).c_str();
- }
-
- changed = true;
-}
-
std::string Configuration::castToString(const libconfig::Setting &v) const
{
// cast depending on type
@@ -216,75 +132,6 @@ std::string Configuration::castToString(const libconfig::Setting &v) const
}
}
-template <typename T>
-bool Configuration::setValue(std::string path, const T &val)
-{
- if(m_userCfg->exists(path)) {
- Setting &setting = m_userCfg->lookup(path);
- // compiler complained about operator= not taking unsinged ints, longs and long longs
- if constexpr(std::is_unsigned_v<T> && !std::is_same_v<T, bool>) {
- setting = static_cast<typename std::make_signed_t<T>>(val);
- } else if constexpr(std::is_same_v<T, std::string>) {
- switch(setting.getType()) {
- case Setting::TypeNone:
- break;
-
- case Setting::TypeInt:
- case Setting::TypeInt64:
- setting = std::stoi(static_cast<std::string>(val));
- break;
-
- case Setting::TypeFloat:
- setting = std::stod(static_cast<std::string>(val));
- break;
-
- case Setting::TypeString:
- setting = static_cast<std::string>(val).c_str();
- break;
-
- case Setting::TypeBoolean:
- if(static_cast<std::string>(val) == "true") {
- setting = true;
- } else if(static_cast<std::string>(val) == "false") {
- setting = false;
- }
- break;
-
- case Setting::TypeGroup:
- break;
- case Setting::TypeArray:
- break;
- case Setting::TypeList:
- break;
- }
-
- } else {
- setting = val;
- }
-
- changed = true;
- return true;
- }
-
- // the entry doesn't exist
- return false;
-}
-
-template bool Configuration::setValue<int>(std::string path, const int &val);
-template bool Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);
-template bool Configuration::setValue<long>(std::string path, const long &val);
-template bool Configuration::setValue<unsigned long>(std::string path, const unsigned long &val);
-
-template bool Configuration::setValue<long long>(std::string path, const long long &val);
-template bool Configuration::setValue<unsigned long long>(std::string path, const unsigned long long &val);
-
-template bool Configuration::setValue<float>(std::string path, const float &val);
-template bool Configuration::setValue<double>(std::string path, const double &val);
-
-template bool Configuration::setValue<bool>(std::string path, const bool &val);
-
-template bool Configuration::setValue<std::string>(std::string path, const std::string &val);
-
std::string patchHome(const std::string &path, const std::string &home)
{
std::string r = path;
diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h
index db93760..82e0c58 100644
--- a/lib/settings/configuration.h
+++ b/lib/settings/configuration.h
@@ -13,6 +13,7 @@
#include <optional>
#include <string>
#include <vector>
+#include <QString>
class Configuration
{
@@ -20,35 +21,86 @@ public:
explicit Configuration(const std::string &path, const std::string &home);
~Configuration();
- bool read();
- bool parse(const std::string &contents);
+ bool read(const QString &path);
bool writeIfNeeded(const std::string &path = std::string());
- bool parseDefaultConfiguration(const std::string &contents);
-
std::vector<std::string> childrenSettings(const char *name = "");
std::vector<std::string> childrenGroups(const char *name = "");
- void resetValue(const char *path);
-
template <typename T>
std::optional<T> value(const char *path) const
{
// if setting doesn't exist, give back a nullopt
if(!m_userCfg->exists(path)) {
- const_cast<Configuration *>(this)->resetValue(path);
- return value<T>(path);
+ return std::nullopt;
}
const libconfig::Setting &v = m_userCfg->lookup(path);
- if constexpr(std::is_same_v<T, std::string>)
- return std::optional<std::string>(castToString(v));
- else
+ if constexpr(std::is_same_v<T, std::string>) {
+ std::string r = castToString(v);
+
+ // check if it's a path
+ if(r.front() == '~') {
+ r.replace(0, 1, m_homePath);
+ }
+
+ return std::optional<std::string>(r);
+ } else
return std::optional<T>(static_cast<T>(v));
}
template <typename T>
- bool setValue(std::string path, const T &val);
+ bool setValue(std::string path, const T &val)
+ {
+ if(!m_userCfg->exists(path)) {
+ return false;
+ }
+
+ libconfig::Setting &setting = m_userCfg->lookup(path);
+ // compiler complained about operator= not taking unsinged ints, longs and long longs
+ if constexpr(std::is_unsigned_v<T> && !std::is_same_v<T, bool>) {
+ setting = static_cast<typename std::make_signed_t<T>>(val);
+ } else if constexpr(std::is_same_v<T, std::string>) {
+ switch(setting.getType()) {
+ case libconfig::Setting::TypeNone:
+ break;
+
+ case libconfig::Setting::TypeInt:
+ case libconfig::Setting::TypeInt64:
+ setting = std::stoi(static_cast<std::string>(val));
+ break;
+
+ case libconfig::Setting::TypeFloat:
+ setting = std::stod(static_cast<std::string>(val));
+ break;
+
+ case libconfig::Setting::TypeString:
+ setting = static_cast<std::string>(val).c_str();
+ break;
+
+ case libconfig::Setting::TypeBoolean:
+ if(static_cast<std::string>(val) == "true") {
+ setting = true;
+ } else if(static_cast<std::string>(val) == "false") {
+ setting = false;
+ }
+ break;
+
+ case libconfig::Setting::TypeGroup:
+ break;
+ case libconfig::Setting::TypeArray:
+ break;
+ case libconfig::Setting::TypeList:
+ break;
+ }
+
+ } else {
+ setting = val;
+ }
+
+ changed = true;
+ return true;
+ }
private:
std::string castToString(const libconfig::Setting &v) const;
@@ -56,29 +108,10 @@ private:
bool changed = false;
std::string m_homePath;
std::string m_userCfgPath;
- libconfig::Config *m_userCfg, *m_defaultCfg;
+ libconfig::Config *m_userCfg;
};
// replace ~ with home
std::string patchHome(const std::string &path, const std::string &home);
-// instantiate functions
-// this needs to be done because the implementation is in the cpp file
-
-// Settings::setValue<>
-extern template bool Configuration::setValue<int>(std::string path, const int &val);
-extern template bool Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);
-extern template bool Configuration::setValue<long>(std::string path, const long &val);
-extern template bool Configuration::setValue<unsigned long>(std::string path, const unsigned long &val);
-
-extern template bool Configuration::setValue<long long>(std::string path, const long long &val);
-extern template bool Configuration::setValue<unsigned long long>(std::string path, const unsigned long long &val);
-
-extern template bool Configuration::setValue<float>(std::string path, const float &val);
-extern template bool Configuration::setValue<double>(std::string path, const double &val);
-
-extern template bool Configuration::setValue<bool>(std::string path, const bool &val);
-
-extern template bool Configuration::setValue<std::string>(std::string path, const std::string &val);
-
#endif // CONFIGURATION_H
diff --git a/lib/settings/settingsdialog.cpp b/lib/settings/settingsdialog.cpp
index 2cad476..36b7d2c 100644
--- a/lib/settings/settingsdialog.cpp
+++ b/lib/settings/settingsdialog.cpp
@@ -71,20 +71,13 @@ inline QHBoxLayout *createEntry(Configuration *config, const std::string &path,
{
QLineEdit *lineEdit = new QLineEdit(widget);
lineEdit->setText(QString::fromStdString(config->value<std::string>(path.c_str()).value()));
- QToolButton *resetButton = new QToolButton(widget);
- resetButton->setIcon(widget->style()->standardIcon(QStyle::SP_DialogResetButton));
- QObject::connect(resetButton, &QToolButton::clicked, widget, [config, path, lineEdit]() {
- config->resetValue(path.c_str());
- lineEdit->setText(QString::fromStdString(config->value<std::string>(path.c_str()).value()));
- });
QObject::connect(lineEdit, &QLineEdit::editingFinished, widget, [config, path, lineEdit]() {
config->setValue<std::string>(path, lineEdit->text().toStdString());
});
QHBoxLayout *hBox = new QHBoxLayout();
hBox->addWidget(lineEdit);
- hBox->addWidget(resetButton);
return hBox;
}
diff --git a/src/main.cpp b/src/main.cpp
index 9356820..66df526 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,31 +19,7 @@
#include <QElapsedTimer>
#endif
-// read config into std::string, supports qrc
-inline std::string readConfig(const QString &path)
-{
- QFile conf(path);
- std::string ret;
- if(conf.open(QIODevice::ReadOnly)) {
- ret = conf.readAll().toStdString();
- conf.close();
- }
- return ret;
-}
-
-void bootstrapUserConfig(const std::string &path, Configuration &config)
-{
- // set firstRun to false so we don't re-init on every run
- config.setValue<bool>("browser.firstRun", false);
-
- config.resetValue("filter.path");
- config.resetValue("profile.path");
- config.resetValue("bookmarks.path");
- config.resetValue("downloads.path");
- config.resetValue("plugins.path");
-}
-
-int main(int argc, char *argv[])
+int main(int argc, char **argv)
{
// Create application object
Browser instance(argc, argv);
@@ -61,7 +37,16 @@ int main(int argc, char *argv[])
// user config, ~/.config/smolbote/smolbote.cfg or empty if there is none
QCommandLineOption configOption({ "c", "config" }, "Set configuration file.", "path");
- configOption.setDefaultValue(QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg"));
+ {
+ // try to locate an existing config
+ QString path = QStandardPaths::locate(QStandardPaths::AppConfigLocation, "smolbote.cfg");
+
+ // it's possible there is no config, so set the path properly
+ if(path.isEmpty())
+ path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg";
+
+ configOption.setDefaultValue(path);
+ }
parser.addOption(configOption);
// default config, :/poi.cfg
@@ -69,14 +54,6 @@ int main(int argc, char *argv[])
defaultConfigOption.setDefaultValue(":/poi.cfg");
parser.addOption(defaultConfigOption);
- // print default config, so users can easily create their overrides
- QCommandLineOption printDefaultConfigOption("print-default-config", "Print default configuration.");
- parser.addOption(printDefaultConfigOption);
-
- // generate user config
- QCommandLineOption generateUserConfigOption("generate-user-config", "Generate user configuration and exit.");
- parser.addOption(generateUserConfigOption);
-
QCommandLineOption profileOption({ "p", "profile" }, "Use this profile.", "PROFILE");
profileOption.setDefaultValue("");
parser.addOption(profileOption);
@@ -99,50 +76,14 @@ int main(int argc, char *argv[])
qDebug("profile=%s", qUtf8Printable(parser.value(profileOption)));
#endif
- if(parser.isSet(printDefaultConfigOption)) {
- std::cout << readConfig(parser.value(defaultConfigOption));
- std::cout.flush();
- return 0;
- }
-
std::shared_ptr<Configuration> config = std::make_shared<Configuration>(
parser.value(configOption).toStdString(),
QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString());
- config->read();
- config->parseDefaultConfiguration(readConfig(parser.value(defaultConfigOption)));
-
- // check if first run
- if(config->value<bool>("browser.firstRun").value_or(true) || parser.isSet(generateUserConfigOption)) {
- // create a user config file
- QString path = parser.value(configOption);
- // make sure we have a path
- if(path.isEmpty()) {
- path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/smolbote.cfg";
- }
- // make sure the directory exists
- QDir configDir = QFileInfo(path).absoluteDir();
- if(!configDir.exists()) {
- configDir.mkpath(".");
- }
-
- // remove any existing config
- if(QFile::exists(path)) {
- QFile::remove(path);
- }
-
- config->parse(readConfig(parser.value(defaultConfigOption)));
-
- // patch paths
- bootstrapUserConfig(path.toStdString(), *config);
-
- std::cout << "Writing configuration: " << (config->writeIfNeeded(path.toStdString()) ? "ok" : "failed") << std::endl;
-
- // exit if this is the only thing we needed to do
- if(parser.isSet(generateUserConfigOption)) {
- return 0;
- }
- }
+ // first load the default configuration
+ config->read(parser.value(defaultConfigOption));
+ // then load in the user configuration, which will overwrite it
+ config->read(parser.value(configOption));
// check for other instances
// if we socket hasn't been disabled (socket is not none)