commit cba9d8d05e3d37687537818d81e90f2b7abd872c
parent 0e29c2a24a16da897e52712ec5c127310a50618e
Author: Brand Huntsman <alpha@qzx.com>
Date: Mon, 13 May 2019 18:01:59 -0600
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>
Diffstat:
M | src/color.c | | | 58 | +++++++++++++++++++++++++++++++++++----------------------- |
M | src/nano.h | | | 15 | +++++++++++++++ |
M | src/proto.h | | | 4 | +++- |
M | src/rcfile.c | | | 135 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
4 files changed, 161 insertions(+), 51 deletions(-)
diff --git a/src/color.c b/src/color.c
@@ -39,11 +39,34 @@
#define A_BANDAID A_NORMAL
#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
- * for the colors in each syntax. */
+ * for the colors in each loaded syntax. */
void set_colorpairs(void)
{
- const syntaxtype *sint;
+ syntaxtype *sint;
bool using_defaults = FALSE;
size_t i;
@@ -82,27 +105,10 @@ void set_colorpairs(void)
free(color_combo[i]);
}
- /* For each syntax, go through its list of colors and assign each
- * its pair number, giving identical color pairs the same number. */
- for (sint = syntaxes; sint != NULL; sint = sint->next) {
- colortype *ink;
- 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;
- }
- }
+ /* For each loaded syntax, assign pair numbers to color combinations. */
+ for (sint = syntaxes; sint != NULL; sint = sint->next)
+ if (sint->filename == NULL)
+ set_syntax_colorpairs(sint);
}
/* 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->colorstrings = (sint == NULL ? NULL : sint->color);
diff --git a/src/nano.h b/src/nano.h
@@ -215,9 +215,24 @@ typedef struct regexlisttype {
/* The next regex. */
} 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 {
char *name;
/* 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;
/* The list of extensions that this syntax applies to. */
regexlisttype *headers;
diff --git a/src/proto.h b/src/proto.h
@@ -465,10 +465,12 @@ int do_yesno_prompt(bool all, const char *msg);
/* Most functions in rcfile.c. */
#ifdef ENABLE_NANORC
void display_rcfile_errors();
+bool parse_syntax_commands(char *keyword, char *ptr);
+void parse_one_include(char *file, syntaxtype *syntax);
#ifdef ENABLE_COLOR
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
#endif
-void parse_rcfile(FILE *rcstream, bool syntax_only);
+void parse_rcfile(FILE *rcstream, bool syntax_only, bool headers_only);
void do_rcfiles(void);
#endif /* ENABLE_NANORC */
diff --git a/src/rcfile.c b/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
* 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;
@@ -324,6 +324,8 @@ void parse_syntax(char *ptr)
/* Initialize a new syntax struct. */
live_syntax = (syntaxtype *)nmalloc(sizeof(syntaxtype));
live_syntax->name = mallocstrcpy(NULL, nameptr);
+ live_syntax->filename = (headers_only ? strdup(nanorc) : NULL);
+ live_syntax->extendsyntax = NULL;
live_syntax->extensions = NULL;
live_syntax->headers = NULL;
live_syntax->magics = NULL;
@@ -539,7 +541,7 @@ bool is_good_file(char *file)
#ifdef ENABLE_COLOR
/* Read and parse one included syntax file. */
-static void parse_one_include(char *file)
+void parse_one_include(char *file, syntaxtype *syntax)
{
FILE *rcstream;
@@ -560,7 +562,49 @@ static void parse_one_include(char *file)
nanorc = file;
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. */
@@ -585,7 +629,7 @@ void parse_includes(char *ptr)
* report an error if it's something other than zero matches. */
if (result == 0) {
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)
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,
* and close it afterwards. If syntax_only is TRUE, allow the file to
* 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;
ssize_t len;
@@ -981,6 +1046,26 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
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;
opensyntax = TRUE;
@@ -996,31 +1081,27 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
/* Try to parse the keyword. */
if (strcasecmp(keyword, "syntax") == 0) {
- if (opensyntax && lastcolor == NULL)
- rcfile_error(N_("Syntax \"%s\" has no color commands"),
- live_syntax->name);
- parse_syntax(ptr);
+ if (headers_only || !syntax_only) {
+ if (opensyntax && lastcolor == NULL && live_syntax->filename == NULL)
+ rcfile_error(N_("Syntax \"%s\" has no color commands"),
+ live_syntax->name);
+ parse_syntax(ptr, headers_only);
+ }
}
- else if (strcasecmp(keyword, "header") == 0)
- grab_and_store("header", ptr, &live_syntax->headers);
- else if (strcasecmp(keyword, "magic") == 0)
+ else if (strcasecmp(keyword, "header") == 0) {
+ if (headers_only || !syntax_only)
+ grab_and_store("header", ptr, &live_syntax->headers);
+ } else if (strcasecmp(keyword, "magic") == 0)
#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
;
#endif
- else if (strcasecmp(keyword, "comment") == 0)
-#ifdef ENABLE_COMMENT
- pick_up_name("comment", ptr, &live_syntax->comment);
-#else
+ else if (headers_only)
+ break;
+ else if (parse_syntax_commands(keyword, ptr))
;
-#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 ||
strcasecmp(keyword, "unset") == 0 ||
strcasecmp(keyword, "bind") == 0 ||
@@ -1046,7 +1127,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
#ifdef ENABLE_COLOR
/* 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;
#endif
@@ -1210,7 +1291,7 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
}
#ifdef ENABLE_COLOR
- if (opensyntax && lastcolor == NULL)
+ if (opensyntax && lastcolor == NULL && !headers_only)
rcfile_error(N_("Syntax \"%s\" has no color commands"),
live_syntax->name);
@@ -1238,7 +1319,7 @@ void parse_one_nanorc(void)
/* If opening the file succeeded, parse it. Otherwise, only
* complain if the file actually exists. */
if (rcstream != NULL)
- parse_rcfile(rcstream, FALSE);
+ parse_rcfile(rcstream, FALSE, FALSE);
else if (errno != ENOENT)
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
}