]> git.neil.brown.name Git - edlib.git/commitdiff
config: support [file:glob] config setting.
authorNeilBrown <neil@brown.name>
Sun, 18 Jun 2023 01:45:04 +0000 (11:45 +1000)
committerNeilBrown <neil@brown.name>
Wed, 28 Jun 2023 07:51:41 +0000 (17:51 +1000)
Make a list of attrs to be added to documents based on file name, and
register a doc:appeared- handler to apply them.

This makes the config.py script irrelevant.

Signed-off-by: NeilBrown <neil@brown.name>
DOC/TODO.md
edlib.ini
lib-config.c
python/config.py [deleted file]

index a3698224d413ea164a6b5da2376a703b0835dc7b..e682acd4102bda433371d3e968e3fa7927405c8e 100644 (file)
@@ -35,7 +35,7 @@ the file.
 - [ ] lib-diff slowness with large diff
 - [ ] linecount :when used in 'view' mode, stack the counting pane with all the
       others so it can easily catch view-changed.
-- [ ] C config module that reads an ini-style file to set attributes
+- [X] C config module that reads an ini-style file to set attributes
       based on path
 - [ ] review all doc:char implementations for simplification.
 - [ ] make it easy for a make-search command to search backwards
@@ -71,6 +71,10 @@ Requirements for a v1.0 release
 Core features
 -------------
 
+- [ ] Do I really need global-multicall- or can I just use
+      notifications.
+      It would mean more modules would need a private pane, but might
+      I want that to support module unload anyway?
 - [ ] if a view creation fails - like render_master_view_attach
       hitting a python error - there will be no active view so the
       screen will be meaningless.  I need to properly abort and
@@ -1082,7 +1086,7 @@ Interaction with gdb would be nice too - things like
 
 ### config
 
-- [ ] C config module that reads an ini-style file to set attributes
+- [X] C config module that reads an ini-style file to set attributes
       based on path
 - [ ] configure "initial_panes"
 - [ ] discard old auto-load??
index 508e6c4c9d43121f90c848961bd592f2ac5f599d..d3917e7c9634b4ea37ac4bc2a994331f6ae6eaec 100644 (file)
--- a/edlib.ini
+++ b/edlib.ini
@@ -120,4 +120,24 @@ lib-utf8 =
        attach-utf8
 lib-charset = ALWAYS
 
-config = ALWAYS
+[file:COMMIT_EDITMSG*]
+APPEND view-default = ,textfill,whitespace,autospell
+fill-width = 72
+
+[file:.stgit]
+APPEND view-default = ,textfill,whitespace,autospell
+fill-width = 72
+
+[file:*.md]
+
+TESTING APPEND view-default = ,textfill,whitespace
+NOTESTING APPEND view-default = ,textfill,whitespace,autospell
+
+fill-width = 72
+word-wrap = 1
+fill:start-re = "^("
+                "[^a-zA-Z0-9\\n]*$|" # empty/puctuation line
+                " *-|"               # list item
+                " *- *\\[[ X]]|"     # todo list item
+                " *#+|"              # section head
+                " *[0-9]*\\.)"       # Numbered list
index 9fac7b50b1b85dbfe6d5f0ca5cf92ed69e7a1c8c..192c2785d0efbe14f6395fc89d291c3367d90dde 100644 (file)
@@ -125,11 +125,119 @@ static void parse_ini(const char *path safe, ini_handle handle, void *data)
        fclose(f);
 }
 
+static bool __glob_match(const char *patn safe, const char *path safe)
+{
+       while(1) {
+               switch (*patn) {
+               case '\0':
+                       return *path == '\0';
+               case '?':
+                       if (!*path || *path == '/')
+                               return False;
+                       patn += 1;
+                       path += 1;
+                       break;
+               case '*':
+                       if (patn[1] == '*') {
+                               if (__glob_match(patn+2, path))
+                                       return True;
+                       } else {
+                               if (__glob_match(patn+1, path))
+                                       return True;
+                               if (*path == '/')
+                                       return False;
+                       }
+                       if (!*path)
+                               return False;
+                       path += 1;
+                       break;
+               default:
+                       if (*patn != *path)
+                               return False;
+                       patn += 1;
+                       path += 1;
+                       break;
+               }
+       }
+}
+
+static bool glob_match(const char *patn safe, const char *path safe)
+{
+       int ret;
+       if (patn[0] != '/' && !strstarts(patn, "**")) {
+               /* must match basename */
+               const char *sl = strrchr(path, '/');
+               if (sl)
+                       path = sl + 1;
+       }
+       ret = __glob_match(patn, path);
+       return ret;
+}
+
 struct config_data {
        struct command c;
+       struct command appeared;
        struct pane *root safe;
+       struct trigger {
+               char *path safe;
+               struct attrset *attrs;
+               struct trigger *next;
+       } *triggers;
 };
 
