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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// return the last error, if any (for now). (Since we have access to an
|
||||
// error string we could e.g. concatenate all errors there.)
|
||||
struct cmd_results *results = NULL;
|
||||
char *exec = strdup(_exec);
|
||||
char *head = exec;
|
||||
char *cmdlist;
|
||||
char *cmd;
|
||||
list_t *views = NULL;
|
||||
|
||||
if (seat == NULL) {
|
||||
|
|
@ -251,43 +329,42 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
|||
head += strspn(head, whitespace);
|
||||
}
|
||||
// Split command list
|
||||
cmdlist = argsep(&head, ";");
|
||||
char *cmdlist = argsep(&head, ";");
|
||||
cmdlist += strspn(cmdlist, whitespace);
|
||||
do {
|
||||
// Split commands
|
||||
cmd = argsep(&cmdlist, ",");
|
||||
char *cmd = argsep(&cmdlist, ",");
|
||||
cmd += strspn(cmd, whitespace);
|
||||
if (strcmp(cmd, "") == 0) {
|
||||
wlr_log(WLR_INFO, "Ignoring empty command.");
|
||||
continue;
|
||||
}
|
||||
wlr_log(WLR_INFO, "Handling command '%s'", cmd);
|
||||
//TODO better handling of argv
|
||||
|
||||
// Identify which command to execute.
|
||||
int argc;
|
||||
char **argv = split_args(cmd, &argc);
|
||||
if (strcmp(argv[0], "exec") != 0) {
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (*argv[i] == '\"' || *argv[i] == '\'') {
|
||||
strip_quotes(argv[i]);
|
||||
}
|
||||
char **argv = split_args(exec, &argc);
|
||||
if (!argv) {
|
||||
if (results) {
|
||||
free_cmd_results(results);
|
||||
}
|
||||
results = cmd_results_new(CMD_INVALID, cmd,
|
||||
"Allocation failure");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
|
||||
if (!handler) {
|
||||
if (results) {
|
||||
free_cmd_results(results);
|
||||
}
|
||||
results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
|
||||
free_argv(argc, argv);
|
||||
results = cmd_results_new(CMD_INVALID, cmd,
|
||||
"Unknown/invalid command");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Var replacement, for all but first argument of set
|
||||
for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
|
||||
argv[i] = do_var_replacement(argv[i]);
|
||||
unescape_string(argv[i]);
|
||||
}
|
||||
// Process command arguments
|
||||
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||
|
||||
if (!config->handler_context.using_criteria) {
|
||||
// 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")) {
|
||||
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) {
|
||||
free_argv(argc, argv);
|
||||
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) {
|
||||
struct sway_view *view = views->items[i];
|
||||
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) {
|
||||
free_argv(argc, argv);
|
||||
if (results) {
|
||||
|
|
@ -324,7 +401,9 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) {
|
|||
free_cmd_results(res);
|
||||
}
|
||||
}
|
||||
free_argv(argc, argv);
|
||||
if (argc) {
|
||||
free_argv(argc, argv);
|
||||
}
|
||||
} while(cmdlist);
|
||||
} while(head);
|
||||
cleanup:
|
||||
|
|
@ -372,18 +451,9 @@ struct cmd_results *config_command(char *exec) {
|
|||
results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
||||
goto cleanup;
|
||||
}
|
||||
int i;
|
||||
// Var replacement, for all but first argument of set
|
||||
// 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]);
|
||||
}
|
||||
|
||||
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||
|
||||
if (handler->handle) {
|
||||
results = handler->handle(argc-1, argv+1);
|
||||
} else {
|
||||
|
|
@ -407,11 +477,9 @@ struct cmd_results *config_subcommand(char **argv, int argc,
|
|||
char *input = argv[0] ? argv[0] : "(empty)";
|
||||
return cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
|
||||
}
|
||||
// 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]);
|
||||
}
|
||||
|
||||
argc = preprocess_arg(handler->handle, argv + 1, argc - 1) + 1;
|
||||
|
||||
if (handler->handle) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return cmd_results_new(CMD_FAILURE, bindtype,
|
||||
"Invalid %s command "
|
||||
"(expected at least 2 non-option arguments, got %d)", bindtype, argc);
|
||||
"Invalid %s command (expected exactly one non-option "
|
||||
"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], "+");
|
||||
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 *error = NULL;
|
||||
if ((error = checkarg(argc, "for_window", EXPECTED_AT_LEAST, 2))) {
|
||||
if ((error = checkarg(argc, "for_window", EXPECTED_EQUAL_TO, 2))) {
|
||||
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;
|
||||
struct criteria *criteria = criteria_parse(argv[0], &err_str);
|
||||
if (!criteria) {
|
||||
|
|
@ -21,7 +29,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
|
|||
}
|
||||
|
||||
criteria->type = CT_COMMAND;
|
||||
criteria->cmdlist = join_args(argv + 1, argc - 1);
|
||||
criteria->cmdlist = cmdlist;
|
||||
|
||||
list_add(config->criteria, criteria);
|
||||
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) {
|
||||
int i;
|
||||
char *find = str;
|
||||
while ((find = strchr(find, '$'))) {
|
||||
// Skip if escaped.
|
||||
|
|
@ -758,15 +757,8 @@ char *do_var_replacement(char *str) {
|
|||
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
|
||||
int i;
|
||||
for (i = 0; i < config->symbols->length; ++i) {
|
||||
struct sway_variable *var = config->symbols->items[i];
|
||||
int vnlen = strlen(var->name);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue