diff --git a/ChangeLog b/ChangeLog
index 193dba82de12b8667e12da3085c96484639e90f6..aedb9a041732cf2bafd6bfcda91d6ca069413e11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,9 @@ CVS code -
 	  properly.  New function init_operating_dir() to handle
 	  setting it both on the command line and in the nanorc file.
 	  (David Benbennick)
+	- Major rewrite of color and screen update routines to fix
+	  minor bugs and increase efficiency.  New function
+	  set_colorpairs() for the former. (David Benbennick)
 - configure.ac:
 	- Added pt_BR to ALL_LINGUAS (Jordi).
 	- Changed --enable-color warning to be slightly less severe.
@@ -122,7 +125,9 @@ CVS code -
 	  format ({} instead of \{\}) (found by DLR).
 	- Add a better string matching sequence that includes escaped
 	  quotes (thanks to Carl E. Lindberg, who doesn't even know he
-	  helped ;-)
+	  helped ;-).  Some unneeded \'s in that sequence removed, and
+	  a new sequence to handle multi-line quotes added, by David
+	  Benbennick.
 - rcfile.c:
   parse_colors()
 	- Stop infinite loop when syntax doesn't begin with " char.
diff --git a/color.c b/color.c
index beae8890fdc7a2c5acf09b6c26ecf722dfe2a3f3..e26b5a5856c43a34f0aa42e18ac3f143ca99cfe8 100644
--- a/color.c
+++ b/color.c
@@ -40,72 +40,91 @@
 #define _(string) (string)
 #endif
 
-void do_colorinit(void)
+/* For each syntax list entry, we go through the list of colors and
+ * assign color pairs. */
+void set_colorpairs(void)
 {
-    int i;
-    colortype *tmpcolor = NULL, *beforenow = NULL;
-    int defok = 0;
+    const syntaxtype *this_syntax = syntaxes;
+
+    for(; this_syntax != NULL; this_syntax = this_syntax->next) {
+	colortype *this_color = this_syntax->color;
+	int color_pair = 1;
+
+	for(; this_color != NULL; this_color = this_color->next) {
+	    const colortype *beforenow = this_syntax->color;
+
+	    for(; beforenow != NULL && beforenow != this_color && 
+			(beforenow->fg != this_color->fg ||
+			 beforenow->bg != this_color->bg ||
+			 beforenow->bright != this_color->bright);
+		    beforenow = beforenow->next)
+		;
+
+	    if (beforenow != NULL && beforenow != this_color)
+		this_color->pairnum = beforenow->pairnum;
+	    else {
+		this_color->pairnum = color_pair;
+		color_pair++;
+	    }
+	}
+    }
+}
 
+void do_colorinit(void)
+{
     if (has_colors()) {
+	const colortype *tmpcolor = NULL;
+#ifdef HAVE_USE_DEFAULT_COLORS
+	int defok;
+#endif
+
 	start_color();
 	/* Add in colors, if available */
 
 #ifdef HAVE_USE_DEFAULT_COLORS
- 	if (use_default_colors() != ERR)
-	    defok = 1;
+	defok = use_default_colors() != ERR;
 #endif
 
-	i = 1;
 	for (tmpcolor = colorstrings; tmpcolor != NULL; 
 		tmpcolor = tmpcolor->next) {
+	    short background = tmpcolor->bg;
 
-	    for (beforenow = colorstrings; beforenow != NULL
-		 && beforenow != tmpcolor && 
-		 (beforenow->fg != tmpcolor->fg || beforenow->bg != tmpcolor->bg
-		 || beforenow->bright != tmpcolor->bright);
-		beforenow = beforenow->next)
-		;
+	    if (background == -1)
+#ifdef HAVE_USE_DEFAULT_COLORS
+		if (!defok)
+#endif
+		    background = COLOR_BLACK;
 
-	    if (beforenow != NULL && beforenow != tmpcolor) {
-		tmpcolor->pairnum = beforenow->pairnum;
-		continue;
-	    }
-	    
-	    if (defok && tmpcolor->bg == -1)
-		init_pair(i, tmpcolor->fg, -1);
-            else if (tmpcolor->bg == -1)
-		init_pair(i, tmpcolor->fg, COLOR_BLACK);
-	    else /* They picked a fg and bg color */
-		init_pair(i, tmpcolor->fg, tmpcolor->bg);
+	    init_pair(tmpcolor->pairnum, tmpcolor->fg, background);
 
 #ifdef DEBUG
 	    fprintf(stderr, _("Running init_pair with fg = %d and bg = %d\n"), tmpcolor->fg, tmpcolor->bg);
 #endif
-
-	    tmpcolor->pairnum = i;
-	    i++;
 	}
     }
-
-    return;
 }
 
 /* Update the color information based on the current filename */
 void update_color(void)
 {
-    syntaxtype *tmpsyntax;
+    const syntaxtype *tmpsyntax;
 
     colorstrings = NULL;
     for (tmpsyntax = syntaxes; tmpsyntax != NULL; tmpsyntax = tmpsyntax->next) {
-	exttype *e;
+	const exttype *e;
+
 	for (e = tmpsyntax->extensions; e != NULL; e = e->next) {
-	    regcomp(&syntaxfile_regexp, e->val, REG_EXTENDED);
+	    regex_t syntaxfile_regexp;
+
+	    regcomp(&syntaxfile_regexp, e->val, REG_EXTENDED | REG_NOSUB);
 
 	    /* Set colorstrings if we matched the extension regex */
-            if (!regexec(&syntaxfile_regexp, filename, 1, synfilematches, 0))
+            if (!regexec(&syntaxfile_regexp, filename, 0, NULL, 0))
 		colorstrings = tmpsyntax->color;
 
 	    regfree(&syntaxfile_regexp);
+	    if (colorstrings != NULL)
+		break;
 	}
     }
 
diff --git a/global.c b/global.c
index 74a171f7e354747aa2b2417cb82cff81de54b965..0e978606c13ccb201a080396bb965269aab22c1c 100644
--- a/global.c
+++ b/global.c
@@ -125,7 +125,7 @@ shortcut *browser_list = NULL;
 #endif
 
 #ifdef ENABLE_COLOR
-    colortype *colorstrings = NULL;
+    const colortype *colorstrings = NULL;
     syntaxtype *syntaxes = NULL;
     char *syntaxstr = NULL;
 #endif
@@ -145,13 +145,6 @@ regex_t search_regexp;		/* Global to store compiled search regexp */
 regmatch_t regmatches[10];	/* Match positions for parenthetical
 				   subexpressions, max of 10 */
 #endif
-#ifdef ENABLE_COLOR
-regex_t color_regexp;          /* Global to store compiled search regexp */
-regmatch_t colormatches[1];    /* Match positions for parenthetical */
-
-regex_t syntaxfile_regexp;     /* Global to store compiled search regexp */
-regmatch_t synfilematches[1];  /* Match positions for parenthetical */
-#endif /* ENABLE_COLOR */
 
 int length_of_list(const shortcut *s) 
 {
diff --git a/nanorc.sample b/nanorc.sample
index 15305bc748a3922eebd33579866108bff7b91b6f..908cd458d34416cba415bb30a9a4359072a1a079 100644
--- a/nanorc.sample
+++ b/nanorc.sample
@@ -102,7 +102,8 @@
 # because syntax highlighting rules will be applied in the order they are
 # read in
 
-# color brightyellow "<[^= ]*>" "\"(\\.|[^\\"])*\""
+# color brightyellow "<[^= ]*>" ""(\\.|[^\"])*""
+# color brightyellow start=""(\\.|[^\"])*\\( |	)*$" end="^(\\.|[^\"])*""
 # color brightblue "//.*"
 # color brightblue start="/\*" end="\*/"
 
diff --git a/proto.h b/proto.h
index 50fb55490e5ca6ccb0d379ff65e8700f050a5bba..0818fb35bdedb0af8274f9df857ec5d57b4962ff 100644
--- a/proto.h
+++ b/proto.h
@@ -71,11 +71,9 @@ extern openfilestruct *open_files;
 #endif
 
 #ifdef ENABLE_COLOR
-extern colortype *colorstrings;
+extern const colortype *colorstrings;
 extern syntaxtype *syntaxes;
 extern char *syntaxstr;
-extern regex_t color_regexp;
-extern regmatch_t colormatches[1];
 #endif
 
 extern shortcut *shortcut_list;
@@ -110,6 +108,7 @@ extern toggle *toggles;
 
 /* Public functions in color.c */
 #ifdef ENABLE_COLOR
+void set_colorpairs(void);
 void do_colorinit(void);
 void update_color(void);
 #endif /* ENABLE_COLOR */
@@ -401,15 +400,18 @@ void set_modified(void);
 void titlebar(const char *path);
 void bottombars(const shortcut *s);
 void onekey(const char *keystroke, const char *desc, int len);
-int get_page_start_virtual(int page);
-int get_page_from_virtual(int virtual);
-int get_page_end_virtual(int page);
+#ifndef NDEBUG
+int check_linenumbers(const filestruct *fileptr);
+#endif
 int get_page_start(int column);
 void reset_cursor(void);
 void add_marked_sameline(int begin, int end, filestruct *fileptr, int y,
 			 int virt_cur_x, int this_page);
-void edit_add(filestruct *fileptr, int yval, int start, int virt_cur_x,
-	      int virt_mark_beginx, int this_page);
+void edit_add(const filestruct *fileptr, int yval, int start
+#ifndef NANO_SMALL
+		, int virt_mark_beginx,	int virt_cur_x
+#endif
+		);
 void update_line(filestruct *fileptr, int index);
 void update_cursor(void);
 void center_cursor(void);
diff --git a/rcfile.c b/rcfile.c
index 32c06fb4836e2ba21aeef7b85820f391a83596ee..0f55f1167b981bc92efa8f6b228f66fced414b08 100644
--- a/rcfile.c
+++ b/rcfile.c
@@ -631,6 +631,9 @@ void do_rcfile(void)
     }
 
     free(nanorc);
+#ifdef ENABLE_COLOR
+    set_colorpairs();
+#endif
 }
 
 #endif /* ENABLE_NANORC */
diff --git a/winio.c b/winio.c
index e672ced1dc56151c041d93d99be6f404e2838f32..fb79153b615ceadaad9b191eebfd95ae9fe40f48 100644
--- a/winio.c
+++ b/winio.c
@@ -59,32 +59,6 @@ int do_last_line(void)
     return 1;
 }
 
-
-/* Like xplustabs, but for a specific index of a specific filestruct */
-int xpt(const filestruct *fileptr, int index)
-{
-    int i, tabs = 0;
-
-    if (fileptr == NULL || fileptr->data == NULL)
-	return 0;
-
-    for (i = 0; i < index && fileptr->data[i] != 0; i++) {
-	tabs++;
-
-	if (fileptr->data[i] == NANO_CONTROL_I) {
-	    if (tabs % tabsize == 0);
-	    else
-		tabs += tabsize - (tabs % tabsize);
-	} else if (is_cntrl_char((int)fileptr->data[i]))
-	    tabs++;
-	else if (fileptr->data[i] & 0x80)
-	    /* Make 8 bit chars only 1 column! */
-	    ;
-    }
-
-    return tabs;
-}
-
 /* Return the placewewant associated with current_x.  That is, xplustabs
  * is the zero-based column position of the cursor.  Value is no smaller
  * than current_x. */
@@ -575,41 +549,23 @@ void onekey(const char *keystroke, const char *desc, int len)
     }
 }
 
-/* And so start the display update routines.  Given a column, this
- * returns the "page" it is on.  "page", in the case of the display
- * columns, means which set of 80 characters is viewable (e.g. page 1
- * shows from 1 to COLS). */
-int get_page_from_virtual(int virtual)
-{
-    int page = 2;
-
-    if (virtual <= COLS - 2)
-	return 1;
-    virtual -= (COLS - 2);
-
-    while (virtual > COLS - 2 - 7) {
-	virtual -= (COLS - 2 - 7);
-	page++;
-    }
-
-    return page;
-}
+/* And so start the display update routines. */
 
-/* The inverse of the above function */
-int get_page_start_virtual(int page)
+#ifndef NDEBUG
+int check_linenumbers(const filestruct *fileptr)
 {
-    int virtual;
-    virtual = --page * (COLS - 7);
-    if (page)
-	virtual -= 2 * page - 1;
-    return virtual;
-}
+    int check_line = 0;
+    const filestruct *filetmp;
 
-int get_page_end_virtual(int page)
-{
-    return get_page_start_virtual(page) + COLS - 1;
+    for (filetmp = edittop; filetmp != fileptr; filetmp = filetmp->next)
+	check_line++;
+    return check_line;
 }
+#endif
 
+ /* nano scrolls horizontally within a line in chunks.  This function
+  * returns the column number of the first character displayed in the
+  * window when the cursor is at the given column. */
 int get_page_start(int column)
 {
     assert(COLS > 9);
@@ -639,474 +595,380 @@ void reset_cursor(void)
     wmove(edit, current_y, x - get_page_start(x));
 }
 
-#ifndef NANO_SMALL
-/* This takes care of the case where there is a mark that covers only
- * the current line.  It expects a line with no tab characters (i.e.
- * the type that edit_add() deals with. */
-void add_marked_sameline(int begin, int end, filestruct *fileptr, int y,
-			 int virt_cur_x, int this_page)
-{
-    /*
-     * The general idea is to break the line up into 3 sections: before
-     * the mark, the mark, and after the mark.  We then paint each in
-     * turn (for those that are currently visible, of course)
-     *
-     * 3 start points: 0 -> begin, begin->end, end->strlen(data)
-     *    in data    :    pre          sel           post        
-     */
-    int this_page_start = get_page_start_virtual(this_page),
-	this_page_end = get_page_end_virtual(this_page);
-
-    /* likewise, 3 data lengths */
-    int pre_data_len = begin, sel_data_len = end - begin, post_data_len = 0;	/* Determined from the other two */
-
-    /* now fix the start locations & lengths according to the cursor's 
-     * position (i.e.: our page) */
-    if (pre_data_len < this_page_start)
-	pre_data_len = 0;
-    else
-	pre_data_len -= this_page_start;
-
-    if (begin < this_page_start)
-	begin = this_page_start;
-
-    if (end < this_page_start)
-	end = this_page_start;
-
-    if (begin > this_page_end)
-	begin = this_page_end;
-
-    if (end > this_page_end)
-	end = this_page_end;
-
-    /* Now calculate the lengths */
-    sel_data_len = end - begin;
-    post_data_len = this_page_end - end;
-
-    wattron(edit, A_REVERSE);
-    mvwaddnstr(edit, y, begin - this_page_start,
-	       &fileptr->data[begin], sel_data_len);
-
-    wattroff(edit, A_REVERSE);
-
-}
-#endif
-
 /* edit_add() takes care of the job of actually painting a line into
  * the edit window.  Called only from update_line().  Expects a
  * converted-to-not-have-tabs line. */
-void edit_add(filestruct *fileptr, int yval, int start, int virt_cur_x,
-	      int virt_mark_beginx, int this_page)
+void edit_add(const filestruct *fileptr, int yval, int start
+#ifndef NANO_SMALL
+		, int virt_mark_beginx,	int virt_cur_x
+#endif
+		)
 {
-
-#ifdef ENABLE_COLOR
-    const colortype *tmpcolor = NULL;
-    int k, paintlen;
-    filestruct *e, *s;
-    regoff_t ematch, smatch;
+#ifdef DEBUG
+    fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno,
+		current->lineno);
 #endif
 
     /* Just paint the string in any case (we'll add color or reverse on
        just the text that needs it */
-    mvwaddnstr(edit, yval, 0, &fileptr->data[start],
-	       get_page_end_virtual(this_page) - start + 1);
+    mvwaddnstr(edit, yval, 0, &fileptr->data[start], COLS);
 
 #ifdef ENABLE_COLOR
-    if (colorstrings != NULL)
-	for (tmpcolor = colorstrings; tmpcolor != NULL;
-	     tmpcolor = tmpcolor->next) {
-
+    if (colorstrings != NULL) {
+	const colortype *tmpcolor = colorstrings;
+
+	for (; tmpcolor != NULL; tmpcolor = tmpcolor->next) {
+	    int x_start;
+		/* Starting column for mvwaddnstr.  Zero-based. */
+	    int paintlen;
+		/* number of chars to paint on this line.  There are COLS
+		 * characters on a whole line. */
+	    regex_t start_regexp;	/* Compiled search regexp */
+	    regmatch_t startmatch;	/* match position for start_regexp*/
+	    regmatch_t endmatch;	/* match position for end_regexp*/
+
+	    regcomp(&start_regexp, tmpcolor->start, REG_EXTENDED);
+
+	    if (tmpcolor->bright)
+		wattron(edit, A_BOLD);
+	    wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
+	    /* Two notes about regexec.  Return value 0 means there is a
+	     * match.  Also, rm_eo is the first non-matching character
+	     * after the match. */
+
+	    /* First case, tmpcolor is a single-line expression. */
 	    if (tmpcolor->end == NULL) {
-
-		/* First, highlight all single-line regexes */
-		k = start;
-		regcomp(&color_regexp, tmpcolor->start, REG_EXTENDED);
-		while (!regexec(&color_regexp, &fileptr->data[k], 1,
-				colormatches, 0)) {
-
-		    if (colormatches[0].rm_eo - colormatches[0].rm_so < 1) {
-			statusbar(_("Refusing 0 length regex match"));
+		size_t k = 0;
+
+		/* We increment k by rm_eo, to move past the end of the
+		   last match.  Even though two matches may overlap, we
+		   want to ignore them, so that we can highlight C-strings
+		   correctly. */
+		while (k < start + COLS) {
+		    /* Note the fifth parameter to regexec.  It says not to
+		     * match the beginning-of-line character unless
+		     * k == 0.  If regexec returns non-zero, there are
+		     * no more matches in the line. */
+		    if (regexec(&start_regexp, &fileptr->data[k], 1,
+				&startmatch, k == 0 ? 0 : REG_NOTBOL))
 			break;
-		    }
-#ifdef DEBUG
-		    fprintf(stderr, _("Match! (%d chars) \"%s\"\n"),
-			    colormatches[0].rm_eo - colormatches[0].rm_so,
-			    &fileptr->data[k + colormatches[0].rm_so]);
-#endif
-		    if (colormatches[0].rm_so < COLS - 1) {
-			if (tmpcolor->bright)
-			    wattron(edit, A_BOLD);
-			wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
-
-			if (colormatches[0].rm_eo + k <= COLS) {
-			    paintlen =
-				colormatches[0].rm_eo - colormatches[0].rm_so;
-#ifdef DEBUG
-			    fprintf(stderr, _("paintlen (%d) = eo (%d) - so (%d)\n"), 
-				paintlen, colormatches[0].rm_eo, colormatches[0].rm_so);
-#endif
-
-			}
-			else {
-			    paintlen = COLS - k - colormatches[0].rm_so - 1;
-#ifdef DEBUG
-			    fprintf(stderr, _("paintlen (%d) = COLS (%d) - k (%d), - rm.so (%d) - 1\n"), 
-					paintlen, COLS, k, colormatches[0].rm_so);
-#endif
-			}
-
-			mvwaddnstr(edit, yval, colormatches[0].rm_so + k,
-				   &fileptr->data[k + colormatches[0].rm_so],
-				   paintlen);
-
-		    }
-
-		    if (tmpcolor->bright)
-			wattroff(edit, A_BOLD);
-		    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
-
-		    k += colormatches[0].rm_eo;
-
+		    /* Translate the match to the beginning of the line. */
+		    startmatch.rm_so += k;
+		    startmatch.rm_eo += k;
+		    if (startmatch.rm_so == startmatch.rm_eo)
+			statusbar(_("Refusing 0 length regex match"));
+		    else if (startmatch.rm_so < start + COLS &&
+				startmatch.rm_eo > start) {
+			x_start = startmatch.rm_so - start;
+			if (x_start < 0)
+			    x_start = 0;
+			paintlen = startmatch.rm_eo - start - x_start;
+			if (paintlen > COLS - x_start)
+			    paintlen = COLS - x_start;
+
+			assert(0 <= x_start && 0 < paintlen &&
+				x_start + paintlen <= COLS);
+			mvwaddnstr(edit, yval, x_start,
+				fileptr->data + start + x_start, paintlen);
+ 		    }
+		    k = startmatch.rm_eo;
 		}
-		regfree(&color_regexp);
-
-	    }
-	    /* Now, if there's an 'end' somewhere below, and a 'start'
-	       somewhere above, things get really fun.  We have to look
-	       down for an end, make sure there's not a start before 
-	       the end after us, and then look up for a start, 
-	       and see if there's an end after the start, before us :) */
-	    else {
-
-		s = fileptr;
-		while (s != NULL) {
-		    regcomp(&color_regexp, tmpcolor->start, REG_EXTENDED);
-		    if (!regexec
-			(&color_regexp, s->data, 1, colormatches, 0)) {
-			regfree(&color_regexp);
+	    } else {
+		/* This is a multi-line regexp.  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
+		 * this line or later.
+		 *
+		 * We find the first line before fileptr matching the
+		 * start.  If every match on that line is followed by an
+		 * end, then go to step two.  Otherwise, find the next line
+		 * after start_line matching the end.  If that line is not
+		 * before fileptr, then paint the beginning of this line. */
+
+		regex_t end_regexp;	/* Compiled search regexp */
+		const filestruct *start_line = fileptr->prev;
+		    /* the first line before fileptr matching start*/
+		regoff_t start_col;
+		    /* where it starts in that line */
+		const filestruct *end_line;
+		int searched_later_lines = 0;
+		    /* Used in step 2.  Have we looked for an end on
+		     * lines after fileptr? */
+
+		regcomp(&end_regexp, tmpcolor->end, REG_EXTENDED);
+
+		while (start_line != NULL &&
+			regexec(&start_regexp, start_line->data, 1,
+				&startmatch, 0)) {
+		    /* If there is an end on this line, there is no need
+		     * to look for starts on earlier lines. */
+		    if (!regexec(&end_regexp, start_line->data, 1,
+				&endmatch, 0))
+			goto step_two;
+		    start_line = start_line->prev;
+		}
+		/* No start found, so skip to the next step. */
+		if (start_line == NULL)
+		    goto step_two;
+		/* Now start_line is the first line before fileptr
+		 * containing a start match.  Is there a start on this
+		 * line not followed by an end on this line? */
+
+		start_col = 0;
+		while (1) {
+		    start_col += startmatch.rm_so;
+		    startmatch.rm_eo -= startmatch.rm_so;
+		    if (regexec(&end_regexp,
+			    start_line->data + start_col + startmatch.rm_eo,
+			    1, &endmatch,
+			    start_col + startmatch.rm_eo == 0 ? 0 : REG_NOTBOL))
+			/* No end found after this start */
 			break;
-		    }
-		    s = s->prev;
-		    regfree(&color_regexp);
+		    start_col++;
+		    if (regexec(&start_regexp,
+			    start_line->data + start_col, 1, &startmatch,
+			    REG_NOTBOL))
+			/* No later start on this line. */
+			goto step_two;
 		}
-
-		if (s != NULL) {
-		    /* We found a start, mark it */
-		    smatch = colormatches[0].rm_so;
-
-		    e = s;
-		    while (e != NULL && e != fileptr) {
-			regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
-			if (!regexec
-			    (&color_regexp, e->data, 1, colormatches, 0)) {
-			    regfree(&color_regexp);
-			    break;
-			}
-			e = e->next;
-			regfree(&color_regexp);
+		/* Indeed, there is a start not followed on this line by an
+		 * end. */
+
+		/* We have already checked that there is no end before
+		 * fileptr and after the start.  Is there an end after
+		 * the start at all?  We don't paint unterminated starts. */
+		end_line = fileptr;
+		while (end_line != NULL &&
+			regexec(&end_regexp, end_line->data, 1,
+				&endmatch, 0))
+		    end_line = end_line->next;
+
+		/* No end found, or it is too early. */
+		if (end_line == NULL ||
+			end_line->lineno < fileptr->lineno ||
+			(end_line == fileptr && endmatch.rm_eo <= start))
+		    goto step_two;
+
+		/* Now paint the start of fileptr. */
+		paintlen = end_line != fileptr
+				? COLS : endmatch.rm_eo - start;
+		if (paintlen > COLS)
+		    paintlen = COLS;
+
+		assert(0 < paintlen && paintlen <= COLS);
+		mvwaddnstr(edit, yval, 0, fileptr->data + start, paintlen);
+
+		/* We have already painted the whole line. */
+		if (paintlen == COLS)
+		    goto skip_step_two;
+
+
+  step_two:	/* Second step, we look for starts on this line. */
+		start_col = 0;
+		while (start_col < start + COLS) {
+		    if (regexec(&start_regexp, fileptr->data + start_col, 1,
+				&startmatch, start_col == 0 ? 0 : REG_NOTBOL)
+			    || start_col + startmatch.rm_so >= start + COLS)
+			/* No more starts on this line. */
+			break;
+		    /* Translate the match to be relative to the
+		     * beginning of the line. */
+		    startmatch.rm_so += start_col;
+		    startmatch.rm_eo += start_col;
+
+		    x_start = startmatch.rm_so - start;
+		    if (x_start < 0) {
+			x_start = 0;
+			startmatch.rm_so = start;
 		    }
-
-		    if (e != fileptr)
-			continue;	/* There's an end before us */
-		    else {	/* Keep looking for an end */
-			while (e != NULL) {
-			    regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
-			    if (!regexec
-				(&color_regexp, e->data, 1, colormatches,
-				 0)) {
-				regfree(&color_regexp);
-				break;
-			    }
-			    e = e->next;
-			    regfree(&color_regexp);
+		    if (!regexec(&end_regexp, fileptr->data + startmatch.rm_eo,
+				1, &endmatch,
+				startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) {
+			/* Translate the end match to be relative to the
+			   beginning of the line. */
+			endmatch.rm_so += startmatch.rm_eo;
+			endmatch.rm_eo += startmatch.rm_eo;
+			/* There is an end on this line.  But does it
+			   appear on this page, and is the match more than
+			   zero characters long? */
+			if (endmatch.rm_eo > start &&
+				endmatch.rm_eo > startmatch.rm_so) {
+			    paintlen = endmatch.rm_eo - start - x_start;
+			    if (x_start + paintlen > COLS)
+				paintlen = COLS - x_start;
+
+			    assert(0 <= x_start && 0 < paintlen &&
+				    x_start + paintlen <= COLS);
+			    mvwaddnstr(edit, yval, x_start,
+				fileptr->data + start + x_start, paintlen);
 			}
-
-			if (e == NULL)
-			    continue;	/* There's no start before the end :) */
-			else {	/* Okay, we found an end, mark it! */
-			    ematch = colormatches[0].rm_eo;
-
-			    while (e != NULL) {
-				regcomp(&color_regexp, tmpcolor->end, REG_EXTENDED);
-				if (!regexec
-				    (&color_regexp, e->data, 1,
-				     colormatches, 0)) {
-				    regfree(&color_regexp);
-				    break;
-				} e = e->next;
-				regfree(&color_regexp);
-			    }
-
-			    if (e == NULL)
-				continue;	/* No end, oh well :) */
-
-			    /* Didn't find another end, we must be in the 
-			       middle of a highlighted bit */
-
-			    if (tmpcolor->bright)
-				wattron(edit, A_BOLD);
-
-			    wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
-
-			    if (s == fileptr && e == fileptr && ematch < COLS) {
-				mvwaddnstr(edit, yval, start + smatch, 
-					&fileptr->data[start + smatch],
-					ematch - smatch);
-#ifdef DEBUG
-			fprintf(stderr, _("start = %d, smatch = %d, ematch = %d\n"), start,
-				smatch, ematch);
-#endif
-
-		    	    } else if (s == fileptr)
-				mvwaddnstr(edit, yval, start + smatch, 
-					&fileptr->data[start + smatch],
-					COLS - smatch);
-			    else if (e == fileptr)
-				mvwaddnstr(edit, yval, start, 
-					&fileptr->data[start],
-					COLS - start);
-			    else
-				mvwaddnstr(edit, yval, start, 
-					&fileptr->data[start],
-					COLS);
-
-			    if (tmpcolor->bright)
-				wattroff(edit, A_BOLD);
-
-			    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
-
+		    } else if (!searched_later_lines) {
+			searched_later_lines = 1;
+			/* There is no end on this line.  But we haven't
+			 * yet looked for one on later lines. */
+			end_line = fileptr->next;
+			while (end_line != NULL &&
+				regexec(&end_regexp, end_line->data, 1,
+				&endmatch, 0))
+			    end_line = end_line->next;
+			if (end_line != NULL) {
+			    assert(0 <= x_start && x_start < COLS);
+			    mvwaddnstr(edit, yval, x_start,
+			    		fileptr->data + start + x_start,
+			    		COLS - x_start);
+			    /* We painted to the end of the line, so
+			     * don't bother checking any more starts. */
+			    break;
 			}
-
 		    }
+		    start_col = startmatch.rm_so + 1;
+		} /* while start_col < start + COLS */
 
-		    /* Else go to the next string, yahoo! =) */
-		}
-
-	    }
-
-	}
+  skip_step_two:
+		regfree(&end_regexp);
+	    } /* if (tmp_color->end != NULL) */
 
+	    regfree(&start_regexp);
+	    wattroff(edit, A_BOLD);
+	    wattroff(edit, COLOR_PAIR(tmpcolor->pairnum));
+	} /* for tmpcolor in colorstrings */
+    }
 #endif				/* ENABLE_COLOR */
-#ifndef NANO_SMALL
 
-    /* There are quite a few cases that could take place; we'll deal
-     * with them each in turn */
-    if (ISSET(MARK_ISSET) &&
-	!((fileptr->lineno > mark_beginbuf->lineno
-	   && fileptr->lineno > current->lineno)
-	  || (fileptr->lineno < mark_beginbuf->lineno
-	      && fileptr->lineno < current->lineno))) {
-	/* If we get here we are on a line that is at least
-	 * partially selected.  The lineno checks above determined
-	 * that */
-	if (fileptr != mark_beginbuf && fileptr != current) {
-	    /* We are on a completely marked line, paint it all
-	     * inverse */
+#ifndef NANO_SMALL
+    if (ISSET(MARK_ISSET)
+	    && (fileptr->lineno <= mark_beginbuf->lineno
+		|| fileptr->lineno <= current->lineno)
+	    && (fileptr->lineno >= mark_beginbuf->lineno
+		|| fileptr->lineno >= current->lineno)) {
+	/* fileptr is at least partially selected. */
+
+	int x_start;
+	    /* Starting column for mvwaddnstr.  Zero-based. */
+	int paintlen;
+	    /* number of chars to paint on this line.  There are COLS
+	     * characters on a whole line. */
+
+	if (mark_beginbuf == fileptr && current == fileptr) {
+	    x_start = virt_mark_beginx < virt_cur_x ? virt_mark_beginx
+	    					    : virt_cur_x;
+	    paintlen = abs(virt_mark_beginx - virt_cur_x);
+	} else {
+	    if (mark_beginbuf->lineno < fileptr->lineno ||
+		    current->lineno < fileptr->lineno)
+		x_start = 0;
+	    else
+		x_start = mark_beginbuf == fileptr ? virt_mark_beginx
+						   : virt_cur_x;
 
+	    if (mark_beginbuf->lineno > fileptr->lineno ||
+		    current->lineno > fileptr->lineno)
+		paintlen = start + COLS;
+	    else
+		paintlen = mark_beginbuf == fileptr ? virt_mark_beginx
+						    : virt_cur_x;
+	}
+	x_start -= start;
+	if (x_start < 0) {
+	    paintlen += x_start;
+	    x_start = 0;
+	}
+	if (x_start + paintlen > COLS)
+	    paintlen = COLS - x_start;
+	if (paintlen > 0) {
 	    wattron(edit, A_REVERSE);
-
-	    mvwaddnstr(edit, yval, 0, fileptr->data, COLS);
-
+	    assert(x_start >= 0 && paintlen > 0 && x_start + paintlen <= COLS);
+	    mvwaddnstr(edit, yval, x_start,
+			fileptr->data + start + x_start, paintlen);
 	    wattroff(edit, A_REVERSE);
-
-	} else if (fileptr == mark_beginbuf && fileptr == current) {
-	    /* Special case, we're still on the same line we started
-	     * marking -- so we call our helper function */
-	    if (virt_cur_x < virt_mark_beginx) {
-		/* To the right of us is marked */
-		add_marked_sameline(virt_cur_x, virt_mark_beginx,
-				    fileptr, yval, virt_cur_x, this_page);
-	    } else {
-		/* To the left of us is marked */
-		add_marked_sameline(virt_mark_beginx, virt_cur_x,
-				    fileptr, yval, virt_cur_x, this_page);
-	    }
-	} else if (fileptr == mark_beginbuf) {
-	    /*
-	     * We're updating the line that was first marked,
-	     * but we're not currently on it.  So we want to
-	     * figure out which half to invert based on our
-	     * relative line numbers.
-	     *
-	     * I.e. if we're above the "beginbuf" line, we want to
-	     * mark the left side.  Otherwise, we're below, so we
-	     * mark the right.
-	     */
-	    int target;
-
-	    if (mark_beginbuf->lineno > current->lineno) {
-
-		wattron(edit, A_REVERSE);
-
-		target =
-		    (virt_mark_beginx <
-		     COLS - 1) ? virt_mark_beginx : COLS - 1;
-
-		mvwaddnstr(edit, yval, 0, fileptr->data, target);
-
-		wattroff(edit, A_REVERSE);
-
-	    }
-
-	    if (mark_beginbuf->lineno < current->lineno) {
-
-		wattron(edit, A_REVERSE);
-		target = (COLS - 1) - virt_mark_beginx;
-
-		if (target < 0)
-		    target = 0;
-
-		mvwaddnstr(edit, yval, virt_mark_beginx,
-			   &fileptr->data[virt_mark_beginx], target);
-
-		wattroff(edit, A_REVERSE);
-	    }
-
-	} else if (fileptr == current) {
-	    /* We're on the cursor's line, but it's not the first
-	     * one we marked.  Similar to the previous logic. */
-	    int this_page_start = get_page_start_virtual(this_page),
-		this_page_end = get_page_end_virtual(this_page);
-
-	    if (mark_beginbuf->lineno < current->lineno) {
-
-		wattron(edit, A_REVERSE);
-
-		if (virt_cur_x > COLS - 2) {
-		    mvwaddnstr(edit, yval, 0,
-			       &fileptr->data[this_page_start],
-			       virt_cur_x - this_page_start);
-		} else
-		    mvwaddnstr(edit, yval, 0, fileptr->data, virt_cur_x);
-
-		wattroff(edit, A_REVERSE);
-
-	    }
-
-	    if (mark_beginbuf->lineno > current->lineno) {
-
-		wattron(edit, A_REVERSE);
-		if (virt_cur_x > COLS - 2)
-		    mvwaddnstr(edit, yval, virt_cur_x - this_page_start,
-			       &fileptr->data[virt_cur_x],
-			       this_page_end - virt_cur_x);
-		else
-		    mvwaddnstr(edit, yval, virt_cur_x,
-			       &fileptr->data[virt_cur_x],
-			       COLS - virt_cur_x);
-
-		wattroff(edit, A_REVERSE);
-
-	    }
 	}
     }
-#endif
-
+#endif /* !NANO_SMALL */
 }
 
-/*
- * Just update one line in the edit buffer.  Basically a wrapper for
- * edit_add().  index gives us a place in the string to update starting
- * from.  Likely args are current_x or 0.
- */
+/* Just update one line in the edit buffer.  Basically a wrapper for
+ * edit_add().  If fileptr != current, then index is considered 0.
+ * The line will be displayed starting with fileptr->data[index].
+ * Likely args are current_x or 0. */
 void update_line(filestruct *fileptr, int index)
 {
-    filestruct *filetmp;
-    int line = 0, col = 0;
-    int virt_cur_x = current_x, virt_mark_beginx = mark_beginx;
-    char *realdata, *tmp;
-    int i, pos, len, page;
+    int line;
+	/* line in the edit window for CURSES calls */
+#ifndef NANO_SMALL
+    int virt_cur_x;
+    int virt_mark_beginx;
+#endif
+    char *original;
+	/* The original string fileptr->data. */
+    char *converted;
+	/* fileptr->data converted to have tabs and control characters
+	 * expanded. */
+    size_t pos;
+    size_t page_start;
 
     if (!fileptr)
 	return;
 
-    /* First, blank out the line (at a minimum) */
-    for (filetmp = edittop; filetmp != fileptr && filetmp != editbot;
-	 filetmp = filetmp->next)
-	line++;
+    line = fileptr->lineno - edittop->lineno;
 
-    mvwaddstr(edit, line, 0, hblank);
+    /* We assume the line numbers are valid.  Is that really true? */
+    assert(line < 0 || line == check_linenumbers(fileptr));
+
+    if (line < 0 || line >= editwinrows)
+	return;
 
-    /* Next, convert all the tabs to spaces, so everything else is easy */
-    index = xpt(fileptr, index);
+    /* First, blank out the line (at a minimum) */
+    mvwaddstr(edit, line, 0, hblank);
 
-    realdata = fileptr->data;
-    len = strlen(realdata);
-    fileptr->data = charalloc(xpt(fileptr, len) + 1);
+    original = fileptr->data;
+    converted = charalloc(strlenpt(original) + 1);
+    
+    /* Next, convert all the tabs to spaces, so everything else is easy. 
+     * Note the internal speller sends us index == -1. */
+    index = fileptr == current && index > 0 ? strnlenpt(original, index) : 0;
+#ifndef NANO_SMALL
+    virt_cur_x = fileptr == current ? strnlenpt(original, current_x) : current_x;
+    virt_mark_beginx = fileptr == mark_beginbuf ? strnlenpt(original, mark_beginx) : mark_beginx;
+#endif
 
     pos = 0;
-    for (i = 0; i < len; i++) {
-	if (realdata[i] == '\t') {
+    for (; *original != '\0'; original++) {
+	if (*original == '\t')
 	    do {
-		fileptr->data[pos++] = ' ';
-		if (i < current_x)
-		    virt_cur_x++;
-		if (i < mark_beginx)
-		    virt_mark_beginx++;
+		converted[pos++] = ' ';
 	    } while (pos % tabsize);
-	    /* must decrement once to account for tab-is-one-character */
-	    if (i < current_x)
-		virt_cur_x--;
-	    if (i < mark_beginx)
-		virt_mark_beginx--;
-	} else if (realdata[i] == 127) {
-	    /* Treat delete characters (ASCII 127's) as ^?'s */
-	    fileptr->data[pos++] = '^';
-	    fileptr->data[pos++] = '?';
-	    if (i < current_x)
-		virt_cur_x++;
-	    if (i < mark_beginx)
-		virt_mark_beginx++;
-	} else if (realdata[i] == 10) {
-	    /* Treat newlines (ASCII 10's) embedded in a line as encoded
-	       nulls (ASCII 0's); the line in question should be run
-	       through unsunder() before reaching here */
-	    fileptr->data[pos++] = '^';
-	    fileptr->data[pos++] = '@';
-	    if (i < current_x)
-		virt_cur_x++;
-	    if (i < mark_beginx)
-		virt_mark_beginx++;
-	} else if (is_cntrl_char(realdata[i])) {
-	    /* Treat control characters as ^symbol's */
-	    fileptr->data[pos++] = '^';
-	    fileptr->data[pos++] = realdata[i] + 64;
-	    if (i < current_x)
-		virt_cur_x++;
-	    if (i < mark_beginx)
-		virt_mark_beginx++;
-	} else {
-	    fileptr->data[pos++] = realdata[i];
-	}
+	else if (is_cntrl_char(*original)) {
+	    converted[pos++] = '^';
+	    if (*original == 127)
+		converted[pos++] = '?';
+	    else if (*original == '\n')
+		/* Treat newlines (ASCII 10's) embedded in a line as encoded
+	   	 * nulls (ASCII 0's); the line in question should be run
+		 * through unsunder() before reaching here */
+		converted[pos++] = '@';
+	    else
+		converted[pos++] = *original + 64;
+	} else
+	    converted[pos++] = *original;
     }
-
-    fileptr->data[pos] = '\0';
+    converted[pos] = '\0';
 
     /* Now, paint the line */
-    if (current == fileptr && index > COLS - 2) {
-	/* This handles when the current line is beyond COLS */
-	/* It requires figuring out what page we're on      */
-	page = get_page_from_virtual(index);
-	col = get_page_start_virtual(page);
+    original = fileptr->data;
+    fileptr->data = converted;
+    page_start = get_page_start(index);
+    edit_add(fileptr, line, page_start
+#ifndef NANO_SMALL
+		, virt_mark_beginx, virt_cur_x
+#endif
+		);
+    free(converted);
+    fileptr->data = original;
 
-	edit_add(filetmp, line, col, virt_cur_x, virt_mark_beginx, page);
+    if (page_start > 0)
 	mvwaddch(edit, line, 0, '$');
-
-	if (strlenpt(fileptr->data) > get_page_end_virtual(page) + 1)
-	    mvwaddch(edit, line, COLS - 1, '$');
-    } else {
-	/* It's not the current line means that it's at x=0 and page=1 */
-	/* If it is the current line, then we're in the same boat      */
-	edit_add(filetmp, line, 0, virt_cur_x, virt_mark_beginx, 1);
-
-	if (strlenpt(&filetmp->data[col]) > COLS)
-	    mvwaddch(edit, line, COLS - 1, '$');
-    }
-
-    /* Clean up our mess */
-    tmp = fileptr->data;
-    fileptr->data = realdata;
-    free(tmp);
+    if (pos > page_start + COLS)
+	mvwaddch(edit, line, COLS - 1, '$');
 }
 
 /* This function updates current, based on where current_y is;
@@ -1151,7 +1013,7 @@ void edit_refresh(void)
     if (edittop == NULL)
 	edittop = current;
 
-    /* Don't make the cursor jump around the scrrn whilst updating */
+    /* Don't make the cursor jump around the screen whilst updating */
     leaveok(edit, TRUE);
 
     editbot = edittop;