fix(criteria): allow con_id to match workspaces

The [con_id=X] criteria selector was failing to match workspace nodes
because criteria_get_containers() only iterated through containers, not
workspaces. This broke scripts that rely on marking workspaces by their
internal ID (a pattern that works in i3).

Rename criteria_get_containers to criteria_get_nodes and extend it to
also iterate over workspaces when con_id is specified. Workspaces only
support con_id matching (not con_mark, since they don't have marks).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Code 2025-12-27 09:28:35 +00:00 committed by Vladimir Panteleev
parent dbe8640035
commit e7bd3f14e5
No known key found for this signature in database
GPG key ID: 5004F0FAD051576D
3 changed files with 30 additions and 15 deletions

View file

@ -84,8 +84,9 @@ struct criteria *criteria_parse(char *raw, char **error);
list_t *criteria_for_view(struct sway_view *view, enum criteria_type types);
/**
* Compile a list of containers matching the given criteria.
* Compile a list of nodes matching the given criteria.
* Returns a list of struct sway_node *.
*/
list_t *criteria_get_containers(struct criteria *criteria);
list_t *criteria_get_nodes(struct criteria *criteria);
#endif

View file

@ -206,7 +206,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
struct sway_container *con) {
char *cmd;
char matched_delim = ';';
list_t *containers = NULL;
list_t *nodes = NULL;
bool using_criteria = false;
if (seat == NULL) {
@ -241,8 +241,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
free(error);
goto cleanup;
}
list_free(containers);
containers = criteria_get_containers(criteria);
list_free(nodes);
nodes = criteria_get_nodes(criteria);
head += strlen(criteria->raw);
criteria_destroy(criteria);
using_criteria = true;
@ -298,14 +298,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
free_argv(argc, argv);
goto cleanup;
}
} else if (containers->length == 0) {
} else if (nodes->length == 0) {
list_add(res_list,
cmd_results_new(CMD_FAILURE, "No matching node."));
} else {
struct cmd_results *fail_res = NULL;
for (int i = 0; i < containers->length; ++i) {
struct sway_container *container = containers->items[i];
set_config_node(&container->node, true);
for (int i = 0; i < nodes->length; ++i) {
struct sway_node *node = nodes->items[i];
set_config_node(node, true);
struct cmd_results *res = handler->handle(argc-1, argv+1);
if (res->status == CMD_SUCCESS) {
free_cmd_results(res);
@ -329,7 +329,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat,
} while(head);
cleanup:
free(exec);
list_free(containers);
list_free(nodes);
return res_list;
}

View file

@ -493,27 +493,41 @@ struct match_data {
list_t *matches;
};
static void criteria_get_containers_iterator(struct sway_container *container,
static void criteria_get_nodes_container_iterator(struct sway_container *container,
void *data) {
struct match_data *match_data = data;
if (container->view) {
if (criteria_matches_view(match_data->criteria, container->view)) {
list_add(match_data->matches, container);
list_add(match_data->matches, &container->node);
}
} else if (has_container_criteria(match_data->criteria)) {
if (criteria_matches_container(match_data->criteria, container)) {
list_add(match_data->matches, container);
list_add(match_data->matches, &container->node);
}
}
}
list_t *criteria_get_containers(struct criteria *criteria) {
static void criteria_get_nodes_workspace_iterator(struct sway_workspace *workspace,
void *data) {
struct match_data *match_data = data;
// Workspaces only support con_id matching (not con_mark, since they don't have marks)
if (match_data->criteria->con_id &&
workspace->node.id == match_data->criteria->con_id) {
list_add(match_data->matches, &workspace->node);
}
}
list_t *criteria_get_nodes(struct criteria *criteria) {
list_t *matches = create_list();
struct match_data data = {
.criteria = criteria,
.matches = matches,
};
root_for_each_container(criteria_get_containers_iterator, &data);
root_for_each_container(criteria_get_nodes_container_iterator, &data);
// Also check workspaces for con_id matching
if (criteria->con_id && !criteria->con_mark) {
root_for_each_workspace(criteria_get_nodes_workspace_iterator, &data);
}
return matches;
}