aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2019-10-22 10:35:37 +0300
committerAqua-sama <aqua@iserlohn-fortress.net>2019-10-22 10:35:37 +0300
commitc72b2de3794c7c5100cc8e007b3c199a2f237fe6 (patch)
treeefa0370529cc128b36c00364d2fc950b1496ec45
parentImprove meson.build files (diff)
downloadsmolbote-c72b2de3794c7c5100cc8e007b3c199a2f237fe6.tar.xz
Use github.com/Taywee/args to parse command line
- This adds 3rd-party/args/args.git subrepository
-rw-r--r--.gitmodules3
m---------3rd-party/args/args.git0
-rw-r--r--3rd-party/args/meson.build5
-rw-r--r--lib/configuration/commandline.cpp59
-rw-r--r--lib/configuration/commandline.h79
-rw-r--r--lib/configuration/meson.build2
-rw-r--r--linux/makepkg/PKGBUILD6
-rw-r--r--meson.build1
-rw-r--r--src/builtins.cpp27
-rw-r--r--src/builtins.h5
-rw-r--r--src/main.cpp120
-rw-r--r--src/meson.build2
12 files changed, 106 insertions, 203 deletions
diff --git a/.gitmodules b/.gitmodules
index 1c11e7c..1695827 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "3rd-party/SingleApplication/SingleApplication.git"]
path = 3rd-party/SingleApplication/SingleApplication.git
url = https://github.com/itay-grudev/SingleApplication.git
+[submodule "3rd-party/args/args.git"]
+ path = 3rd-party/args/args.git
+ url = https://github.com/Taywee/args
diff --git a/3rd-party/args/args.git b/3rd-party/args/args.git
new file mode 160000
+Subproject 78e27faf75ff7d20f232f11ffcef65cde43c449
diff --git a/3rd-party/args/meson.build b/3rd-party/args/meson.build
new file mode 100644
index 0000000..c4ef5dc
--- /dev/null
+++ b/3rd-party/args/meson.build
@@ -0,0 +1,5 @@
+# This is a header-only lib, all we need to do is include it
+dep_args = declare_dependency(
+ include_directories: include_directories('args.git')
+)
+
diff --git a/lib/configuration/commandline.cpp b/lib/configuration/commandline.cpp
deleted file mode 100644
index 4581c84..0000000
--- a/lib/configuration/commandline.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * This file is part of smolbote. It's copyrighted by the contributors recorded
- * in the version control history of the file, available from its original
- * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
- *
- * SPDX-License-Identifier: GPL-3.0
- */
-
-#include "commandline.h"
-#include "config.h"
-#include <QStandardPaths>
-
-namespace po = boost::program_options;
-
-inline std::string defaultUserConfigLocation()
-{
-#ifdef CONFIG_PATH_CONFIG
- return CONFIG_PATH_CONFIG;
-#else
- // try to locate an existing config
- QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg");
-
- // 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
-}
-
-CommandLine::CommandLine(int argc, char **argv)
- : m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
-{
- m_description.add_options()
- ("help,h", "Display command-line options list.")
- ("version,v", "Display version information.")
- ("build", "Display build commit.")
-
- ("config,c", po::value<std::string>()->default_value(defaultUserConfigLocation()), "Set the configuration file.")
- ("no-remote", "Do not accept or send remote commands.")
-
- ("session,s", po::value<std::string>(), "Open the selected session.")
- ("pick-session", "Show all available sessions and select which one to open.")
-
- ("args", po::value<std::vector<std::string>>(), "Command(s) and/or URL(s).")
- ;
-
- m_arguments.add("args", -1);
-
- try {
- auto cmd = po::command_line_parser(argc, argv);
- cmd.allow_unregistered();
- cmd.options(m_description);
- cmd.positional(m_arguments);
- po::store(cmd.run(), vm);
- } catch(const po::error &e) {
- qWarning("Error parsing cmd: %s", e.what());
- }
-}
diff --git a/lib/configuration/commandline.h b/lib/configuration/commandline.h
deleted file mode 100644
index 3c4dd81..0000000
--- a/lib/configuration/commandline.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file is part of smolbote. It's copyrighted by the contributors recorded
- * in the version control history of the file, available from its original
- * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
- *
- * SPDX-License-Identifier: GPL-3.0
- */
-
-#ifndef SMOLBOTE_COMMANDLINE_H
-#define SMOLBOTE_COMMANDLINE_H
-
-#include <QString>
-#include <QStringList>
-#include <boost/program_options.hpp>
-
-class CommandLine
-{
-public:
- CommandLine(int argc, char **argv);
-
- bool exists(const char *path) const
- {
- return (vm.count(path) > 0);
- }
-
- template <typename T>
- std::optional<T> value(const char *path) const
- {
- if(vm.count(path) == 0) {
- return std::nullopt;
- }
-
- if constexpr(std::is_same_v<T, QString>) {
- return std::optional<QString>(QString::fromStdString(this->value<std::string>(path).value()));
- //return std::optional<QString>(vm[path].as<const char*>());
-
- } else if constexpr(std::is_same_v<T, QStringList>) {
- QStringList r;
- for(const std::string &item : this->value<std::vector<std::string>>(path).value()) {
- r.append(QString::fromStdString(item));
- }
- return std::optional<QStringList>(r);
-
- } else if constexpr(std::is_same_v<T, std::string>) {
-
- if(vm[path].value().type() == typeid(int)) {
- return std::optional<std::string>(std::to_string(vm[path].as<int>()));
- }
-
- if(vm[path].value().type() == typeid(bool)) {
- return std::optional<std::string>(vm[path].as<bool>() ? "true" : "false");
- }
-
- std::string r = vm[path].as<std::string>();
-
- // 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>(vm[path].as<T>());
- }
-
- const boost::program_options::options_description& description() const
- {
- return m_description;
- }
-
-private:
- const std::string m_homePath;
- boost::program_options::options_description m_description;
- boost::program_options::positional_options_description m_arguments;
- boost::program_options::variables_map vm;
-};
-
-#endif // SMOLBOTE_COMMANDLINE_H
diff --git a/lib/configuration/meson.build b/lib/configuration/meson.build
index 57bafbc..19f57f4 100644
--- a/lib/configuration/meson.build
+++ b/lib/configuration/meson.build
@@ -3,7 +3,7 @@ configuration_moc = mod_qt5.preprocess(
dependencies: dep_qt5
)
-configuration_lib = static_library('configuration', ['commandline.cpp', 'configuration.cpp', configuration_moc],
+configuration_lib = static_library('configuration', ['configuration.cpp', configuration_moc],
dependencies: [dep_boost, dep_qt5, autogen_config]
)
diff --git a/linux/makepkg/PKGBUILD b/linux/makepkg/PKGBUILD
index 9a4d13a..4fed183 100644
--- a/linux/makepkg/PKGBUILD
+++ b/linux/makepkg/PKGBUILD
@@ -18,9 +18,11 @@ makedepends=('git' 'meson' 'boost' 'python-kconfiglib' 'openssl' 'qt5-tools' 'sc
# this is the central repository
source=("git+https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote.git"
- "git+https://github.com/itay-grudev/SingleApplication.git")
+ "git+https://github.com/itay-grudev/SingleApplication.git"
+ "git+https://github.com/Taywee/args")
sha512sums=('SKIP'
+ 'SKIP'
'SKIP')
#validgpgkeys=(# Aqua-sama <aqua@iserlohn-fortress.net>
@@ -42,6 +44,8 @@ prepare() {
git submodule init
git config submodule.3rd-party/SingleApplication/SingleApplication.git.url $srcdir/SingleApplication
git submodule update 3rd-party/SingleApplication/SingleApplication.git
+ git config submodule.3rd-party/args/args.git.url $srcdir/args
+ git submodule update 3rd-party/args/args.git
}
pkgver() {
diff --git a/meson.build b/meson.build
index 6412730..af2dd63 100644
--- a/meson.build
+++ b/meson.build
@@ -81,6 +81,7 @@ subdir('lib/urlfilter')
subdir('lib/webprofile')
subdir('3rd-party/SingleApplication')
+subdir('3rd-party/args')
subdir('src')
subdir('lang')
diff --git a/src/builtins.cpp b/src/builtins.cpp
index 55bdc31..1af2dc8 100644
--- a/src/builtins.cpp
+++ b/src/builtins.cpp
@@ -34,30 +34,3 @@ int builtins::build()
std::cout << poi_Version << std::endl;
return 0;
}
-
-int builtins::help(const char *cmd,
- const boost::program_options::options_description &cmd_opts,
- const boost::program_options::options_description &config_opts,
- const CommandHash_t &pluginCommands, const QTranslator *translator)
-{
- const auto version = QVersionNumber::fromString(QLatin1String(poi_Version)).toString().toStdString();
- std::cout << tr(translator, "smolbote ") << version << tr(translator, ": yet another no-frills browser\n");
- std::cout << tr(translator, "Usage: ") << cmd << tr(translator, " [options] [command/URL(s)]\n\n");
-
- std::cout << tr(translator, "Command-line Options:\n") << cmd_opts << '\n';
-
- std::cout << tr(translator, "Commands: \n");
- for(auto it = pluginCommands.constBegin(); it != pluginCommands.constEnd(); ++it)
- std::cout << " " << it.key().toStdString() << '\n';
- std::cout << '\n';
-
- std::cout << tr(translator, "Configuration Options:\n") << config_opts << '\n';
-
-#ifdef Q_OS_UNIX
- std::cout << tr(translator, "For more information on usage, refer to the manual page smolbote.7\n");
- std::cout << tr(translator, "For more information on configuration, refer to the manual page smolbote.5\n");
-#endif
-
- std::cout << std::endl;
- return 0;
-}
diff --git a/src/builtins.h b/src/builtins.h
index e151e8d..a3b9b07 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -16,11 +16,6 @@ namespace builtins
{
int version();
int build();
-int help(const char *cmd,
- const boost::program_options::options_description &cmd_opts,
- const boost::program_options::options_description &config_opts,
- const CommandHash_t &pluginCommands,
- const QTranslator *translator);
}
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 8063b86..02a1168 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,22 +8,57 @@
#include "browser.h"
#include "builtins.h"
-#include "commandline.h"
#include "configuration.h"
+#include "crashhandler.h"
#include "session/session.h"
#include "session/sessiondialog.h"
#include "util.h"
-#include "crashhandler.h"
#include "version.h"
#include <QFile>
#include <QLibraryInfo>
#include <QPluginLoader>
-#include <pluginloader.h>
#include <QTranslator>
+#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 = ", ")
+{
+ std::vector<std::string> keys(map.size());
+ std::transform(map.begin(), map.end(), keys.begin(), [](auto pair) { return pair.first; });
+ std::sort(keys.begin(), keys.end());
+
+ std::string k;
+ std::for_each(keys.begin(), keys.end() - 1, [&k, &sep](const std::string &piece) { k += piece + sep; });
+ k += keys.back();
+
+ return k;
+}
+
+#include <QStandardPaths>
+inline std::string defaultUserConfigLocation()
+{
+#ifdef CONFIG_PATH_CONFIG
+ return CONFIG_PATH_CONFIG;
+#else
+ // try to locate an existing config
+ QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg");
+
+ // 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
+}
+
#include "config.h"
#if defined(CONFIG_USEPLASMA) && !defined(PLASMA)
#error "You have enabled Plasma integration, but Frameworks was not found."
@@ -41,15 +76,40 @@ int main(int argc, char **argv)
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
#endif
- const std::unique_ptr<CommandLine> cmd = std::make_unique<CommandLine>(argc, argv);
- // --version
- if(cmd->exists("version")) {
- return builtins::version();
- }
+ 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.");
+ parser.Prog(argv[0]);
+
+ 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" });
+
+ args::ValueFlag<std::string> cmd_config(parser, "config", "Set the configuration file.", { 'c', "config" });
+
+ args::Flag cmd_noRemote(parser, "no-remote", "Do not accept or send remote commands.", { "no-remote" });
+
+ args::Flag cmd_pickSession(parser, "pick-session", "Show all available sessions and select which one to open", { "pick-session" });
+ 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");
+
+ try {
+ auto next = parser.ParseArgs(args);
+
+ if(cmd_version)
+ return builtins::version();
+ if(cmd_build)
+ return builtins::build();
- // --build
- if(cmd->exists("build")) {
- return builtins::build();
+ } catch(args::Help) {
+ std::cout << parser;
+ //std::cout << "Available subcommands: " << command_keys << std::endl;
+ return 0;
+
+ } catch(args::Error e) {
+ std::cerr << e.what() << std::endl;
+ std::cerr << parser;
+ return -1;
}
// Disable Chromium's crash handler so breakpad can capture crashes instead.
@@ -60,7 +120,13 @@ int main(int argc, char **argv)
}
// create and load configuration
- std::unique_ptr<Configuration> config = std::make_unique<Configuration>(argc, argv, cmd->value<std::string>("config").value());
+ const std::string config_path = [&]() {
+ if(cmd_config)
+ return args::get(cmd_config);
+ else
+ return defaultUserConfigLocation();
+ }();
+ std::unique_ptr<Configuration> config = std::make_unique<Configuration>(argc, argv, config_path);
QTranslator translator;
if(config->exists("browser.translation")) {
translator.load(config->value<QString>("browser.translation").value());
@@ -70,7 +136,7 @@ int main(int argc, char **argv)
CommandHash_t pluginCommands;
// Load plugins
- for(const QString &path : Util::files(config->value<QString>("plugins.path").value(), {"*.so", "*.dll"})) {
+ for(const QString &path : Util::files(config->value<QString>("plugins.path").value(), { "*.so", "*.dll" })) {
auto *loader = new PluginLoader(path);
const bool loaded = loader->load();
spdlog::info("{} plugin {}", loaded ? "Loaded" : "Failed to load", qUtf8Printable(path));
@@ -85,10 +151,6 @@ int main(int argc, char **argv)
}
}
- if(cmd->exists("help")) {
- return builtins::help(argv[0], cmd->description(), config->description(), pluginCommands, &translator);
- }
-
// argc, argv, allowSecondary
Browser app(argc, argv);
// set this, otherwise the webview becomes black when using a stylesheet
@@ -129,27 +191,25 @@ int main(int argc, char **argv)
#endif
#endif // CONFIG_USEBREAKPAD
- const bool isStandalone = cmd->exists("no-remote");
const auto profile = config->value<QString>("profile.default");
app.setConfiguration(config); // app takes ownership of config
app.setup(plugins);
QStringList urls;
- if(const auto arguments = cmd->value<std::vector<std::string>>("args")) {
- for(const auto &u : arguments.value()) {
- if(pluginCommands.contains(QString::fromStdString(u))) {
- return pluginCommands.value(QString::fromStdString(u))();
- } else {
- urls.append(QString::fromStdString(u));
- }
+
+ for(const auto &u : args::get(cmd_args)) {
+ if(pluginCommands.contains(QString::fromStdString(u))) {
+ return pluginCommands.value(QString::fromStdString(u))();
+ } else {
+ urls.append(QString::fromStdString(u));
}
}
if(urls.isEmpty())
urls.append(QString());
// if app is primary, create new sessions from received messages
- if(app.isPrimary() && !isStandalone) {
+ if(app.isPrimary() && !cmd_noRemote) {
QObject::connect(&app, &Browser::receivedMessage, &app, [](quint32 instanceId, QByteArray message) {
Q_UNUSED(instanceId);
auto doc = QJsonDocument::fromJson(message);
@@ -160,14 +220,14 @@ int main(int argc, char **argv)
{
QJsonObject sessionData;
- if(cmd->exists("pick-session")) {
+ if(cmd_pickSession) {
auto *dlg = new SessionDialog();
if(const auto pick = dlg->pickSession())
sessionData = pick.value();
else
sessionData = Session::fromCommandLine(profile.value(), urls);
- } else if(const auto session = cmd->value<QString>("session")) {
- QFile sessionJson(session.value());
+ } else if(cmd_session) {
+ QFile sessionJson(QString::fromStdString(args::get(cmd_session)));
if(sessionJson.open(QIODevice::ReadOnly | QIODevice::Text)) {
sessionData = QJsonDocument::fromJson(sessionJson.readAll()).object();
sessionJson.close();
@@ -176,7 +236,7 @@ int main(int argc, char **argv)
sessionData = Session::fromCommandLine(profile.value(), urls);
}
- if(app.isPrimary() || isStandalone) {
+ if(app.isPrimary() || cmd_noRemote) {
Session::restoreSession(sessionData);
} else {
// app is secondary and not standalone
diff --git a/src/meson.build b/src/meson.build
index ea866b9..d2ff9ad 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -13,7 +13,7 @@ poi_moc = mod_qt5.preprocess(
poi = executable(get_option('poiName'), install: true,
cpp_args: ['-DQAPPLICATION_CLASS=QApplication'],
- dependencies: [dep_qt5, dep_boost, dep_spdlog, dep_SingleApplication, optional_deps,
+ dependencies: [dep_qt5, dep_boost, dep_spdlog, dep_SingleApplication, dep_args, optional_deps,
dep_about, dep_addressbar, dep_bookmarks, dep_configuration, dep_downloads, dep_pluginloader, dep_urlfilter, dep_webprofile],
include_directories: [include],
sources: ['main.cpp', 'builtins.cpp', 'crashhandler.cpp', poi_moc, version_h,