aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkoekeishiya <aasvi93@hotmail.com>2019-03-03 22:24:14 +0100
committerkoekeishiya <aasvi93@hotmail.com>2019-03-03 22:24:14 +0100
commitac494e3f72e397aaf3245b0401bd1b963bd4ebd3 (patch)
tree4284cc6367dc72da738b76a7d65c19c3636e9a79
parent56b94a6eed9fe4642382f533666dc19901fad3fc (diff)
downloadskhd-ac494e3f72e397aaf3245b0401bd1b963bd4ebd3.tar.gz
skhd-ac494e3f72e397aaf3245b0401bd1b963bd4ebd3.zip
#58 load/include additional config files
-rw-r--r--README.md10
-rw-r--r--examples/skhdrc9
-rw-r--r--src/parse.c82
-rw-r--r--src/parse.h10
-rw-r--r--src/skhd.c30
5 files changed, 121 insertions, 20 deletions
diff --git a/README.md b/README.md
index 3ab4481..24b9226 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,15 @@ command = command is executed through '$SHELL -c' and
General options that configure the behaviour of **skhd**:
```
-# prevents skhd from monitoring events for listed processes
+# specify a file that should be included as an additional config-file.
+# treated as an absolutepath if the filename begins with '/' otherwise
+# the file is relative to the path of the config-file it was loaded from.
+
+.load "/Users/Koe/.config/partial_skhdrc"
+.load "partial_skhdrc"
+
+# prevents skhd from monitoring events for listed processes.
+
.blacklist [
"terminal"
"qutebrowser"
diff --git a/examples/skhdrc b/examples/skhdrc
index bf0f7a3..48b5424 100644
--- a/examples/skhdrc
+++ b/examples/skhdrc
@@ -86,7 +86,14 @@
# "finder" : false
# ]
-# prevent skhd from monitoring events for specific applications
+# specify a file that should be included as an additional config-file.
+# treated as an absolutepath if the filename begins with '/' otherwise
+# the file is relative to the path of the config-file it was loaded from.
+#
+# .load "/Users/Koe/.config/partial_skhdrc"
+# .load "partial_skhdrc"
+
+# prevent skhd from monitoring events for specific applications.
#
# .blacklist [
# "kitty"
diff --git a/src/parse.c b/src/parse.c
index 4e673f4..9f14389 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -402,6 +402,32 @@ void parse_option_blacklist(struct parser *parser)
}
}
+void parse_option_load(struct parser *parser, struct token option)
+{
+ struct token filename_token = parser_previous(parser);
+ char *filename = copy_string_count(filename_token.text, filename_token.length);
+ debug("\t%s\n", filename);
+
+ if (*filename != '/') {
+ char *directory = file_directory(parser->file);
+
+ size_t directory_length = strlen(directory);
+ size_t filename_length = strlen(filename);
+ size_t total_length = directory_length + filename_length + 2;
+
+ char *absolutepath = malloc(total_length * sizeof(char));
+ snprintf(absolutepath, total_length, "%s/%s", directory, filename);
+ free(filename);
+
+ filename = absolutepath;
+ }
+
+ buf_push(parser->load_directives, ((struct load_directive) {
+ .file = filename,
+ .option = option
+ }));
+}
+
void parse_option(struct parser *parser)
{
parser_match(parser, Token_Option);
@@ -414,22 +440,26 @@ void parse_option(struct parser *parser)
} else {
parser_report_error(parser, option, "expected '[' followed by list of process names\n");
}
+ } else if (token_equals(option, "load")) {
+ if (parser_match(parser, Token_String)) {
+ debug("load :: #%d {\n", option.line);
+ parse_option_load(parser, option);
+ debug("}\n");
+ } else {
+ parser_report_error(parser, option, "expected filename\n");
+ }
} else {
parser_report_error(parser, option, "invalid option specified\n");
}
}
-void parse_config(struct parser *parser)
+bool parse_config(struct parser *parser)
{
struct mode *mode;
struct hotkey *hotkey;
while (!parser_eof(parser)) {
- if (parser->error) {
- free_mode_map(parser->mode_map);
- free_blacklist(parser->blacklst);
- return;
- }
+ if (parser->error) break;
if ((parser_check(parser, Token_Identifier)) ||
(parser_check(parser, Token_Modifier)) ||
@@ -450,6 +480,14 @@ void parse_config(struct parser *parser)
parser_report_error(parser, parser_peek(parser), "expected decl, modifier or key-literal\n");
}
}
+
+ if (parser->error) {
+ free_mode_map(parser->mode_map);
+ free_blacklist(parser->blacklst);
+ return false;
+ }
+
+ return true;
}
struct hotkey *
@@ -550,11 +588,43 @@ void parser_report_error(struct parser *parser, struct token token, const char *
parser->error = true;
}
+void parser_do_directives(struct parser *parser, struct hotloader *hotloader)
+{
+ bool error = false;
+
+ for (int i = 0; i < buf_len(parser->load_directives); ++i) {
+ struct load_directive load = parser->load_directives[i];
+
+ struct parser directive_parser;
+ if (parser_init(&directive_parser, parser->mode_map, parser->blacklst, load.file)) {
+ hotloader_add_file(hotloader, load.file);
+
+ if (parse_config(&directive_parser)) {
+ parser_do_directives(&directive_parser, hotloader);
+ } else {
+ error = true;
+ }
+ parser_destroy(&directive_parser);
+ } else {
+ warn("skhd: could not open file '%s' from load directive #%d:%d\n", load.file, load.option.line, load.option.cursor);
+ }
+
+ free(load.file);
+ }
+ buf_free(parser->load_directives);
+
+ if (error) {
+ free_mode_map(parser->mode_map);
+ free_blacklist(parser->blacklst);
+ }
+}
+
bool parser_init(struct parser *parser, struct table *mode_map, struct table *blacklst, char *file)
{
memset(parser, 0, sizeof(struct parser));
char *buffer = read_file(file);
if (buffer) {
+ parser->file = file;
parser->mode_map = mode_map;
parser->blacklst = blacklst;
tokenizer_init(&parser->tokenizer, buffer);
diff --git a/src/parse.h b/src/parse.h
index 95813c2..6576f7a 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -4,18 +4,26 @@
#include "tokenize.h"
#include <stdbool.h>
+struct load_directive
+{
+ char *file;
+ struct token option;
+};
+
struct table;
struct parser
{
+ char *file;
struct token previous_token;
struct token current_token;
struct tokenizer tokenizer;
struct table *mode_map;
struct table *blacklst;
+ struct load_directive *load_directives;
bool error;
};
-void parse_config(struct parser *parser);
+bool parse_config(struct parser *parser);
struct hotkey *parse_keypress(struct parser *parser);
struct token parser_peek(struct parser *parser);
diff --git a/src/skhd.c b/src/skhd.c
index ceea857..c90c4b6 100644
--- a/src/skhd.c
+++ b/src/skhd.c
@@ -51,16 +51,33 @@ global struct table mode_map;
global struct table blacklst;
global char *config_file;
+internal HOTLOADER_CALLBACK(config_handler);
+
internal void
parse_config_helper(char *absolutepath)
{
struct parser parser;
if (parser_init(&parser, &mode_map, &blacklst, absolutepath)) {
- parse_config(&parser);
+ hotloader_end(&hotloader);
+ hotloader_add_file(&hotloader, absolutepath);
+
+ if (parse_config(&parser)) {
+ parser_do_directives(&parser, &hotloader);
+ }
parser_destroy(&parser);
+
+ if (hotloader_begin(&hotloader, config_handler)) {
+ debug("skhd: watching files for changes:\n", absolutepath);
+ for (int i = 0; i < hotloader.watch_count; ++i) {
+ debug("\t%s\n", hotloader.watch_list[i].file_info.absolutepath);
+ }
+ } else {
+ warn("skhd: could not start watcher.. hotloading is not enabled\n");
+ }
} else {
warn("skhd: could not open file '%s'\n", absolutepath);
}
+
current_mode = table_find(&mode_map, "default");
}
@@ -70,7 +87,7 @@ internal HOTLOADER_CALLBACK(config_handler)
debug("skhd: config-file has been modified.. reloading config\n");
free_mode_map(&mode_map);
free_blacklist(&blacklst);
- parse_config_helper(absolutepath);
+ parse_config_helper(config_file);
END_TIMED_BLOCK();
}
@@ -254,15 +271,6 @@ int main(int argc, char **argv)
event_tap.mask = (1 << kCGEventKeyDown) | (1 << NX_SYSDEFINED);
event_tap_begin(&event_tap, key_handler);
END_SCOPED_TIMED_BLOCK();
-
- BEGIN_SCOPED_TIMED_BLOCK("begin_hotloader");
- if (hotloader_add_file(&hotloader, config_file) &&
- hotloader_begin(&hotloader, config_handler)) {
- debug("skhd: watching '%s' for changes\n", config_file);
- } else {
- warn("skhd: could not watch '%s'\n", config_file);
- }
- END_SCOPED_TIMED_BLOCK();
END_SCOPED_TIMED_BLOCK();
CFRunLoopRun();