From 3077f0b589be8894a471007773bb371438dfac1b Mon Sep 17 00:00:00 2001 From: rajj28 Date: Wed, 28 Jan 2026 17:12:19 +0000 Subject: [PATCH] config: add include_one directive with basename deduplication --- include/sway/commands.h | 1 + sway/commands.c | 1 + sway/commands/include_one.c | 111 ++++++++++++++++++++++++++++++++++++ sway/meson.build | 1 + 4 files changed, 114 insertions(+) create mode 100644 sway/commands/include_one.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 389c382eb..4dd198833 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -145,6 +145,7 @@ sway_cmd cmd_fullscreen; sway_cmd cmd_gaps; sway_cmd cmd_hide_edge_borders; sway_cmd cmd_include; +sway_cmd cmd_include_one; sway_cmd cmd_inhibit_idle; sway_cmd cmd_input; sway_cmd cmd_seat; diff --git a/sway/commands.c b/sway/commands.c index c2c12ee65..2c21d5339 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -103,6 +103,7 @@ static const struct cmd_handler handlers[] = { static const struct cmd_handler config_handlers[] = { { "default_orientation", cmd_default_orientation }, { "include", cmd_include }, + { "include_one", cmd_include_one }, { "primary_selection", cmd_primary_selection }, { "swaybg_command", cmd_swaybg_command }, { "swaynag_command", cmd_swaynag_command }, diff --git a/sway/commands/include_one.c b/sway/commands/include_one.c new file mode 100644 index 000000000..fce251927 --- /dev/null +++ b/sway/commands/include_one.c @@ -0,0 +1,111 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include "list.h" +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" + +static bool basename_in_list(list_t *basenames, const char *path) { + char *path_copy = strdup(path); + if (!path_copy) { + return false; + } + char *base = basename(path_copy); + + for (int i = 0; i < basenames->length; ++i) { + if (strcmp(basenames->items[i], base) == 0) { + free(path_copy); + return true; + } + } + free(path_copy); + return false; +} + +static char *get_basename_copy(const char *path) { + char *path_copy = strdup(path); + if (!path_copy) { + return NULL; + } + char *base = basename(path_copy); + char *result = strdup(base); + free(path_copy); + return result; +} + +struct cmd_results *cmd_include_one(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "include_one", EXPECTED_AT_LEAST, 2))) { + return error; + } + + list_t *included_basenames = create_list(); + if (!included_basenames) { + return cmd_results_new(CMD_FAILURE, + "Unable to allocate basename list"); + } + + char *wd = getcwd(NULL, 0); + char *parent_path = strdup(config->current_config_path); + if (!wd || !parent_path) { + free(wd); + free(parent_path); + list_free(included_basenames); + sway_log(SWAY_ERROR, "Unable to allocate memory for include_one"); + return cmd_results_new(CMD_SUCCESS, NULL); + } + const char *parent_dir = dirname(parent_path); + + if (chdir(parent_dir) < 0) { + sway_log(SWAY_ERROR, "failed to change working directory"); + goto cleanup; + } + + for (int glob_idx = 0; glob_idx < argc; ++glob_idx) { + wordexp_t p; + if (wordexp(argv[glob_idx], &p, 0) != 0) { + continue; + } + + for (size_t i = 0; i < p.we_wordc; ++i) { + const char *path = p.we_wordv[i]; + + // For subsequent globs (not the first), skip files whose + // basename was already included + if (glob_idx > 0 && basename_in_list(included_basenames, path)) { + sway_log(SWAY_DEBUG, + "include_one: skipping %s (basename already included)", + path); + continue; + } + + // Record the basename before including + char *base_copy = get_basename_copy(path); + if (base_copy) { + list_add(included_basenames, base_copy); + } + + // Use the existing load_include_configs mechanism for a single file + // We call it directly with the path, it will handle the inclusion + load_include_configs(path, config, &config->swaynag_config_errors); + } + + wordfree(&p); + } + + // Attempt to restore working directory before returning. + if (chdir(wd) < 0) { + sway_log(SWAY_ERROR, "failed to change working directory"); + } + +cleanup: + free(parent_path); + free(wd); + list_free_items_and_destroy(included_basenames); + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index cb03a4d28..c4b496bc6 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -76,6 +76,7 @@ sway_sources = files( 'commands/max_render_time.c', 'commands/opacity.c', 'commands/include.c', + 'commands/include_one.c', 'commands/input.c', 'commands/layout.c', 'commands/mode.c',