diff --git a/include/list.h b/include/list.h index 29b988aa..aff6800f 100644 --- a/include/list.h +++ b/include/list.h @@ -13,5 +13,7 @@ void list_add(list_t *list, void *item); void list_insert(list_t *list, int index, void *item); void list_del(list_t *list, int index); void list_cat(list_t *list, list_t *source); +// See qsort +void list_sort(list_t *list, int compare(const void *left, const void *right)); #endif diff --git a/sway.5.txt b/sway.5.txt index 595333c4..9bcfef42 100644 --- a/sway.5.txt +++ b/sway.5.txt @@ -85,6 +85,11 @@ Commands Sets the layout mode of the focused container. _mode_ can be one of _splith_, _splitv_, or _toggle split_. +**mode** :: + Switches to the given mode_name. the default mode is simply _default_. To + create a new mode in config append _{_ to this command, the following lines + will be keybinds for that mode, and _}_ on its own line to close the block. + **move** :: Moves the focused container _left_, _right_, _up_, or _down_. diff --git a/sway/commands.c b/sway/commands.c index e7ddfa71..44407bfa 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -139,8 +139,7 @@ static bool cmd_bindsym(int argc, char **argv) { // TODO: Check if there are other commands with this key binding struct sway_mode *mode = config->current_mode; list_add(mode->bindings, binding); - qsort(mode->bindings->items, mode->bindings->length, - sizeof(mode->bindings->items[0]), bindsym_sort); + list_sort(mode->bindings, bindsym_sort); sway_log(L_DEBUG, "bindsym - Bound %s to command %s", argv[0], binding->command); return true; @@ -828,14 +827,36 @@ static bool cmd_scratchpad(int argc, char **argv) { } } +// sort in order of longest->shortest +static int compare_set(const void *_l, const void *_r) { + struct sway_variable * const *l = _l; + struct sway_variable * const *r = _r; + return strlen((*r)->name) - strlen((*l)->name); +} + static bool cmd_set(int argc, char **argv) { if (!checkarg(argc, "set", EXPECTED_EQUAL_TO, 2)) { return false; } - struct sway_variable *var = malloc(sizeof(struct sway_variable)); - var->name = strdup(argv[0]); + struct sway_variable *var = NULL; + // Find old variable if it exists + int i; + for (i = 0; i < config->symbols->length; ++i) { + var = config->symbols->items[i]; + if (strcmp(var->name, argv[0]) == 0) { + break; + } + var = NULL; + } + if (var) { + free(var->value); + } else { + var = malloc(sizeof(struct sway_variable)); + var->name = strdup(argv[0]); + list_add(config->symbols, var); + list_sort(config->symbols, compare_set); + } var->value = strdup(argv[1]); - list_add(config->symbols, var); return true; } @@ -1048,7 +1069,8 @@ bool handle_command(char *exec) { bool exec_success = false; if (handler) { int i; - for (i = 1; i < argc; ++i) { + // Skip var replacement for first value of cmd_set + for (i = (handler->handle == cmd_set ? 2 : 1); i < argc; ++i) { argv[i] = do_var_replacement(argv[i]); } exec_success = handler->handle(argc - 1, argv + 1); diff --git a/sway/config.c b/sway/config.c index 6c8fe8c1..daaedeed 100644 --- a/sway/config.c +++ b/sway/config.c @@ -230,19 +230,17 @@ bool read_config(FILE *file, bool is_active) { char *line; while (!feof(file)) { line = read_line(file); - line = strip_whitespace(line); line = strip_comments(line); - if (line[0] == '\0') { - goto _continue; + list_t *args = split_string(line, whitespace); + if (!args->length) { + goto cleanup; } - if (line[0] == '}') { + //TODO make this better, it only handles modes right now, and very + //simply at that + if (strncmp(args->items[0], "}", 1) == 0) { config->current_mode = default_mode; - goto _continue; + goto cleanup; } - - // Any command which would require wlc to be initialized - // should be queued for later execution - list_t *args = split_string(line, whitespace); struct cmd_handler *handler; if ((handler = find_handler(args->items[0]))) { if (handler->config_type == CMD_KEYBIND) { @@ -259,9 +257,8 @@ bool read_config(FILE *file, bool is_active) { } else { sway_log(L_ERROR, "Invalid command ``%s''", line); } + cleanup: free_flat_list(args); - -_continue: free(line); } @@ -277,27 +274,33 @@ _continue: } char *do_var_replacement(char *str) { - // TODO: Handle escaping $ and using $ in string literals int i; - for (i = 0; str[i]; ++i) { - if (str[i] == '$') { - // Try for match (note: this could be faster) - int j; - for (j = 0; j < config->symbols->length; ++j) { - struct sway_variable *var = config->symbols->items[j]; - if (strstr(str + i, var->name) == str + i) { - // Match, do replacement - char *new_string = malloc( - strlen(str) - - strlen(var->name) + - strlen(var->value) + 1); - strncpy(new_string, str, i); - new_string[i] = 0; - strcat(new_string, var->value); - strcat(new_string, str + i + strlen(var->name)); - free(str); - str = new_string; - } + char *find = str; + while ((find = strchr(find, '$'))) { + // Skip if escaped. + if (find > str + 1 && find[-1] == '\\') { + if (!(find > str + 2 && find[-2] == '\\')) { + continue; + } + } + // Find matching variable + for (i = 0; i < config->symbols->length; ++i) { + struct sway_variable *var = config->symbols->items[i]; + int vnlen = strlen(var->name); + if (strncmp(find, var->name, vnlen) == 0) { + int vvlen = strlen(var->value); + char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); + char *newptr = newstr; + int offset = find - str; + strncpy(newptr, str, offset); + newptr += offset; + strncpy(newptr, var->value, vvlen); + newptr += vvlen; + strcpy(newptr, find + vnlen); + free(str); + str = newstr; + find = str + offset + vvlen; + break; } } } diff --git a/sway/list.c b/sway/list.c index 1be1e17c..45efc16f 100644 --- a/sway/list.c +++ b/sway/list.c @@ -49,3 +49,7 @@ void list_cat(list_t *list, list_t *source) { list_add(list, source->items[i]); } } + +void list_sort(list_t *list, int compare(const void *left, const void *right)) { + qsort(list->items, list->length, sizeof(void *), compare); +}