From: NeilBrown Date: Wed, 14 Jun 2023 10:21:58 +0000 (+1000) Subject: Add a config-file parser. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=3e50f74e3018fb91f5ce8a61e5ed970f75a22688;p=edlib.git Add a config-file parser. An "ini" style file can be read to set global attributes, configure auto-loading of modules (listing commands that they define) and eventually per-doc configurations based on file name. All module loading requests are now in edlib.ini. Signed-off-by: NeilBrown --- diff --git a/Makefile b/Makefile index 2c0dccb1..c927b30d 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ SHOBJ = O/doc-text.o O/doc-dir.o O/doc-docs.o \ O/lib-search.o O/lib-messageline.o O/lib-input.o O/lib-libevent.o \ O/lib-history.o O/lib-crop.o O/lib-markup.o O/lib-rfc822header.o \ O/lib-viewer.o O/lib-base64.o O/lib-qprint.o O/lib-utf8.o \ - O/lib-charset.o \ + O/lib-charset.o O/lib-config.o \ O/lib-copybuf.o O/lib-whitespace.o O/lib-colourmap.o \ O/lib-renderline.o O/lib-x11selection-gtk.o O/lib-autosave.o \ O/lib-x11selection-xcb.o O/display-x11-xcb.o \ diff --git a/doc-email.c b/doc-email.c index b6742318..94a3c791 100644 --- a/doc-email.c +++ b/doc-email.c @@ -1302,11 +1302,4 @@ void edlib_init(struct pane *ed safe) "open-doc-email"); call_comm("global-set-command", ed, &attach_email_view, 0, NULL, "attach-email-view"); - - call("global-load-module", ed, 0, NULL, "lib-html-to-text"); - call("global-load-module", ed, 0, NULL, "lib-html-w3m"); - - call("global-load-module", ed, 0, NULL, "lib-pdf-to-text"); - call("global-load-module", ed, 0, NULL, "lib-doc-to-text"); - call("global-load-module", ed, 0, NULL, "lib-ical-to-text"); } diff --git a/edlib.c b/edlib.c index 6471c635..0fdfafac 100644 --- a/edlib.c +++ b/edlib.c @@ -77,33 +77,10 @@ int main(int argc, char *argv[]) setlocale(LC_ALL, ""); setlocale(LC_CTYPE, "enUS.UTF-8"); + call("global-load-module", ed, 0, NULL, "lib-config"); + call("config-load", ed, 0, NULL, "edlib.ini", 0, NULL, argv[0]); + call("attach-doc-docs", ed); - call("global-load-module", ed, 0, NULL, "lib-linecount"); - call("global-load-module", ed, 0, NULL, "lib-search"); - call("global-load-module", ed, 0, NULL, "lib-popup"); - call("global-load-module", ed, 0, NULL, "lang-python"); - call("global-load-module", ed, 0, NULL, "doc-text"); - call("global-load-module", ed, 0, NULL, "doc-dir"); - call("global-load-module", ed, 0, NULL, "render-hex"); - call("global-load-module", ed, 0, NULL, "render-present"); - call("global-load-module", ed, 0, NULL, "render-lines"); - call("global-load-module", ed, 0, NULL, "module-notmuch"); - call("global-load-module", ed, 0, NULL, "doc-email"); - call("global-load-module", ed, 0, NULL, "lib-viewer"); - call("global-load-module", ed, 0, NULL, "lib-qprint"); - call("global-load-module", ed, 0, NULL, "lib-copybuf"); - call("global-load-module", ed, 0, NULL, "lib-colourmap"); - call("global-load-module", ed, 0, NULL, "lib-textfill"); - call("global-load-module", ed, 0, NULL, "lib-autosave"); - call("global-load-module", ed, 0, NULL, "render-format"); - - call("global-load-module", ed, 0, NULL, "render-c-mode"); - call("global-load-module", ed, 0, NULL, "lib-make"); - call("global-load-module", ed, 0, NULL, "lib-server"); - call("global-load-module", ed, 0, NULL, "lib-utf8"); - call("global-load-module", ed, 0, NULL, "lib-charset"); - - call("global-load-module", ed, 0, NULL, "config"); while (optind < argc) { char *file = argv[optind++]; diff --git a/edlib.ini b/edlib.ini new file mode 100644 index 00000000..508e6c4c --- /dev/null +++ b/edlib.ini @@ -0,0 +1,123 @@ + +include = config.ini + +[module] + +lang-python = global-load-modules:python + +lib-popup = PopupTile +lib-linecount = + Countlines + CountLinesAsync +lib-search = + text-search + text-match + make-search + text-equals +doc-text = + attach-doc-text + open-doc-text +doc-dir = + attach-doc-dir + open-doc-dir +doc-email = + open-doc-email + attach-email-view + +display-x11-xcb = + interactive-cmd-x11window + attach-display-x11 +display-pygtk = + interactice-cmd-gtkwindow + attach-display-gtk + +render-hex = + attach-render-hex + doc:appeared-hex +render-present = + attach-markdown-present + attach-present + doc:appeared-present +render-lines = + attach-render-lines + attach-render-text +render-format = attach-render-format +render-c-mode = + doc:appeared-c-mode + doc:appeared-py-mode + interactive-cmd-indent + +lib-viewer = + attach-viewer + doc:appeared-viewer +lib-qprint = + attach-quoted_printable + attach-qprint +lib-copybuf = + copy:save + copy:get +lib-colourmap = colour:map +lib-textfill = + attach-textfill + interactive-cmd-fill-mode +lib-autosave = + startup-autosave + interactice-cmd-recover + doc:appeared-check-autosave +lib-make = + interactive-cmd-make + interactive-cmd-grep + interactive-cmd-git-grep + interactive-cmd-next-match +lib-server = ALWAYS +lib-macro = macro:capture +lib-aspell = + Spell:Check + Spell:Suggest + Spell:ThisWord + Spell:NextWord +lib-calc = + CalcExpr + interactive-cmd-calc-replace +render-calc = + interactive-cmd-calc + doc:appeared-calc +lib-mergeview = + interactice-cmd-merge-mode + doc:appeared-mergeview +lib-compose-email = attach-compose-email +lib-autospell = + interactive-cmd-autospell + attach-autospell +lib-whitespace = + attach-whitespace + interactice-cmd-whitespace-mode +lib-x11selection-xcb = attach-x11selection +lib-url = + url:mark-up + attach-render-url-view +lib-diff = + attach-diff + interactive-cmd-diff-mode +lib-wiggle = MakeWiggle + +module-notmuch = + interactive-cmd-nm + interactive-cmd-nmc + interactive-cmd-nms + +emacs-search = + attach-emacs-search + attach-emacs-search-highlight + +lib-html-to-text = html-to-text +lib-html-w3m = html-to-text-w3m +lib-pdf-to-text = pdf-to-text +lib-doc-to-text = doc-to-text +lib-ical-to-text = ical-to-text +lib-utf8 = + attach-charset-utf-8 + attach-utf8 +lib-charset = ALWAYS + +config = ALWAYS diff --git a/lib-config.c b/lib-config.c new file mode 100644 index 00000000..e247b1c1 --- /dev/null +++ b/lib-config.c @@ -0,0 +1,259 @@ +/* + * Copyright Neil Brown ©2023 + * May be distributed under terms of GPLv2 - see file:COPYING + * + * Read an "ini" config file and set some attributes. + * Sections: + * global - set attr on editor + * module - set trigger to load module + * file:pattern - set attributes when matching file visited + * (not implemented fully yet) + * + * When not in a section, include= will load another file. + * + * Syntax for ini file + * - individual lines must not exceed 256 chars. Longer lines are + * silently truncated. + * - leading white space continues the previous line, this allowing large + * values. The newline and leading white space are stripped. + * - white space around "=", at EOL, and around section name in [section] + * is stripped + * - Double quotes at both ends of a value are stripped. + * - If first non-white is '#', line is ignored. + * - Everything after closing ']' of section is ignored + * - If value is no quoted, everything after first '#' is ignored + * - blank lines are ignored + */ + +#include +#include +#include +#include +#include +#include "core.h" + +typedef void (*ini_handle)(void *data, char *section safe, + char *name safe, char *value safe, + const char *path safe, + int append); +static void load_config(const char *path safe, struct pane *ed, const char *base); + +static void parse_ini(const char *path safe, ini_handle handle, void *data) +{ + FILE *f = fopen(path, "r"); + char line[257]; + char section[257] = ""; + char name[257] = ""; + + if (!f) + return; + while (fgets(line, sizeof(line), f) != NULL) { + char *st, *eq; + char *eol = strchr(line, '\n'); + int append, quote; + + if (!eol) { + int ch; + while ((ch = fgetc(f)) != '\n' && + ch != EOF) + ; + } else + *eol = 0; + if (line[0] == '[') { + eol = strchr(line, ']'); + if (!eol) + continue; + while (eol > line && isblank(eol[-1])) + eol -= 1; + *eol = 0; + st = line+1; + while (isblank(*st)) + st += 1; + strcpy(section, st); + name[0] = 0; + continue; + } + /* find/strip comment */ + st = line; quote = 0; + while (*st && (quote || *st != '#')) { + if (*st == '"') + quote = !quote; + st += 1; + } + if (*st == '#') + *st = 0; + if (isblank(line[0])) { + if (!name[0]) + /* Nothing to continue */ + continue; + st = line; + while (isblank(*st)) + st += 1; + if (!*st) + /* Blank line */ + continue; + append = 1; + } else { + name[0] = 0; + /* There must be an '=' */ + eq = strchr(line, '='); + if (!eq) + continue; + st = eq + 1; + while (eq > line && isblank(eq[-1])) + eq -= 1; + *eq = 0; + if (!line[0]) + /* No name before '=' */ + continue; + strcpy(name, line); + append = 0; + } + /* A value is at 'st', to be set or appended */ + eol = st + strlen(st); + while (isblank(*st)) + st += 1; + while (eol > st && isblank(eol[-1])) + eol -= 1; + if (*st == '"' && eol > st + 1 && eol[-1] == '"') { + st += 1; + eol -= 1; + } + *eol = 0; + handle(data, section, name, st, path, append); + } + fclose(f); +} + +struct mod_cmd { + char *module; + int tried; + struct command c; +}; + +DEF_CB(autoload) +{ + struct mod_cmd *mc = container_of(ci->comm, struct mod_cmd, c); + + if (mc->tried) + return Efallthrough; + mc->tried = 1; + + /* NOTE: this might free mc, so don't touch it again */ + call("global-load-module", ci->home, 0, NULL, mc->module); + return home_call(ci->home, ci->key, ci->focus, + ci->num, ci->mark, ci->str, + ci->num2, ci->mark2, ci->str2, + ci->x, ci->y, ci->comm2); +} + +static void al_free(struct command *c safe) +{ + struct mod_cmd *mc = container_of(c, struct mod_cmd, c); + + free(mc->module); + free(mc); +} + +static void handle(void *data, char *section safe, char *name safe, char *value safe, + const char *path safe, int append) +{ + struct pane *p = data; + + if (!p) + return; + + if (strcmp(section, "") == 0) { + if (strcmp(name, "include") == 0) { + load_config(value, p, path); + return; + } + return; + } + + if (strcmp(section, "global") == 0) { + call("global-set-attr", p, append, NULL, name, + 0, NULL, value); + return; + } + + if (strcmp(section, "module") == 0 && value[0]) { + struct mod_cmd *mc; + if (strcmp(value, "ALWAYS") == 0) { + call("global-load-module", p, 0, NULL, name); + return; + } + mc = malloc(sizeof(*mc)); + mc->module = strdup(name); + mc->tried = 0; + mc->c = autoload; + mc->c.free = al_free; + call_comm("global-set-command", p, &mc->c, 0, NULL, + value); + return; + } + + if (strncmp(section, "file:", 5) == 0) { + char *k = strconcat(NULL, "global-file-attr:", section+5); + call(k, p, append, NULL, name, 0, NULL, value); + return; + } +} + +static void load_config(const char *path safe, struct pane *ed, const char *base) +{ + char *sl, *p, *h; + if (*path == '/') { + parse_ini(path, handle, ed); + return; + } + /* + * Relative paths can be loaded from: + * dirname(base) + * /usr/share/edlib/ + * $HOME/.config/edlib/ + */ + if (base && (sl = strrchr(base, '/')) != NULL) { + sl += 1; + p = malloc((sl - base) + strlen(path) + 1); + memcpy(p, base, sl - base); + strcpy(p + (sl - base), path); + if (access(p, F_OK) == 0) { + parse_ini(p, handle, ed); + free(p); + return; + } + free(p); + } + p = strconcat(NULL, "/usr/share/edlib/", path); + if (access(p, F_OK) == 0) { + parse_ini(p, handle, ed); + free(p); + return; + } + free(p); + + h = getenv("HOME"); + if (h == NULL || *h != '/') + return; + p = strconcat(NULL, h, "/.config/edlib/", path); + if (access(p, F_OK) == 0) { + parse_ini(p, handle, ed); + free(p); + return; + } + free(p); +} + +DEF_CMD(config_load) +{ + if (ci->str) + load_config(ci->str, ci->home, ci->str2); + return 1; +} + +void edlib_init(struct pane *ed safe) +{ + call_comm("global-set-command", ed, &config_load, + 0, NULL, "config-load"); +} diff --git a/mode-emacs.c b/mode-emacs.c index 7dc48653..2f3991e9 100644 --- a/mode-emacs.c +++ b/mode-emacs.c @@ -3330,9 +3330,4 @@ void edlib_init(struct pane *ed safe) call_comm("global-set-command", ed, &attach_mode_emacs, 0, NULL, "attach-mode-emacs"); call_comm("global-set-command", ed, &attach_file_entry, 0, NULL, "attach-file-entry"); call_comm("global-set-command", ed, &emacs_shell, 0, NULL, "attach-shell-prompt"); - - call("global-load-module", ed, 0, NULL, "emacs-search"); - call("global-load-module", ed, 0, NULL, "lib-macro"); - call("global-load-module", ed, 0, NULL, "lib-aspell"); - call("global-load-module", ed, 0, NULL, "lib-calc"); } diff --git a/python/config.py b/python/config.py index ead98436..b7c42f4a 100644 --- a/python/config.py +++ b/python/config.py @@ -38,23 +38,3 @@ def config_appeared(key, focus, **a): " *[0-9]*\\.)") # Numbered list editor.call("global-set-command", "doc:appeared-config", config_appeared) - -# Some modules I want auto-loaded. -editor.call("global-load-module", "lib-mergeview") -editor.call("global-load-module", "render-calc") -editor.call("global-load-module", "lib-compose-email") -editor.call("global-load-module", "lib-autospell") -editor.call("global-load-module", "lib-whitespace") -editor.call("global-load-module", "display-pygtk") -editor.call("global-load-module", "display-x11-xcb") -editor.call("global-load-module", "lib-x11selection-xcb") -editor.call("global-load-module", "lib-url") - -if 'HOME' in os.environ: - path = os.environ['HOME'] + "/.config/edlib/config.py" -try: - with open(path, 'r') as fp: - out = fp.read() - exec(out) -except: - pass diff --git a/python/lib-diff.py b/python/lib-diff.py index 1e783121..5ccbd88a 100644 --- a/python/lib-diff.py +++ b/python/lib-diff.py @@ -336,4 +336,3 @@ def add_diff(key, focus, **a): edlib.editor.call("global-set-command", "attach-diff", diff_view_attach) edlib.editor.call("global-set-command", "interactive-cmd-diff-mode", add_diff) -edlib.editor.call("global-load-module", "lib-wiggle") diff --git a/python/lib-mergeview.py b/python/lib-mergeview.py index 35fed198..855dc983 100644 --- a/python/lib-mergeview.py +++ b/python/lib-mergeview.py @@ -474,5 +474,4 @@ def add_merge(key, focus, mark, **a): edlib.editor.call("global-set-command", "attach-merge", merge_view_attach) edlib.editor.call("global-set-command", "interactive-cmd-merge-mode", add_merge) -edlib.editor.call("global-load-module", "lib-wiggle") edlib.editor.call("global-set-command", "doc:appeared-mergeview", merge_appeared) diff --git a/python/render-calc.py b/python/render-calc.py index 97277275..4e1b27aa 100644 --- a/python/render-calc.py +++ b/python/render-calc.py @@ -175,6 +175,5 @@ def calc_appeared(key, focus, **a): return edlib.Efallthrough edlib.editor.call("global-set-command", "attach-view-calc", calc_view_attach) -edlib.editor.call("global-load-module", "lib-calc") edlib.editor.call("global-set-command", "interactive-cmd-calc", add_calc) edlib.editor.call("global-set-command", "doc:appeared-calc", calc_appeared)