From 2f98c6aded0567d0fe29f9ea68556ab87995c5f9 Mon Sep 17 00:00:00 2001 From: Adrian Sinclair Date: Wed, 11 May 2022 18:20:02 -0400 Subject: [PATCH] add .load_glob directive --- README.md | 4 +++ examples/skhdrc | 4 +++ src/parse.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parse.h | 7 +++++ 4 files changed, 87 insertions(+) diff --git a/README.md b/README.md index b819fc0..1bf2e12 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,10 @@ General options that configure the behaviour of **skhd**: .load "/Users/Koe/.config/partial_skhdrc" .load "partial_skhdrc" +# specify a glob pattern for files that should be included. + +.load_glob "../skhd.d/*.conf" + # prevents skhd from monitoring events for listed processes. .blacklist [ diff --git a/examples/skhdrc b/examples/skhdrc index b631aab..5a75c76 100644 --- a/examples/skhdrc +++ b/examples/skhdrc @@ -97,6 +97,10 @@ # .load "/Users/Koe/.config/partial_skhdrc" # .load "partial_skhdrc" +# specify a glob pattern for files that should be included. +# +# .load_glob "../skhd.d/*.conf" + # prevent skhd from monitoring events for specific applications. # # .blacklist [ diff --git a/src/parse.c b/src/parse.c index 42feca2..f6d0400 100644 --- a/src/parse.c +++ b/src/parse.c @@ -4,6 +4,7 @@ #include "hotkey.h" #include "hashtable.h" +#include #include #include #include @@ -442,6 +443,32 @@ void parse_option_load(struct parser *parser, struct token option) })); } +void parse_option_load_glob(struct parser *parser, struct token option) +{ + struct token glob_pattern_token = parser_previous(parser); + char *pattern = copy_string_count(glob_pattern_token.text, glob_pattern_token.length); + debug("\t%s\n", pattern); + + if (*pattern != '/') { + char *directory = file_directory(parser->file); + + size_t directory_length = strlen(directory); + size_t pattern_length = strlen(pattern); + size_t total_length = directory_length + pattern_length + 2; + + char *absolute_pattern = malloc(total_length * sizeof(char)); + snprintf(absolute_pattern, total_length, "%s/%s", directory, pattern); + free(pattern); + + pattern = absolute_pattern; + } + + buf_push(parser->load_glob_directives, ((struct load_glob_directive) { + .pattern = pattern, + .option = option + })); +} + void parse_option(struct parser *parser) { parser_match(parser, Token_Option); @@ -462,6 +489,14 @@ void parse_option(struct parser *parser) } else { parser_report_error(parser, option, "expected filename\n"); } + } else if (token_equals(option, "load_glob")) { + if (parser_match(parser, Token_String)) { + debug("load_glob :: #%d {\n", option.line); + parse_option_load_glob(parser, option); + debug("}\n"); + } else { + parser_report_error(parser, option, "expected glob pattern\n"); + } } else { parser_report_error(parser, option, "invalid option specified\n"); } @@ -630,6 +665,43 @@ void parser_do_directives(struct parser *parser, struct hotloader *hotloader, bo } buf_free(parser->load_directives); + for (int i = 0; i < buf_len(parser->load_glob_directives); ++i) { + struct load_glob_directive load_glob = parser->load_glob_directives[i]; + + glob_t glob_result; + int glob_err = glob(load_glob.pattern, 0, NULL, &glob_result); + + if (glob_err != 0 && errno != GLOB_NOMATCH) { + globfree(&glob_result); + free(load_glob.pattern); + parser_report_error(parser, load_glob.option, "failed to expand glob pattern"); + return; + } + + for (int j = 0; j < glob_result.gl_matchc; j++) { + struct parser directive_parser; + if (parser_init(&directive_parser, parser->mode_map, parser->blacklst, glob_result.gl_pathv[j])) { + if (!thwart_hotloader) { + hotloader_add_file(hotloader, glob_result.gl_pathv[j]); + } + + if (parse_config(&directive_parser)) { + parser_do_directives(&directive_parser, hotloader, thwart_hotloader); + } else { + error = true; + } + + parser_destroy(&directive_parser); + } else { + warn("skhd: could not open file '%s' expanded from load_glob directive #%d:%d\n", glob_result.gl_pathv[j], load_glob.option.line, load_glob.option.cursor); + } + } + + globfree(&glob_result); + free(load_glob.pattern); + } + buf_free(parser->load_directives); + if (error) { free_mode_map(parser->mode_map); free_blacklist(parser->blacklst); diff --git a/src/parse.h b/src/parse.h index 6576f7a..482cba1 100644 --- a/src/parse.h +++ b/src/parse.h @@ -10,6 +10,12 @@ struct load_directive struct token option; }; +struct load_glob_directive +{ + char *pattern; + struct token option; +}; + struct table; struct parser { @@ -20,6 +26,7 @@ struct parser struct table *mode_map; struct table *blacklst; struct load_directive *load_directives; + struct load_glob_directive *load_glob_directives; bool error; };