]> git.neil.brown.name Git - edlib.git/commitdiff
Add a config-file parser.
authorNeilBrown <neil@brown.name>
Wed, 14 Jun 2023 10:21:58 +0000 (20:21 +1000)
committerNeilBrown <neil@brown.name>
Wed, 28 Jun 2023 07:51:41 +0000 (17:51 +1000)
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 <neil@brown.name>
Makefile
doc-email.c
edlib.c
edlib.ini [new file with mode: 0644]
lib-config.c [new file with mode: 0644]
mode-emacs.c
python/config.py
python/lib-diff.py
python/lib-mergeview.py
python/render-calc.py

index 2c0dccb1ddec120c4248c147940d211d594c3c49..c927b30d9a310f7d4f9dfa49f2aaf7ec12fbfc91 100644 (file)
--- 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 \
index b6742318bbdee225912d703e7e2568ec1741cf32..94a3c7910dfe4409a992c23ecb171a82e1c73348 100644 (file)
@@ -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 6471c635a60db2564f03e44560039a227e2d0c64..0fdfafac427158116fda6500373c069512e139a1 100644 (file)
--- 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 (file)
index 0000000..508e6c4
--- /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 (file)
index 0000000..e247b1c
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright Neil Brown ©2023 <neil@brown.name>
+ * 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 <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <ctype.h>
+#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");
+}
index 7dc48653ff88455e82eb27b2033a8c1b2a0375f4..2f3991e968ad98d9bacb2ab77d16c1ea81841420 100644 (file)
@@ -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");
 }
index ead98436b81e5e03fb3b879604528d8fcd9be6bb..b7c42f4a2405e46964d5386552106f9fa6c8e25e 100644 (file)
@@ -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
index 1e78312132210de029c353f0d14eaa547f549c2b..5ccbd88af1b5ba5161ebf38b1f66327a718baaa9 100644 (file)
@@ -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")
index 35fed1987fa01ada0b23653a0406d5aba7445f7b..855dc9839a0145c1382c80c7c0874f0ecf1e99a6 100644 (file)
@@ -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)
index 9727727564c22396ee9dbc522fdab90790285b39..4e1b27aac896f95761ccc784c804658e8311c7d7 100644 (file)
@@ -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)