]> git.wh0rd.org Git - nano.git/commitdiff
port over some of DB's refactored display code, most importantly the
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 16 Sep 2003 01:16:49 +0000 (01:16 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 16 Sep 2003 01:16:49 +0000 (01:16 +0000)
display_string() function, and convert some parts of nano to use it

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1552 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/move.c
src/nano.c
src/nano.h
src/proto.h
src/search.c
src/utils.c
src/winio.c

index 56ebe609cf4d799d0b0159ac28d1df6475e6af15..2b6ce6e361203206330e519ed47ae8f3ed5c326f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -38,6 +38,20 @@ CVS code -
          wrap_reset() calls with DISABLE_WRAPPING #ifdefs. (DLR)
        - Change enum "topmidbotnone" to "topmidnone", as there's no
          BOTTOM option anymore. (DLR)
+       - Split out the string-displaying routine from update_line()
+         into a separate function; convert the edit window, statusbar
+         display, and statusbar prompt to use it, so that they can all
+         properly display control characters and tabs; free and NULL
+         the backup search string in one place in the search code
+         instead of several; and do some other minor refactoring of
+         related display functions to simplify them.  New functions
+         mark_order() and display_string(); changes to actual_x(),
+         edit_add(), update_line(), statusbar(), and
+         do_replace_highlight(). (David Benbennick)  DLR: Add minor
+         cosmetic tweaks, add missing NANO_SMALL #ifdef around the text
+         for a backwards search in the refactored code, and enclose
+         dump_buffer() and dump_buffer_reverse() in one ENABLE_DEBUG
+         #ifdef instead of two.
 - files.c:
   do_browser()
        - Some of the Pico compatibility options in the file browser
index cf088b52162c97ae0635932d0e476b698b461a81..93472f4b96220313e64d2fecc1d79f2747ae5179 100644 (file)
@@ -81,7 +81,7 @@ int do_page_up(void)
 #endif
     }
     /* Get the equivalent x-coordinate of the new line. */
-    current_x = actual_x(current, placewewant);
+    current_x = actual_x(current->data, placewewant);
 
     edit_refresh();
 
@@ -125,7 +125,7 @@ int do_page_down(void)
 #endif
     }
     /* Get the equivalent x-coordinate of the new line. */
-    current_x = actual_x(current, placewewant);
+    current_x = actual_x(current->data, placewewant);
 
     edit_refresh();
 
@@ -145,7 +145,7 @@ int do_up(void)
 
     assert(current_y == current->lineno - edittop->lineno);
     current = current->prev;
