]> git.wh0rd.org Git - nano.git/commitdiff
2008-09-21 Chris Allegretta <chrisa@asty.org>
authorChris Allegretta <chrisa@asty.org>
Sun, 21 Sep 2008 23:02:30 +0000 (23:02 +0000)
committerChris Allegretta <chrisa@asty.org>
Sun, 21 Sep 2008 23:02:30 +0000 (23:02 +0000)
        * rcfile.c, color.c, nano.h: Add new capability for matching a syntax type by the "header" (1st line)
          of a file being edited.  Based on Savannah bug 24197 and inital proof of concept by Dave Geering
          <dgeering@toshiba-tap.com>

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4328 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
doc/syntax/nanorc.nanorc
doc/syntax/perl.nanorc
doc/syntax/sh.nanorc
src/color.c
src/nano.h
src/rcfile.c

index e224a67fae67fa63dbcda55fed08b893b7b9662e..5ea8c33badd9f05ae03c1b75a0eff59c55259afa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-09-21 Chris Allegretta <chrisa@asty.org>
+       * rcfile.c, color.c, nano.h: Add new capability for matching a syntax type by the "header" (1st line)
+         of a file being edited.  Based on Savannah bug 24197 and inital proof of concept by Dave Geering 
+         <dgeering@toshiba-tap.com>
 2008-09-16 Chris Allegretta <chrisa@asty.org>
        * text.c: Add support for undoing a text uncut.  Split out the undo and redo of a text cut 
          in order to avoid code duplication.
index f63d770dfd2f3a8267b847dfe979f7c9f1479dbb..ae7baec3b57acce71502785b33f2283f591ce57a 100644 (file)
@@ -5,7 +5,7 @@ syntax "nanorc" "\.?nanorc$"
 icolor brightwhite "^[[:space:]]*((un)?set|include|syntax|i?color).*$"
 ## Keywords
 icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(autoindent|backup|backupdir|backwards|boldtext|brackets|casesensitive|const|cut|fill|historylog|matchbrackets|morespace|mouse|multibuffer|noconvert|nofollow|nohelp|nonewlines|nowrap|operatingdir|preserve|punct)\>" "^[[:space:]]*(set|unset)[[:space:]]+(quickblank|quotestr|rebinddelete|rebindkeypad|regexp|smarthome|smooth|speller|suspend|tabsize|tabstospaces|tempfile|view|whitespace|wordbounds)\>"
-icolor green "^[[:space:]]*(set|unset|include|syntax)\>"
+icolor green "^[[:space:]]*(set|unset|include|syntax|header)\>"
 ## Colors
 icolor yellow "^[[:space:]]*i?color[[:space:]]*(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\>"
 icolor magenta "^[[:space:]]*i?color\>" "\<(start|end)="
index 7bca4cd1bec8736d9b17d0851fa6eda914191882..b5a56062c7836043c586b9ff361ce251dd5aa6ae 100644 (file)
@@ -1,6 +1,7 @@
 ## Here is an example for Perl.
 ##
 syntax "perl" "\.p[lm]$"
+header "^#!.*/perl[-0-9._]*"
 color red "\<(accept|alarm|atan2|bin(d|mode)|c(aller|h(dir|mod|op|own|root)|lose(dir)?|onnect|os|rypt)|d(bm(close|open)|efined|elete|ie|o|ump)|e(ach|of|val|x(ec|ists|it|p))|f(cntl|ileno|lock|ork))\>" "\<(get(c|login|peername|pgrp|ppid|priority|pwnam|(host|net|proto|serv)byname|pwuid|grgid|(host|net)byaddr|protobynumber|servbyport)|([gs]et|end)(pw|gr|host|net|proto|serv)ent|getsock(name|opt)|gmtime|goto|grep|hex|index|int|ioctl|join)\>" "\<(keys|kill|last|length|link|listen|local(time)?|log|lstat|m|mkdir|msg(ctl|get|snd|rcv)|next|oct|open(dir)?|ord|pack|pipe|pop|printf?|push|q|qq|qx|rand|re(ad(dir|link)?|cv|do|name|quire|set|turn|verse|winddir)|rindex|rmdir|s|scalar|seek(dir)?)\>" "\<(se(lect|mctl|mget|mop|nd|tpgrp|tpriority|tsockopt)|shift|shm(ctl|get|read|write)|shutdown|sin|sleep|socket(pair)?|sort|spli(ce|t)|sprintf|sqrt|srand|stat|study|substr|symlink|sys(call|read|tem|write)|tell(dir)?|time|tr(y)?|truncate|umask)\>" "\<(un(def|link|pack|shift)|utime|values|vec|wait(pid)?|wantarray|warn|write)\>"
 color magenta "\<(continue|else|elsif|do|for|foreach|if|unless|until|while|eq|ne|lt|gt|le|ge|cmp|x|my|sub|use|package|can|isa)\>"
 icolor cyan start="[$@%]" end="( |[^0-9A-Z_]|-)"
index f540f1b71d92ca6946186d7a5fc2e5a56f9e5151..61098e37effc55a0d8d6efbe8af6fc3a830a6e21 100644 (file)
@@ -1,6 +1,7 @@
 ## Here is an example for Bourne shell scripts.
 ##
 syntax "sh" "\.sh$"
+header "^#!.*/(ba|k|pdk|)sh[-0-9_]*"
 icolor brightgreen "^[0-9A-Z_]+\(\)"
 color green "\<(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)\>"
 color green "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"
index bbe46bd9054ee6ebba4515aca5212f5c67c5ddf5..353a5bafec55d3d607bc1bb43606fc06ba96287f 100644 (file)
@@ -131,7 +131,7 @@ void color_update(void)
 
     /* If we didn't specify a syntax override string, or if we did and
      * there was no syntax by that name, get the syntax based on the
-     * file extension. */
+     * file extension, and then look in the header. */
     if (openfile->colorstrings == NULL) {
        for (tmpsyntax = syntaxes; tmpsyntax != NULL;
                tmpsyntax = tmpsyntax->next) {
@@ -174,8 +174,51 @@ void color_update(void)
                }
            }
        }
+
+       /* If we haven't matched anything yet, try the headers */
+       if (openfile->colorstrings == NULL) {
+#ifdef DEBUG
+           fprintf(stderr, "No match for file extensions, looking at headers...\n");
+#endif
+           for (tmpsyntax = syntaxes; tmpsyntax != NULL;
+               tmpsyntax = tmpsyntax->next) {
+               exttype *e;
+
+               for (e = tmpsyntax->headers; e != NULL; e = e->next) {
+                   bool not_compiled = (e->ext == NULL);
+
+                   /* e->ext_regex has already been checked for validity
+                    * elsewhere.  Compile its specified regex if we haven't
+                    * already. */
+                   if (not_compiled) {
+                       e->ext = (regex_t *)nmalloc(sizeof(regex_t));
+                       regcomp(e->ext, fixbounds(e->ext_regex), REG_EXTENDED);
+                   }
+
+                   /* Set colorstrings if we matched the extension
+                    * regex. */
+#ifdef DEBUG
+               fprintf(stderr, "Comparing header regex \"%s\" to fileage \"%s\"...\n", e->ext_regex, openfile->fileage->data);
+#endif
+                   if (regexec(e->ext, openfile->fileage->data, 0, NULL, 0) == 0)
+                       openfile->colorstrings = tmpsyntax->color;
+
+                   if (openfile->colorstrings != NULL)
+                       break;
+
+                   /* Decompile e->ext_regex's specified regex if we aren't
+                    * going to use it. */
+                   if (not_compiled) {
+                       regfree(e->ext);
+                       free(e->ext);
+                       e->ext = NULL;
+                   }
+               }
+           }
+       }
     }
 
+
     /* If we didn't get a syntax based on the file extension, and we
      * have a default syntax, use it. */
     if (openfile->colorstrings == NULL && defcolor != NULL)
