diff options
-rw-r--r-- | common/readline.c | 23 | ||||
-rw-r--r-- | include/readline.h | 1 | ||||
-rw-r--r-- | include/sway/commands.h | 29 | ||||
-rw-r--r-- | include/sway/config.h | 2 | ||||
-rw-r--r-- | sway/commands.c | 153 | ||||
-rw-r--r-- | sway/commands/bar.c | 118 | ||||
-rw-r--r-- | sway/commands/bar/colors.c | 26 | ||||
-rw-r--r-- | sway/commands/bar/id.c | 3 | ||||
-rw-r--r-- | sway/commands/input.c | 103 | ||||
-rw-r--r-- | sway/commands/mode.c | 28 | ||||
-rw-r--r-- | sway/commands/seat.c | 61 | ||||
-rw-r--r-- | sway/config.c | 196 | ||||
-rw-r--r-- | sway/input/keyboard.c | 1 | ||||
-rw-r--r-- | sway/ipc-server.c | 1 |
14 files changed, 349 insertions, 396 deletions
diff --git a/common/readline.c b/common/readline.c index ed5801de..1c396a90 100644 --- a/common/readline.c +++ b/common/readline.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include "readline.h" #include "log.h" #include <stdlib.h> @@ -48,6 +49,28 @@ char *read_line(FILE *file) { return string; } +char *peek_line(FILE *file, int line_offset, long *position) { + long pos = ftell(file); + size_t length = 0; + char *line = NULL; + for (int i = 0; i <= line_offset; i++) { + ssize_t read = getline(&line, &length, file); + if (read < 0) { + free(line); + line = NULL; + break; + } + if (read > 0 && line[read - 1] == '\n') { + line[read - 1] = '\0'; + } + } + if (position) { + *position = ftell(file); + } + fseek(file, pos, SEEK_SET); + return line; +} + char *read_line_buffer(FILE *file, char *string, size_t string_len) { size_t length = 0; if (!string) { diff --git a/include/readline.h b/include/readline.h index b3e06d4b..ee2eba5d 100644 --- a/include/readline.h +++ b/include/readline.h @@ -4,6 +4,7 @@ #include <stdio.h> char *read_line(FILE *file); +char *peek_line(FILE *file, int line_offset, long *position); char *read_line_buffer(FILE *file, char *string, size_t string_len); #endif diff --git a/include/sway/commands.h b/include/sway/commands.h index b2255c4b..593ae0f1 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -3,6 +3,13 @@ #include "config.h" +typedef struct cmd_results *sway_cmd(int argc, char **argv); + +struct cmd_handler { + char *command; + sway_cmd *handle; +}; + /** * Indicates the result of a command's execution. */ @@ -11,16 +18,9 @@ enum cmd_status { CMD_FAILURE, /**< The command resulted in an error */ CMD_INVALID, /**< Unknown command or parser error */ CMD_DEFER, /**< Command execution deferred */ - // Config Blocks - CMD_BLOCK_END, - CMD_BLOCK_MODE, - CMD_BLOCK_BAR, - CMD_BLOCK_BAR_COLORS, - CMD_BLOCK_INPUT, - CMD_BLOCK_SEAT, + CMD_BLOCK, CMD_BLOCK_COMMANDS, - CMD_BLOCK_IPC, - CMD_BLOCK_IPC_EVENTS, + CMD_BLOCK_END }; /** @@ -45,6 +45,8 @@ enum expected_args { struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val); +struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, + int handlers_size); /** * Parse and executes a command. */ @@ -54,7 +56,12 @@ struct cmd_results *execute_command(char *command, struct sway_seat *seat); * * Do not use this under normal conditions. */ -struct cmd_results *config_command(char *command, enum cmd_status block); +struct cmd_results *config_command(char *command); +/** + * Parse and handle a sub command + */ +struct cmd_results *config_subcommand(char **argv, int argc, + struct cmd_handler *handlers, size_t handlers_size); /* * Parses a command policy rule. */ @@ -77,8 +84,6 @@ const char *cmd_results_to_json(struct cmd_results *results); struct cmd_results *add_color(const char *name, char *buffer, const char *color); -typedef struct cmd_results *sway_cmd(int argc, char **argv); - sway_cmd cmd_assign; sway_cmd cmd_bar; sway_cmd cmd_bindcode; diff --git a/include/sway/config.h b/include/sway/config.h index de651ea4..b597da75 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -403,8 +403,6 @@ bool read_config(FILE *file, struct sway_config *config); */ void free_config(struct sway_config *config); -void config_clear_handler_context(struct sway_config *config); - void free_sway_variable(struct sway_variable *var); /** diff --git a/sway/commands.c b/sway/commands.c index e9762bef..3a86ae53 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -16,11 +16,6 @@ #include "stringop.h" #include "log.h" -struct cmd_handler { - char *command; - sway_cmd *handle; -}; - // Returns error object, or NULL if check succeeds. struct cmd_results *checkarg(int argc, const char *name, enum expected_args type, int val) { struct cmd_results *error = NULL; @@ -122,47 +117,6 @@ static struct cmd_handler handlers[] = { { "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth }, }; -static struct cmd_handler bar_handlers[] = { - { "activate_button", bar_cmd_activate_button }, - { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, - { "bindsym", bar_cmd_bindsym }, - { "colors", bar_cmd_colors }, - { "context_button", bar_cmd_context_button }, - { "font", bar_cmd_font }, - { "height", bar_cmd_height }, - { "hidden_state", bar_cmd_hidden_state }, - { "icon_theme", bar_cmd_icon_theme }, - { "id", bar_cmd_id }, - { "mode", bar_cmd_mode }, - { "modifier", bar_cmd_modifier }, - { "output", bar_cmd_output }, - { "pango_markup", bar_cmd_pango_markup }, - { "position", bar_cmd_position }, - { "secondary_button", bar_cmd_secondary_button }, - { "separator_symbol", bar_cmd_separator_symbol }, - { "status_command", bar_cmd_status_command }, - { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, - { "swaybar_command", bar_cmd_swaybar_command }, - { "tray_output", bar_cmd_tray_output }, - { "tray_padding", bar_cmd_tray_padding }, - { "workspace_buttons", bar_cmd_workspace_buttons }, - { "wrap_scroll", bar_cmd_wrap_scroll }, -}; - -static struct cmd_handler bar_colors_handlers[] = { - { "active_workspace", bar_colors_cmd_active_workspace }, - { "background", bar_colors_cmd_background }, - { "binding_mode", bar_colors_cmd_binding_mode }, - { "focused_background", bar_colors_cmd_focused_background }, - { "focused_separator", bar_colors_cmd_focused_separator }, - { "focused_statusline", bar_colors_cmd_focused_statusline }, - { "focused_workspace", bar_colors_cmd_focused_workspace }, - { "inactive_workspace", bar_colors_cmd_inactive_workspace }, - { "separator", bar_colors_cmd_separator }, - { "statusline", bar_colors_cmd_statusline }, - { "urgent_workspace", bar_colors_cmd_urgent_workspace }, -}; - /* Config-time only commands. Keep alphabetized */ static struct cmd_handler config_handlers[] = { { "default_orientation", cmd_default_orientation }, @@ -202,62 +156,14 @@ static int handler_compare(const void *_a, const void *_b) { return strcasecmp(a->command, b->command); } -// must be in order for the bsearch -static struct cmd_handler input_handlers[] = { - { "accel_profile", input_cmd_accel_profile }, - { "click_method", input_cmd_click_method }, - { "drag_lock", input_cmd_drag_lock }, - { "dwt", input_cmd_dwt }, - { "events", input_cmd_events }, - { "left_handed", input_cmd_left_handed }, - { "map_from_region", input_cmd_map_from_region }, - { "map_to_output", input_cmd_map_to_output }, - { "middle_emulation", input_cmd_middle_emulation }, - { "natural_scroll", input_cmd_natural_scroll }, - { "pointer_accel", input_cmd_pointer_accel }, - { "repeat_delay", input_cmd_repeat_delay }, - { "repeat_rate", input_cmd_repeat_rate }, - { "scroll_method", input_cmd_scroll_method }, - { "tap", input_cmd_tap }, - { "xkb_layout", input_cmd_xkb_layout }, - { "xkb_model", input_cmd_xkb_model }, - { "xkb_options", input_cmd_xkb_options }, - { "xkb_rules", input_cmd_xkb_rules }, - { "xkb_variant", input_cmd_xkb_variant }, -}; - -// must be in order for the bsearch -static struct cmd_handler seat_handlers[] = { - { "attach", seat_cmd_attach }, - { "cursor", seat_cmd_cursor }, - { "fallback", seat_cmd_fallback }, -}; - -static struct cmd_handler *find_handler(char *line, enum cmd_status block) { +struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, + int handlers_size) { struct cmd_handler d = { .command=line }; struct cmd_handler *res = NULL; - wlr_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_SEAT); + wlr_log(L_DEBUG, "find_handler(%s)", line); bool config_loading = config->reading || !config->active; - if (block == CMD_BLOCK_BAR) { - return bsearch(&d, bar_handlers, - sizeof(bar_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_BAR_COLORS) { - return bsearch(&d, bar_colors_handlers, - sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_INPUT) { - return bsearch(&d, input_handlers, - sizeof(input_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } else if (block == CMD_BLOCK_SEAT) { - return bsearch(&d, seat_handlers, - sizeof(seat_handlers) / sizeof(struct cmd_handler), - sizeof(struct cmd_handler), handler_compare); - } - if (!config_loading) { res = bsearch(&d, command_handlers, sizeof(command_handlers) / sizeof(struct cmd_handler), @@ -278,8 +184,13 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { } } - res = bsearch(&d, handlers, - sizeof(handlers) / sizeof(struct cmd_handler), + if (!cmd_handlers) { + cmd_handlers = handlers; + handlers_size = sizeof(handlers); + } + + res = bsearch(&d, cmd_handlers, + handlers_size / sizeof(struct cmd_handler), sizeof(struct cmd_handler), handler_compare); return res; @@ -349,7 +260,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { } } } - struct cmd_handler *handler = find_handler(argv[0], CMD_BLOCK_END); + struct cmd_handler *handler = find_handler(argv[0], NULL, 0); if (!handler) { if (results) { free_cmd_results(results); @@ -413,7 +324,7 @@ cleanup: // be chained together) // 4) execute_command handles all state internally while config_command has // some state handled outside (notably the block mode, in read_config) -struct cmd_results *config_command(char *exec, enum cmd_status block) { +struct cmd_results *config_command(char *exec) { struct cmd_results *results = NULL; int argc; char **argv = split_args(exec, &argc); @@ -422,13 +333,21 @@ struct cmd_results *config_command(char *exec, enum cmd_status block) { goto cleanup; } - wlr_log(L_INFO, "handling config command '%s'", exec); + // Start block + if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) { + char *block = join_args(argv, argc - 1); + results = cmd_results_new(CMD_BLOCK, block, NULL); + free(block); + goto cleanup; + } + // Endblock - if (**argv == '}') { + if (strcmp(argv[argc - 1], "}") == 0) { results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); goto cleanup; } - struct cmd_handler *handler = find_handler(argv[0], block); + wlr_log(L_INFO, "handling config command '%s'", exec); + struct cmd_handler *handler = find_handler(argv[0], NULL, 0); if (!handler) { char *input = argv[0] ? argv[0] : "(empty)"; results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); @@ -457,6 +376,30 @@ cleanup: return results; } +struct cmd_results *config_subcommand(char **argv, int argc, + struct cmd_handler *handlers, size_t handlers_size) { + char *command = join_args(argv, argc); + wlr_log(L_DEBUG, "Subcommand: %s", command); + free(command); + + struct cmd_handler *handler = find_handler(argv[0], handlers, + handlers_size); + if (!handler) { + 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]); + } + if (handler->handle) { + return handler->handle(argc - 1, argv + 1); + } + return cmd_results_new(CMD_INVALID, argv[0], + "This command is shimmed, but unimplemented"); +} + struct cmd_results *config_commands_command(char *exec) { struct cmd_results *results = NULL; int argc; @@ -474,7 +417,7 @@ struct cmd_results *config_commands_command(char *exec) { goto cleanup; } - struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); + struct cmd_handler *handler = find_handler(cmd, NULL, 0); if (!handler && strcmp(cmd, "*") != 0) { char *input = cmd ? cmd : "(empty)"; results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); diff --git a/sway/commands/bar.c b/sway/commands/bar.c index ff111163..d84ce808 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 500 #include <string.h> #include <strings.h> #include <wlr/util/log.h> @@ -5,53 +6,110 @@ #include "sway/config.h" #include "util.h" +// Must be in alphabetical order for bsearch +static struct cmd_handler bar_handlers[] = { + { "activate_button", bar_cmd_activate_button }, + { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, + { "bindsym", bar_cmd_bindsym }, + { "colors", bar_cmd_colors }, + { "context_button", bar_cmd_context_button }, + { "font", bar_cmd_font }, + { "height", bar_cmd_height }, + { "hidden_state", bar_cmd_hidden_state }, + { "icon_theme", bar_cmd_icon_theme }, + { "id", bar_cmd_id }, + { "mode", bar_cmd_mode }, + { "modifier", bar_cmd_modifier }, + { "output", bar_cmd_output }, + { "pango_markup", bar_cmd_pango_markup }, + { "position", bar_cmd_position }, + { "secondary_button", bar_cmd_secondary_button }, + { "separator_symbol", bar_cmd_separator_symbol }, + { "status_command", bar_cmd_status_command }, + { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, + { "swaybar_command", bar_cmd_swaybar_command }, + { "tray_output", bar_cmd_tray_output }, + { "tray_padding", bar_cmd_tray_padding }, + { "workspace_buttons", bar_cmd_workspace_buttons }, + { "wrap_scroll", bar_cmd_wrap_scroll }, +}; + +// Must be in alphabetical order for bsearch +static struct cmd_handler bar_config_handlers[] = { + { "hidden_state", bar_cmd_hidden_state }, + { "mode", bar_cmd_mode } +}; + struct cmd_results *cmd_bar(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { return error; } - if (config->reading && strcmp("{", argv[0]) != 0) { - return cmd_results_new(CMD_INVALID, "bar", - "Expected '{' at start of bar config definition."); + if (!config->reading) { + if (!find_handler(argv[0], bar_config_handlers, + sizeof(bar_config_handlers))) { + return cmd_results_new(CMD_FAILURE, "bar", + "Can only be used in config file."); + } + return config_subcommand(argv, argc, bar_config_handlers, + sizeof(bar_config_handlers)); } - if (!config->reading) { - if (argc > 1) { - if (strcasecmp("mode", argv[0]) == 0) { - return bar_cmd_mode(argc-1, argv + 1); + if (argc > 1) { + struct bar_config *bar = NULL; + if (!find_handler(argv[0], bar_handlers, sizeof(bar_handlers)) + && find_handler(argv[1], bar_handlers, sizeof(bar_handlers))) { + for (int i = 0; i < config->bars->length; ++i) { + struct bar_config *item = config->bars->items[i]; + if (strcmp(item->id, argv[0]) == 0) { + wlr_log(L_DEBUG, "Selecting bar: %s", argv[0]); + bar = item; + break; + } } + if (!bar) { + wlr_log(L_DEBUG, "Creating bar: %s", argv[0]); + bar = default_bar_config(); + if (!bar) { + return cmd_results_new(CMD_FAILURE, "bar", + "Unable to allocate bar state"); + } - if (strcasecmp("hidden_state", argv[0]) == 0) { - return bar_cmd_hidden_state(argc-1, argv + 1); + bar->id = strdup(argv[0]); } + config->current_bar = bar; + ++argv; --argc; } - return cmd_results_new(CMD_FAILURE, "bar", "Can only be used in config file."); } - // Create new bar with default values - struct bar_config *bar = default_bar_config(); - if (!bar) { - return cmd_results_new(CMD_FAILURE, "bar", "Unable to allocate bar state"); - } + if (!config->current_bar) { + // Create new bar with default values + struct bar_config *bar = default_bar_config(); + if (!bar) { + return cmd_results_new(CMD_FAILURE, "bar", + "Unable to allocate bar state"); + } - // set bar id - for (int i = 0; i < config->bars->length; ++i) { - if (bar == config->bars->items[i]) { - const int len = 5 + numlen(i); // "bar-" + i + \0 - bar->id = malloc(len * sizeof(char)); - if (bar->id) { - snprintf(bar->id, len, "bar-%d", i); - } else { - return cmd_results_new(CMD_FAILURE, - "bar", "Unable to allocate bar ID"); + // set bar id + for (int i = 0; i < config->bars->length; ++i) { + if (bar == config->bars->items[i]) { + const int len = 5 + numlen(i); // "bar-" + i + \0 + bar->id = malloc(len * sizeof(char)); + if (bar->id) { + snprintf(bar->id, len, "bar-%d", i); + } else { + return cmd_results_new(CMD_FAILURE, + "bar", "Unable to allocate bar ID"); + } + break; } - break; } + + // Set current bar + config->current_bar = bar; + wlr_log(L_DEBUG, "Creating bar %s", bar->id); } - // Set current bar - config->current_bar = bar; - wlr_log(L_DEBUG, "Configuring bar %s", bar->id); - return cmd_results_new(CMD_BLOCK_BAR, NULL, NULL); + return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); } diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c index 17ba9b7c..8c862ca9 100644 --- a/sway/commands/bar/colors.c +++ b/sway/commands/bar/colors.c @@ -1,6 +1,21 @@ #include <string.h> #include "sway/commands.h" +// Must be in alphabetical order for bsearch +static struct cmd_handler bar_colors_handlers[] = { + { "active_workspace", bar_colors_cmd_active_workspace }, + { "background", bar_colors_cmd_background }, + { "binding_mode", bar_colors_cmd_binding_mode }, + { "focused_background", bar_colors_cmd_focused_background }, + { "focused_separator", bar_colors_cmd_focused_separator }, + { "focused_statusline", bar_colors_cmd_focused_statusline }, + { "focused_workspace", bar_colors_cmd_focused_workspace }, + { "inactive_workspace", bar_colors_cmd_inactive_workspace }, + { "separator", bar_colors_cmd_separator }, + { "statusline", bar_colors_cmd_statusline }, + { "urgent_workspace", bar_colors_cmd_urgent_workspace }, +}; + static struct cmd_results *parse_single_color(char **color, const char *cmd_name, int argc, char **argv) { struct cmd_results *error = NULL; @@ -37,15 +52,8 @@ static struct cmd_results *parse_three_colors(char ***colors, } struct cmd_results *bar_cmd_colors(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "colors", EXPECTED_EQUAL_TO, 1))) { - return error; - } - if (strcmp("{", argv[0]) != 0) { - return cmd_results_new(CMD_INVALID, "colors", - "Expected '{' at the start of colors config definition."); - } - return cmd_results_new(CMD_BLOCK_BAR_COLORS, NULL, NULL); + return config_subcommand(argv, argc, bar_colors_handlers, + sizeof(bar_colors_handlers)); } struct cmd_results *bar_colors_cmd_active_workspace(int argc, char **argv) { diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c index c1e56f03..6ce86fef 100644 --- a/sway/commands/bar/id.c +++ b/sway/commands/bar/id.c @@ -11,6 +11,9 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) { const char *name = argv[0]; const char *oldname = config->current_bar->id; + if (strcmp(name, oldname) == 0) { + return cmd_results_new(CMD_SUCCESS, NULL, NULL); // NOP + } // check if id is used by a previously defined bar for (int i = 0; i < config->bars->length; ++i) { struct bar_config *find = config->bars->items[i]; diff --git a/sway/commands/input.c b/sway/commands/input.c index eeb4ee75..22a0bb7c 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -3,85 +3,50 @@ #include "sway/commands.h" #include "sway/input/input-manager.h" #include "log.h" +#include "stringop.h" + +// must be in order for the bsearch +static struct cmd_handler input_handlers[] = { + { "accel_profile", input_cmd_accel_profile }, + { "click_method", input_cmd_click_method }, + { "drag_lock", input_cmd_drag_lock }, + { "dwt", input_cmd_dwt }, + { "events", input_cmd_events }, + { "left_handed", input_cmd_left_handed }, + { "map_from_region", input_cmd_map_from_region }, + { "map_to_output", input_cmd_map_to_output }, + { "middle_emulation", input_cmd_middle_emulation }, + { "natural_scroll", input_cmd_natural_scroll }, + { "pointer_accel", input_cmd_pointer_accel }, + { "repeat_delay", input_cmd_repeat_delay }, + { "repeat_rate", input_cmd_repeat_rate }, + { "scroll_method", input_cmd_scroll_method }, + { "tap", input_cmd_tap }, + { "xkb_layout", input_cmd_xkb_layout }, + { "xkb_model", input_cmd_xkb_model }, + { "xkb_options", input_cmd_xkb_options }, + { "xkb_rules", input_cmd_xkb_rules }, + { "xkb_variant", input_cmd_xkb_variant }, +}; struct cmd_results *cmd_input(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { + if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 1))) { return error; } - if (config->reading && strcmp("{", argv[1]) == 0) { - free_input_config(config->handler_context.input_config); - config->handler_context.input_config = new_input_config(argv[0]); - if (!config->handler_context.input_config) { - return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); - } - wlr_log(L_DEBUG, "entering input block: %s", argv[0]); - return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); - } - - if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 3))) { - return error; - } + wlr_log(L_DEBUG, "entering input block: %s", argv[0]); - bool has_context = (config->handler_context.input_config != NULL); - if (!has_context) { - // caller did not give a context so create one just for this command - config->handler_context.input_config = new_input_config(argv[0]); - if (!config->handler_context.input_config) { - return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); - } + config->handler_context.input_config = new_input_config(argv[0]); + if (!config->handler_context.input_config) { + return cmd_results_new(CMD_FAILURE, NULL, "Couldn't allocate config"); } - int argc_new = argc-2; - char **argv_new = argv+2; + struct cmd_results *res = config_subcommand(argv + 1, argc - 1, + input_handlers, sizeof(input_handlers)); - struct cmd_results *res; - if (strcasecmp("accel_profile", argv[1]) == 0) { - res = input_cmd_accel_profile(argc_new, argv_new); - } else if (strcasecmp("click_method", argv[1]) == 0) { - res = input_cmd_click_method(argc_new, argv_new); - } else if (strcasecmp("drag_lock", argv[1]) == 0) { - res = input_cmd_drag_lock(argc_new, argv_new); - } else if (strcasecmp("dwt", argv[1]) == 0) { - res = input_cmd_dwt(argc_new, argv_new); - } else if (strcasecmp("events", argv[1]) == 0) { - res = input_cmd_events(argc_new, argv_new); - } else if (strcasecmp("left_handed", argv[1]) == 0) { - res = input_cmd_left_handed(argc_new, argv_new); - } else if (strcasecmp("middle_emulation", argv[1]) == 0) { - res = input_cmd_middle_emulation(argc_new, argv_new); - } else if (strcasecmp("natural_scroll", argv[1]) == 0) { - res = input_cmd_natural_scroll(argc_new, argv_new); - } else if (strcasecmp("pointer_accel", argv[1]) == 0) { - res = input_cmd_pointer_accel(argc_new, argv_new); - } else if (strcasecmp("repeat_delay", argv[1]) == 0) { - res = input_cmd_repeat_delay(argc_new, argv_new); - } else if (strcasecmp("repeat_rate", argv[1]) == 0) { - res = input_cmd_repeat_rate(argc_new, argv_new); - } else if (strcasecmp("scroll_method", argv[1]) == 0) { - res = input_cmd_scroll_method(argc_new, argv_new); - } else if (strcasecmp("tap", argv[1]) == 0) { - res = input_cmd_tap(argc_new, argv_new); - } else if (strcasecmp("xkb_layout", argv[1]) == 0) { - res = input_cmd_xkb_layout(argc_new, argv_new); - } else if (strcasecmp("xkb_model", argv[1]) == 0) { - res = input_cmd_xkb_model(argc_new, argv_new); - } else if (strcasecmp("xkb_options", argv[1]) == 0) { - res = input_cmd_xkb_options(argc_new, argv_new); - } else if (strcasecmp("xkb_rules", argv[1]) == 0) { - res = input_cmd_xkb_rules(argc_new, argv_new); - } else if (strcasecmp("xkb_variant", argv[1]) == 0) { - res = input_cmd_xkb_variant(argc_new, argv_new); - } else { - res = cmd_results_new(CMD_INVALID, "input <device>", "Unknown command %s", argv[1]); - } - - if (!has_context) { - // clean up the context we created earlier - free_input_config(config->handler_context.input_config); - config->handler_context.input_config = NULL; - } + free_input_config(config->handler_context.input_config); + config->handler_context.input_config = NULL; return res; } diff --git a/sway/commands/mode.c b/sway/commands/mode.c index c30a8bac..00331ccc 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c @@ -7,6 +7,13 @@ #include "sway/ipc-server.h" #include "list.h" #include "log.h" +#include "stringop.h" + +// Must be in order for the bsearch +static struct cmd_handler mode_handlers[] = { + { "bindcode", cmd_bindcode }, + { "bindsym", cmd_bindsym } +}; struct cmd_results *cmd_mode(int argc, char **argv) { struct cmd_results *error = NULL; @@ -14,12 +21,12 @@ struct cmd_results *cmd_mode(int argc, char **argv) { return error; } - const char *mode_name = argv[0]; - bool new_mode = (argc == 2 && strcmp(argv[1], "{") == 0); - if (new_mode && !config->reading) { + if (argc > 1 && !config->reading) { return cmd_results_new(CMD_FAILURE, "mode", "Can only be used in config file."); } + + const char *mode_name = argv[0]; struct sway_mode *mode = NULL; // Find mode for (int i = 0; i < config->modes->length; ++i) { @@ -30,7 +37,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) { } } // Create mode if it doesn't exist - if (!mode && new_mode) { + if (!mode && argc > 1) { mode = calloc(1, sizeof(struct sway_mode)); if (!mode) { return cmd_results_new(CMD_FAILURE, @@ -46,14 +53,21 @@ struct cmd_results *cmd_mode(int argc, char **argv) { "mode", "Unknown mode `%s'", mode_name); return error; } - if ((config->reading && new_mode) || (!config->reading && !new_mode)) { + if ((config->reading && argc > 1) || (!config->reading && argc == 1)) { wlr_log(L_DEBUG, "Switching to mode `%s'",mode->name); } // Set current mode config->current_mode = mode; - if (!new_mode) { + if (argc == 1) { // trigger IPC mode event ipc_event_mode(config->current_mode->name); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } - return cmd_results_new(new_mode ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); + + // Create binding + struct cmd_results *result = config_subcommand(argv + 1, argc - 1, + mode_handlers, sizeof(mode_handlers)); + config->current_mode = config->modes->items[0]; + + return result; } diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 5916015f..5e3c0bd0 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -3,59 +3,32 @@ #include "sway/commands.h" #include "sway/input/input-manager.h" #include "log.h" +#include "stringop.h" + +// must be in order for the bsearch +static struct cmd_handler seat_handlers[] = { + { "attach", seat_cmd_attach }, + { "cursor", seat_cmd_cursor }, + { "fallback", seat_cmd_fallback }, +}; struct cmd_results *cmd_seat(int argc, char **argv) { struct cmd_results *error = NULL; - if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 2))) { + if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 1))) { return error; } - if (config->reading && strcmp("{", argv[1]) == 0) { - free_seat_config(config->handler_context.seat_config); - config->handler_context.seat_config = new_seat_config(argv[0]); - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, NULL, - "Couldn't allocate config"); - } - wlr_log(L_DEBUG, "entering seat block: %s", argv[0]); - return cmd_results_new(CMD_BLOCK_SEAT, NULL, NULL); + config->handler_context.seat_config = new_seat_config(argv[0]); + if (!config->handler_context.seat_config) { + return cmd_results_new(CMD_FAILURE, NULL, + "Couldn't allocate config"); } - if ((error = checkarg(argc, "seat", EXPECTED_AT_LEAST, 3))) { - return error; - } - - bool has_context = (config->handler_context.seat_config != NULL); - if (!has_context) { - config->handler_context.seat_config = new_seat_config(argv[0]); - if (!config->handler_context.seat_config) { - return cmd_results_new(CMD_FAILURE, NULL, - "Couldn't allocate config"); - } - } + struct cmd_results *res = config_subcommand(argv + 1, argc - 1, + seat_handlers, sizeof(seat_handlers)); - int argc_new = argc-2; - char **argv_new = argv+2; - - struct cmd_results *res; - if (strcasecmp("attach", argv[1]) == 0) { - res = seat_cmd_attach(argc_new, argv_new); - } else if (strcasecmp("cursor", argv[1]) == 0) { - res = seat_cmd_cursor(argc_new, argv_new); - } else if (strcasecmp("fallback", argv[1]) == 0) { - res = seat_cmd_fallback(argc_new, argv_new); - } else { - res = - cmd_results_new(CMD_INVALID, - "seat <name>", "Unknown command %s", - argv[1]); - } - - if (!has_context) { - // clean up the context we created earlier - free_seat_config(config->handler_context.seat_config); - config->handler_context.seat_config = NULL; - } + free_seat_config(config->handler_context.seat_config); + config->handler_context.seat_config = NULL; return res; } diff --git a/sway/config.c b/sway/config.c index 27308066..88cc6843 100644 --- a/sway/config.c +++ b/sway/config.c @@ -59,12 +59,12 @@ static void free_mode(struct sway_mode *mode) { } void free_config(struct sway_config *config) { - config_clear_handler_context(config); - if (!config) { return; } + memset(&config->handler_context, 0, sizeof(config->handler_context)); + // TODO: handle all currently unhandled lists as we add implementations if (config->symbols) { for (int i = 0; i < config->symbols->length; ++i) { @@ -107,7 +107,6 @@ void free_config(struct sway_config *config) { list_free(config->command_policies); list_free(config->feature_policies); list_free(config->ipc_policies); - free(config->current_bar); free(config->floating_scroll_up_cmd); free(config->floating_scroll_down_cmd); free(config->floating_scroll_left_cmd); @@ -514,37 +513,87 @@ bool load_include_configs(const char *path, struct sway_config *config) { return true; } -void config_clear_handler_context(struct sway_config *config) { - free_input_config(config->handler_context.input_config); - free_seat_config(config->handler_context.seat_config); +static int detect_brace_on_following_line(FILE *file, char *line, + int line_number) { + int lines = 0; + if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') { + char *peeked = NULL; + long position = 0; + do { + wlr_log(L_DEBUG, "Peeking line %d", line_number + lines + 1); + free(peeked); + peeked = peek_line(file, lines, &position); + if (peeked) { + peeked = strip_whitespace(peeked); + } + wlr_log(L_DEBUG, "Peeked line: `%s`", peeked); + lines++; + } while (peeked && strlen(peeked) == 0); - memset(&config->handler_context, 0, sizeof(config->handler_context)); + if (peeked && strlen(peeked) == 1 && peeked[0] == '{') { + fseek(file, position, SEEK_SET); + } else { + lines = 0; + } + free(peeked); + } + return lines; +} + +static char *expand_line(const char *block, const char *line, bool add_brace) { + int size = (block ? strlen(block) + 1 : 0) + strlen(line) + + (add_brace ? 2 : 0) + 1; + char *expanded = calloc(1, size); + if (!expanded) { + wlr_log(L_ERROR, "Cannot allocate expanded line buffer"); + return NULL; + } + snprintf(expanded, size, "%s%s%s%s", block ? block : "", + block ? " " : "", line, add_brace ? " {" : ""); + return expanded; } bool read_config(FILE *file, struct sway_config *config) { bool success = true; - enum cmd_status block = CMD_BLOCK_END; - int line_number = 0; char *line; + list_t *stack = create_list(); while (!feof(file)) { + char *block = stack->length ? stack->items[0] : NULL; line = read_line(file); if (!line) { continue; } line_number++; + wlr_log(L_DEBUG, "Read line %d: %s", line_number, line); line = strip_whitespace(line); if (line[0] == '#') { free(line); continue; } + if (strlen(line) == 0) { + free(line); + continue; + } + int brace_detected = detect_brace_on_following_line(file, line, + line_number); + if (brace_detected > 0) { + line_number += brace_detected; + wlr_log(L_DEBUG, "Detected open brace on line %d", line_number); + } + char *expanded = expand_line(block, line, brace_detected > 0); + if (!expanded) { + return false; + } + wlr_log(L_DEBUG, "Expanded line: %s", expanded); struct cmd_results *res; - if (block == CMD_BLOCK_COMMANDS) { + if (block && strcmp(block, "<commands>") == 0) { // Special case - res = config_commands_command(line); + res = config_commands_command(expanded); } else { - res = config_command(line, block); + res = config_command(expanded); } + free(expanded); switch(res->status) { case CMD_FAILURE: case CMD_INVALID: @@ -558,126 +607,41 @@ bool read_config(FILE *file, struct sway_config *config) { list_add(config->cmd_queue, strdup(line)); break; - case CMD_BLOCK_MODE: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_MODE; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_INPUT: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_INPUT; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_SEAT: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_SEAT; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_BAR: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_BAR; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_BAR_COLORS: - if (block == CMD_BLOCK_BAR) { - block = CMD_BLOCK_BAR_COLORS; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - case CMD_BLOCK_COMMANDS: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_COMMANDS; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } - break; - - case CMD_BLOCK_IPC: - if (block == CMD_BLOCK_END) { - block = CMD_BLOCK_IPC; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); - } + wlr_log(L_DEBUG, "Entering commands block"); + list_insert(stack, 0, "<commands>"); break; - case CMD_BLOCK_IPC_EVENTS: - if (block == CMD_BLOCK_IPC) { - block = CMD_BLOCK_IPC_EVENTS; - } else { - wlr_log(L_ERROR, "Invalid block '%s'", line); + case CMD_BLOCK: + wlr_log(L_DEBUG, "Entering block '%s'", res->input); + list_insert(stack, 0, strdup(res->input)); + if (strcmp(res->input, "bar") == 0) { + config->current_bar = NULL; } break; case CMD_BLOCK_END: - switch(block) { - case CMD_BLOCK_MODE: - wlr_log(L_DEBUG, "End of mode block"); - config->current_mode = config->modes->items[0]; - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_INPUT: - wlr_log(L_DEBUG, "End of input block"); - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_SEAT: - wlr_log(L_DEBUG, "End of seat block"); - block = CMD_BLOCK_END; + if (!block) { + wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number); + success = false; break; + } + wlr_log(L_DEBUG, "Exiting block '%s'", block); + list_del(stack, 0); + free(block); - case CMD_BLOCK_BAR: - wlr_log(L_DEBUG, "End of bar block"); + if (strcmp(block, "bar") == 0) { config->current_bar = NULL; - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_BAR_COLORS: - wlr_log(L_DEBUG, "End of bar colors block"); - block = CMD_BLOCK_BAR; - break; - - case CMD_BLOCK_COMMANDS: - wlr_log(L_DEBUG, "End of commands block"); - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_IPC: - wlr_log(L_DEBUG, "End of IPC block"); - block = CMD_BLOCK_END; - break; - - case CMD_BLOCK_IPC_EVENTS: - wlr_log(L_DEBUG, "End of IPC events block"); - block = CMD_BLOCK_IPC; - break; - - case CMD_BLOCK_END: - wlr_log(L_ERROR, "Unmatched }"); - break; - - default:; } - config_clear_handler_context(config); + memset(&config->handler_context, 0, + sizeof(config->handler_context)); default:; } free(line); free_cmd_results(res); } + list_foreach(stack, free); + list_free(stack); return success; } diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 420cefa6..d90655f2 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -98,7 +98,6 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, struct sway_binding *binding) { wlr_log(L_DEBUG, "running command for binding: %s", binding->command); - config_clear_handler_context(config); config->handler_context.seat = keyboard->seat_device->sway_seat; struct cmd_results *results = execute_command(binding->command, NULL); if (results->status != CMD_SUCCESS) { diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 15ed6f80..8d9ab06a 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -469,7 +469,6 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { - config_clear_handler_context(config); struct cmd_results *results = execute_command(buf, NULL); const char *json = cmd_results_to_json(results); char reply[256]; |