rcfile: fully parse a syntax file only when needed
When parsing an included syntax file, stop reading when a command other than 'syntax', 'header' or 'magic' is encountered. The syntax file is fully parsed the first time that a file needs it. Each 'extendsyntax' command is stored for unloaded syntaxes and applied after the syntax is loaded. Closing a buffer does not unload the syntax, even if no longer used by another buffer. This addresses https://savannah.gnu.org/bugs/?54928. Signed-off-by: Brand Huntsman <alpha@qzx.com>master
parent
0e29c2a24a
commit
cba9d8d05e
58
src/color.c
58
src/color.c
|
@ -39,11 +39,34 @@
|
||||||
#define A_BANDAID A_NORMAL
|
#define A_BANDAID A_NORMAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Assign pair numbers for the colors in the given syntax, giving identical
|
||||||
|
* color pairs the same number. */
|
||||||
|
void set_syntax_colorpairs(syntaxtype *sint)
|
||||||
|
{
|
||||||
|
int new_number = NUMBER_OF_ELEMENTS + 1;
|
||||||
|
colortype *ink;
|
||||||
|
|
||||||
|
for (ink = sint->color; ink != NULL; ink = ink->next) {
|
||||||
|
const colortype *beforenow = sint->color;
|
||||||
|
|
||||||
|
while (beforenow != ink && (beforenow->fg != ink->fg ||
|
||||||
|
beforenow->bg != ink->bg))
|
||||||
|
beforenow = beforenow->next;
|
||||||
|
|
||||||
|
if (beforenow != ink)
|
||||||
|
ink->pairnum = beforenow->pairnum;
|
||||||
|
else
|
||||||
|
ink->pairnum = new_number++;
|
||||||
|
|
||||||
|
ink->attributes |= COLOR_PAIR(ink->pairnum) | A_BANDAID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the colors for nano's interface, and assign pair numbers
|
/* Initialize the colors for nano's interface, and assign pair numbers
|
||||||
* for the colors in each syntax. */
|
* for the colors in each loaded syntax. */
|
||||||
void set_colorpairs(void)
|
void set_colorpairs(void)
|
||||||
{
|
{
|
||||||
const syntaxtype *sint;
|
syntaxtype *sint;
|
||||||
bool using_defaults = FALSE;
|
bool using_defaults = FALSE;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
@ -82,27 +105,10 @@ void set_colorpairs(void)
|
||||||
free(color_combo[i]);
|
free(color_combo[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For each syntax, go through its list of colors and assign each
|
/* For each loaded syntax, assign pair numbers to color combinations. */
|
||||||
* its pair number, giving identical color pairs the same number. */
|
for (sint = syntaxes; sint != NULL; sint = sint->next)
|
||||||
for (sint = syntaxes; sint != NULL; sint = sint->next) {
|
if (sint->filename == NULL)
|
||||||
colortype *ink;
|
set_syntax_colorpairs(sint);
|
||||||
int new_number = NUMBER_OF_ELEMENTS + 1;
|
|
||||||
|
|
||||||
for (ink = sint->color; ink != NULL; ink = ink->next) {
|
|
||||||
const colortype *beforenow = sint->color;
|
|
||||||
|
|
||||||
while (beforenow != ink && (beforenow->fg != ink->fg ||
|
|
||||||
beforenow->bg != ink->bg))
|
|
||||||
beforenow = beforenow->next;
|
|
||||||
|
|
||||||
if (beforenow != ink)
|
|
||||||
ink->pairnum = beforenow->pairnum;
|
|
||||||
else
|
|
||||||
ink->pairnum = new_number++;
|
|
||||||
|
|
||||||
ink->attributes |= COLOR_PAIR(ink->pairnum) | A_BANDAID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the color information. */
|
/* Initialize the color information. */
|
||||||
|
@ -267,6 +273,12 @@ void color_update(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When the syntax isn't loaded yet, parse it and initialize its colors. */
|
||||||
|
if (sint->filename != NULL) {
|
||||||
|
parse_one_include(sint->filename, sint);
|
||||||
|
set_syntax_colorpairs(sint);
|
||||||
|
}
|
||||||
|
|
||||||
openfile->syntax = sint;
|
openfile->syntax = sint;
|
||||||
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
|
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
|
||||||
|
|
||||||
|
|
15
src/nano.h
15
src/nano.h
|
@ -215,9 +215,24 @@ typedef struct regexlisttype {
|
||||||
/* The next regex. */
|
/* The next regex. */
|
||||||
} regexlisttype;
|
} regexlisttype;
|
||||||
|
|
||||||
|
typedef struct extendsyntaxstruct {
|
||||||
|
char *filename;
|
||||||
|
/* The file where the syntax is extended. */
|
||||||
|
ssize_t lineno;
|
||||||
|
/* The number of the line of the extendsyntax command. */
|
||||||
|
char *data;
|
||||||
|
/* The text of the line. */
|
||||||
|
struct extendsyntaxstruct *next;
|
||||||
|
/* Next node. */
|
||||||
|
} extendsyntaxstruct;
|
||||||
|
|
||||||
typedef struct syntaxtype {
|
typedef struct syntaxtype {
|
||||||
char *name;
|
char *name;
|
||||||
/* The name of this syntax. */
|
/* The name of this syntax. */
|
||||||
|
char *filename;
|
||||||
|
/* File where the syntax is defined, or NULL if not an included file. */
|
||||||
|
struct extendsyntaxstruct *extendsyntax;
|
||||||
|
/* List of extendsyntax commands to apply when loaded. */
|
||||||
regexlisttype *extensions;
|
regexlisttype *extensions;
|
||||||
/* The list of extensions that this syntax applies to. */
|
/* The list of extensions that this syntax applies to. */
|
||||||
regexlisttype *headers;
|
regexlisttype *headers;
|
||||||
|
|
|
@ -465,10 +465,12 @@ int do_yesno_prompt(bool all, const char *msg);
|
||||||
/* Most functions in rcfile.c. */
|
/* Most functions in rcfile.c. */
|
||||||
#ifdef ENABLE_NANORC
|
#ifdef ENABLE_NANORC
|
||||||
void display_rcfile_errors();
|
void display_rcfile_errors();
|
||||||
|
bool parse_syntax_commands(char *keyword, char *ptr);
|
||||||
|
void parse_one_include(char *file, syntaxtype *syntax);
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
|
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
|
||||||
#endif
|
#endif
|
||||||
void parse_rcfile(FILE *rcstream, bool syntax_only);
|
void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only);
|
||||||
void do_rcfiles(void);
|
void do_rcfiles(void);
|
||||||
#endif /* ENABLE_NANORC */
|
#endif /* ENABLE_NANORC */
|
||||||
|
|
||||||
|
|
135
src/rcfile.c
135
src/rcfile.c
|
@ -288,7 +288,7 @@ bool nregcomp(const char *regex, int compile_flags)
|
||||||
|
|
||||||
/* Parse the next syntax name and its possible extension regexes from the
|
/* Parse the next syntax name and its possible extension regexes from the
|
||||||
* line at ptr, and add it to the global linked list of color syntaxes. */
|
* line at ptr, and add it to the global linked list of color syntaxes. */
|
||||||
void parse_syntax(char *ptr)
|
void parse_syntax(char *ptr, bool headers_only)
|
||||||
{
|
{
|
||||||
char *nameptr = ptr;
|
char *nameptr = ptr;
|
||||||
|
|
||||||
|
@ -324,6 +324,8 @@ void parse_syntax(char *ptr)
|
||||||
/* Initialize a new syntax struct. */
|
/* Initialize a new syntax struct. */
|
||||||
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
|
||||||
live_syntax->name = mallocstrcpy(NULL, nameptr);
|
live_syntax->name = mallocstrcpy(NULL, nameptr);
|
||||||
|
live_syntax->filename = (headers_only ? strdup(nanorc) : NULL);
|
||||||
|
live_syntax->extendsyntax = NULL;
|
||||||
live_syntax->extensions = NULL;
|
live_syntax->extensions = NULL;
|
||||||
live_syntax->headers = NULL;
|
live_syntax->headers = NULL;
|
||||||
live_syntax->magics = NULL;
|
live_syntax->magics = NULL;
|
||||||
|
@ -539,7 +541,7 @@ bool is_good_file(char *file)
|
||||||
|
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
/* Read and parse one included syntax file. */
|
/* Read and parse one included syntax file. */
|
||||||
static void parse_one_include(char *file)
|
void parse_one_include(char *file, syntaxtype *syntax)
|
||||||
{
|
{
|
||||||
FILE *rcstream;
|
FILE *rcstream;
|
||||||
|
|
||||||
|
@ -560,7 +562,49 @@ static void parse_one_include(char *file)
|
||||||
nanorc = file;
|
nanorc = file;
|
||||||
lineno = 0;
|
lineno = 0;
|
||||||
|
|
||||||
parse_rcfile(rcstream, TRUE);
|
/* If this is the first pass, parse only the prologue. */
|
||||||
|
if (syntax == NULL) {
|
||||||
|
parse_rcfile(rcstream, TRUE, TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
live_syntax = syntax;
|
||||||
|
opensyntax = TRUE;
|
||||||
|
lastcolor = NULL;
|
||||||
|
|
||||||
|
/* Parse the included file fully. */
|
||||||
|
parse_rcfile(rcstream, TRUE, FALSE);
|
||||||
|
opensyntax = TRUE;
|
||||||
|
|
||||||
|
lastcolor = syntax->color;
|
||||||
|
if (lastcolor != NULL)
|
||||||
|
while (lastcolor->next != NULL)
|
||||||
|
lastcolor = lastcolor->next;
|
||||||
|
|
||||||
|
extendsyntaxstruct *es = syntax->extendsyntax;
|
||||||
|
|
||||||
|
/* Apply any stored extendsyntax commands. */
|
||||||
|
while (es != NULL) {
|
||||||
|
extendsyntaxstruct *next = es->next;
|
||||||
|
char *keyword = es->data, *ptr = parse_next_word(es->data);
|
||||||
|
|
||||||
|
nanorc = es->filename;
|
||||||
|
lineno = es->lineno;
|
||||||
|
|
||||||
|
if (!parse_syntax_commands(keyword, ptr))
|
||||||
|
rcfile_error(N_("Command \"%s\" not understood"), keyword);
|
||||||
|
|
||||||
|
free(es->filename);
|
||||||
|
free(es->data);
|
||||||
|
free(es);
|
||||||
|
|
||||||
|
es = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(syntax->filename);
|
||||||
|
syntax->filename = NULL;
|
||||||
|
syntax->extendsyntax = NULL;
|
||||||
|
opensyntax = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expand globs in the passed name, and parse the resultant files. */
|
/* Expand globs in the passed name, and parse the resultant files. */
|
||||||
|
@ -585,7 +629,7 @@ void parse_includes(char *ptr)
|
||||||
* report an error if it's something other than zero matches. */
|
* report an error if it's something other than zero matches. */
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
for (size_t i = 0; i < files.gl_pathc; ++i)
|
for (size_t i = 0; i < files.gl_pathc; ++i)
|
||||||
parse_one_include(files.gl_pathv[i]);
|
parse_one_include(files.gl_pathv[i], NULL);
|
||||||
} else if (result != GLOB_NOMATCH)
|
} else if (result != GLOB_NOMATCH)
|
||||||
rcfile_error(_("Error expanding %s: %s"), pattern, strerror(errno));
|
rcfile_error(_("Error expanding %s: %s"), pattern, strerror(errno));
|
||||||
|
|
||||||
|
@ -931,10 +975,31 @@ static void check_vitals_mapped(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse syntax-only commands. */
|
||||||
|
bool parse_syntax_commands(char *keyword, char *ptr)
|
||||||
|
{
|
||||||
|
if (strcasecmp(keyword, "comment") == 0)
|
||||||
|
#ifdef ENABLE_COMMENT
|
||||||
|
pick_up_name("comment", ptr, &live_syntax->comment);
|
||||||
|
#else
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
else if (strcasecmp(keyword, "color") == 0)
|
||||||
|
parse_colors(ptr, NANO_REG_EXTENDED);
|
||||||
|
else if (strcasecmp(keyword, "icolor") == 0)
|
||||||
|
parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE);
|
||||||
|
else if (strcasecmp(keyword, "linter") == 0)
|
||||||
|
pick_up_name("linter", ptr, &live_syntax->linter);
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse the rcfile, once it has been opened successfully at rcstream,
|
/* Parse the rcfile, once it has been opened successfully at rcstream,
|
||||||
* and close it afterwards. If syntax_only is TRUE, allow the file to
|
* and close it afterwards. If syntax_only is TRUE, allow the file to
|
||||||
* to contain only color syntax commands. */
|
* to contain only color syntax commands. */
|
||||||
void parse_rcfile(FILE *rcstream, bool syntax_only)
|
void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only)
|
||||||
{
|
{
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
@ -981,6 +1046,26 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When the syntax isn't loaded yet, store extendsyntax commands. */
|
||||||
|
if (sint->filename != NULL) {
|
||||||
|
extendsyntaxstruct *newextendsyntax = nmalloc(sizeof(extendsyntaxstruct));;
|
||||||
|
|
||||||
|
newextendsyntax->filename = strdup(nanorc);
|
||||||
|
newextendsyntax->lineno = lineno;
|
||||||
|
newextendsyntax->data = strdup(ptr);
|
||||||
|
newextendsyntax->next = NULL;
|
||||||
|
|
||||||
|
if (sint->extendsyntax != NULL) {
|
||||||
|
extendsyntaxstruct *es = sint->extendsyntax;
|
||||||
|
while (es->next != NULL)
|
||||||
|
es = es->next;
|
||||||
|
es->next = newextendsyntax;
|
||||||
|
} else
|
||||||
|
sint->extendsyntax = newextendsyntax;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
live_syntax = sint;
|
live_syntax = sint;
|
||||||
opensyntax = TRUE;
|
opensyntax = TRUE;
|
||||||
|
|
||||||
|
@ -996,31 +1081,27 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
|
||||||
|
|
||||||
/* Try to parse the keyword. */
|
/* Try to parse the keyword. */
|
||||||
if (strcasecmp(keyword, "syntax") == 0) {
|
if (strcasecmp(keyword, "syntax") == 0) {
|
||||||
if (opensyntax && lastcolor == NULL)
|
if (headers_only || !syntax_only) {
|
||||||
rcfile_error(N_("Syntax \"%s\" has no color commands"),
|
if (opensyntax && lastcolor == NULL && live_syntax->filename == NULL)
|
||||||
live_syntax->name);
|
rcfile_error(N_("Syntax \"%s\" has no color commands"),
|
||||||
parse_syntax(ptr);
|
live_syntax->name);
|
||||||
|
parse_syntax(ptr, headers_only);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (strcasecmp(keyword, "header") == 0)
|
else if (strcasecmp(keyword, "header") == 0) {
|
||||||
grab_and_store("header", ptr, &live_syntax->headers);
|
if (headers_only || !syntax_only)
|
||||||
else if (strcasecmp(keyword, "magic") == 0)
|
grab_and_store("header", ptr, &live_syntax->headers);
|
||||||
|
} else if (strcasecmp(keyword, "magic") == 0)
|
||||||
#ifdef HAVE_LIBMAGIC
|
#ifdef HAVE_LIBMAGIC
|
||||||
grab_and_store("magic", ptr, &live_syntax->magics);
|
if (headers_only || !syntax_only)
|
||||||
|
grab_and_store("magic", ptr, &live_syntax->magics);
|
||||||
#else
|
#else
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
else if (strcasecmp(keyword, "comment") == 0)
|
else if (headers_only)
|
||||||
#ifdef ENABLE_COMMENT
|
break;
|
||||||
pick_up_name("comment", ptr, &live_syntax->comment);
|
else if (parse_syntax_commands(keyword, ptr))
|
||||||
#else
|
|
||||||
;
|
;
|
||||||
#endif
|
|
||||||
else if (strcasecmp(keyword, "color") == 0)
|
|
||||||
parse_colors(ptr, NANO_REG_EXTENDED);
|
|
||||||
else if (strcasecmp(keyword, "icolor") == 0)
|
|
||||||
parse_colors(ptr, NANO_REG_EXTENDED | REG_ICASE);
|
|
||||||
else if (strcasecmp(keyword, "linter") == 0)
|
|
||||||
pick_up_name("linter", ptr, &live_syntax->linter);
|
|
||||||
else if (syntax_only && (strcasecmp(keyword, "set") == 0 ||
|
else if (syntax_only && (strcasecmp(keyword, "set") == 0 ||
|
||||||
strcasecmp(keyword, "unset") == 0 ||
|
strcasecmp(keyword, "unset") == 0 ||
|
||||||
strcasecmp(keyword, "bind") == 0 ||
|
strcasecmp(keyword, "bind") == 0 ||
|
||||||
|
@ -1046,7 +1127,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
|
||||||
|
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
/* If a syntax was extended, it stops at the end of the command. */
|
/* If a syntax was extended, it stops at the end of the command. */
|
||||||
if (live_syntax != syntaxes)
|
if (!syntax_only && live_syntax != syntaxes)
|
||||||
opensyntax = FALSE;
|
opensyntax = FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1210,7 +1291,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_COLOR
|
#ifdef ENABLE_COLOR
|
||||||
if (opensyntax && lastcolor == NULL)
|
if (opensyntax && lastcolor == NULL && !headers_only)
|
||||||
rcfile_error(N_("Syntax \"%s\" has no color commands"),
|
rcfile_error(N_("Syntax \"%s\" has no color commands"),
|
||||||
live_syntax->name);
|
live_syntax->name);
|
||||||
|
|
||||||
|
@ -1238,7 +1319,7 @@ void parse_one_nanorc(void)
|
||||||
/* If opening the file succeeded, parse it. Otherwise, only
|
/* If opening the file succeeded, parse it. Otherwise, only
|
||||||
* complain if the file actually exists. */
|
* complain if the file actually exists. */
|
||||||
if (rcstream != NULL)
|
if (rcstream != NULL)
|
||||||
parse_rcfile(rcstream, FALSE);
|
parse_rcfile(rcstream, FALSE, FALSE);
|
||||||
else if (errno != ENOENT)
|
else if (errno != ENOENT)
|
||||||
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
|
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue