From c72b2de3794c7c5100cc8e007b3c199a2f237fe6 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Tue, 22 Oct 2019 10:35:37 +0300 Subject: Use github.com/Taywee/args to parse command line - This adds 3rd-party/args/args.git subrepository --- src/builtins.cpp | 27 ------------- src/builtins.h | 5 --- src/main.cpp | 120 +++++++++++++++++++++++++++++++++++++++++-------------- src/meson.build | 2 +- 4 files changed, 91 insertions(+), 63 deletions(-) (limited to 'src') 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 #include #include -#include #include +#include +#include #include #include +#include #include +typedef std::function::const_iterator, std::vector::const_iterator)> subcommand_func; +typedef std::unordered_map 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 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 +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 cmd = std::make_unique(argc, argv); - // --version - if(cmd->exists("version")) { - return builtins::version(); - } + const std::vector 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 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 cmd_session(parser, "session", "Open the specified session.", { 's', "session" }); + + args::PositionalList 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 config = std::make_unique(argc, argv, cmd->value("config").value()); + const std::string config_path = [&]() { + if(cmd_config) + return args::get(cmd_config); + else + return defaultUserConfigLocation(); + }(); + std::unique_ptr config = std::make_unique(argc, argv, config_path); QTranslator translator; if(config->exists("browser.translation")) { translator.load(config->value("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("plugins.path").value(), {"*.so", "*.dll"})) { + for(const QString &path : Util::files(config->value("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("profile.default"); app.setConfiguration(config); // app takes ownership of config app.setup(plugins); QStringList urls; - if(const auto arguments = cmd->value>("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("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, -- cgit v1.2.1