quickshell/src/launch/parsecommand.cpp
outfoxxed d03c59768c
Some checks failed
Build / Nix (push) Has been cancelled
Build / Nix-1 (push) Has been cancelled
Build / Nix-2 (push) Has been cancelled
Build / Nix-3 (push) Has been cancelled
Build / Nix-4 (push) Has been cancelled
Build / Nix-5 (push) Has been cancelled
Build / Nix-6 (push) Has been cancelled
Build / Nix-7 (push) Has been cancelled
Build / Nix-8 (push) Has been cancelled
Build / Nix-9 (push) Has been cancelled
Build / Nix-10 (push) Has been cancelled
Build / Nix-11 (push) Has been cancelled
Build / Nix-12 (push) Has been cancelled
Build / Nix-13 (push) Has been cancelled
Build / Nix-14 (push) Has been cancelled
Build / Nix-15 (push) Has been cancelled
Build / Nix-16 (push) Has been cancelled
Build / Nix-17 (push) Has been cancelled
Build / Nix-18 (push) Has been cancelled
Build / Nix-19 (push) Has been cancelled
Build / Nix-20 (push) Has been cancelled
Build / Nix-21 (push) Has been cancelled
Build / Nix-22 (push) Has been cancelled
Build / Nix-23 (push) Has been cancelled
Build / Nix-24 (push) Has been cancelled
Build / Nix-25 (push) Has been cancelled
Build / Nix-26 (push) Has been cancelled
Build / Nix-27 (push) Has been cancelled
Build / Nix-28 (push) Has been cancelled
Build / Nix-29 (push) Has been cancelled
Build / Nix-30 (push) Has been cancelled
Build / Nix-31 (push) Has been cancelled
Build / Nix-32 (push) Has been cancelled
Build / Nix-33 (push) Has been cancelled
Build / Archlinux (push) Has been cancelled
Lint / Lint (push) Has been cancelled
io/ipchandler: add signal listener support
2026-01-15 23:40:03 -08:00

282 lines
9.6 KiB
C++

#include <cstddef>
#include <limits>
#include <memory>
#include <utility>
#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 filtering = false) {
auto* group =
cmd->add_option_group("Config Selection")
->description(
"Quickshell detects configurations as named directories under each XDG config "
"directory as `<xdg dir>/quickshell/<config name>/shell.qml`.\n\n"
"If `<xdg dir>/quickshell/shell.qml` exists, it will be registered as the "
"'default' configuration, and no subdirectories will be considered. "
"If --config is not passed, 'default' will be assumed.\n\n"
"Alternatively, a config can be selected by path with --path.\n\n"
"Examples:\n"
"- `~/.config/quickshell/shell.qml` can be run with `qs`\n"
"- `/etc/xdg/quickshell/myconfig/shell.qml` can be run with `qs -c myconfig`\n"
"- `~/myshell/shell.qml` can be run with `qs -p ~/myshell`\n"
"- `~/myshell/randomfile.qml` can be run with `qs -p ~/myshell/randomfile.qml`"
);
auto* path = group->add_option("-p,--path", state.config.path)
->description("Path to a QML file or config folder.")
->envname("QS_CONFIG_PATH");
group->add_option("-c,--config", state.config.name)
->description("Name of a quickshell configuration to run.")
->envname("QS_CONFIG_NAME")
->excludes(path);
group->add_option("-m,--manifest", state.config.manifest)
->description(
"[DEPRECATED] Path to a quickshell manifest.\n"
"If a manifest is specified, configs named by -c will point to its entries.\n"
"Defaults to $XDG_CONFIG_HOME/quickshell/manifest.conf"
)
->envname("QS_MANIFEST")
->excludes(path);
if (filtering) {
group->add_flag("-n,--newest", state.config.newest)
->description("Operate on the most recently launched instance instead of the oldest");
group->add_flag("--any-display", state.config.anyDisplay)
->description(
"If passed, instances will not be filtered by the display connection they "
"were launched on."
);
}
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 "
"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, "
"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, true)->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.");
sub->add_flag("--show-dead", state.instance.includeDead)
->description("Include dead instances in the list.");
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("ipc", "Communicate with other Quickshell instances.")
->require_subcommand();
state.ipc.ipc = sub;
auto* instance = addInstanceSelection(sub);
addConfigSelection(sub, true)->excludes(instance);
addLoggingOptions(sub, false, true);
{
auto* show = sub->add_subcommand("show", "Print information about available IPC targets.");
state.ipc.show = show;
}
{
auto* call = sub->add_subcommand("call", "Call an IpcHandler function.");
state.ipc.call = call;
call->add_option("target", state.ipc.target, "The target to message.");
call->add_option("function", state.ipc.name)
->description("The function to call in the target.");
call->add_option("arguments", state.ipc.arguments)
->description("Arguments to the called function.")
->allow_extra_args();
}
auto signalCmd = [&](std::string cmd, std::string desc) {
auto* scmd = sub->add_subcommand(std::move(cmd), std::move(desc));
scmd->add_option("target", state.ipc.target, "The target to listen on.");
scmd->add_option("signal", state.ipc.name, "The signal to listen for.");
return scmd;
};
state.ipc.wait = signalCmd("wait", "Wait for one IpcHandler signal.");
state.ipc.listen = signalCmd("listen", "Listen for IpcHandler signals.");
{
auto* prop =
sub->add_subcommand("prop", "Manipulate IpcHandler properties.")->require_subcommand();
{
auto* get = prop->add_subcommand("get", "Read the value of a property.");
state.ipc.getprop = get;
get->add_option("target", state.ipc.target, "The target to read the property of.");
get->add_option("property", state.ipc.name)->description("The property to read.");
}
}
}
{
auto* sub = cli->add_subcommand("msg", "[DEPRECATED] Moved to `ipc call`.")->require_option();
sub->add_option("target", state.ipc.target, "The target to message.");
sub->add_option("function", state.ipc.name)->description("The function to call in the target.");
sub->add_option("arguments", state.ipc.arguments)
->description("Arguments to the called function.")
->allow_extra_args();
sub->add_flag("-s,--show", state.ipc.showOld)
->description(
"Print information about a function or target if given, or all available "
"targets if not."
);
auto* instance = addInstanceSelection(sub);
addConfigSelection(sub, true)->excludes(instance);
addLoggingOptions(sub, false, true);
state.subcommand.msg = sub;
}
CLI11_PARSE(*cli, argc, argv);
return 65535;
}
} // namespace qs::launch