summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2016-03-26 12:31:53 +0100
committerLibravatar Mikkel Oscar Lyderik <mikkeloscar@gmail.com>2016-03-26 16:37:50 +0100
commit71a5350b681e022e9738b50f2977ddb529110bfb (patch)
tree4c199980a9f80c07d69130a72402a5cfe2a8a63f
parentUpdate README.md (diff)
downloadsway-71a5350b681e022e9738b50f2977ddb529110bfb.tar.gz
sway-71a5350b681e022e9738b50f2977ddb529110bfb.tar.zst
sway-71a5350b681e022e9738b50f2977ddb529110bfb.zip
Implement include command
The include command (`include <path>`) makes it possible to include sub config files from the main config file (or from within other sub config files). The include command uses the following rules for including config files: * the `path` can be either a full path or a path that is relative to the parent config. Shell expansion is supported, so it's possible to do `include ~/.config/sway.d/*`. * The same config file can only be included once (to prevent include cycles). If a config is included multiple times it will just be ignored after it has been included once. * Including a sub config file is the same as inserting the content of that file into the parent config, thus rules about overwriting bindsyms etc. works the same as for a single config. Implement #542
-rw-r--r--include/config.h20
-rw-r--r--sway/commands.c17
-rw-r--r--sway/config.c151
-rw-r--r--sway/main.c4
4 files changed, 155 insertions, 37 deletions
diff --git a/include/config.h b/include/config.h
index 9356140d..4bcf55e8 100644
--- a/include/config.h
+++ b/include/config.h
@@ -184,15 +184,27 @@ struct sway_config {
184 bool smart_gaps; 184 bool smart_gaps;
185 int gaps_inner; 185 int gaps_inner;
186 int gaps_outer; 186 int gaps_outer;
187
188 list_t *config_chain;
189 const char *current_config;
187}; 190};
188 191
189/** 192/**
190 * Loads the config from the given path. 193 * Loads the main config from the given path. is_active should be true when
194 * reloading the config.
191 */ 195 */
192bool load_config(const char *file); 196bool load_main_config(const char *path, bool is_active);
193/** Reads the config from the given FILE. 197
198/**
199 * Loads an included config. Can only be used after load_main_config.
194 */ 200 */
195bool read_config(FILE *file, bool is_active); 201bool load_include_configs(const char *path, struct sway_config *config);
202
203/**
204 * Reads the config from the given FILE.
205 */
206bool read_config(FILE *file, struct sway_config *config);
207
196/** 208/**
197 * Free config struct 209 * Free config struct
198 */ 210 */
diff --git a/sway/commands.c b/sway/commands.c
index 26fa771e..bc8c42eb 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -55,6 +55,7 @@ static sway_cmd cmd_font;
55static sway_cmd cmd_for_window; 55static sway_cmd cmd_for_window;
56static sway_cmd cmd_fullscreen; 56static sway_cmd cmd_fullscreen;
57static sway_cmd cmd_gaps; 57static sway_cmd cmd_gaps;
58static sway_cmd cmd_include;
58static sway_cmd cmd_input; 59static sway_cmd cmd_input;
59static sway_cmd cmd_kill; 60static sway_cmd cmd_kill;
60static sway_cmd cmd_layout; 61static sway_cmd cmd_layout;
@@ -1141,6 +1142,19 @@ static struct cmd_results *input_cmd_tap(int argc, char **argv) {
1141 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1142 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1142} 1143}
1143 1144
1145static struct cmd_results *cmd_include(int argc, char **argv) {
1146 struct cmd_results *error = NULL;
1147 if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) {
1148 return error;
1149 }
1150
1151 if (!load_include_configs(argv[0], config)) {
1152 return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]);
1153 }
1154
1155 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1156}
1157
1144static struct cmd_results *cmd_input(int argc, char **argv) { 1158static struct cmd_results *cmd_input(int argc, char **argv) {
1145 struct cmd_results *error = NULL; 1159 struct cmd_results *error = NULL;
1146 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { 1160 if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) {
@@ -1541,7 +1555,7 @@ static struct cmd_results *cmd_reload(int argc, char **argv) {
1541 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { 1555 if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) {
1542 return error; 1556 return error;
1543 } 1557 }
1544 if (!load_config(NULL)) return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); 1558 if (!load_main_config(NULL, true)) return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config.");
1545 1559
1546 load_swaybars(); 1560 load_swaybars();
1547 1561
@@ -2053,6 +2067,7 @@ static struct cmd_handler handlers[] = {
2053 { "for_window", cmd_for_window }, 2067 { "for_window", cmd_for_window },
2054 { "fullscreen", cmd_fullscreen }, 2068 { "fullscreen", cmd_fullscreen },
2055 { "gaps", cmd_gaps }, 2069 { "gaps", cmd_gaps },
2070 { "include", cmd_include },
2056 { "input", cmd_input }, 2071 { "input", cmd_input },
2057 { "kill", cmd_kill }, 2072 { "kill", cmd_kill },
2058 { "layout", cmd_layout }, 2073 { "layout", cmd_layout },
diff --git a/sway/config.c b/sway/config.c
index a5fdf850..d54ce213 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -2,6 +2,7 @@
2#include <stdbool.h> 2#include <stdbool.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <unistd.h> 4#include <unistd.h>
5#include <libgen.h>
5#include <wordexp.h> 6#include <wordexp.h>
6#include <sys/types.h> 7#include <sys/types.h>
7#include <sys/wait.h> 8#include <sys/wait.h>
@@ -126,6 +127,7 @@ void free_config(struct sway_config *config) {
126 list_free(config->output_configs); 127 list_free(config->output_configs);
127 128
128 list_free(config->active_bar_modifiers); 129 list_free(config->active_bar_modifiers);
130 free_flat_list(config->config_chain);
129 free(config->font); 131 free(config->font);
130 free(config); 132 free(config);
131} 133}
@@ -175,6 +177,9 @@ static void config_defaults(struct sway_config *config) {
175 config->gaps_outer = 0; 177 config->gaps_outer = 0;
176 178
177 config->active_bar_modifiers = create_list(); 179 config->active_bar_modifiers = create_list();
180
181 config->config_chain = create_list();
182 config->current_config = NULL;
178} 183}
179 184
180static int compare_modifiers(const void *left, const void *right) { 185static int compare_modifiers(const void *left, const void *right) {
@@ -237,16 +242,7 @@ static char *get_config_path(void) {
237 return NULL; // Not reached 242 return NULL; // Not reached
238} 243}
239 244
240bool load_config(const char *file) { 245static bool load_config(const char *path, struct sway_config *config) {
241 input_init();
242
243 char *path;
244 if (file != NULL) {
245 path = strdup(file);
246 } else {
247 path = get_config_path();
248 }
249
250 sway_log(L_INFO, "Loading config from %s", path); 246 sway_log(L_INFO, "Loading config from %s", path);
251 247
252 if (path == NULL) { 248 if (path == NULL) {
@@ -257,20 +253,12 @@ bool load_config(const char *file) {
257 FILE *f = fopen(path, "r"); 253 FILE *f = fopen(path, "r");
258 if (!f) { 254 if (!f) {
259 sway_log(L_ERROR, "Unable to open %s for reading", path); 255 sway_log(L_ERROR, "Unable to open %s for reading", path);
260 free(path);
261 return false; 256 return false;
262 } 257 }
263 free(path);
264 258
265 bool config_load_success; 259 bool config_load_success = read_config(f, config);
266 if (config) {
267 config_load_success = read_config(f, true);
268 } else {
269 config_load_success = read_config(f, false);
270 }
271 fclose(f); 260 fclose(f);
272 261
273 update_active_bar_modifiers();
274 262
275 if (!config_load_success) { 263 if (!config_load_success) {
276 sway_log(L_ERROR, "Error(s) loading config!"); 264 sway_log(L_ERROR, "Error(s) loading config!");
@@ -279,17 +267,129 @@ bool load_config(const char *file) {
279 return true; 267 return true;
280} 268}
281 269
282bool read_config(FILE *file, bool is_active) { 270bool load_main_config(const char *file, bool is_active) {
271 input_init();
272
273 char *path;
274 if (file != NULL) {
275 path = strdup(file);
276 } else {
277 path = get_config_path();
278 }
279
283 struct sway_config *old_config = config; 280 struct sway_config *old_config = config;
284 config = calloc(1, sizeof(struct sway_config)); 281 config = calloc(1, sizeof(struct sway_config));
285 282
286 config_defaults(config); 283 config_defaults(config);
287 config->reading = true;
288 if (is_active) { 284 if (is_active) {
289 sway_log(L_DEBUG, "Performing configuration file reload"); 285 sway_log(L_DEBUG, "Performing configuration file reload");
290 config->reloading = true; 286 config->reloading = true;
291 config->active = true; 287 config->active = true;
292 } 288 }
289
290 config->current_config = path;
291 list_add(config->config_chain, path);
292
293 config->reading = true;
294 bool success = load_config(path, config);
295
296 if (is_active) {
297 config->reloading = false;
298 }
299
300 if (old_config) {
301 free_config(old_config);
302 }
303 config->reading = false;
304
305 if (success) {
306 update_active_bar_modifiers();
307 }
308
309 return success;
310}
311
312static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) {
313 // save parent config
314 const char *parent_config = config->current_config;
315
316 char *full_path = strdup(path);
317 int len = strlen(path);
318 if (len >= 1 && path[0] != '/') {
319 len = len + strlen(parent_dir) + 2;
320 full_path = malloc(len * sizeof(char));
321 snprintf(full_path, len, "%s/%s", parent_dir, path);
322 }
323
324 char *real_path = realpath(full_path, NULL);
325 free(full_path);
326
327 // check if config has already been included
328 int j;
329 for (j = 0; j < config->config_chain->length; ++j) {
330 char *old_path = config->config_chain->items[j];
331 if (strcmp(real_path, old_path) == 0) {
332 sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path);
333 free(real_path);
334 return false;
335 }
336 }
337
338 config->current_config = real_path;
339 list_add(config->config_chain, real_path);
340 int index = config->config_chain->length - 1;
341
342 if (!load_config(real_path, config)) {
343 free(real_path);
344 config->current_config = parent_config;
345 list_del(config->config_chain, index);
346 return false;
347 }
348
349 // restore current_config
350 config->current_config = parent_config;
351 return true;
352}
353
354bool load_include_configs(const char *path, struct sway_config *config) {
355 char *wd = getcwd(NULL, 0);
356 char *parent_path = strdup(config->current_config);
357 const char *parent_dir = dirname(parent_path);
358
359 if (chdir(parent_dir) < 0) {
360 free(parent_path);
361 free(wd);
362 return false;
363 }
364
365 wordexp_t p;
366
367 if (wordexp(path, &p, 0) < 0) {
368 free(parent_path);
369 free(wd);
370 return false;
371 }
372
373 char **w = p.we_wordv;
374 size_t i;
375 for (i = 0; i < p.we_wordc; ++i) {
376 load_include_config(w[i], parent_dir, config);
377 }
378 free(parent_path);
379 wordfree(&p);
380
381 // restore wd
382 if (chdir(wd) < 0) {
383 free(wd);
384 sway_log(L_ERROR, "failed to restore working directory");
385 return false;
386 }
387
388 free(wd);
389 return true;
390}
391
392bool read_config(FILE *file, struct sway_config *config) {
293 bool success = true; 393 bool success = true;
294 enum cmd_status block = CMD_BLOCK_END; 394 enum cmd_status block = CMD_BLOCK_END;
295 395
@@ -386,15 +486,6 @@ bool read_config(FILE *file, bool is_active) {
386 free(res); 486 free(res);
387 } 487 }
388 488
389 if (is_active) {
390 config->reloading = false;
391 arrange_windows(&root_container, -1, -1);
392 }
393 if (old_config) {
394 free_config(old_config);
395 }
396
397 config->reading = false;
398 return success; 489 return success;
399} 490}
400 491
diff --git a/sway/main.c b/sway/main.c
index c4a5d497..4aaac556 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -206,11 +206,11 @@ int main(int argc, char **argv) {
206 init_layout(); 206 init_layout();
207 207
208 if (validate) { 208 if (validate) {
209 bool valid = load_config(config_path); 209 bool valid = load_main_config(config_path, false);
210 return valid ? 0 : 1; 210 return valid ? 0 : 1;
211 } 211 }
212 212
213 if (!load_config(config_path)) { 213 if (!load_main_config(config_path, false)) {
214 sway_terminate(EXIT_FAILURE); 214 sway_terminate(EXIT_FAILURE);
215 } 215 }
216 216