-    current_x = actual_x(current, placewewant);
+    current_x = actual_x(current->data, placewewant);
     if (current_y > 0) {
        update_line(current->next, 0);
            /* It was necessary to change current first, so the mark
@@ -175,7 +175,7 @@ int do_down(void)
 
     assert(current_y == current->lineno - edittop->lineno);
     current = current->next;
-    current_x = actual_x(current, placewewant);
+    current_x = actual_x(current->data, placewewant);
 
     /* Note that current_y is zero-based.  This test checks for the
      * cursor's being not on the last row of the edit window. */
index f020735cfb7eeb7672bbbdf0e68791056aad5e02..67fc1595976932e86b703d65ab466e57aae45f86 100644 (file)
@@ -917,7 +917,7 @@ void do_mouse(void)
        for(; current_y > mevent.y && current->prev != NULL; current_y--)
            current = current->prev;
 
-       xcur = actual_x(current, get_page_start(xplustabs()) + mevent.x);
+       xcur = actual_x(current->data, get_page_start(xplustabs()) + mevent.x);
 
        /* Selecting where the cursor is toggles the mark.  As does
           selecting beyond the line length with the cursor at the end of
index 32e254ed308b6e4382241279eeb89a3bbeef32ef..03203c1234bce152c8d34a22e825fccab03d66b7 100644 (file)
@@ -35,6 +35,7 @@
 /* Define charalloc as a macro rather than duplicating code */
 #define charalloc(howmuch) (char *)nmalloc((howmuch) * sizeof(char))
 #define charealloc(ptr, howmuch) (char *)nrealloc(ptr, (howmuch) * sizeof(char))
+#define charmove(dest, src, n) memmove(dest, src, (n) * sizeof(char))
 #ifdef BROKEN_REGEXEC
 #define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags)
 #endif
index 62b3c46029115fa7d80fce214a3be806be6f17ec..138a4269f4f6b5b3daa984a26180a3e8e346504b 100644 (file)
@@ -426,6 +426,10 @@ void *nmalloc(size_t howmuch);
 void *nrealloc(void *ptr, size_t howmuch);
 char *mallocstrcpy(char *dest, const char *src);
 void new_magicline(void);
+#ifndef NANO_SMALL
+void mark_order(const filestruct **top, size_t *top_x,
+               const filestruct **bot, size_t *bot_x);
+#endif
 #ifndef DISABLE_TABCOMP
 int check_wildcard_match(const char *text, const char *pattern);
 #endif
@@ -443,7 +447,7 @@ int do_first_line(void);
 int do_last_line(void);
 int xpt(const filestruct *fileptr, int index);
 size_t xplustabs(void);
-size_t actual_x(const filestruct *fileptr, size_t xplus);
+size_t actual_x(const char *str, size_t xplus);
 size_t strnlenpt(const char *buf, size_t size);
 size_t strlenpt(const char *buf);
 void blank_bottombars(void);
@@ -452,7 +456,8 @@ void blank_edit(void);
 void blank_statusbar(void);
 void blank_statusbar_refresh(void);
 void check_statblank(void);
-void nanoget_repaint(const char *buf, const char *inputbuf, int x);
+char *display_string(const char *buf, size_t start_col, int len);
+void nanoget_repaint(const char *buf, const char *inputbuf, size_t x);
 int nanogetstr(int allowtabs, const char *buf, const char *def,
 #ifndef NANO_SMALL
                historyheadtype *history_list,
@@ -473,12 +478,9 @@ 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(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 edit_add(const filestruct *fileptr, const char *converted,
+               int yval, size_t start);
+void update_line(const filestruct *fileptr, size_t index);
 void update_cursor(void);
 void center_cursor(void);
 void edit_refresh(void);
index 43fbd65d5345f0834006beb53c4ca34128e47938..0d7dca9a2807be7479e3d86c24e6f941af1c3617 100644 (file)
@@ -107,18 +107,22 @@ int search_init(int replacing)
 
     search_init_globals();
 
+    /* If we don't already have a backupstring, set it. */
     if (backupstring == NULL)
-       backupstring = mallocstrcpy(backupstring, "");
+       backupstring = mallocstrcpy(NULL, "");
 
 #ifndef NANO_SMALL
     search_history.current = (historytype *)&search_history.next;
 #endif
 
     if (last_search[0] != '\0') {
+       char *disp = display_string(last_search, 0, COLS / 3);
+
        buf = charalloc(COLS / 3 + 7);
        /* We use COLS / 3 here because we need to see more on the line */
-       sprintf(buf, " [%.*s%s]", COLS / 3, last_search,
-               strlen(last_search) > COLS / 3 ? "..." : "");
+       sprintf(buf, " [%s%s]", disp,
+               strlenpt(last_search) > COLS / 3 ? "..." : "");
+       free(disp);
     } else {
        buf = charalloc(1);
        buf[0] = '\0';
@@ -132,17 +136,23 @@ int search_init(int replacing)
        "%s%s%s%s%s%s",
        _("Search"),
 
+#ifndef NANO_SMALL
        /* This string is just a modifier for the search prompt,
           no grammar is implied */
-       ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : "",
+       ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") :
+#endif
+               "",
 
        /* This string is just a modifier for the search prompt,
           no grammar is implied */
        ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
 
+#ifndef NANO_SMALL
        /* This string is just a modifier for the search prompt,
           no grammar is implied */
-       ISSET(REVERSE_SEARCH) ? _(" [Backwards]") : "",
+       ISSET(REVERSE_SEARCH) ? _(" [Backwards]") :
+#endif
+               "",
 
        replacing ? _(" (to replace)") : "",
        buf);
@@ -150,12 +160,13 @@ int search_init(int replacing)
     /* Release buf now that we don't need it anymore */
     free(buf);
 
+    free(backupstring);
+    backupstring = NULL;
+
     /* Cancel any search, or just return with no previous search */
     if (i == -1 || (i < 0 && last_search[0] == '\0')) {
        statusbar(_("Search Cancelled"));
        reset_cursor();
-       free(backupstring);
-       backupstring = NULL;
 #ifndef NANO_SMALL
        search_history.current = search_history.next;
 #endif
@@ -169,29 +180,23 @@ int search_init(int replacing)
                if (regexp_init(last_search) == 0) {
                    statusbar(regex_error, last_search);
                    reset_cursor();
-                   free(backupstring);
-                   backupstring = NULL;
                    return -3;
                }
 #endif
            break;
        case 0:         /* They entered something new */
+           last_replace[0] = '\0';
 #ifdef HAVE_REGEX_H
            if (ISSET(USE_REGEXP))
                if (regexp_init(answer) == 0) {
                    statusbar(regex_error, answer);
                    reset_cursor();
-                   free(backupstring);
-                   backupstring = NULL;
 #ifndef NANO_SMALL
                    search_history.current = search_history.next;
 #endif
                    return -3;
                }
 #endif
-           free(backupstring);
-           backupstring = NULL;
-           last_replace[0] = '\0';
            break;
 #ifndef NANO_SMALL
        case TOGGLE_CASE_KEY:
@@ -213,8 +218,6 @@ int search_init(int replacing)
            backupstring = mallocstrcpy(backupstring, answer);
            return -2;          /* Call the opposite search function */
        case NANO_FROMSEARCHTOGOTO_KEY:
-           free(backupstring);
-           backupstring = NULL;
 #ifndef NANO_SMALL
            search_history.current = search_history.next;
 #endif
@@ -226,8 +229,6 @@ int search_init(int replacing)
            return -3;
        default:
            do_early_abort();
-           free(backupstring);
-           backupstring = NULL;
            return -3;
        }
     }
@@ -631,6 +632,8 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
 
     last_replace = mallocstrcpy(last_replace, answer);
     while (1) {
+       size_t match_len;
+
        /* Sweet optimization by Rocco here */
        fileptr = findnextstr(fileptr || replaceall || search_last_line,
                                FALSE, begin, *beginx, prevanswer);
@@ -651,13 +654,27 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
        if (numreplaced == -1)
            numreplaced = 0;
 
+#ifdef HAVE_REGEX_H
+       if (ISSET(USE_REGEXP))
+           match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
+       else
+#endif
+           match_len = strlen(prevanswer);
+
        if (!replaceall) {
+           char *exp_word;
+           size_t xpt = xplustabs();
+
+           exp_word = display_string(current->data, xpt,
+               strnlenpt(current->data, match_len + current_x) - xpt);
+
            curs_set(0);
-           do_replace_highlight(TRUE, prevanswer);
+           do_replace_highlight(TRUE, exp_word);
 
            *i = do_yesno(1, 1, _("Replace this instance?"));
 
-           do_replace_highlight(FALSE, prevanswer);
+           do_replace_highlight(FALSE, exp_word);
+           free(exp_word);
            curs_set(1);
        }
 
index f18f86a3cf4015c25e2990563236050d34a2ae42..1628418d8667876f4c3fbe301d0d1b54a94ded4e 100644 (file)
@@ -302,6 +302,28 @@ void new_magicline(void)
     totsize++;
 }
 
+#ifndef NANO_SMALL
+/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
+ * respectively, based on the locations of top and bot. */
+void mark_order(const filestruct **top, size_t *top_x,
+               const filestruct **bot, size_t *bot_x)
+{
+    assert(top != NULL && top_x != NULL && bot != NULL && bot_x != NULL);
+    if ((current->lineno == mark_beginbuf->lineno && current_x > mark_beginx)
+       || current->lineno > mark_beginbuf->lineno) {
+       *top = mark_beginbuf;
+       *top_x = mark_beginx;
+       *bot = current;
+       *bot_x = current_x;
+    } else {
+       *bot = mark_beginbuf;
+       *bot_x = mark_beginx;
+       *top = current;
+       *top_x = current_x;
+    }
+}
+#endif
+
 #ifndef DISABLE_TABCOMP
 /*
  * Routine to see if a text string is matched by a wildcard pattern.
index 7b5f8de966794dfe2eb1c3c1b2b17525d17930b8..74f368ba86bcefc1b303c42c26f5bbf195f7bb09 100644 (file)
@@ -343,36 +343,32 @@ size_t xplustabs(void)
     return strnlenpt(current->data, current_x);
 }
 
-/* Return what current_x should be, given xplustabs() for the line. */
-size_t actual_x(const filestruct *fileptr, size_t xplus)
+/* actual_x() gives the index in str of the character displayed at
+ * column xplus.  That is, actual_x() is the largest value such that
+ * strnlenpt(str, actual_x(str, xplus)) <= xplus. */
+size_t actual_x(const char *str, size_t xplus)
 {
     size_t i = 0;
-       /* the position in fileptr->data, returned */
+       /* the position in str, returned */
     size_t length = 0;
-       /* the screen display width to data[i] */
-    char *c;
-       /* fileptr->data + i */
+       /* the screen display width to str[i] */
 
-    assert(fileptr != NULL && fileptr->data != NULL);
+    assert(str != NULL);
 
-    for (c = fileptr->data; length < xplus && *c != '\0'; i++, c++) {
-       if (*c == '\t')
+    for (; length < xplus && *str != '\0'; i++, str++) {
+       if (*str == '\t')
            length += tabsize - length % tabsize;
-       else if (is_cntrl_char((int)*c))
+       else if (is_cntrl_char((int)*str))
            length += 2;
        else
            length++;
     }
-    assert(length == strnlenpt(fileptr->data, i));
-    assert(i <= strlen(fileptr->data));
+    assert(length == strnlenpt(str - i, i));
+    assert(i <= strlen(str - i));
 
     if (length > xplus)
        i--;
 
-#ifdef DEBUG
-    fprintf(stderr, "actual_x for xplus=%d returns %d\n", xplus, i);
-#endif
-
     return i;
 }
 
@@ -444,26 +440,97 @@ void check_statblank(void)
     }
 }
 
+/* Convert buf into a string that can be displayed on screen.  The
+ * caller wants to display buf starting with column start_col, and
+ * extending for at most len columns.  start_col is zero-based.  len is
+ * one-based, so len == 0 means you get "" returned.  The returned
+ * string is dynamically allocated, and should be freed. */
+char *display_string(const char *buf, size_t start_col, int len)
+{
+    size_t start_index;
+       /* Index in buf of first character shown in return value. */
+    size_t column;
+       /* Screen column start_index corresponds to. */
+    size_t end_index;
+       /* Index in buf of last character shown in return value. */
+    size_t alloc_len;
+       /* The length of memory allocated for converted. */
+    char *converted;
+       /* The string we return. */
+    size_t index;
+       /* Current position in converted. */
+
+    if (len == 0)
+       return mallocstrcpy(NULL, "");
+
+    start_index = actual_x(buf, start_col);
+    column = strnlenpt(buf, start_index);
+    assert(column <= start_col);
+    end_index = actual_x(buf, start_col + len - 1);
+    alloc_len = strnlenpt(buf, end_index + 1) - column;
+    if (len > alloc_len + column - start_col)
+       len = alloc_len + column - start_col;
+    converted = charalloc(alloc_len + 1);
+    buf += start_index;
+    index = 0;
+
+    for (; index < alloc_len; buf++) {
+       if (*buf == '\t')
+           do {
+               converted[index++] = ' ';
+           } while ((column + index) % tabsize);
+       else if (is_cntrl_char(*buf)) {
+           converted[index++] = '^';
+           if (*buf == '\n')
+               /* Treat newlines embedded in a line as encoded nulls;
+                * the line in question should be run through unsunder()
+                * before reaching here. */
+               converted[index++] = '@';
+           else if (*buf == NANO_CONTROL_8)
+               converted[index++] = '?';
+           else
+               converted[index++] = *buf + 64;
+       } else
+           converted[index++] = *buf;
+    }
+    assert(len <= alloc_len + column - start_col);
+    charmove(converted, converted + start_col - column, len);
+    null_at(&converted, len);
+
+    return charealloc(converted, len + 1);
+}
+
 /* Repaint the statusbar when getting a character in nanogetstr().  buf
- * should be no longer than COLS - 4.
+ * should be no longer than max(0, COLS - 4).
  *
  * Note that we must turn on A_REVERSE here, since do_help() turns it
  * off! */
-void nanoget_repaint(const char *buf, const char *inputbuf, int x)
+void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
 {
-    int len = strlen(buf) + 2;
-    int wid = COLS - len;
+    size_t x_real = strnlenpt(inputbuf, x);
+    int wid = COLS - strlen(buf) - 2;
 
-    assert(wid >= 2);
     assert(0 <= x && x <= strlen(inputbuf));
 
     wattron(bottomwin, A_REVERSE);
     blank_statusbar();
+
     mvwaddstr(bottomwin, 0, 0, buf);
     waddch(bottomwin, ':');
-    waddch(bottomwin, x < wid ? ' ' : '$');
-    waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid);
-    wmove(bottomwin, 0, (x % wid) + len);
+
+    if (COLS > 1)
+       waddch(bottomwin, x_real < wid ? ' ' : '$');
+    if (COLS > 2) {
+       size_t page_start = x_real - x_real % wid;
+       char *expanded = display_string(inputbuf, page_start, wid);
+
+       assert(wid > 0);
+       assert(strlen(expanded) <= wid);
+       waddstr(bottomwin, expanded);
+       free(expanded);
+       wmove(bottomwin, 0, COLS - wid + x_real - page_start);
+    } else
+       wmove(bottomwin, 0, COLS - 1);
     wattroff(bottomwin, A_REVERSE);
 }
 
