From 29282f362d5f663ec3da17b135751f3b9b2bd0fd Mon Sep 17 00:00:00 2001 From: pommicket Date: Tue, 17 Oct 2023 20:51:33 -0400 Subject: accept regex for path-specific settings --- README.md | 13 +++++++++++++ config.c | 53 +++++++++++++++++++++++++++++++++++------------------ ted-internal.h | 3 ++- ted.cfg | 12 ------------ 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 2147c06..e6379ab 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,19 @@ You can set settings for specific programming languages like this: tab-width = 2 ``` +Or settings for specific paths like this: + +``` +[/foo//core] +# set tab width in /foo to 17 +tab-width = 17 + +# PCRE regex is supported! (the start is anchored but the end isn't) +[~/foo/.*\.hmtgf//core] +# set tab width for .hmtgf files in ~/foo +tab-width = 9 +``` + To reset your ted configuration to the default settings, delete your ted.cfg file (`~/.local/share/ted/ted.cfg` on Linux, `C:\Users\\AppData\Local\ted\ted.cfg` on Windows) or move it somewhere else. diff --git a/config.c b/config.c index a8c5f92..56a4ac7 100644 --- a/config.c +++ b/config.c @@ -8,6 +8,7 @@ // asdf = 123 #include "ted-internal.h" +#include "pcre-inc.h" /// Sections of `ted.cfg` typedef enum { @@ -161,18 +162,27 @@ static const SettingKeyCombo settings_key_combo[] = { bool config_applies_to(Config *cfg, const char *path, Language language) { if (cfg->language && language != cfg->language) return false; - if (cfg->path && (!path || !str_has_path_prefix(path, cfg->path))) - return false; + if (cfg->path) { + if (!path) + return false; + pcre2_match_data_8 *match_data = pcre2_match_data_create_from_pattern_8(cfg->path, NULL); + bool match = pcre2_match_8(cfg->path, (const u8 *)path, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL) > 0; + pcre2_match_data_free_8(match_data); + if (!match) + return false; + } return true; } -static bool config_has_same_context(const Config *a, const Config *b) { + +// if this returns true, `a` and `b` have the same context (`a` only applies if `b` does) +static bool config_definitely_has_same_context(const Config *a, const Config *b) { if (a->language != b->language) return false; - if (a->path && !b->path) + if (a->path_regex && !b->path_regex) return false; - if (!a->path && b->path) + if (!a->path_regex && b->path_regex) return false; - if (a->path && !streq(a->path, b->path)) + if (a->path_regex && !streq(a->path_regex, b->path_regex)) return false; return true; } @@ -274,13 +284,14 @@ void settings_free(Settings *settings) { static void config_free(Config *cfg) { settings_free(&cfg->settings); - free(cfg->path); + pcre2_code_free_8(cfg->path); + free(cfg->path_regex); memset(cfg, 0, sizeof *cfg); } i32 config_priority(const Config *cfg) { - size_t path_len = cfg->path ? strlen(cfg->path) : 0; + size_t path_len = cfg->path ? strlen(cfg->path_regex) : 0; return (i32)path_len * 2 + (cfg->language != 0); } @@ -956,16 +967,12 @@ static void config_read_file(Ted *ted, const char *cfg_path, const char ***inclu char header[256]; config_read_to_eol(reader, header, sizeof header); char path[TED_PATH_MAX]; path[0] = '\0'; - char *closing = strchr(header, ']'); Language language = 0; - if (!closing) { - config_err(reader, "Unmatched [. " SECTION_HEADER_HELP); - break; - } else if (closing[1] != '\0') { - config_err(reader, "Text after section. " SECTION_HEADER_HELP); + if (strlen(header) == 0 || header[strlen(header) - 1] != ']') { + config_err(reader, "Section header doesn't end with ]\n" SECTION_HEADER_HELP); break; } else { - *closing = '\0'; + header[strlen(header) - 1] = 0; char *p = header; char *path_end = strstr(p, "//"); if (path_end) { @@ -1015,20 +1022,30 @@ static void config_read_file(Ted *ted, const char *cfg_path, const char ***inclu } Config new_cfg = { .language = language, - .path = *path ? path : NULL, + .path_regex = *path ? path : NULL, }; cfg = NULL; // search for config with same context to update arr_foreach_ptr(ted->all_configs, Config, conf) { - if (config_has_same_context(conf, &new_cfg)) { + if (config_definitely_has_same_context(conf, &new_cfg)) { cfg = conf; } } if (!cfg) { // create new config cfg = arr_addp(ted->all_configs); - cfg->path = *path ? str_dup(path) : NULL; + cfg->path_regex = *path ? str_dup(path) : NULL; cfg->language = language; + if (cfg->path_regex) { + // compile regex + int error_code = 0; + PCRE2_SIZE error_offset = 0; + cfg->path = pcre2_compile_8((const u8 *)cfg->path_regex, PCRE2_ZERO_TERMINATED, PCRE2_ANCHORED, &error_code, &error_offset, NULL); + if (!cfg->path) { + config_err(reader, "Bad regex (at offset %u): %s", (unsigned)error_offset, cfg->path_regex); + free(cfg->path_regex); cfg->path_regex = NULL; + } + } } } else if (c == '%') { char line[2048]; diff --git a/ted-internal.h b/ted-internal.h index 59fca78..af5f2dd 100644 --- a/ted-internal.h +++ b/ted-internal.h @@ -155,7 +155,8 @@ struct Settings { typedef struct { Language language; - char *path; + struct pcre2_real_code_8 *path; + char *path_regex; Settings settings; bool settings_set[sizeof (Settings)]; } Config; diff --git a/ted.cfg b/ted.cfg index 8ad5362..6c86fd9 100644 --- a/ted.cfg +++ b/ted.cfg @@ -458,15 +458,3 @@ Java = .java Go = .go CSS = .css GDScript = .gd - -# You can add language-specific settings like this: -# [HTML.core] -# tab-width = 2 - -# Or path-specific settings like this: -# [/path/to/special/project//colors] -# keyword = #f0f - -# Or both! -# [/path/to/special/project//Javascript.keyboard] -# Ctrl+J = "function() {" :insert-text -- cgit v1.2.3