From 364763f4d1e466d0bc4ae8db8656f63f56588ac3 Mon Sep 17 00:00:00 2001
From: Chris Allegretta <chrisa@asty.org>
Date: Tue, 3 Feb 2009 05:05:58 +0000
Subject: [PATCH] 2009-02-02 Chris Allegretta <chrisa@asty.org>         * New
 color precalculation code for mult-line regexes.  New function
 precalc_multicolorinfo(),           new structure multidata for keeping track
 of where regexes start/stop.  More           performance improvements
 forthcoming.

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@4362 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
---
 src/color.c | 14 ++++----
 src/files.c |  2 +-
 src/nano.c  | 98 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/nano.h  | 16 ++++++++-
 src/winio.c | 35 ++++++++++++-------
 5 files changed, 137 insertions(+), 28 deletions(-)

diff --git a/src/color.c b/src/color.c
index 4babe482..deac8b4e 100644
--- a/src/color.c
+++ b/src/color.c
@@ -265,22 +265,22 @@ void reset_multis(filestruct *fileptr)
 
     for (i = 0; i < openfile->syntax->nmultis; i++) {
 	for (oof = fileptr->next; oof != NULL; oof = oof->next) {
-	    if (oof->multiswatching == NULL)
+	    if (oof->multidata == NULL)
 		continue;
-	    if (oof->multiswatching[i] == FALSE)
-		oof->multiswatching[i] = TRUE;
+	    if (oof->multidata[i] != 0)
+		oof->multidata[i] = -1;
 	    else
 		break;
 	}
 	for (oof = fileptr->prev; oof != NULL; oof = oof->prev) {
-	    if (oof->multiswatching == NULL)
+	    if (oof->multidata == NULL)
 		continue;
-	    if (oof->multiswatching[i] == FALSE)
-		oof->multiswatching[i] = TRUE;
+	    if (oof->multidata[i] == 0)
+		oof->multidata[i] = -1;
 	    else
 		break;
 	    }
-	fileptr->multiswatching[i] = TRUE;
+	fileptr->multidata[i] = -1;
     }
 }
 #endif /* ENABLE_COLOR */
diff --git a/src/files.c b/src/files.c
index 0f599c9c..2e95010b 100644
--- a/src/files.c
+++ b/src/files.c
@@ -312,7 +312,7 @@ filestruct *read_line(char *buf, filestruct *prevnode, bool
 #endif
 
 #ifdef ENABLE_COLOR
-	fileptr->multiswatching = NULL;
+	fileptr->multidata = NULL;
 #endif
 
     if (*first_line_ins) {
diff --git a/src/nano.c b/src/nano.c
index cdf302e9..72cd925e 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -68,7 +68,7 @@ filestruct *make_new_node(filestruct *prevnode)
     newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
 
 #ifdef ENABLE_COLOR
-    newnode->multiswatching = NULL;
+    newnode->multidata = NULL;
 #endif
 
     return newnode;
@@ -88,7 +88,7 @@ filestruct *copy_node(const filestruct *src)
     dst->prev = src->prev;
     dst->lineno = src->lineno;
 #ifdef ENABLE_COLOR
-    dst->multiswatching = NULL;
+    dst->multidata = NULL;
 #endif
 
     return dst;
@@ -127,8 +127,8 @@ void delete_node(filestruct *fileptr)
 	free(fileptr->data);
 
 #ifdef ENABLE_COLOR
-    if (fileptr->multiswatching)
-	free(fileptr->multiswatching);
+    if (fileptr->multidata)
+	free(fileptr->multidata);
 #endif
 
     free(fileptr);
@@ -369,7 +369,7 @@ void move_to_filestruct(filestruct **file_top, filestruct **file_bot,
     openfile->filebot = openfile->fileage;
 
 #ifdef ENABLE_COLOR
-    openfile->fileage->multiswatching = NULL;
+    openfile->fileage->multidata = NULL;
 #endif
 
     /* Restore the current line and cursor position.  If the mark begins
@@ -1596,7 +1596,7 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool
 				iso_me_harder_funcmap(s->scfunc);
 #ifdef ENABLE_COLOR
 				if (!f->viewok && openfile->syntax != NULL 
-					&& openfile->current->multiswatching && openfile->syntax->nmultis > 0) {
+					&& openfile->current->multidata && openfile->syntax->nmultis > 0) {
 				    reset_multis(openfile->current);
 				    edit_refresh();
 				}
@@ -1675,6 +1675,87 @@ int do_mouse(void)
 }
 #endif /* !DISABLE_MOUSE */
 
+#ifdef ENABLE_COLOR
+/* Precalculate the multi-line start and end regex info so we can speed up
+   rendering (with any hope at all...) */
+void precalc_multicolorinfo(void)
+{
+    if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) {
+	const colortype *tmpcolor = openfile->colorstrings;
+	regmatch_t startmatch, endmatch;
+	filestruct *fileptr, *endptr;
+	time_t last_check = time(NULL), cur_check = 0;
+
+	/* Let us get keypresses to see if the user is trying to
+	   start editing.  We may want to throw up a statusbar
+	   message before starting this later if it takes
+	   too long to do this routine.  For now silently
+	   abort if they hit a key */
+ 	nodelay(edit, FALSE);
+
+	for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
+
+	    /* If it's not a multi-line regex, amscray */
+	    if (tmpcolor->end == NULL)
+		continue;
+
+	    for (fileptr = openfile->fileage; fileptr != NULL; fileptr = fileptr->next) {
+		int startx = 0;
+
+		if (!fileptr->multidata)
+		    fileptr->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
+
+		if ((cur_check = time(NULL)) - last_check > 1) {
+		    last_check = cur_check;
+		    if (wgetch(edit) != ERR)
+	   		goto precalc_cleanup;
+		}
+
+		fileptr->multidata[tmpcolor->id] = CNONE;
+		while (regexec(tmpcolor->start, &fileptr->data[startx], 1, &startmatch, 0)  == 0) {
+		    /* Look for end and start marking how many lines are encompassed
+		       whcih should speed up rendering later */
+		     startx += startmatch.rm_eo;
+
+		    /* Look on this line first for end */
+		    if (regexec(tmpcolor->end, &fileptr->data[startx], 1, &endmatch, 0)  == 0) {
+			startx += endmatch.rm_eo;
+			fileptr->multidata[tmpcolor->id] |= CSTARTENDHERE;
+			continue;
+		    }
+
+		    /* Nice, we didn't find the end regex on this line.  Let's start looking for it */
+		    for (endptr = fileptr->next; endptr != NULL; endptr = endptr->next) {
+
+			/* Check for keyboard input  again */
+			if ((cur_check = time(NULL)) - last_check > 1) {
+			    last_check = cur_check;
+			    if (wgetch(edit) != ERR)
+		   		goto precalc_cleanup;
+			}
+			if (regexec(tmpcolor->end, &endptr->data[startx], 1, &endmatch, 0) == 0)
+			   break;
+		    }
+
+		    if (endptr == NULL)
+			break;
+
+		    /* We found it, we found it, la la la la la.  Mark all the
+			lines in between and the ends properly */
+		    fileptr->multidata[tmpcolor->id] |= CENDAFTER;
+		    for (fileptr = fileptr->next; fileptr != endptr; fileptr = fileptr->next) {
+			fileptr->multidata[tmpcolor->id] = CWHOLELINE;
+		    }
+		    endptr->multidata[tmpcolor->id] |= CBEGINBEFORE;
+		}
+	    }
+	}
+    }
+precalc_cleanup:
+    nodelay(edit, FALSE);
+}
+#endif /* ENABLE_COLOR */
+
 /* The user typed output_len multibyte characters.  Add them to the edit
  * buffer, filtering out all ASCII control characters if allow_cntrls is
  * TRUE. */
@@ -2373,6 +2454,11 @@ int main(int argc, char **argv)
     fprintf(stderr, "Main: top and bottom win\n");
 #endif
 
+#ifdef ENABLE_COLOR
+    if (openfile->syntax && openfile->syntax->nmultis > 0)
+	precalc_multicolorinfo();
+#endif
+
     if (startline > 1 || startcol > 1)
 	do_gotolinecolumn(startline, startcol, FALSE, FALSE, FALSE,
 		FALSE);
diff --git a/src/nano.h b/src/nano.h
index 5613db60..e4beb8dc 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -223,6 +223,20 @@ typedef struct syntaxtype {
     struct syntaxtype *next;
 	/* Next syntax. */
 } syntaxtype;
+
+#define CNONE 		(1<<0)
+	/* Yay, regex doesn't apply to this line at all! */
+#define CBEGINBEFORE 	(1<<1)
+	/* regex starts on an earlier line, ends on this one */
+#define CENDAFTER 	(1<<2)
+	/* regex sraers on this line and ends on a later one */
+#define CWHOLELINE 	(1<<3)
+	/* whole line engulfed by the regex  start < me, end > me */
+#define CSTARTENDHERE 	(1<<4)
+	/* regex starts and ends within this line */
+#define CWTF		(1<<5)
+	/* Something else */
+
 #endif /* ENABLE_COLOR */
 
 
@@ -237,7 +251,7 @@ typedef struct filestruct {
     struct filestruct *prev;
 	/* Previous node. */
 #ifdef ENABLE_COLOR
-    bool *multiswatching;		/* Array of which multi-line regexes apply to this line */
+    short *multidata;		/* Array of which multi-line regexes apply to this line */
 #endif
 } filestruct;
 
diff --git a/src/winio.c b/src/winio.c
index d0e67781..90f9e91f 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -2479,12 +2479,12 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 	const colortype *tmpcolor = openfile->colorstrings;
 
 	/* Set up multi-line color data for this line if it's not yet calculated  */
-        if (fileptr->multiswatching == NULL && openfile->syntax
+        if (fileptr->multidata == NULL && openfile->syntax
 		&& openfile->syntax->nmultis > 0) {
  	    int i;
-	    fileptr->multiswatching = nmalloc(openfile->syntax->nmultis * sizeof(bool));
-            for (i = 0; i < openfile->syntax->nmultis; i++) 
-		fileptr->multiswatching[i] = TRUE;	/* Assue this applies until we know otherwise */
+	    fileptr->multidata = nmalloc(openfile->syntax->nmultis * sizeof(short));
+            for (i = 0; i < openfile->syntax->nmultis; i++)
+		fileptr->multidata[i] = -1;	/* Assue this applies until we know otherwise */
 	}
 	for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
 	    int x_start;
@@ -2551,7 +2551,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 		    }
 		    k = startmatch.rm_eo;
 		}
-	    } else if (fileptr->multiswatching != NULL && fileptr->multiswatching[tmpcolor->id] == TRUE) {
+	    } else if (fileptr->multidata != NULL && fileptr->multidata[tmpcolor->id] != 0) {
 		/* This is a multi-line regex.  There are two steps.
 		 * First, we have to see if the beginning of the line is
 		 * colored by a start on an earlier line, and an end on
@@ -2568,8 +2568,16 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 		regoff_t start_col;
 		    /* Where it starts in that line. */
 		const filestruct *end_line;
-
-		fileptr->multiswatching[tmpcolor->id] = FALSE; /* until we find out otherwise */
+		short md = fileptr->multidata[tmpcolor->id];
+
+		if (md == -1)
+		    fileptr->multidata[tmpcolor->id] = 0; /* until we find out otherwise */
+		else if (md == CNONE)
+		    continue;
+		else if (md == CWHOLELINE) {
+		    mvwaddnstr(edit, line, 0, converted, -1);
+		    continue;
+		}
 
 		while (start_line != NULL && regexec(tmpcolor->start,
 			start_line->data, 1, &startmatch, 0) ==
@@ -2633,15 +2641,16 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 		     * expanded location of the end of the match minus
 		     * the expanded location of the beginning of the
 		     * page. */
-		    if (end_line != fileptr)
+		    if (end_line != fileptr) {
 			paintlen = -1;
-		    else
+			fileptr->multidata[tmpcolor->id] = CWHOLELINE;
+		    } else {
 			paintlen = actual_x(converted,
 				strnlenpt(fileptr->data,
 				endmatch.rm_eo) - start);
-
+			fileptr->multidata[tmpcolor->id] = CBEGINBEFORE;
+		    }
 		    mvwaddnstr(edit, line, 0, converted, paintlen);
-		    fileptr->multiswatching[tmpcolor->id] = TRUE;
   step_two:
 		    /* Second step, we look for starts on this line. */
 		    start_col = 0;
@@ -2687,7 +2696,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 				mvwaddnstr(edit, line, x_start,
 					converted + index, paintlen);
 				if (paintlen > 0)
-				    fileptr->multiswatching[tmpcolor->id] = TRUE;
+				    fileptr->multidata[tmpcolor->id] = CSTARTENDHERE;
 
 			    }
 			} else {
@@ -2709,7 +2718,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
 				/* We painted to the end of the line, so
 				 * don't bother checking any more
 				 * starts. */
-				fileptr->multiswatching[tmpcolor->id] = TRUE;
+				fileptr->multidata[tmpcolor->id] = CENDAFTER;
 				break;
 			    }
 			}
-- 
GitLab