aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands.c
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-10-25 12:58:05 -0400
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-11-10 21:53:10 -0500
commitb27700060196cb41df1180f51a3d7a254a97fd27 (patch)
treece2f52dfe9b7c1b69df89aad8e6680e00be35b72 /sway/commands.c
parentMerge pull request #3098 from c-edw/feature/RefactorArgParse (diff)
downloadsway-b27700060196cb41df1180f51a3d7a254a97fd27.tar.gz
sway-b27700060196cb41df1180f51a3d7a254a97fd27.tar.zst
sway-b27700060196cb41df1180f51a3d7a254a97fd27.zip
Alter config variable replacement process
Currently, variables cannot contain commands and cannot span more than one argument. This is due to variable replacement happening after determining the handler and after splitting the config line into arguments. This changes the process to: 0. Check for empty lines and block boundaries 1. Split the arguments as before 2. Verify that the first argument is not a variable. If needed the following occurs a. Perform variable replacement on just the first argument b. Join the arguments back together then split the arguments again. This is needed when the variable contains the command and arguments for the command. 3. Determine the handler 4. If the handler is cmd_set, escape the variable name so that it does not get replaced 5. Join the arguments back together, do variable replacement on the full command, and split the arguments again 6. Perform any needed quote stripping or unescaping on arguments 7. Run the command handler This allows for config snippets such as: ``` set $super bindsym Mod4 $super+a exec some-command ``` and ``` set $bg bg #ffffff solid_color output * $bg ```
Diffstat (limited to 'sway/commands.c')
-rw-r--r--sway/commands.c61
1 files changed, 46 insertions, 15 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 37c7169a..4b86c2fa 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -353,12 +353,14 @@ struct cmd_results *config_command(char *exec) {
353 struct cmd_results *results = NULL; 353 struct cmd_results *results = NULL;
354 int argc; 354 int argc;
355 char **argv = split_args(exec, &argc); 355 char **argv = split_args(exec, &argc);
356
357 // Check for empty lines
356 if (!argc) { 358 if (!argc) {
357 results = cmd_results_new(CMD_SUCCESS, NULL, NULL); 359 results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
358 goto cleanup; 360 goto cleanup;
359 } 361 }
360 362
361 // Start block 363 // Check for the start of a block
362 if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) { 364 if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) {
363 char *block = join_args(argv, argc - 1); 365 char *block = join_args(argv, argc - 1);
364 results = cmd_results_new(CMD_BLOCK, block, NULL); 366 results = cmd_results_new(CMD_BLOCK, block, NULL);
@@ -366,22 +368,54 @@ struct cmd_results *config_command(char *exec) {
366 goto cleanup; 368 goto cleanup;
367 } 369 }
368 370
369 // Endblock 371 // Check for the end of a block
370 if (strcmp(argv[argc - 1], "}") == 0) { 372 if (strcmp(argv[argc - 1], "}") == 0) {
371 results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); 373 results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
372 goto cleanup; 374 goto cleanup;
373 } 375 }
374 wlr_log(WLR_INFO, "handling config command '%s'", exec); 376
377 // Make sure the command is not stored in a variable
378 if (*argv[0] == '$') {
379 argv[0] = do_var_replacement(argv[0]);
380 char *temp = join_args(argv, argc);
381 free_argv(argc, argv);
382 argv = split_args(temp, &argc);
383 free(temp);
384 if (!argc) {
385 results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
386 goto cleanup;
387 }
388 }
389
390 // Determine the command handler
391 wlr_log(WLR_INFO, "Config command: %s", exec);
375 struct cmd_handler *handler = find_handler(argv[0], NULL, 0); 392 struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
376 if (!handler) { 393 if (!handler || !handler->handle) {
377 char *input = argv[0] ? argv[0] : "(empty)"; 394 char *input = argv[0] ? argv[0] : "(empty)";
378 results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); 395 char *error = handler
396 ? "This command is shimmed, but unimplemented"
397 : "Unknown/invalid command";
398 results = cmd_results_new(CMD_INVALID, input, error);
379 goto cleanup; 399 goto cleanup;
380 } 400 }
381 int i; 401
382 // Var replacement, for all but first argument of set 402 // Do variable replacement
383 // TODO commands 403 if (handler->handle == cmd_set && argc > 1 && *argv[1] == '$') {
384 for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) { 404 // Escape the variable name so it does not get replaced by one shorter
405 char *temp = calloc(1, strlen(argv[1]) + 2);
406 temp[0] = '$';
407 strcpy(&temp[1], argv[1]);
408 free(argv[1]);
409 argv[1] = temp;
410 }
411 char *command = do_var_replacement(join_args(argv, argc));
412 wlr_log(WLR_INFO, "After replacement: %s", command);
413 free_argv(argc, argv);
414 argv = split_args(command, &argc);
415 free(command);
416
417 // Strip quotes and unescape the string
418 for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
385 if (handler->handle != cmd_exec && handler->handle != cmd_exec_always 419 if (handler->handle != cmd_exec && handler->handle != cmd_exec_always
386 && handler->handle != cmd_bindsym 420 && handler->handle != cmd_bindsym
387 && handler->handle != cmd_bindcode 421 && handler->handle != cmd_bindcode
@@ -389,14 +423,11 @@ struct cmd_results *config_command(char *exec) {
389 && (*argv[i] == '\"' || *argv[i] == '\'')) { 423 && (*argv[i] == '\"' || *argv[i] == '\'')) {
390 strip_quotes(argv[i]); 424 strip_quotes(argv[i]);
391 } 425 }
392 argv[i] = do_var_replacement(argv[i]);
393 unescape_string(argv[i]); 426 unescape_string(argv[i]);
394 } 427 }
395 if (handler->handle) { 428
396 results = handler->handle(argc-1, argv+1); 429 // Run command
397 } else { 430 results = handler->handle(argc - 1, argv + 1);
398 results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented");
399 }
400 431
401cleanup: 432cleanup:
402 free_argv(argc, argv); 433 free_argv(argc, argv);