@@ -933,23 +1000,34 @@ void reset_cursor(void)
     wmove(edit, current_y, x - get_page_start(x));
 }
 
-/* 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(const filestruct *fileptr, int yval, int start
-#ifndef NANO_SMALL
-               , int virt_mark_beginx, int virt_cur_x
-#endif
-               )
+/* edit_add() takes care of the job of actually painting a line into the
+ * edit window.  fileptr is the line to be painted, at row yval of the
+ * window.  converted is the actual string to be written to the window,
+ * with tabs and control characters replaced by strings of regular
+ * characters.  start is the column number of the first character
+ * of this page.  That is, the first character of converted corresponds to
+ * character number actual_x(fileptr->data, start) of the line. */
+void edit_add(const filestruct *fileptr, const char *converted,
+               int yval, size_t start)
 {
-#ifdef DEBUG
-    fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno,
-               current->lineno);
+#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
+    size_t startpos = actual_x(fileptr->data, start);
+       /* The position in fileptr->data of the leftmost character
+        * that displays at least partially on the window. */
+    size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
+       /* The position in fileptr->data of the first character that is
+        * completely off the window to the right.
+        *
+        * Note that endpos might be beyond the null terminator of the
+        * string. */
 #endif
 
+    assert(fileptr != NULL && converted != NULL);
+    assert(strlen(converted) <= COLS);
+
     /* 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], COLS);
+     * just the text that needs it). */
+    mvwaddstr(edit, yval, 0, converted);
 
 #ifdef ENABLE_COLOR
     if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