index b286f0d03e4479613f4eda7c6bb4e743c4bfe4a0..c82122d61515a8cdbe803238f8bc98802571710e 100644 (file)
@@ -242,6 +242,8 @@ typedef struct syntaxtype {
        /* The name of this syntax. */
     exttype *extensions;
        /* The list of extensions that this syntax applies to. */
+    exttype *headers;
+       /* Regexes to match on the 'header' (1st line) of the file */
     colortype *color;
        /* The colors used in this syntax. */
     struct syntaxtype *next;
index 85fb991363399c14004d985670a332dc38be1702..24ec588e2451968e55b4070e2c2d7e61b9c3160b 100644 (file)
@@ -103,6 +103,8 @@ static char *nanorc = NULL;
 #ifdef ENABLE_COLOR
 static syntaxtype *endsyntax = NULL;
        /* The end of the list of syntaxes. */
+static exttype *endheader = NULL;
+       /* End of header list */
 static colortype *endcolor = NULL;
        /* The end of the color list for the current syntax. */
 #endif
@@ -290,7 +292,9 @@ void parse_syntax(char *ptr)
     endsyntax->desc = mallocstrcpy(NULL, nameptr);
     endsyntax->color = NULL;
     endcolor = NULL;
+    endheader = NULL;
     endsyntax->extensions = NULL;
+    endsyntax->headers = NULL;
     endsyntax->next = NULL;
 
 #ifdef DEBUG
@@ -715,6 +719,71 @@ void parse_colors(char *ptr, bool icase)
        }
     }
 }
+
+/* Parse the headers (1st line) of the file which may influence the regex used. */
+void parse_headers(char *ptr)
+{
+    char *h, *regstr;
+
+    assert(ptr != NULL);
+
+    if (syntaxes == NULL) {
+       rcfile_error(
+               N_("Cannot add a header regex without a syntax command"));
+       return;
+    }
+
+    if (*ptr == '\0') {
+       rcfile_error(N_("Missing regex string"));
+       return;
+    }
+
+    /* Now for the fun part.  Start adding regexes to individual strings
+     * in the colorstrings array, woo! */
+    while (ptr != NULL && *ptr != '\0') {
+       exttype *newheader;
+           /* The new color structure. */
+       bool cancelled = FALSE;
+           /* The start expression was bad. */
+
+       if (*ptr != '"') {
+           rcfile_error(
+               N_("Regex strings must begin and end with a \" character"));
+           ptr = parse_next_regex(ptr);
+           continue;
+       }
+
+       ptr++;
+
+       regstr = ptr;
+       ptr = parse_next_regex(ptr);
+       if (ptr == NULL)
+           break;
+
+       newheader = (exttype *)nmalloc(sizeof(exttype));
+
+       /* Save the regex string if it's valid */
+       if (nregcomp(regstr, 0)) {
+           newheader->ext_regex = mallocstrcpy(NULL, regstr);
+           newheader->ext = NULL;
+           newheader->next = NULL;
+
+#ifdef DEBUG
+            fprintf(stderr, "Starting a new header entry: %s\n", newheader->ext_regex);
+#endif
+
+           if (endheader == NULL) {
+               endsyntax->headers = newheader;
+           } else {
+               endheader->next = newheader;
+           }
+
+           endheader = newheader;
+       } else
+           free(newheader);
+
+    }
+}
 #endif /* ENABLE_COLOR */
 
 /* Check whether the user has unmapped every shortcut for a
@@ -812,7 +881,9 @@ void parse_rcfile(FILE *rcstream
                rcfile_error(N_("Syntax \"%s\" has no color commands"),
                        endsyntax->desc);
            parse_syntax(ptr);
-       } else if (strcasecmp(keyword, "color") == 0)
+       } else if (strcasecmp(keyword, "header") == 0)
+           parse_headers(ptr);
+       else if (strcasecmp(keyword, "color") == 0)
            parse_colors(ptr, FALSE);
        else if (strcasecmp(keyword, "icolor") == 0)
            parse_colors(ptr, TRUE);