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>



git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4328 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
Chris Allegretta 2008-09-21 23:02:30 +00:00
parent b549f3761a
commit f30c1390c7
7 changed files with 125 additions and 3 deletions

View File

@ -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.

View 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)="

View 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_]|-)"

View 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 "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)"

View 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)

View 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;

View 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);