mirror of
https://github.com/swaywm/sway.git
synced 2026-04-29 06:46:22 -04:00
Merge 01757979de into 1a30c50ef4
This commit is contained in:
commit
64283197e0
5 changed files with 131 additions and 57 deletions
|
|
@ -51,7 +51,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
|
||||||
/**
|
/**
|
||||||
* Parse and executes a command.
|
* Parse and executes a command.
|
||||||
*/
|
*/
|
||||||
struct cmd_results *execute_command(char *command, struct sway_seat *seat);
|
struct cmd_results *execute_command(const char *command, struct sway_seat *seat);
|
||||||
/**
|
/**
|
||||||
* Parse and handles a command during config file loading.
|
* Parse and handles a command during config file loading.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
148
sway/commands.c
148
sway/commands.c
|
|
@ -209,15 +209,93 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
/**
|
||||||
|
* A command is followed by its list of arguments. For instance, "floating" and
|
||||||
|
* ["toggle"]. This function is passed that list, in split_args format, and then
|
||||||
|
* strips quotes, unescapes the content, and expands variables. Some commands
|
||||||
|
* require slightly different preprocessing. (Variable expansion happens
|
||||||
|
* after unescaping so we don't double-unescape variable values.)
|
||||||
|
*
|
||||||
|
* The function returns the new (possibly smaller) value of argc, and if so
|
||||||
|
* zeros out the trailing values of argv.
|
||||||
|
*/
|
||||||
|
static int preprocess_arg(sway_cmd handle, char **argv, int argc) {
|
||||||
|
if (handle == cmd_exec) {
|
||||||
|
// Quotes are not stripped
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
unescape_string(argv[i]);
|
||||||
|
argv[i] = do_var_replacement(argv[i]);
|
||||||
|
}
|
||||||
|
} else if (handle == cmd_for_window) {
|
||||||
|
// After first argument, merge remainder without preprocessing
|
||||||
|
if (*argv[0] == '\"' || *argv[0] == '\'') {
|
||||||
|
strip_quotes(argv[0]);
|
||||||
|
}
|
||||||
|
unescape_string(argv[0]);
|
||||||
|
argv[0] = do_var_replacement(argv[0]);
|
||||||
|
if (argc >= 2) {
|
||||||
|
// Compress the last arguments to one.
|
||||||
|
char *joined = join_args(argv + 1, argc - 1);
|
||||||
|
argv[1] = joined;
|
||||||
|
while (argc > 2) {
|
||||||
|
argc--;
|
||||||
|
free(argv[argc]);
|
||||||
|
argv[argc] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (handle == cmd_bindcode || handle == cmd_bindsym) {
|
||||||
|
// After the argument after the last '--X' option, merge
|
||||||
|
// remaining arguments without preprocessing.
|
||||||
|
int i = 0;
|
||||||
|
for (; i < argc; i++) {
|
||||||
|
if (*argv[i] == '\"' || *argv[i] == '\'') {
|
||||||
|
strip_quotes(argv[i]);
|
||||||
|
}
|
||||||
|
unescape_string(argv[i]);
|
||||||
|
argv[i] = do_var_replacement(argv[i]);
|
||||||
|
if (argv[i][0] != '-' || argv[i][1] != '-') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < argc) {
|
||||||
|
if (*argv[i] == '\"' || *argv[i] == '\'') {
|
||||||
|
strip_quotes(argv[i]);
|
||||||
|
}
|
||||||
|
unescape_string(argv[i]);
|
||||||
|
argv[i] = do_var_replacement(argv[i]);
|
||||||
|
}
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
char *joined = join_args(argv + i + 1, argc - i - 1);
|
||||||
|
argv[i + 1] = joined;
|
||||||
|
while (argc > i + 2) {
|
||||||
|
argc--;
|
||||||
|
free(argv[argc]);
|
||||||
|
argv[argc] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Default case: strip quotes, unescape, and expand variables
|
||||||
|
// When setting a variable, the first argument is ignored.
|
||||||
|
int start = handle == cmd_set ? 1 : 0;
|
||||||
|
for (int i = start; i < argc; ++i) {
|
||||||
|
if (*argv[i] == '\"' || *argv[i] == '\'') {
|
||||||
|
strip_quotes(argv[i]);
|
||||||
|
}
|
||||||
|
unescape_string(argv[i]);
|
||||||
|
argv[i] = do_var_replacement(argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmd_results *execute_command(const char *_exec, struct sway_seat *seat) {
|
||||||
// Even though this function will process multiple commands we will only
|
// Even though this function will process multiple commands we will only
|
||||||
// return the last error, if any (for now). (Since we have access to an
|
// return the last error, if any (for now). (Since we have access to an
|
||||||
// error string we could e.g. concatenate all errors there.)
|
// error string we could e.g. concatenate all errors there.)
|
||||||
struct cmd_results *results = NULL;
|
struct cmd_results *results = NULL;
|
||||||
char *exec = strdup(_exec);
|
char *exec = strdup(_exec);
|
||||||
char *head = exec;
|
char *head = exec;
|
||||||
char *cmdlist;
|
|
||||||
char *cmd;
|
|
||||||
list_t *views = NULL;
|
list_t *views = NULL;
|
||||||
|
|
||||||
if (seat == NULL) {
|
if (seat == NULL) {
|
||||||
|
|
@ -251,43 +329,42 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
head += strspn(head, whitespace);
|
head += strspn(head, whitespace);
|
||||||
}
|
}
|
||||||
// Split command list
|
// Split command list
|
||||||
cmdlist = argsep(&head, ";");
|
char *cmdlist = argsep(&head, ";");
|
||||||
cmdlist += strspn(cmdlist, whitespace);
|
cmdlist += strspn(cmdlist, whitespace);
|
||||||
do {
|
do {
|
||||||
// Split commands
|
// Split commands
|
||||||
cmd = argsep(&cmdlist, ",");
|
char *cmd = argsep(&cmdlist, ",");
|
||||||
cmd += strspn(cmd, whitespace);
|
cmd += strspn(cmd, whitespace);
|
||||||
if (strcmp(cmd, "") == 0) {
|
if (strcmp(cmd, "") == 0) {
|
||||||
wlr_log(WLR_INFO, "Ignoring empty command.");
|
wlr_log(WLR_INFO, "Ignoring empty command.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
wlr_log(WLR_INFO, "Handling command '%s'", cmd);
|
wlr_log(WLR_INFO, "Handling command '%s'", cmd);
|
||||||
//TODO better handling of argv
|
|
||||||
|
// Identify which command to execute.
|
||||||
int argc;
|
int argc;
|
||||||
char **argv = split_args(cmd, &argc);
|
char **argv = split_args(exec, &argc);
|
||||||
if (strcmp(argv[0], "exec") != 0) {
|
if (!argv) {
|
||||||
int i;
|
if (results) {
|
||||||
for (i = 1; i < argc; ++i) {
|
free_cmd_results(results);
|
||||||
if (*argv[i] == '\"' || *argv[i] == '\'') {
|
|
||||||
strip_quotes(argv[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
results = cmd_results_new(CMD_INVALID, cmd,
|
||||||
|
"Allocation failure");
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
|
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
if (results) {
|
if (results) {
|
||||||
free_cmd_results(results);
|
free_cmd_results(results);
|
||||||
}
|
}
|
||||||
results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
|
results = cmd_results_new(CMD_INVALID, cmd,
|
||||||
free_argv(argc, argv);
|
"Unknown/invalid command");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Var replacement, for all but first argument of set
|
// Process command arguments
|
||||||
for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
|
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||||
argv[i] = do_var_replacement(argv[i]);
|
|
||||||
unescape_string(argv[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config->handler_context.using_criteria) {
|
if (!config->handler_context.using_criteria) {
|
||||||
// without criteria, the command acts upon the focused
|
// without criteria, the command acts upon the focused
|
||||||
|
|
@ -298,7 +375,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
"could not get focus-inactive for root container")) {
|
"could not get focus-inactive for root container")) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
struct cmd_results *res = handler->handle(argc - 1, argv + 1);
|
||||||
if (res->status != CMD_SUCCESS) {
|
if (res->status != CMD_SUCCESS) {
|
||||||
free_argv(argc, argv);
|
free_argv(argc, argv);
|
||||||
if (results) {
|
if (results) {
|
||||||
|
|
@ -312,7 +389,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
for (int i = 0; i < views->length; ++i) {
|
for (int i = 0; i < views->length; ++i) {
|
||||||
struct sway_view *view = views->items[i];
|
struct sway_view *view = views->items[i];
|
||||||
config->handler_context.current_container = view->swayc;
|
config->handler_context.current_container = view->swayc;
|
||||||
struct cmd_results *res = handler->handle(argc-1, argv+1);
|
struct cmd_results *res = handler->handle(argc - 1, argv + 1);
|
||||||
if (res->status != CMD_SUCCESS) {
|
if (res->status != CMD_SUCCESS) {
|
||||||
free_argv(argc, argv);
|
free_argv(argc, argv);
|
||||||
if (results) {
|
if (results) {
|
||||||
|
|
@ -324,7 +401,9 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
||||||
free_cmd_results(res);
|
free_cmd_results(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free_argv(argc, argv);
|
if (argc) {
|
||||||
|
free_argv(argc, argv);
|
||||||
|
}
|
||||||
} while(cmdlist);
|
} while(cmdlist);
|
||||||
} while(head);
|
} while(head);
|
||||||
cleanup:
|
cleanup:
|
||||||
|
|
@ -372,18 +451,9 @@ struct cmd_results *config_command(char *exec) {
|
||||||
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
int i;
|
|
||||||
// Var replacement, for all but first argument of set
|
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||||
// TODO commands
|
|
||||||
for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
|
|
||||||
argv[i] = do_var_replacement(argv[i]);
|
|
||||||
unescape_string(argv[i]);
|
|
||||||
}
|
|
||||||
// Strip quotes for first argument.
|
|
||||||
// TODO This part needs to be handled much better
|
|
||||||
if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
|
|
||||||
strip_quotes(argv[1]);
|
|
||||||
}
|
|
||||||
if (handler->handle) {
|
if (handler->handle) {
|
||||||
results = handler->handle(argc-1, argv+1);
|
results = handler->handle(argc-1, argv+1);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -407,11 +477,9 @@ struct cmd_results *config_subcommand(char **argv, int argc,
|
||||||
char *input = argv[0] ? argv[0] : "(empty)";
|
char *input = argv[0] ? argv[0] : "(empty)";
|
||||||
return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
||||||
}
|
}
|
||||||
// Strip quotes for first argument.
|
|
||||||
// TODO This part needs to be handled much better
|
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||||
if (argc > 1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
|
|
||||||
strip_quotes(argv[1]);
|
|
||||||
}
|
|
||||||
if (handler->handle) {
|
if (handler->handle) {
|
||||||
return handler->handle(argc - 1, argv + 1);
|
return handler->handle(argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -206,14 +206,20 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
||||||
binding->type = BINDING_MOUSE;
|
binding->type = BINDING_MOUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc < 2) {
|
// the arguments to bindsym and bindcode are specially preprocessed,
|
||||||
|
// so that the command to be executed is provided as the final argument.
|
||||||
|
if (argc != 2) {
|
||||||
free_sway_binding(binding);
|
free_sway_binding(binding);
|
||||||
return cmd_results_new(CMD_FAILURE, bindtype,
|
return cmd_results_new(CMD_FAILURE, bindtype,
|
||||||
"Invalid %s command "
|
"Invalid %s command (expected exactly one non-option "
|
||||||
"(expected at least 2 non-option arguments, got %d)", bindtype, argc);
|
"argument, followed by a command)", bindtype);
|
||||||
|
}
|
||||||
|
binding->command = strdup(argv[1]);
|
||||||
|
if (!binding->command) {
|
||||||
|
free_sway_binding(binding);
|
||||||
|
return cmd_results_new(CMD_FAILURE, bindtype,
|
||||||
|
"Unable to allocate a copy of the command");
|
||||||
}
|
}
|
||||||
|
|
||||||
binding->command = join_args(argv + 1, argc - 1);
|
|
||||||
|
|
||||||
list_t *split = split_string(argv[0], "+");
|
list_t *split = split_string(argv[0], "+");
|
||||||
for (int i = 0; i < split->length; ++i) {
|
for (int i = 0; i < split->length; ++i) {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,18 @@
|
||||||
|
|
||||||
struct cmd_results *cmd_for_window(int argc, char **argv) {
|
struct cmd_results *cmd_for_window(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if ((error = checkarg(argc, "for_window", EXPECTED_AT_LEAST, 2))) {
|
if ((error = checkarg(argc, "for_window", EXPECTED_EQUAL_TO, 2))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the arguments to cmd_for_window are specially preprocessed,
|
||||||
|
// so that the command to be executed is provided as the final argument.
|
||||||
|
char *cmdlist = strdup(argv[1]);
|
||||||
|
if (!cmdlist) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "for_window",
|
||||||
|
"Unable to allocate a copy of the command");
|
||||||
|
}
|
||||||
|
|
||||||
char *err_str = NULL;
|
char *err_str = NULL;
|
||||||
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
||||||
if (!criteria) {
|
if (!criteria) {
|
||||||
|
|
@ -21,7 +29,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
criteria->type = CT_COMMAND;
|
criteria->type = CT_COMMAND;
|
||||||
criteria->cmdlist = join_args(argv + 1, argc - 1);
|
criteria->cmdlist = cmdlist;
|
||||||
|
|
||||||
list_add(config->criteria, criteria);
|
list_add(config->criteria, criteria);
|
||||||
wlr_log(WLR_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
|
wlr_log(WLR_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist);
|
||||||
|
|
|
||||||
|
|
@ -748,7 +748,6 @@ bool read_config(FILE *file, struct sway_config *config,
|
||||||
}
|
}
|
||||||
|
|
||||||
char *do_var_replacement(char *str) {
|
char *do_var_replacement(char *str) {
|
||||||
int i;
|
|
||||||
char *find = str;
|
char *find = str;
|
||||||
while ((find = strchr(find, '$'))) {
|
while ((find = strchr(find, '$'))) {
|
||||||
// Skip if escaped.
|
// Skip if escaped.
|
||||||
|
|
@ -758,15 +757,8 @@ char *do_var_replacement(char *str) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unescape double $ and move on
|
|
||||||
if (find[1] == '$') {
|
|
||||||
size_t length = strlen(find + 1);
|
|
||||||
memmove(find, find + 1, length);
|
|
||||||
find[length] = '\0';
|
|
||||||
++find;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Find matching variable
|
// Find matching variable
|
||||||
|
int i;
|
||||||
for (i = 0; i < config->symbols->length; ++i) {
|
for (i = 0; i < config->symbols->length; ++i) {
|
||||||
struct sway_variable *var = config->symbols->items[i];
|
struct sway_variable *var = config->symbols->items[i];
|
||||||
int vnlen = strlen(var->name);
|
int vnlen = strlen(var->name);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue