From 5c6f3d7266ab0c63015715f12c8e15eb144311a2 Mon Sep 17 00:00:00 2001 From: Brian Ashworth Date: Tue, 27 Nov 2018 21:42:09 -0500 Subject: [PATCH] Change execute_command to return a list of results This matches i3's behavior of returning a list of results that contain the result of each command that was executed. Additionally, the `parse_error` attribute has been added to the IPC JSON reply. --- include/sway/commands.h | 6 ++-- sway/commands.c | 67 +++++++++++++++++------------------------ sway/commands/bind.c | 21 ++++++++----- sway/ipc-server.c | 11 +++++-- sway/main.c | 13 +++++--- sway/tree/view.c | 9 ++++-- 6 files changed, 69 insertions(+), 58 deletions(-) diff --git a/include/sway/commands.h b/include/sway/commands.h index eb446eae..c3913c79 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -56,7 +56,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, * all matching containers. Otherwise, it'll run on the `con` container. If * `con` is NULL then it'll run on the currently focused container. */ -struct cmd_results *execute_command(char *command, struct sway_seat *seat, +list_t *execute_command(char *command, struct sway_seat *seat, struct sway_container *con); /** * Parse and handles a command during config file loading. @@ -82,11 +82,11 @@ struct cmd_results *cmd_results_new(enum cmd_status status, const char* input, c */ void free_cmd_results(struct cmd_results *results); /** - * Serializes cmd_results to a JSON string. + * Serializes a list of cmd_results to a JSON string. * * Free the JSON string later on. */ -char *cmd_results_to_json(struct cmd_results *results); +char *cmd_results_to_json(list_t *res_list); struct cmd_results *add_color(const char *name, char *buffer, const char *color); diff --git a/sway/commands.c b/sway/commands.c index bffc18f6..34e66ce9 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -215,12 +215,9 @@ static void set_config_node(struct sway_node *node) { } } -struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, +list_t *execute_command(char *_exec, struct sway_seat *seat, struct sway_container *con) { - // 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; + list_t *res_list = create_list(); char *exec = strdup(_exec); char *head = exec; char *cmdlist; @@ -254,8 +251,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, char *error = NULL; struct criteria *criteria = criteria_parse(head, &error); if (!criteria) { - results = cmd_results_new(CMD_INVALID, head, - "%s", error); + list_add(res_list, cmd_results_new(CMD_INVALID, head, + "%s", error)); free(error); goto cleanup; } @@ -291,10 +288,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, } 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"); + list_add(res_list, cmd_results_new(CMD_INVALID, cmd, + "Unknown/invalid command")); free_argv(argc, argv); goto cleanup; } @@ -308,29 +303,21 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, if (!config->handler_context.using_criteria) { set_config_node(node); struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status != CMD_SUCCESS) { + list_add(res_list, res); + if (res->status == CMD_INVALID) { free_argv(argc, argv); - if (results) { - free_cmd_results(results); - } - results = res; goto cleanup; } - free_cmd_results(res); } else { for (int i = 0; i < views->length; ++i) { struct sway_view *view = views->items[i]; set_config_node(&view->container->node); struct cmd_results *res = handler->handle(argc-1, argv+1); - if (res->status != CMD_SUCCESS) { + list_add(res_list, res); + if (res->status == CMD_INVALID) { free_argv(argc, argv); - if (results) { - free_cmd_results(results); - } - results = res; goto cleanup; } - free_cmd_results(res); } } free_argv(argc, argv); @@ -339,10 +326,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat, cleanup: free(exec); list_free(views); - if (!results) { - results = cmd_results_new(CMD_SUCCESS, NULL, NULL); - } - return results; + return res_list; } // this is like execute_command above, except: @@ -574,20 +558,25 @@ void free_cmd_results(struct cmd_results *results) { free(results); } -char *cmd_results_to_json(struct cmd_results *results) { +char *cmd_results_to_json(list_t *res_list) { json_object *result_array = json_object_new_array(); - json_object *root = json_object_new_object(); - json_object_object_add(root, "success", - json_object_new_boolean(results->status == CMD_SUCCESS)); - if (results->input) { - json_object_object_add( - root, "input", json_object_new_string(results->input)); - } - if (results->error) { - json_object_object_add( - root, "error", json_object_new_string(results->error)); + for (int i = 0; i < res_list->length; ++i) { + struct cmd_results *results = res_list->items[i]; + json_object *root = json_object_new_object(); + json_object_object_add(root, "success", + json_object_new_boolean(results->status == CMD_SUCCESS)); + if (results->error) { + json_object_object_add(root, "parse_error", + json_object_new_boolean(results->status == CMD_INVALID)); + json_object_object_add( + root, "error", json_object_new_string(results->error)); + } + if (results->input) { + json_object_object_add( + root, "input", json_object_new_string(results->input)); + } + json_object_array_add(result_array, root); } - json_object_array_add(result_array, root); const char *json = json_object_to_json_string(result_array); char *res = strdup(json); json_object_put(result_array); diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 08acbe7a..34881b0f 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -289,13 +289,20 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); config->handler_context.seat = seat; - struct cmd_results *results = execute_command(binding->command, NULL, NULL); - if (results->status == CMD_SUCCESS) { + list_t *res_list = execute_command(binding->command, NULL, NULL); + bool success = true; + while (res_list->length) { + struct cmd_results *results = res_list->items[0]; + if (results->status != CMD_SUCCESS) { + wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", + binding->command, results->error); + success = false; + } + free_cmd_results(results); + list_del(res_list, 0); + } + list_free(res_list); + if (success) { ipc_event_binding(binding); - } else { - wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", - binding->command, results->error); } - - free_cmd_results(results); } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index aa0f0fad..95433d97 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -597,13 +597,18 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { - struct cmd_results *results = execute_command(buf, NULL, NULL); + list_t *res_list = execute_command(buf, NULL, NULL); transaction_commit_dirty(); - char *json = cmd_results_to_json(results); + char *json = cmd_results_to_json(res_list); int length = strlen(json); client_valid = ipc_send_reply(client, json, (uint32_t)length); free(json); - free_cmd_results(results); + while (res_list->length) { + struct cmd_results *results = res_list->items[0]; + free_cmd_results(results); + list_del(res_list, 0); + } + list_free(res_list); goto exit_cleanup; } diff --git a/sway/main.c b/sway/main.c index a21970e2..a74183fe 100644 --- a/sway/main.c +++ b/sway/main.c @@ -392,11 +392,16 @@ int main(int argc, char **argv) { wlr_log(WLR_DEBUG, "Running deferred commands"); while (config->cmd_queue->length) { char *line = config->cmd_queue->items[0]; - struct cmd_results *res = execute_command(line, NULL, NULL); - if (res->status != CMD_SUCCESS) { - wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); + list_t *res_list = execute_command(line, NULL, NULL); + while (res_list->length) { + struct cmd_results *res = res_list->items[0]; + if (res->status != CMD_SUCCESS) { + wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); + } + free_cmd_results(res); + list_del(res_list, 0); } - free_cmd_results(res); + list_free(res_list); free(line); list_del(config->cmd_queue, 0); } diff --git a/sway/tree/view.c b/sway/tree/view.c index febba3b9..511c2ecc 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -437,9 +437,14 @@ void view_execute_criteria(struct sway_view *view) { wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); list_add(view->executed_criteria, criteria); - struct cmd_results *res = execute_command( + list_t *res_list = execute_command( criteria->cmdlist, NULL, view->container); - free_cmd_results(res); + while (res_list->length) { + struct cmd_results *res = res_list->items[0]; + free_cmd_results(res); + list_del(res_list, 0); + } + list_free(res_list); } list_free(criterias); }