TL;DR "support" because this is not about supporting the fancy new
stuff, but just not breaking on a universal-ctags generated tag file.
I'd just like to tell mg enough of the file format to ignore the
extensions over plain tag files.

The diff is mostly from troglobit' mg:
https://github.com/troglobit/mg/commit/64cd07ecf5c521d50966eca8ba04026e7c9f3be8

The documentation about the universal-ctags extension over tags files
is documented in utags(5) after you install the universal-ctags
package.  Tags file entries follows this scheme:

        {tagname}<tab>{tagfile}<tab>{tagaddress}

where tagaddress is an ex command (could be anything, I haven't
checked how vi(1) actually implements it, but mg assumes it's a search
and just does that.  Works most of the times).

To store extra metadata about the tag itself, the address is put a
comment in the tagaddress.  For example, here's how the main() entry
would look like.  Not the type information after ;"

% uctags *.c
% g ^main tags
tags:526: main  main.c  /^main(int argc, char **argv)$/;"       f       
typeref:typename:int

Similarly, universal-ctags introduced support for some meta-tag using
some dummy entries under the !_TAG_ "namespace"
(e.g. !_TAG_FILE_FORMAT, !_TAG_FILE_SORTED, ...)

So, the idea is to just ignore tags starting with !_TAG_ and ignore
comments.  As simple as that :-)

Index: tags.c
===================================================================
RCS file: /home/cvs/src/usr.bin/mg/tags.c,v
retrieving revision 1.27
diff -u -p -r1.27 tags.c
--- tags.c      29 Mar 2023 19:09:04 -0000      1.27
+++ tags.c      27 Sep 2023 16:21:42 -0000
@@ -281,6 +281,10 @@ loadtags(const char *fn)
        }
        while ((l = fparseln(fd, NULL, NULL, "\\\\\0",
            FPARSELN_UNESCCONT | FPARSELN_UNESCREST)) != NULL) {
+               if (!strncmp(l, "!_TAG_", 6)) {
+                       free(l);
+                       continue;
+               }
                if (addctag(l) == FALSE) {
                        fclose(fd);
                        return (FALSE);
@@ -340,7 +344,7 @@ int
 addctag(char *s)
 {
        struct ctag *t = NULL;
-       char *l;
+       char *l, *c;
 
        if ((t = malloc(sizeof(struct ctag))) == NULL) {
                dobeep();
@@ -357,6 +361,15 @@ addctag(char *s)
        *l++ = '\0';
        if (*l == '\0')
                goto cleanup;
+
+       /*
+        * Newer universal ctags format abuse vi comments in the
+        * pattern to store extra metadata.  Since we don't support it
+        * remove it so the pattern is not mangled.
+        */
+       if ((c = strstr(l, ";\"")) != NULL)
+               *c = '\0';
+
        t->pat = strip(l, strlen(l));
        if (RB_INSERT(tagtree, &tags, t) != NULL) {
                free(t);

Reply via email to