1
0
Fork 0
quickshell/src/launch/parsecommand.cpp

204 lines
7.1 KiB
C++

#include <cstddef>
#include <limits>
#include <memory>
#include <CLI/App.hpp>
#include <CLI/CLI.hpp> // NOLINT: Need to include this for impls of some CLI11 classes
#include <CLI/Validators.hpp>
#include "launch_p.hpp"
namespace qs::launch {
int parseCommand(int argc, char** argv, CommandState& state) {
state.exec = {
.argc = argc,
.argv = argv,
};
auto addConfigSelection = [&](CLI::App* cmd, bool withNewestOption = false) {
auto* group = cmd->add_option_group("Config Selection")
->description("If no options in this group are specified,\n"
"$XDG_CONFIG_HOME/quickshell/shell.qml will be used.");
auto* path = group->add_option("-p,--path", state.config.path)
->description("Path to a QML file.")
->envname("QS_CONFIG_PATH");
group->add_option("-m,--manifest", state.config.manifest)
->description("Path to a quickshell manifest.\n"
"Defaults to $XDG_CONFIG_HOME/quickshell/manifest.conf")
->envname("QS_MANIFEST")
->excludes(path);
group->add_option("-c,--config", state.config.name)
->description("Name of a quickshell configuration to run.\n"
"If -m is specified, this is a configuration in the manifest,\n"
"otherwise it is the name of a folder in $XDG_CONFIG_HOME/quickshell.")
->envname("QS_CONFIG_NAME");
if (withNewestOption) {
group->add_flag("-n,--newest", state.config.newest)
->description("Operate on the most recently launched instance instead of the oldest");
}
return group;
};
auto addDebugOptions = [&](CLI::App* cmd) {
auto* group = cmd->add_option_group("Debugging", "Options for QML debugging.");
auto* debug = group->add_option("--debug", state.debug.port)
->description("Open the given port for a QML debugger connection.")
->check(CLI::Range(0, 65535));
group->add_flag("--waitfordebug", state.debug.wait)
->description("Wait for a QML debugger to connect before executing the configuration.")
->needs(debug);
return group;
};
auto addLoggingOptions = [&](CLI::App* cmd, bool noGroup, bool noDisplay = false) {
auto* group = noGroup ? cmd : cmd->add_option_group(noDisplay ? "" : "Logging");
group->add_flag("--no-color", state.log.noColor)
->description("Disables colored logging.\n"
"Colored logging can also be disabled by specifying a non empty value\n"
"for the NO_COLOR environment variable.");
group->add_flag("--log-times", state.log.timestamp)
->description("Log timestamps with each message.");
group->add_option("--log-rules", state.log.rules)
->description("Log rules to apply, in the format of QT_LOGGING_RULES.");
group->add_flag("-v,--verbose", [&](size_t count) { state.log.verbosity = count; })
->description("Increases log verbosity.\n"
"-v will show INFO level internal logs.\n"
"-vv will show DEBUG level internal logs.");
auto* hgroup = cmd->add_option_group("");
hgroup->add_flag("--no-detailed-logs", state.log.sparse);
};
auto addInstanceSelection = [&](CLI::App* cmd) {
auto* group = cmd->add_option_group("Instance Selection");
group->add_option("-i,--id", state.instance.id)
->description("The instance id to operate on.\n"
"You may also use a substring the id as long as it is unique,\n"
"for example \"abc\" will select \"abcdefg\".");
group->add_option("--pid", state.instance.pid)
->description("The process id of the instance to operate on.");
return group;
};
state.app = std::make_unique<CLI::App>();
auto* cli = state.app.get();
// Require 0-1 subcommands. Without this, positionals can be parsed as more subcommands.
cli->require_subcommand(0, 1);
addConfigSelection(cli);
addLoggingOptions(cli, false);
addDebugOptions(cli);
{
cli->add_option_group("")->add_flag("--private-check-compat", state.misc.checkCompat);
cli->add_flag("-V,--version", state.misc.printVersion)
->description("Print quickshell's version and exit.");
cli->add_flag("-n,--no-duplicate", state.misc.noDuplicate)
->description("Exit immediately if another instance of the given config is running.");
cli->add_flag("-d,--daemonize", state.misc.daemonize)
->description("Detach from the controlling terminal.");
}
{
auto* sub = cli->add_subcommand("log", "Print quickshell logs.");
auto* file = sub->add_option("file", state.log.file, "Log file to read.");
sub->add_option("-t,--tail", state.log.tail)
->description("Maximum number of lines to print, starting from the bottom.")
->check(CLI::Range(1, std::numeric_limits<int>::max(), "INT > 0"));
sub->add_flag("-f,--follow", state.log.follow)
->description("Keep reading the log until the logging process terminates.");
sub->add_option("-r,--rules", state.log.readoutRules, "Log file to read.")
->description("Rules to apply to the log being read, in the format of QT_LOGGING_RULES.");
auto* instance = addInstanceSelection(sub)->excludes(file);
addConfigSelection(sub)->excludes(instance)->excludes(file);
addLoggingOptions(sub, false);
state.subcommand.log = sub;
}
{
auto* sub = cli->add_subcommand("list", "List running quickshell instances.");
auto* all = sub->add_flag("-a,--all", state.instance.all)
->description("List all instances.\n"
"If unspecified, only instances of"
"the selected config will be listed.");
sub->add_flag("-j,--json", state.output.json, "Output the list as a json.");
addConfigSelection(sub, true)->excludes(all);
addLoggingOptions(sub, false, true);
state.subcommand.list = sub;
}
{
auto* sub = cli->add_subcommand("kill", "Kill quickshell instances.");
//sub->add_flag("-a,--all", "Kill all matching instances instead of just one.");
auto* instance = addInstanceSelection(sub);
addConfigSelection(sub, true)->excludes(instance);
addLoggingOptions(sub, false, true);
state.subcommand.kill = sub;
}
{
auto* sub = cli->add_subcommand("msg", "Send messages to IpcHandlers.")->require_option();
auto* target = sub->add_option("target", state.ipc.target, "The target to message.");
auto* function = sub->add_option("function", state.ipc.function)
->description("The function to call in the target.")
->needs(target);
auto* arguments = sub->add_option("arguments", state.ipc.arguments)
->description("Arguments to the called function.")
->needs(function)
->allow_extra_args();
sub->add_flag("-s,--show", state.ipc.info)
->description("Print information about a function or target if given, or all available "
"targets if not.")
->excludes(arguments);
auto* instance = addInstanceSelection(sub);
addConfigSelection(sub, true)->excludes(instance);
addLoggingOptions(sub, false, true);
sub->require_option();
state.subcommand.msg = sub;
}
CLI11_PARSE(*cli, argc, argv);
return 65535;
}
} // namespace qs::launch