commit 5ffbec56f6c6487e245eb26e24b51dad80006595
parent b23554fa25c4e223f56957b00cdeb9ce9acb7789
Author: David Lawrence Ramsey <pooka109@gmail.com>
Date: Tue, 16 Sep 2003 01:16:49 +0000
port over some of DB's refactored display code, most importantly the
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
Diffstat:
8 files changed, 393 insertions(+), 314 deletions(-)
diff --git 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
diff --git a/src/move.c b/src/move.c
@@ -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. */
diff --git a/src/nano.c b/src/nano.c
@@ -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
diff --git a/src/nano.h b/src/nano.h
@@ -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
diff --git a/src/proto.h b/src/proto.h
@@ -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);
diff --git a/src/search.c b/src/search.c
@@ -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);
}
diff --git a/src/utils.c b/src/utils.c
@@ -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.
diff --git a/src/winio.c b/src/winio.c
@@ -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
+ * a 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, ¤t->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;