@@ -959,16 +1037,16 @@ void edit_add(const filestruct *fileptr, int yval, int start
            int x_start;
                /* Starting column for mvwaddnstr.  Zero-based. */
            int paintlen;
-               /* number of chars to paint on this line.  There are COLS
+               /* Number of chars to paint on this line.  There are COLS
                 * characters on a whole line. */
-           regmatch_t startmatch;      /* match position for start_regexp*/
-           regmatch_t endmatch;        /* match position for end_regexp*/
+           regmatch_t startmatch;      /* match position for start_regexp */
+           regmatch_t endmatch;        /* match position for end_regexp */
 
            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
+           /* Two notes about regexec().  Return value 0 means there is
+            * match.  Also, rm_eo is the first non-matching character
             * after the match. */
 
            /* First case, tmpcolor is a single-line expression. */
@@ -976,16 +1054,16 @@ void edit_add(const filestruct *fileptr, int yval, int start
                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 nonzero, there are no
-                    * more matches in the line. */
+                * last match.  Even though two matches may overlap, we
+                * want to ignore them, so that we can highlight
+                * C-strings correctly. */
+               while (k < endpos) {
+                   /* Note the fifth parameter to regexec().  It says
+                    * not to match the beginning-of-line character
+                    * unless k is 0.  If regexec() returns REG_NOMATCH,
+                    * there are no more matches in the line. */
                    if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
-                               &startmatch, k == 0 ? 0 : REG_NOTBOL))
+                       &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
                        break;
                    /* Translate the match to the beginning of the line. */
                    startmatch.rm_so += k;
@@ -993,20 +1071,23 @@ void edit_add(const filestruct *fileptr, int yval, int start
                    if (startmatch.rm_so == startmatch.rm_eo) {
                        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)
+                   } else if (startmatch.rm_so < endpos &&
+                               startmatch.rm_eo > startpos) {
+                       if (startmatch.rm_so <= startpos)
                            x_start = 0;
-                       paintlen = startmatch.rm_eo - start - x_start;
+                       else
+                           x_start = strnlenpt(fileptr->data, startmatch.rm_so)
+                               - start;
+                       paintlen = strnlenpt(fileptr->data, 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);
-                   }
+                               converted + x_start, paintlen);
+                   }
                    k = startmatch.rm_eo;
                }
            } else {
@@ -1022,7 +1103,7 @@ void edit_add(const filestruct *fileptr, int yval, int start
                 * before fileptr, then paint the beginning of this line. */
 
                const filestruct *start_line = fileptr->prev;
-                   /* the first line before fileptr matching start*/
+                   /* the first line before fileptr matching start */
                regoff_t start_col;
                    /* where it starts in that line */
                const filestruct *end_line;
@@ -1032,11 +1113,11 @@ void edit_add(const filestruct *fileptr, int yval, int start
 
                while (start_line != NULL &&
                        regexec(&tmpcolor->start, start_line->data, 1,
-                               &startmatch, 0)) {
+                       &startmatch, 0) == REG_NOMATCH) {
                    /* If there is an end on this line, there is no need
                     * to look for starts on earlier lines. */
-                   if (!regexec(tmpcolor->end, start_line->data, 1,
-                               &endmatch, 0))
+                   if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
+                       == 0)
                        goto step_two;
                    start_line = start_line->prev;
                }
@@ -1051,43 +1132,44 @@ void edit_add(const filestruct *fileptr, int yval, int start
                while (1) {
                    start_col += startmatch.rm_so;
                    startmatch.rm_eo -= startmatch.rm_so;
-                   if (regexec(tmpcolor->end,
-                           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 */
+                   if (regexec(tmpcolor->end,
+                       start_line->data + start_col + startmatch.rm_eo,
+                       0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
+                       REG_NOTBOL) == REG_NOMATCH)
+                       /* No end found after this start. */
                        break;
                    start_col++;
                    if (regexec(&tmpcolor->start,
                            start_line->data + start_col, 1, &startmatch,
-                           REG_NOTBOL))
+                           REG_NOTBOL) == REG_NOMATCH)
                        /* No later start on this line. */
                        goto step_two;
                }
-               /* Indeed, there is a start not followed on this line by an
-                * end. */
+               /* 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. */
+                * the start at all?  We don't paint unterminated
+                * starts. */
                end_line = fileptr;
                while (end_line != NULL &&
                        regexec(tmpcolor->end, 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))
+               if (end_line == NULL ||
+                       (end_line == fileptr && endmatch.rm_eo <= startpos))
                    goto step_two;
 
                /* Now paint the start of fileptr. */
-               paintlen = end_line != fileptr
-                               ? COLS : endmatch.rm_eo - start;
+               paintlen = end_line != fileptr ? COLS :
+                       strnlenpt(fileptr->data, endmatch.rm_eo) - start;
                if (paintlen > COLS)
                    paintlen = COLS;
 
                assert(0 < paintlen && paintlen <= COLS);
-               mvwaddnstr(edit, yval, 0, fileptr->data + start, paintlen);
+               mvwaddnstr(edit, yval, 0, converted, paintlen);
 
                /* We have already painted the whole line. */
                if (paintlen == COLS)
@@ -1095,10 +1177,11 @@ void edit_add(const filestruct *fileptr, int yval, int start
 
   step_two:    /* Second step, we look for starts on this line. */
                start_col = 0;
-               while (start_col < start + COLS) {
+               while (start_col < endpos) {
                    if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
-                               &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
-                           || start_col + startmatch.rm_so >= start + COLS)
+                       &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
+                       == REG_NOMATCH || start_col + startmatch.rm_so >=
+                       endpos)
                        /* No more starts on this line. */
                        break;
                    /* Translate the match to be relative to the
@@ -1106,52 +1189,54 @@ void edit_add(const filestruct *fileptr, int yval, int start
                    startmatch.rm_so += start_col;
                    startmatch.rm_eo += start_col;
 
-                   x_start = startmatch.rm_so - start;
-                   if (x_start < 0) {
+                   if (startmatch.rm_so <= startpos)
                        x_start = 0;
-                       startmatch.rm_so = start;
-                   }
-                   if (!regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
-                               1, &endmatch,
-                               startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) {
+                   else
+                       x_start = strnlenpt(fileptr->data, startmatch.rm_so)
+                                       - start;
+                   if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
+                       1, &endmatch, startmatch.rm_eo == 0 ? 0 :
+                       REG_NOTBOL) == 0) {
                        /* Translate the end match to be relative to the
-                          beginning of the line. */
+                        * 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 &&
+                        * appear on this page, and is the match more than
+                        * zero characters long? */
+                       if (endmatch.rm_eo > startpos &&
                                endmatch.rm_eo > startmatch.rm_so) {
-                           paintlen = endmatch.rm_eo - start - x_start;
+                           paintlen = strnlenpt(fileptr->data, 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);
+                               converted + x_start, paintlen);
                        }
                    } 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(tmpcolor->end,
-                               end_line->data, 1, &endmatch, 0))
+                       while (end_line != NULL &&
+                               regexec(tmpcolor->end, end_line->data, 0,
+                               NULL, 0) == REG_NOMATCH)
                            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);
+                                       converted + 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 */
+               } /* while start_col < endpos */
            } /* if (tmp_color->end != NULL) */
 
   skip_step_two:
@@ -1169,43 +1254,39 @@ void edit_add(const filestruct *fileptr, int yval, int start
                || fileptr->lineno >= current->lineno)) {
        /* fileptr is at least partially selected. */
 
+       const filestruct *top;
+           /* Either current or mark_beginbuf, whichever is first. */
+       size_t top_x;
+           /* current_x or mark_beginx, corresponding to top. */
+       const filestruct *bot;
+       size_t bot_x;
        int x_start;
            /* Starting column for mvwaddnstr.  Zero-based. */
        int paintlen;
-           /* number of chars to paint on this line.  There are COLS
+           /* 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;
+       mark_order(&top, &top_x, &bot, &bot_x);
+
+       if (top->lineno < fileptr->lineno || top_x < startpos)
+           top_x = startpos;
+       if (bot->lineno > fileptr->lineno || bot_x > endpos)
+           bot_x = endpos;
 
-           if (mark_beginbuf->lineno > fileptr->lineno ||
-                   current->lineno > fileptr->lineno)
-               paintlen = start + COLS;
+       /* the selected bit of fileptr is on this page */
+       if (top_x < endpos && bot_x > startpos) {
+           assert(startpos <= top_x);
+           x_start = strnlenpt(fileptr->data + startpos, top_x - startpos);
+
+           if (bot_x >= endpos)
+               paintlen = -1;  /* Paint everything. */
            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) {
+               paintlen = strnlenpt(fileptr->data + top_x, bot_x - top_x);
+
+           assert(x_start >= 0 && x_start <= strlen(converted));
+
            wattron(edit, A_REVERSE);
-           assert(x_start >= 0 && paintlen > 0 && x_start + paintlen <= COLS);
-           mvwaddnstr(edit, yval, x_start,
-                       fileptr->data + start + x_start, paintlen);
+           mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
            wattroff(edit, A_REVERSE);
        }
     }
