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
This commit is contained in:
David Lawrence Ramsey 2003-09-16 01:16:49 +00:00
parent b23554fa25
commit 5ffbec56f6
8 changed files with 391 additions and 312 deletions

View File

@ -38,6 +38,20 @@ CVS code -
wrap_reset() calls with DISABLE_WRAPPING #ifdefs. (DLR) wrap_reset() calls with DISABLE_WRAPPING #ifdefs. (DLR)
- Change enum "topmidbotnone" to "topmidnone", as there's no - Change enum "topmidbotnone" to "topmidnone", as there's no
BOTTOM option anymore. (DLR) 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: - files.c:
do_browser() do_browser()
- Some of the Pico compatibility options in the file browser - Some of the Pico compatibility options in the file browser

View File

@ -81,7 +81,7 @@ int do_page_up(void)
#endif #endif
} }
/* Get the equivalent x-coordinate of the new line. */ /* Get the equivalent x-coordinate of the new line. */
current_x = actual_x(current, placewewant); current_x = actual_x(current->data, placewewant);
edit_refresh(); edit_refresh();
@ -125,7 +125,7 @@ int do_page_down(void)
#endif #endif
} }
/* Get the equivalent x-coordinate of the new line. */ /* Get the equivalent x-coordinate of the new line. */
current_x = actual_x(current, placewewant); current_x = actual_x(current->data, placewewant);
edit_refresh(); edit_refresh();
@ -145,7 +145,7 @@ int do_up(void)
assert(current_y == current->lineno - edittop->lineno); assert(current_y == current->lineno - edittop->lineno);
current = current->prev; current = current->prev;
current_x = actual_x(current, placewewant); current_x = actual_x(current->data, placewewant);
if (current_y > 0) { if (current_y > 0) {
update_line(current->next, 0); update_line(current->next, 0);
/* It was necessary to change current first, so the mark /* 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); assert(current_y == current->lineno - edittop->lineno);
current = current->next; 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 /* Note that current_y is zero-based. This test checks for the
* cursor's being not on the last row of the edit window. */ * cursor's being not on the last row of the edit window. */

View File

@ -917,7 +917,7 @@ void do_mouse(void)
for(; current_y > mevent.y && current->prev != NULL; current_y--) for(; current_y > mevent.y && current->prev != NULL; current_y--)
current = current->prev; 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 where the cursor is toggles the mark. As does
selecting beyond the line length with the cursor at the end of selecting beyond the line length with the cursor at the end of

View File

@ -35,6 +35,7 @@
/* Define charalloc as a macro rather than duplicating code */ /* Define charalloc as a macro rather than duplicating code */
#define charalloc(howmuch) (char *)nmalloc((howmuch) * sizeof(char)) #define charalloc(howmuch) (char *)nmalloc((howmuch) * sizeof(char))
#define charealloc(ptr, howmuch) (char *)nrealloc(ptr, (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 #ifdef BROKEN_REGEXEC
#define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags) #define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags)
#endif #endif

View File

@ -426,6 +426,10 @@ void *nmalloc(size_t howmuch);
void *nrealloc(void *ptr, size_t howmuch); void *nrealloc(void *ptr, size_t howmuch);
char *mallocstrcpy(char *dest, const char *src); char *mallocstrcpy(char *dest, const char *src);
void new_magicline(void); 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 #ifndef DISABLE_TABCOMP
int check_wildcard_match(const char *text, const char *pattern); int check_wildcard_match(const char *text, const char *pattern);
#endif #endif
@ -443,7 +447,7 @@ int do_first_line(void);
int do_last_line(void); int do_last_line(void);
int xpt(const filestruct *fileptr, int index); int xpt(const filestruct *fileptr, int index);
size_t xplustabs(void); 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 strnlenpt(const char *buf, size_t size);
size_t strlenpt(const char *buf); size_t strlenpt(const char *buf);
void blank_bottombars(void); void blank_bottombars(void);
@ -452,7 +456,8 @@ void blank_edit(void);
void blank_statusbar(void); void blank_statusbar(void);
void blank_statusbar_refresh(void); void blank_statusbar_refresh(void);
void check_statblank(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, int nanogetstr(int allowtabs, const char *buf, const char *def,
#ifndef NANO_SMALL #ifndef NANO_SMALL
historyheadtype *history_list, historyheadtype *history_list,
@ -473,12 +478,9 @@ int get_page_start(int column);
void reset_cursor(void); void reset_cursor(void);
void add_marked_sameline(int begin, int end, filestruct *fileptr, int y, void add_marked_sameline(int begin, int end, filestruct *fileptr, int y,
int virt_cur_x, int this_page); int virt_cur_x, int this_page);
void edit_add(const filestruct *fileptr, int yval, int start void edit_add(const filestruct *fileptr, const char *converted,
#ifndef NANO_SMALL int yval, size_t start);
, int virt_mark_beginx, int virt_cur_x void update_line(const filestruct *fileptr, size_t index);
#endif
);
void update_line(filestruct *fileptr, int index);
void update_cursor(void); void update_cursor(void);
void center_cursor(void); void center_cursor(void);
void edit_refresh(void); void edit_refresh(void);

View File

@ -107,18 +107,22 @@ int search_init(int replacing)
search_init_globals(); search_init_globals();
/* If we don't already have a backupstring, set it. */
if (backupstring == NULL) if (backupstring == NULL)
backupstring = mallocstrcpy(backupstring, ""); backupstring = mallocstrcpy(NULL, "");
#ifndef NANO_SMALL #ifndef NANO_SMALL
search_history.current = (historytype *)&search_history.next; search_history.current = (historytype *)&search_history.next;
#endif #endif
if (last_search[0] != '\0') { if (last_search[0] != '\0') {
char *disp = display_string(last_search, 0, COLS / 3);
buf = charalloc(COLS / 3 + 7); buf = charalloc(COLS / 3 + 7);
/* We use COLS / 3 here because we need to see more on the line */ /* We use COLS / 3 here because we need to see more on the line */
sprintf(buf, " [%.*s%s]", COLS / 3, last_search, sprintf(buf, " [%s%s]", disp,
strlen(last_search) > COLS / 3 ? "..." : ""); strlenpt(last_search) > COLS / 3 ? "..." : "");
free(disp);
} else { } else {
buf = charalloc(1); buf = charalloc(1);
buf[0] = '\0'; buf[0] = '\0';
@ -132,17 +136,23 @@ int search_init(int replacing)
"%s%s%s%s%s%s", "%s%s%s%s%s%s",
_("Search"), _("Search"),
#ifndef NANO_SMALL
/* This string is just a modifier for the search prompt, /* This string is just a modifier for the search prompt,
no grammar is implied */ 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, /* This string is just a modifier for the search prompt,
no grammar is implied */ no grammar is implied */
ISSET(USE_REGEXP) ? _(" [Regexp]") : "", ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
#ifndef NANO_SMALL
/* This string is just a modifier for the search prompt, /* This string is just a modifier for the search prompt,
no grammar is implied */ no grammar is implied */
ISSET(REVERSE_SEARCH) ? _(" [Backwards]") : "", ISSET(REVERSE_SEARCH) ? _(" [Backwards]") :
#endif
"",
replacing ? _(" (to replace)") : "", replacing ? _(" (to replace)") : "",
buf); buf);
@ -150,12 +160,13 @@ int search_init(int replacing)
/* Release buf now that we don't need it anymore */ /* Release buf now that we don't need it anymore */
free(buf); free(buf);
free(backupstring);
backupstring = NULL;
/* Cancel any search, or just return with no previous search */ /* Cancel any search, or just return with no previous search */
if (i == -1 || (i < 0 && last_search[0] == '\0')) { if (i == -1 || (i < 0 && last_search[0] == '\0')) {
statusbar(_("Search Cancelled")); statusbar(_("Search Cancelled"));
reset_cursor(); reset_cursor();
free(backupstring);
backupstring = NULL;
#ifndef NANO_SMALL #ifndef NANO_SMALL
search_history.current = search_history.next; search_history.current = search_history.next;
#endif #endif
@ -169,29 +180,23 @@ int search_init(int replacing)
if (regexp_init(last_search) == 0) { if (regexp_init(last_search) == 0) {
statusbar(regex_error, last_search); statusbar(regex_error, last_search);
reset_cursor(); reset_cursor();
free(backupstring);
backupstring = NULL;
return -3; return -3;
} }
#endif #endif
break; break;
case 0: /* They entered something new */ case 0: /* They entered something new */
last_replace[0] = '\0';
#ifdef HAVE_REGEX_H #ifdef HAVE_REGEX_H
if (ISSET(USE_REGEXP)) if (ISSET(USE_REGEXP))
if (regexp_init(answer) == 0) { if (regexp_init(answer) == 0) {
statusbar(regex_error, answer); statusbar(regex_error, answer);
reset_cursor(); reset_cursor();
free(backupstring);
backupstring = NULL;
#ifndef NANO_SMALL #ifndef NANO_SMALL
search_history.current = search_history.next; search_history.current = search_history.next;
#endif #endif
return -3; return -3;
} }
#endif #endif
free(backupstring);
backupstring = NULL;
last_replace[0] = '\0';
break; break;
#ifndef NANO_SMALL #ifndef NANO_SMALL
case TOGGLE_CASE_KEY: case TOGGLE_CASE_KEY:
@ -213,8 +218,6 @@ int search_init(int replacing)
backupstring = mallocstrcpy(backupstring, answer); backupstring = mallocstrcpy(backupstring, answer);
return -2; /* Call the opposite search function */ return -2; /* Call the opposite search function */
case NANO_FROMSEARCHTOGOTO_KEY: case NANO_FROMSEARCHTOGOTO_KEY:
free(backupstring);
backupstring = NULL;
#ifndef NANO_SMALL #ifndef NANO_SMALL
search_history.current = search_history.next; search_history.current = search_history.next;
#endif #endif
@ -226,8 +229,6 @@ int search_init(int replacing)
return -3; return -3;
default: default:
do_early_abort(); do_early_abort();
free(backupstring);
backupstring = NULL;
return -3; return -3;
} }
} }
@ -631,6 +632,8 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
last_replace = mallocstrcpy(last_replace, answer); last_replace = mallocstrcpy(last_replace, answer);
while (1) { while (1) {
size_t match_len;
/* Sweet optimization by Rocco here */ /* Sweet optimization by Rocco here */
fileptr = findnextstr(fileptr || replaceall || search_last_line, fileptr = findnextstr(fileptr || replaceall || search_last_line,
FALSE, begin, *beginx, prevanswer); FALSE, begin, *beginx, prevanswer);
@ -651,13 +654,27 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
if (numreplaced == -1) if (numreplaced == -1)
numreplaced = 0; 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) { 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); curs_set(0);
do_replace_highlight(TRUE, prevanswer); do_replace_highlight(TRUE, exp_word);
*i = do_yesno(1, 1, _("Replace this instance?")); *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); curs_set(1);
} }

View File

@ -302,6 +302,28 @@ void new_magicline(void)
totsize++; 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 #ifndef DISABLE_TABCOMP
/* /*
* Routine to see if a text string is matched by a wildcard pattern. * Routine to see if a text string is matched by a wildcard pattern.

View File

@ -343,36 +343,32 @@ size_t xplustabs(void)
return strnlenpt(current->data, current_x); return strnlenpt(current->data, current_x);
} }
/* Return what current_x should be, given xplustabs() for the line. */ /* actual_x() gives the index in str of the character displayed at
size_t actual_x(const filestruct *fileptr, size_t xplus) * 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; size_t i = 0;
/* the position in fileptr->data, returned */ /* the position in str, returned */
size_t length = 0; size_t length = 0;
/* the screen display width to data[i] */ /* the screen display width to str[i] */
char *c;
/* fileptr->data + i */
assert(fileptr != NULL && fileptr->data != NULL); assert(str != NULL);
for (c = fileptr->data; length < xplus && *c != '\0'; i++, c++) { for (; length < xplus && *str != '\0'; i++, str++) {
if (*c == '\t') if (*str == '\t')
length += tabsize - length % tabsize; length += tabsize - length % tabsize;
else if (is_cntrl_char((int)*c)) else if (is_cntrl_char((int)*str))
length += 2; length += 2;
else else
length++; length++;
} }
assert(length == strnlenpt(fileptr->data, i)); assert(length == strnlenpt(str - i, i));
assert(i <= strlen(fileptr->data)); assert(i <= strlen(str - i));
if (length > xplus) if (length > xplus)
i--; i--;
#ifdef DEBUG
fprintf(stderr, "actual_x for xplus=%d returns %d\n", xplus, i);
#endif
return i; 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 /* 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 * Note that we must turn on A_REVERSE here, since do_help() turns it
* off! */ * 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; size_t x_real = strnlenpt(inputbuf, x);
int wid = COLS - len; int wid = COLS - strlen(buf) - 2;
assert(wid >= 2);
assert(0 <= x && x <= strlen(inputbuf)); assert(0 <= x && x <= strlen(inputbuf));
wattron(bottomwin, A_REVERSE); wattron(bottomwin, A_REVERSE);
blank_statusbar(); blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf); mvwaddstr(bottomwin, 0, 0, buf);
waddch(bottomwin, ':'); waddch(bottomwin, ':');
waddch(bottomwin, x < wid ? ' ' : '$');
waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid); if (COLS > 1)
wmove(bottomwin, 0, (x % wid) + len); 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); wattroff(bottomwin, A_REVERSE);
} }
@ -933,23 +1000,34 @@ void reset_cursor(void)
wmove(edit, current_y, x - get_page_start(x)); wmove(edit, current_y, x - get_page_start(x));
} }
/* edit_add() takes care of the job of actually painting a line into /* edit_add() takes care of the job of actually painting a line into the
* the edit window. Called only from update_line(). Expects a * edit window. fileptr is the line to be painted, at row yval of the
* converted-to-not-have-tabs line. */ * window. converted is the actual string to be written to the window,
void edit_add(const filestruct *fileptr, int yval, int start * with tabs and control characters replaced by strings of regular
#ifndef NANO_SMALL * characters. start is the column number of the first character
, int virt_mark_beginx, int virt_cur_x * of this page. That is, the first character of converted corresponds to
#endif * 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 #if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno, size_t startpos = actual_x(fileptr->data, start);
current->lineno); /* 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 #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 paint the string in any case (we'll add color or reverse on
just the text that needs it */ * just the text that needs it). */
mvwaddnstr(edit, yval, 0, &fileptr->data[start], COLS); mvwaddstr(edit, yval, 0, converted);
#ifdef ENABLE_COLOR #ifdef ENABLE_COLOR
if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) { if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
@ -959,16 +1037,16 @@ void edit_add(const filestruct *fileptr, int yval, int start
int x_start; int x_start;
/* Starting column for mvwaddnstr. Zero-based. */ /* Starting column for mvwaddnstr. Zero-based. */
int paintlen; 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. */ * characters on a whole line. */
regmatch_t startmatch; /* match position for start_regexp*/ regmatch_t startmatch; /* match position for start_regexp */
regmatch_t endmatch; /* match position for end_regexp*/ regmatch_t endmatch; /* match position for end_regexp */
if (tmpcolor->bright) if (tmpcolor->bright)
wattron(edit, A_BOLD); wattron(edit, A_BOLD);
wattron(edit, COLOR_PAIR(tmpcolor->pairnum)); wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
/* Two notes about regexec. Return value 0 means there is a /* Two notes about regexec(). Return value 0 means there is
* match. Also, rm_eo is the first non-matching character * a match. Also, rm_eo is the first non-matching character
* after the match. */ * after the match. */
/* First case, tmpcolor is a single-line expression. */ /* 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; size_t k = 0;
/* We increment k by rm_eo, to move past the end of the /* We increment k by rm_eo, to move past the end of the
last match. Even though two matches may overlap, we * last match. Even though two matches may overlap, we
want to ignore them, so that we can highlight C-strings * want to ignore them, so that we can highlight
correctly. */ * C-strings correctly. */
while (k < start + COLS) { while (k < endpos) {
/* Note the fifth parameter to regexec. It says not to /* Note the fifth parameter to regexec(). It says
* match the beginning-of-line character unless * not to match the beginning-of-line character
* k == 0. If regexec returns nonzero, there are no * unless k is 0. If regexec() returns REG_NOMATCH,
* more matches in the line. */ * there are no more matches in the line. */
if (regexec(&tmpcolor->start, &fileptr->data[k], 1, if (regexec(&tmpcolor->start, &fileptr->data[k], 1,
&startmatch, k == 0 ? 0 : REG_NOTBOL)) &startmatch, k == 0 ? 0 : REG_NOTBOL) == REG_NOMATCH)
break; break;
/* Translate the match to the beginning of the line. */ /* Translate the match to the beginning of the line. */
startmatch.rm_so += k; 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) { if (startmatch.rm_so == startmatch.rm_eo) {
startmatch.rm_eo++; startmatch.rm_eo++;
statusbar(_("Refusing 0 length regex match")); statusbar(_("Refusing 0 length regex match"));
} else if (startmatch.rm_so < start + COLS && } else if (startmatch.rm_so < endpos &&
startmatch.rm_eo > start) { startmatch.rm_eo > startpos) {
x_start = startmatch.rm_so - start; if (startmatch.rm_so <= startpos)
if (x_start < 0)
x_start = 0; 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) if (paintlen > COLS - x_start)
paintlen = COLS - x_start; paintlen = COLS - x_start;
assert(0 <= x_start && 0 < paintlen && assert(0 <= x_start && 0 < paintlen &&
x_start + paintlen <= COLS); x_start + paintlen <= COLS);
mvwaddnstr(edit, yval, x_start, mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen); converted + x_start, paintlen);
} }
k = startmatch.rm_eo; k = startmatch.rm_eo;
} }
} else { } else {
@ -1022,7 +1103,7 @@ void edit_add(const filestruct *fileptr, int yval, int start
* before fileptr, then paint the beginning of this line. */ * before fileptr, then paint the beginning of this line. */
const filestruct *start_line = fileptr->prev; const filestruct *start_line = fileptr->prev;
/* the first line before fileptr matching start*/ /* the first line before fileptr matching start */
regoff_t start_col; regoff_t start_col;
/* where it starts in that line */ /* where it starts in that line */
const filestruct *end_line; const filestruct *end_line;
@ -1032,11 +1113,11 @@ void edit_add(const filestruct *fileptr, int yval, int start
while (start_line != NULL && while (start_line != NULL &&
regexec(&tmpcolor->start, start_line->data, 1, 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 /* If there is an end on this line, there is no need
* to look for starts on earlier lines. */ * to look for starts on earlier lines. */
if (!regexec(tmpcolor->end, start_line->data, 1, if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0)
&endmatch, 0)) == 0)
goto step_two; goto step_two;
start_line = start_line->prev; start_line = start_line->prev;
} }
@ -1051,43 +1132,44 @@ void edit_add(const filestruct *fileptr, int yval, int start
while (1) { while (1) {
start_col += startmatch.rm_so; start_col += startmatch.rm_so;
startmatch.rm_eo -= startmatch.rm_so; startmatch.rm_eo -= startmatch.rm_so;
if (regexec(tmpcolor->end, if (regexec(tmpcolor->end,
start_line->data + start_col + startmatch.rm_eo, start_line->data + start_col + startmatch.rm_eo,
1, &endmatch, 0, NULL, start_col + startmatch.rm_eo == 0 ? 0 :
start_col + startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) REG_NOTBOL) == REG_NOMATCH)
/* No end found after this start */ /* No end found after this start. */
break; break;
start_col++; start_col++;
if (regexec(&tmpcolor->start, if (regexec(&tmpcolor->start,
start_line->data + start_col, 1, &startmatch, start_line->data + start_col, 1, &startmatch,
REG_NOTBOL)) REG_NOTBOL) == REG_NOMATCH)
/* No later start on this line. */ /* No later start on this line. */
goto step_two; goto step_two;
} }
/* Indeed, there is a start not followed on this line by an /* Indeed, there is a start not followed on this line by
* end. */ * an end. */
/* We have already checked that there is no end before /* We have already checked that there is no end before
* fileptr and after the start. Is there an end after * 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; end_line = fileptr;
while (end_line != NULL && while (end_line != NULL &&
regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0)) regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0))
end_line = end_line->next; end_line = end_line->next;
/* No end found, or it is too early. */ /* No end found, or it is too early. */
if (end_line == NULL || end_line->lineno < fileptr->lineno || if (end_line == NULL ||
(end_line == fileptr && endmatch.rm_eo <= start)) (end_line == fileptr && endmatch.rm_eo <= startpos))
goto step_two; goto step_two;
/* Now paint the start of fileptr. */ /* Now paint the start of fileptr. */
paintlen = end_line != fileptr paintlen = end_line != fileptr ? COLS :
? COLS : endmatch.rm_eo - start; strnlenpt(fileptr->data, endmatch.rm_eo) - start;
if (paintlen > COLS) if (paintlen > COLS)
paintlen = COLS; paintlen = COLS;
assert(0 < paintlen && 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. */ /* We have already painted the whole line. */
if (paintlen == COLS) 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. */ step_two: /* Second step, we look for starts on this line. */
start_col = 0; start_col = 0;
while (start_col < start + COLS) { while (start_col < endpos) {
if (regexec(&tmpcolor->start, fileptr->data + start_col, 1, if (regexec(&tmpcolor->start, fileptr->data + start_col, 1,
&startmatch, start_col == 0 ? 0 : REG_NOTBOL) &startmatch, start_col == 0 ? 0 : REG_NOTBOL)
|| start_col + startmatch.rm_so >= start + COLS) == REG_NOMATCH || start_col + startmatch.rm_so >=
endpos)
/* No more starts on this line. */ /* No more starts on this line. */
break; break;
/* Translate the match to be relative to the /* 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_so += start_col;
startmatch.rm_eo += start_col; startmatch.rm_eo += start_col;
x_start = startmatch.rm_so - start; if (startmatch.rm_so <= startpos)
if (x_start < 0) {
x_start = 0; x_start = 0;
startmatch.rm_so = start; else
} x_start = strnlenpt(fileptr->data, startmatch.rm_so)
if (!regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo, - start;
1, &endmatch, if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo,
startmatch.rm_eo == 0 ? 0 : REG_NOTBOL)) { 1, &endmatch, startmatch.rm_eo == 0 ? 0 :
REG_NOTBOL) == 0) {
/* Translate the end match to be relative to the /* 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_so += startmatch.rm_eo;
endmatch.rm_eo += startmatch.rm_eo; endmatch.rm_eo += startmatch.rm_eo;
/* There is an end on this line. But does it /* There is an end on this line. But does it
appear on this page, and is the match more than * appear on this page, and is the match more than
zero characters long? */ * zero characters long? */
if (endmatch.rm_eo > start && if (endmatch.rm_eo > startpos &&
endmatch.rm_eo > startmatch.rm_so) { 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) if (x_start + paintlen > COLS)
paintlen = COLS - x_start; paintlen = COLS - x_start;
assert(0 <= x_start && 0 < paintlen && assert(0 <= x_start && 0 < paintlen &&
x_start + paintlen <= COLS); x_start + paintlen <= COLS);
mvwaddnstr(edit, yval, x_start, mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen); converted + x_start, paintlen);
} }
} else if (!searched_later_lines) { } else if (!searched_later_lines) {
searched_later_lines = 1; searched_later_lines = 1;
/* There is no end on this line. But we haven't /* There is no end on this line. But we haven't
* yet looked for one on later lines. */ * yet looked for one on later lines. */
end_line = fileptr->next; end_line = fileptr->next;
while (end_line != NULL && regexec(tmpcolor->end, while (end_line != NULL &&
end_line->data, 1, &endmatch, 0)) regexec(tmpcolor->end, end_line->data, 0,
NULL, 0) == REG_NOMATCH)
end_line = end_line->next; end_line = end_line->next;
if (end_line != NULL) { if (end_line != NULL) {
assert(0 <= x_start && x_start < COLS); assert(0 <= x_start && x_start < COLS);
mvwaddnstr(edit, yval, x_start, mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, converted + x_start,
COLS - x_start); COLS - x_start);
/* We painted to the end of the line, so /* We painted to the end of the line, so
* don't bother checking any more starts. */ * don't bother checking any more starts. */
break; break;
} }
} }
start_col = startmatch.rm_so + 1; start_col = startmatch.rm_so + 1;
} /* while start_col < start + COLS */ } /* while start_col < endpos */
} /* if (tmp_color->end != NULL) */ } /* if (tmp_color->end != NULL) */
skip_step_two: skip_step_two:
@ -1169,43 +1254,39 @@ void edit_add(const filestruct *fileptr, int yval, int start
|| fileptr->lineno >= current->lineno)) { || fileptr->lineno >= current->lineno)) {
/* fileptr is at least partially selected. */ /* 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; int x_start;
/* Starting column for mvwaddnstr. Zero-based. */ /* Starting column for mvwaddnstr. Zero-based. */
int paintlen; 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. */ * characters on a whole line. */
if (mark_beginbuf == fileptr && current == fileptr) { mark_order(&top, &top_x, &bot, &bot_x);
x_start = virt_mark_beginx < virt_cur_x ? virt_mark_beginx
: virt_cur_x;
paintlen = abs(virt_mark_beginx - virt_cur_x);
} else {
if (mark_beginbuf->lineno < fileptr->lineno ||
current->lineno < fileptr->lineno)
x_start = 0;
else
x_start = mark_beginbuf == fileptr ? virt_mark_beginx
: virt_cur_x;
if (mark_beginbuf->lineno > fileptr->lineno || if (top->lineno < fileptr->lineno || top_x < startpos)
current->lineno > fileptr->lineno) top_x = startpos;
paintlen = start + COLS; if (bot->lineno > fileptr->lineno || bot_x > endpos)
bot_x = endpos;
/* 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 else
paintlen = mark_beginbuf == fileptr ? virt_mark_beginx paintlen = strnlenpt(fileptr->data + top_x, bot_x - top_x);
: virt_cur_x;
} assert(x_start >= 0 && x_start <= strlen(converted));
x_start -= start;
if (x_start < 0) {
paintlen += x_start;
x_start = 0;
}
if (x_start + paintlen > COLS)
paintlen = COLS - x_start;
if (paintlen > 0) {
wattron(edit, A_REVERSE); wattron(edit, A_REVERSE);
assert(x_start >= 0 && paintlen > 0 && x_start + paintlen <= COLS); mvwaddnstr(edit, yval, x_start, converted + x_start, paintlen);
mvwaddnstr(edit, yval, x_start,
fileptr->data + start + x_start, paintlen);
wattroff(edit, A_REVERSE); 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 /* 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]. * The line will be displayed starting with fileptr->data[index].
* Likely args are current_x or 0. */ * 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; int line;
/* line in the edit window for CURSES calls */ /* 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; char *converted;
/* fileptr->data converted to have tabs and control characters /* fileptr->data converted to have tabs and control characters
* expanded. */ * expanded. */
size_t pos;
size_t page_start; size_t page_start;
if (fileptr == NULL) assert(fileptr != NULL);
return;
line = fileptr->lineno - edittop->lineno; line = fileptr->lineno - edittop->lineno;
@ -1246,54 +1321,22 @@ void update_line(filestruct *fileptr, int index)
/* First, blank out the line (at a minimum) */ /* First, blank out the line (at a minimum) */
mvwaddstr(edit, line, 0, hblank); mvwaddstr(edit, line, 0, hblank);
original = fileptr->data; /* Next, convert variables that index the line to their equivalent
converted = charalloc(strlenpt(original) + 1); * 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. /* Expand the line, replacing Tab by spaces, and control characters
* Note the internal speller sends us index == -1. */ * by their display form. */
index = fileptr == current && index > 0 ? strnlenpt(original, index) : 0; converted = display_string(fileptr->data, page_start, COLS);
#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';
/* Now, paint the line */ /* Now, paint the line */
original = fileptr->data; edit_add(fileptr, converted, line, page_start);
fileptr->data = converted;
page_start = get_page_start(index);
edit_add(fileptr, line, page_start
#ifndef NANO_SMALL
, virt_mark_beginx, virt_cur_x
#endif
);
free(converted); free(converted);
fileptr->data = original;
if (page_start > 0) if (page_start > 0)
mvwaddch(edit, line, 0, '$'); mvwaddch(edit, line, 0, '$');
if (pos > page_start + COLS) if (strlenpt(fileptr->data) > page_start + COLS)
mvwaddch(edit, line, COLS - 1, '$'); mvwaddch(edit, line, COLS - 1, '$');
} }
@ -1328,8 +1371,8 @@ void center_cursor(void)
/* Refresh the screen without changing the position of lines. */ /* Refresh the screen without changing the position of lines. */
void edit_refresh(void) void edit_refresh(void)
{ {
/* Neither of these conditions should occur, but they do. edittop is /* Neither of these conditions should occur, but they do. edittop
* NULL when you open an existing file on the command line, and * is NULL when you open an existing file on the command line, and
* ENABLE_COLOR is defined. Yuck. */ * ENABLE_COLOR is defined. Yuck. */
if (current == NULL) if (current == NULL)
return; return;
@ -1346,7 +1389,8 @@ void edit_refresh(void)
else { else {
int nlines = 0; 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); leaveok(edit, TRUE);
editbot = edittop; editbot = edittop;
@ -1362,7 +1406,7 @@ void edit_refresh(void)
nlines++; nlines++;
} }
/* What the hell are we expecting to update the screen if this /* What the hell are we expecting to update the screen if this
isn't here? Luck? */ * isn't here? Luck? */
wrefresh(edit); wrefresh(edit);
leaveok(edit, FALSE); leaveok(edit, FALSE);
} }
@ -1377,10 +1421,8 @@ void edit_refresh_clearok(void)
clearok(edit, FALSE); clearok(edit, FALSE);
} }
/* /* Nice generic routine to update the edit buffer, given a pointer to the
* Nice generic routine to update the edit buffer, given a pointer to the * file struct =) */
* file struct =)
*/
void edit_update(filestruct *fileptr, topmidnone location) void edit_update(filestruct *fileptr, topmidnone location)
{ {
if (fileptr == NULL) if (fileptr == NULL)
@ -1396,14 +1438,12 @@ void edit_update(filestruct *fileptr, topmidnone location)
edit_refresh(); 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 * 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 * otherwise, the valid shortcut key caught. Def is any editable text we
* want to put up by default. * 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, int statusq(int tabs, const shortcut *s, const char *def,
#ifndef NANO_SMALL #ifndef NANO_SMALL
historyheadtype *which_history, historyheadtype *which_history,
@ -1469,7 +1509,7 @@ int statusq(int tabs, const shortcut *s, const char *def,
#ifndef DISABLE_TABCOMP #ifndef DISABLE_TABCOMP
/* if we've done tab completion, there might be a list of /* if we've done tab completion, there might be a list of
filename matches on the edit window at this point; make sure filename matches on the edit window at this point; make sure
they're cleared off */ they're cleared off. */
if (list) if (list)
edit_refresh(); edit_refresh();
#endif #endif
@ -1477,11 +1517,9 @@ int statusq(int tabs, const shortcut *s, const char *def,
return ret; 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 * 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, ...) int do_yesno(int all, int leavecursor, const char *msg, ...)
{ {
va_list ap; 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 *nostr; /* Same for no */
const char *allstr; /* And all, surprise! */ const char *allstr; /* And all, surprise! */
/* Yes, no and all are strings of any length. Each string consists of /* Yes, no and all are strings of any length. Each string consists
all characters accepted as a valid character for that value. * of all characters accepted as a valid character for that value.
The first value will be the one displayed in the shortcuts. */ * The first value will be the one displayed in the shortcuts. */
yesstr = _("Yy"); yesstr = _("Yy");
nostr = _("Nn"); nostr = _("Nn");
allstr = _("Aa"); 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)) { 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(); blank_bottombars();
sprintf(shortstr, " %c", yesstr[0]); sprintf(shortstr, " %c", yesstr[0]);
@ -1555,20 +1594,21 @@ int do_yesno(int all, int leavecursor, const char *msg, ...)
mevent.y >= editwinrows + 3) { mevent.y >= editwinrows + 3) {
int x = mevent.x /= 16; int x = mevent.x /= 16;
/* Did we click in the first column of shortcuts, or the /* Did we click in the first column of shortcuts, or the
second? */ * second? */
int y = mevent.y - editwinrows - 3; int y = mevent.y - editwinrows - 3;
/* Did we click in the first row of shortcuts? */ /* Did we click in the first row of shortcuts? */
assert(0 <= x && x <= 1 && 0 <= y && y <= 1); assert(0 <= x && x <= 1 && 0 <= y && y <= 1);
/* x = 0 means they clicked Yes or No. /* 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; ok = -2 * x * y + x - y + 1;
if (ok == 2 && !all) if (ok == 2 && !all)
ok = -2; ok = -2;
} }
#endif #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) else if (strchr(yesstr, kbinput) != NULL)
ok = 1; ok = 1;
else if (strchr(nostr, kbinput) != NULL) else if (strchr(nostr, kbinput) != NULL)
@ -1608,52 +1648,52 @@ void display_main_list(void)
void statusbar(const char *msg, ...) void statusbar(const char *msg, ...)
{ {
va_list ap; va_list ap;
char *foo;
int start_x = 0;
size_t foo_len;
va_start(ap, msg); va_start(ap, msg);
/* Curses mode is turned off. If we use wmove() now, it will muck up /* Curses mode is turned off. If we use wmove() now, it will muck
the terminal settings. So we just use vfprintf(). */ * up the terminal settings. So we just use vfprintf(). */
if (curses_ended) { if (curses_ended) {
vfprintf(stderr, msg, ap); vfprintf(stderr, msg, ap);
va_end(ap); va_end(ap);
return; return;
} }
assert(COLS >= 4); /* Blank out the line. */
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_statusbar(); blank_statusbar();
wmove(bottomwin, 0, start_x); 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;
wattron(bottomwin, A_REVERSE); wmove(bottomwin, 0, start_x);
wattron(bottomwin, A_REVERSE);
waddstr(bottomwin, "[ "); waddstr(bottomwin, "[ ");
waddstr(bottomwin, foo); waddstr(bottomwin, foo);
free(foo); free(foo);
waddstr(bottomwin, " ]"); waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wattroff(bottomwin, A_REVERSE); wnoutrefresh(bottomwin);
wrefresh(edit);
wrefresh(bottomwin); /* Leave the cursor at its position in the edit window, not
* in the statusbar. */
}
SET(DISABLE_CURPOS); SET(DISABLE_CURPOS);
statblank = 26; 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 * the cursor position. Otherwise, we display it only if the character
* position changed, and DISABLE_CURPOS is not set. * position changed, and DISABLE_CURPOS is not set.
* *
@ -1685,9 +1725,9 @@ int do_cursorpos(int constant)
return 0; return 0;
} }
/* if constant is false, display the position on the statusbar /* If constant is false, display the position on the statusbar
unconditionally; otherwise, only display the position when the * unconditionally; otherwise, only display the position when the
character values have changed */ * character values have changed. */
if (!constant || old_i != i || old_totsize != totsize) { if (!constant || old_i != i || old_totsize != totsize) {
unsigned long xpt = xplustabs() + 1; unsigned long xpt = xplustabs() + 1;
unsigned long cur_len = strlenpt(current->data) + 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. */ /* Don't wrap at the first of two spaces following a period. */
if (*ptr == ' ' && *(ptr + 1) == ' ') if (*ptr == ' ' && *(ptr + 1) == ' ')
j++; 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) { while (*ptr != ' ' && j > 0) {
ptr--; ptr--;
j--; j--;
} }
/* Word longer than COLS - 5 chars just gets broken */ /* Word longer than COLS - 5 chars just gets broken. */
if (j == 0) if (j == 0)
j = COLS - 5; j = COLS - 5;
} }
@ -1741,8 +1781,8 @@ int line_len(const char *ptr)
return j; return j;
} }
/* Our shortcut-list-compliant help function, which is /* Our shortcut-list-compliant help function, which is better than
* better than nothing, and dynamic! */ * nothing, and dynamic! */
int do_help(void) int do_help(void)
{ {
#ifndef DISABLE_HELP #ifndef DISABLE_HELP
@ -1755,7 +1795,7 @@ int do_help(void)
wattroff(bottomwin, A_REVERSE); wattroff(bottomwin, A_REVERSE);
blank_statusbar(); blank_statusbar();
/* set help_text as the string to display */ /* Set help_text as the string to display. */
help_init(); help_init();
assert(help_text != NULL); assert(help_text != NULL);
@ -1765,8 +1805,8 @@ int do_help(void)
if (ISSET(NO_HELP)) { if (ISSET(NO_HELP)) {
/* Well, if we're going to do this, we should at least /* Well, if we're going to do this, we should at least do it the
do it the right way */ * right way. */
no_help_flag = 1; no_help_flag = 1;
UNSET(NO_HELP); UNSET(NO_HELP);
window_init(); window_init();
@ -1801,7 +1841,8 @@ int do_help(void)
break; 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++) { for (i = 1; i < page * (editwinrows - 1); i++) {
ptr += line_len(ptr); ptr += line_len(ptr);
if (*ptr == '\n') if (*ptr == '\n')
@ -1837,7 +1878,7 @@ int do_help(void)
edit_refresh(); edit_refresh();
/* The help_init() at the beginning allocated help_text, which has /* 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); free(help_text);
help_text = NULL; help_text = NULL;
@ -1848,49 +1889,31 @@ int do_help(void)
return 1; 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) void do_replace_highlight(int highlight_flag, const char *word)
{ {
char *highlight_word = NULL; int y = xplustabs();
int x, y, word_len; size_t word_len = strlen(word);
highlight_word = y = get_page_start(y) + COLS - y;
mallocstrcpy(highlight_word, &current->data[current_x]); /* Now y is the number of characters we can display on this
* line. */
#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 */
reset_cursor(); reset_cursor();
if (highlight_flag) if (highlight_flag)
wattron(edit, A_REVERSE); 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) if (highlight_flag)
wattroff(edit, A_REVERSE); wattroff(edit, A_REVERSE);
free(highlight_word);
} }
/* Fix editbot, based on the assumption that edittop is correct. */ /* Fix editbot, based on the assumption that edittop is correct. */
@ -1904,8 +1927,9 @@ void fix_editbot(void)
} }
#ifdef DEBUG #ifdef DEBUG
/* Dump the current file structure to stderr */ /* Dump the passed-in file structure to stderr. */
void dump_buffer(const filestruct *inptr) { void dump_buffer(const filestruct *inptr)
{
if (inptr == fileage) if (inptr == fileage)
fprintf(stderr, "Dumping file buffer to stderr...\n"); fprintf(stderr, "Dumping file buffer to stderr...\n");
else if (inptr == cutbuffer) else if (inptr == cutbuffer)
@ -1918,9 +1942,8 @@ void dump_buffer(const filestruct *inptr) {
inptr = inptr->next; inptr = inptr->next;
} }
} }
#endif /* DEBUG */
#ifdef DEBUG /* Dump the file structure to stderr in reverse. */
void dump_buffer_reverse(void) void dump_buffer_reverse(void)
{ {
const filestruct *fileptr = filebot; const filestruct *fileptr = filebot;