+static void add_trigger(struct config_data *cd safe, char *path safe,
+                       char *name safe, char *val safe, int append)
+{
+       struct trigger *t = cd->triggers;
+
+       if (strstarts(name, "TESTING ")) {
+               if (getenv("EDLIB_TESTING") == NULL)
+                       return;
+               name += 8;
+       }
+       if (strstarts(name, "NOTESTING ")) {
+               if (getenv("EDLIB_TESTING") != NULL)
+                       return;
+               name += 10;
+       }
+       if (!t || strcmp(t->path, path) != 0) {
+               alloc(t, pane);
+               t->next = cd->triggers;
+               cd->triggers = t;
+               t->path = strdup(path);
+       }
+       if (append) {
+               const char *old = attr_find(t->attrs, name);
+               if (old) {
+                       val = strconcat(NULL, old, val);
+                       attr_set_str(&t->attrs, name, val);
+                       free(val);
+               } else
+                       attr_set_str(&t->attrs, name, val);
+       } else
+               attr_set_str(&t->attrs, name, val);
+}
+
+static void config_file(char *path safe, struct pane *doc safe,
+                       struct config_data *cd safe)
+{
+       struct trigger *t;
+
+       for (t = cd->triggers; t; t = t->next)
+               if (glob_match(t->path, path)) {
+                       const char *val;
+                       const char *k = "";
+                       while ((k = attr_get_next_key(t->attrs, k, -1, &val)) != NULL) {
+                               if (strstarts(k, "APPEND "))
+                                       call("doc:append:", doc, 0, NULL, val,
+                                            0, NULL, k + 7);
+                               else
+                                       call("doc:set:", doc, 0, NULL, val,
+                                            0, NULL, k);
+                       }
+               }
+}
+
 struct mod_cmd {
        char *module;
        int tried;
@@ -200,8 +308,7 @@ static void handle(void *data, char *section safe, char *name safe, char *value
        }
 
        if (strstarts(section, "file:")) {
-               char *k = strconcat(NULL, "global-file-attr:", section+5);
-               call(k, cd->root, append, NULL, name, 0, NULL, value);
+               add_trigger(cd, section+5, name, value, append);
                return;
        }
 }
@@ -257,6 +364,16 @@ static void config_free(struct command *c safe)
        free(cd);
 }
 
+DEF_CMD(config_appeared)
+{
+       struct config_data *cd = container_of(ci->comm, struct config_data, appeared);
+       char *path = pane_attr_get(ci->focus, "filename");
+       if (!path)
+               return Efallthrough;
+       config_file(path, ci->focus, cd);
+       return Efallthrough;
+}
+
 DEF_CMD(config_load)
 {
        struct config_data *cd;
@@ -267,8 +384,11 @@ DEF_CMD(config_load)
                alloc(cd, pane);
                cd->c = config_load;
                cd->c.free = config_free;
+               cd->appeared = config_appeared;
                cd->root = ci->home;
                call_comm("global-set-command", ci->home, &cd->c, 0, NULL, "config-load");
+               call_comm("global-set-command", ci->home, &cd->appeared,
+                         0, NULL, "doc:appeared-config");
        } else {
                cd = container_of(ci->comm, struct config_data, c);
        }
diff --git a/python/config.py b/python/config.py
deleted file mode 100644 (file)
index b7c42f4..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright Neil Brown ©2020-2023 <neil@brown.name>
-# May be distributed under terms of GPLv2 - see file:COPYING
-
-# This is a "config" script.  It just for experimenting
-# with simple configuration.  I plan to write a proper
-# config module with a more abstract language one day.
-# But I want some simple configuration NOW
-
-from edlib import editor
-import os
-
-def config_appeared(key, focus, **a):
-
-    p = focus['filename']
-
-    if p and ("COMMIT_EDITMSG" in p or "/.stgit" in p):
-        focus.call("doc:append:view-default", ",textfill,whitespace,autospell")
-        focus.call("doc:set:fill-width", "72")
-        if "/git/lustre-release/" in p:
-            # looks like a lustre commit, need to limit line width
-            focus.call("doc:set:fill-width", "70")
-            focus.call("doc:set:whitespace-width", "60")
-
-    if p and p[-3:] == ".md":
-        # Until I have a real markdown module, I need this at least.
-        if os.getenv("EDLIB_TESTING"):
-            focus.call("doc:append:view-default", ",textfill,whitespace")
-        else:
-            focus.call("doc:append:view-default", ",textfill,whitespace,autospell")
-        focus["fill-width"] = "72"
-        focus["word-wrap"] = "1"
-        focus["fill:start-re"] = ("^("
-                                  "[^a-zA-Z0-9\\n]*$|" # empty/puctuation line
-                                  " *-|"               # list item
-                                  " *- *\\[[ X]]|"     # todo list item
-                                  " *#+|"              # section head
-                                  " *[0-9]*\\.)")      # Numbered list
-
-editor.call("global-set-command", "doc:appeared-config", config_appeared)