@@ -1213,27 +1294,21 @@ void edit_add(const filestruct *fileptr, int yval, int start
 }
 
 /* Just update one line in the edit buffer.  Basically a wrapper for
- * edit_add().  If fileptr != current, then index is considered 0.
+ * 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)
+void update_line(const filestruct *fileptr, size_t index)
 {
     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 == NULL)
-       return;
+    assert(fileptr != NULL);
 
     line = fileptr->lineno - edittop->lineno;
 
@@ -1246,54 +1321,22 @@ void update_line(filestruct *fileptr, int index)
     /* First, blank out the line (at a minimum) */
     mvwaddstr(edit, line, 0, hblank);
 
-    original = fileptr->data;
-    converted = charalloc(strlenpt(original) + 1);
+    /* Next, convert variables that index the line to their equivalent
+     * positions in the expanded line. */
+    index = fileptr == current ? strnlenpt(fileptr->data, index) : 0;
+    page_start = get_page_start(index);
 
-    /* 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 (; *original != '\0'; original++) {
-       if (*original == '\t')
-           do {
-               converted[pos++] = ' ';
-           } while (pos % tabsize);
-       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;
-    }
-    converted[pos] = '\0';
+    /* Expand the line, replacing Tab by spaces, and control characters
+     * by their display form. */
+    converted = display_string(fileptr->data, page_start, COLS);
 
     /* Now, paint the line */
-    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
-               );
+    edit_add(fileptr, converted, line, page_start);
     free(converted);
-    fileptr->data = original;
 
     if (page_start > 0)
        mvwaddch(edit, line, 0, '$');
-    if (pos > page_start + COLS)
+    if (strlenpt(fileptr->data) > page_start + COLS)
        mvwaddch(edit, line, COLS - 1, '$');
 }
 
@@ -1328,8 +1371,8 @@ void center_cursor(void)
 /* Refresh the screen without changing the position of lines. */
 void edit_refresh(void)
 {
-    /* Neither of these conditions should occur, but they do.  edittop is
-     * NULL when you open an existing file on the command line, and
+    /* Neither of these conditions should occur, but they do.  edittop
+     * is NULL when you open an existing file on the command line, and
      * ENABLE_COLOR is defined.  Yuck. */
     if (current == NULL)
        return;
@@ -1346,7 +1389,8 @@ void edit_refresh(void)
     else {
        int nlines = 0;
 
-       /* Don't make the cursor jump around the screen whilst updating */
+       /* Don't make the cursor jump around the screen whilst
+        * updating. */
        leaveok(edit, TRUE);
 
        editbot = edittop;
@@ -1362,7 +1406,7 @@ void edit_refresh(void)
            nlines++;
        }
        /* What the hell are we expecting to update the screen if this
-          isn't here?  Luck? */
+        * isn't here?  Luck? */
        wrefresh(edit);
        leaveok(edit, FALSE);
     }
@@ -1377,10 +1421,8 @@ void edit_refresh_clearok(void)
     clearok(edit, FALSE);
 }
 
-/*
- * Nice generic routine to update the edit buffer, given a pointer to the
- * file struct =) 
- */
+/* Nice generic routine to update the edit buffer, given a pointer to the
+ * file struct =) */
 void edit_update(filestruct *fileptr, topmidnone location)
 {
     if (fileptr == NULL)
@@ -1396,14 +1438,12 @@ void edit_update(filestruct *fileptr, topmidnone location)
     edit_refresh();
 }
 
-/*
- * Ask a question on the statusbar.  Answer will be stored in answer
+/* Ask a question on the statusbar.  Answer will be stored in answer
  * global.  Returns -1 on aborted enter, -2 on a blank string, and 0
  * otherwise, the valid shortcut key caught.  Def is any editable text we
  * want to put up by default.
  *
- * New arg tabs tells whether or not to allow tab completion.
- */
+ * New arg tabs tells whether or not to allow tab completion. */
 int statusq(int tabs, const shortcut *s, const char *def,
 #ifndef NANO_SMALL
                historyheadtype *which_history,
@@ -1469,7 +1509,7 @@ int statusq(int tabs, const shortcut *s, const char *def,
 #ifndef DISABLE_TABCOMP
        /* if we've done tab completion, there might be a list of
           filename matches on the edit window at this point; make sure
-          they're cleared off */
+          they're cleared off. */
        if (list)
            edit_refresh();
 #endif
@@ -1477,11 +1517,9 @@ int statusq(int tabs, const shortcut *s, const char *def,
     return ret;
 }
 
-/*
- * Ask a simple yes/no question on the statusbar.  Returns 1 for Y, 0
+/* Ask a simple yes/no question on the statusbar.  Returns 1 for Y, 0
  * for N, 2 for All (if all is nonzero when passed in) and -1 for abort
- * (^C).
- */
+ * (^C). */
 int do_yesno(int all, int leavecursor, const char *msg, ...)
 {
     va_list ap;
@@ -1491,18 +1529,19 @@ int do_yesno(int all, int leavecursor, const char *msg, ...)
     const char *nostr;         /* Same for no */
     const char *allstr;                /* And all, surprise! */
 
-    /* Yes, no and all are strings of any length.  Each string consists of
-       all characters accepted as a valid character for that value.
-       The first value will be the one displayed in the shortcuts. */
+    /* Yes, no and all are strings of any length.  Each string consists
+     * of all characters accepted as a valid character for that value.
+     * The first value will be the one displayed in the shortcuts. */
     yesstr = _("Yy");
     nostr = _("Nn");
     allstr = _("Aa");
 
-    /* Remove gettext call for keybindings until we clear the thing up */
+    /* Remove gettext call for keybindings until we clear the thing
+     * up. */
     if (!ISSET(NO_HELP)) {
-       char shortstr[3];               /* Temp string for Y, N, A */
+       char shortstr[3];               /* Temp string for Y, N, A. */
 
-       /* Write the bottom of the screen */
+       /* Write the bottom of the screen. */
        blank_bottombars();
 
        sprintf(shortstr, " %c", yesstr[0]);
@@ -1555,20 +1594,21 @@ int do_yesno(int all, int leavecursor, const char *msg, ...)
                mevent.y >= editwinrows + 3) {
            int x = mevent.x /= 16;
                /* Did we click in the first column of shortcuts, or the
-                  second? */
+                * second? */
            int y = mevent.y - editwinrows - 3;
                /* Did we click in the first row of shortcuts? */
 
            assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
            /* x = 0 means they clicked Yes or No.
-              y = 0 means Yes or All. */
+            * y = 0 means Yes or All. */
            ok = -2 * x * y + x - y + 1;
 
            if (ok == 2 && !all)
                ok = -2;
        }
 #endif
-       /* Look for the kbinput in the yes, no and (optionally) all str */
+       /* Look for the kbinput in the yes, no and (optionally) all
+        * str. */
        else if (strchr(yesstr, kbinput) != NULL)
            ok = 1;
        else if (strchr(nostr, kbinput) != NULL)
@@ -1608,52 +1648,52 @@ void display_main_list(void)
 void statusbar(const char *msg, ...)
 {
     va_list ap;
-    char *foo;
-    int start_x = 0;
-    size_t foo_len;
 
     va_start(ap, msg);
 
-    /* Curses mode is turned off.  If we use wmove() now, it will muck up
-       the terminal settings.  So we just use vfprintf(). */
+    /* Curses mode is turned off.  If we use wmove() now, it will muck
+     * up the terminal settings.  So we just use vfprintf(). */
     if (curses_ended) {
        vfprintf(stderr, msg, ap);
        va_end(ap);
        return;
     }
 
-    assert(COLS >= 4);
-    foo = charalloc(COLS - 3);
-
-    vsnprintf(foo, COLS - 3, msg, ap);
-    va_end(ap);
-
-    foo[COLS - 4] = '\0';
-    foo_len = strlen(foo);
-    start_x = (COLS - foo_len - 4) / 2;
-
-    /* Blank out line */
+    /* Blank out the line. */
     blank_statusbar();
 
-    wmove(bottomwin, 0, start_x);
-
-    wattron(bottomwin, A_REVERSE);
-
-    waddstr(bottomwin, "[ ");
-    waddstr(bottomwin, foo);
-    free(foo);
-    waddstr(bottomwin, " ]");
-
-    wattroff(bottomwin, A_REVERSE);
-
-    wrefresh(bottomwin);
+    if (COLS >= 4) {
+       char *bar;
+       char *foo;
+       int start_x = 0;
+       size_t foo_len;
+       bar = charalloc(COLS - 3);
+       vsnprintf(bar, COLS - 3, msg, ap);
+       va_end(ap);
+       foo = display_string(bar, 0, COLS - 4);
+       free(bar);
+       foo_len = strlen(foo);
+       start_x = (COLS - foo_len - 4) / 2;
+
+       wmove(bottomwin, 0, start_x);
+       wattron(bottomwin, A_REVERSE);
+
+       waddstr(bottomwin, "[ ");
+       waddstr(bottomwin, foo);
+       free(foo);
+       waddstr(bottomwin, " ]");
+       wattroff(bottomwin, A_REVERSE);
+       wnoutrefresh(bottomwin);
+       wrefresh(edit);
+           /* Leave the cursor at its position in the edit window, not
+            * in the statusbar. */
+    }
 
     SET(DISABLE_CURPOS);
     statblank = 26;
 }
 
-/*
- * If constant is false, the user typed ^C so we unconditionally display
+/* If constant is false, the user typed ^C so we unconditionally display
  * the cursor position.  Otherwise, we display it only if the character
  * position changed, and DISABLE_CURPOS is not set.
  *
@@ -1685,9 +1725,9 @@ int do_cursorpos(int constant)
        return 0;
     }
 
-    /* if constant is false, display the position on the statusbar
-       unconditionally; otherwise, only display the position when the
-       character values have changed */
+    /* If constant is false, display the position on the statusbar
+     * unconditionally; otherwise, only display the position when the
+     * character values have changed. */
     if (!constant || old_i != i || old_totsize != totsize) {
        unsigned long xpt = xplustabs() + 1;
        unsigned long cur_len = strlenpt(current->data) + 1;
@@ -1728,12 +1768,12 @@ int line_len(const char *ptr)
        /* Don't wrap at the first of two spaces following a period. */
        if (*ptr == ' ' && *(ptr + 1) == ' ')
            j++;
-       /* Don't print half a word if we've run out of space */
+       /* Don't print half a word if we've run out of space. */
        while (*ptr != ' ' && j > 0) {
            ptr--;
            j--;
        }
-       /* Word longer than COLS - 5 chars just gets broken */
+       /* Word longer than COLS - 5 chars just gets broken. */
        if (j == 0)
            j = COLS - 5;
     }
@@ -1741,8 +1781,8 @@ int line_len(const char *ptr)
     return j;
 }
 
-/* Our shortcut-list-compliant help function, which is
- * better than nothing, and dynamic! */
+/* Our shortcut-list-compliant help function, which is better than
+ * nothing, and dynamic! */
 int do_help(void)
 {
 #ifndef DISABLE_HELP
@@ -1755,7 +1795,7 @@ int do_help(void)
     wattroff(bottomwin, A_REVERSE);
     blank_statusbar();
 
-    /* set help_text as the string to display */
+    /* Set help_text as the string to display. */
     help_init();
     assert(help_text != NULL);
 
@@ -1765,8 +1805,8 @@ int do_help(void)
 
     if (ISSET(NO_HELP)) {
 
-       /* Well, if we're going to do this, we should at least
-          do it the right way */
+       /* Well, if we're going to do this, we should at least do it the
+        * right way. */
        no_help_flag = 1;
        UNSET(NO_HELP);
        window_init();
@@ -1801,7 +1841,8 @@ int do_help(void)
            break;
        }
 
-       /* Calculate where in the text we should be, based on the page */
+       /* Calculate where in the text we should be, based on the
+        * page. */
        for (i = 1; i < page * (editwinrows - 1); i++) {
            ptr += line_len(ptr);
            if (*ptr == '\n')
@@ -1837,7 +1878,7 @@ int do_help(void)
     edit_refresh();
 
     /* The help_init() at the beginning allocated help_text, which has
-       now been written to screen. */
+     * now been written to the screen. */
     free(help_text);
     help_text = NULL;
 
@@ -1848,49 +1889,31 @@ int do_help(void)
     return 1;
 }
 
-/* Highlight the current word being replaced or spell checked. */
+/* Highlight the current word being replaced or spell checked.  We
+ * expect word to have tabs and control characters expanded. */
 void do_replace_highlight(int highlight_flag, const char *word)
 {
-    char *highlight_word = NULL;
-    int x, y, word_len;
-
-    highlight_word =
-       mallocstrcpy(highlight_word, &current->data[current_x]);
+    int y = xplustabs();
+    size_t word_len = strlen(word);
 
-#ifdef HAVE_REGEX_H
-    if (ISSET(USE_REGEXP))
-       /* if we're using regexps, the highlight is the length of the
-          search result, not the length of the regexp string */
-       word_len = regmatches[0].rm_eo - regmatches[0].rm_so;
-    else
-#endif
-       word_len = strlen(word);
-
-    highlight_word[word_len] = '\0';
-
-    /* adjust output when word extends beyond screen */
-
-    x = xplustabs();
-    y = get_page_start(x) + COLS;
-
-    if ((COLS - (y - x) + word_len) > COLS) {
-       highlight_word[y - x - 1] = '$';
-       highlight_word[y - x] = '\0';
-    }
-
-    /* OK display the output */
+    y = get_page_start(y) + COLS - y;
+       /* Now y is the number of characters we can display on this
+        * line. */
 
     reset_cursor();
 
     if (highlight_flag)
        wattron(edit, A_REVERSE);
 
-    waddstr(edit, highlight_word);
+    waddnstr(edit, word, y - 1);
+
+    if (word_len > y)
+       waddch(edit, '$');
+    else if (word_len == y)
+       waddch(edit, word[word_len - 1]);
 
     if (highlight_flag)
        wattroff(edit, A_REVERSE);
-
-    free(highlight_word);
 }
 
 /* Fix editbot, based on the assumption that edittop is correct. */
@@ -1904,8 +1927,9 @@ void fix_editbot(void)
 }
 
 #ifdef DEBUG
-/* Dump the current file structure to stderr */
-void dump_buffer(const filestruct *inptr) {
+/* Dump the passed-in file structure to stderr. */
+void dump_buffer(const filestruct *inptr)
+{
     if (inptr == fileage)
        fprintf(stderr, "Dumping file buffer to stderr...\n");
     else if (inptr == cutbuffer)
@@ -1918,9 +1942,8 @@ void dump_buffer(const filestruct *inptr) {
        inptr = inptr->next;
     }
 }
-#endif /* DEBUG */
 
-#ifdef DEBUG
+/* Dump the file structure to stderr in reverse. */
 void dump_buffer_reverse(void)
 {
     const filestruct *fileptr = filebot;