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
master
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)
- 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

View File

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

View File

@ -917,7 +917,7 @@ void do_mouse(void)
for(; current_y > mevent.y && current->prev != NULL; current_y--)
current = current->prev;
xcur = actual_x(current, get_page_start(xplustabs()) + mevent.x);
xcur = actual_x(current->data, get_page_start(xplustabs()) + mevent.x);
/* Selecting where the cursor is toggles the mark. As does
selecting beyond the line length with the cursor at the end of

View File

@ -35,6 +35,7 @@
/* Define charalloc as a macro rather than duplicating code */
#define charalloc(howmuch) (char *)nmalloc((howmuch) * sizeof(char))
#define charealloc(ptr, howmuch) (char *)nrealloc(ptr, (howmuch) * sizeof(char))
#define charmove(dest, src, n) memmove(dest, src, (n) * sizeof(char))
#ifdef BROKEN_REGEXEC
#define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags)
#endif

View File

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

View File

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

View File

@ -302,6 +302,28 @@ void new_magicline(void)
totsize++;
}
#ifndef NANO_SMALL
/* Set top_x and bot_x to the top and bottom x-coordinates of the mark,
* respectively, based on the locations of top and bot. */
void mark_order(const filestruct **top, size_t *top_x,
const filestruct **bot, size_t *bot_x)
{
assert(top != NULL && top_x != NULL && bot != NULL && bot_x != NULL);
if ((current->lineno == mark_beginbuf->lineno && current_x > mark_beginx)
|| current->lineno > mark_beginbuf->lineno) {
*top = mark_beginbuf;
*top_x = mark_beginx;
*bot = current;
*bot_x = current_x;
} else {
*bot = mark_beginbuf;
*bot_x = mark_beginx;
*top = current;
*top_x = current_x;
}
}
#endif
#ifndef DISABLE_TABCOMP
/*
* Routine to see if a text string is matched by a wildcard pattern.

View File

@ -343,36 +343,32 @@ size_t xplustabs(void)
return strnlenpt(current->data, current_x);
}
/* Return what current_x should be, given xplustabs() for the line. */
size_t actual_x(const filestruct *fileptr, size_t xplus)
/* actual_x() gives the index in str of the character displayed at
* column xplus. That is, actual_x() is the largest value such that
* strnlenpt(str, actual_x(str, xplus)) <= xplus. */
size_t actual_x(const char *str, size_t xplus)
{
size_t i = 0;
/* the position in fileptr->data, returned */
/* the position in str, returned */
size_t length = 0;
/* the screen display width to data[i] */
char *c;
/* fileptr->data + i */
/* the screen display width to str[i] */
assert(fileptr != NULL && fileptr->data != NULL);
assert(str != NULL);
for (c = fileptr->data; length < xplus && *c != '\0'; i++, c++) {
if (*c == '\t')
for (; length < xplus && *str != '\0'; i++, str++) {
if (*str == '\t')
length += tabsize - length % tabsize;
else if (is_cntrl_char((int)*c))
else if (is_cntrl_char((int)*str))
length += 2;
else
length++;
}
assert(length == strnlenpt(fileptr->data, i));
assert(i <= strlen(fileptr->data));
assert(length == strnlenpt(str - i, i));
assert(i <= strlen(str - i));
if (length > xplus)
i--;
#ifdef DEBUG
fprintf(stderr, "actual_x for xplus=%d returns %d\n", xplus, i);
#endif
return i;
}
@ -444,26 +440,97 @@ void check_statblank(void)
}
}
/* Convert buf into a string that can be displayed on screen. The
* caller wants to display buf starting with column start_col, and
* extending for at most len columns. start_col is zero-based. len is
* one-based, so len == 0 means you get "" returned. The returned
* string is dynamically allocated, and should be freed. */
char *display_string(const char *buf, size_t start_col, int len)
{
size_t start_index;
/* Index in buf of first character shown in return value. */
size_t column;
/* Screen column start_index corresponds to. */
size_t end_index;
/* Index in buf of last character shown in return value. */
size_t alloc_len;
/* The length of memory allocated for converted. */
char *converted;
/* The string we return. */
size_t index;
/* Current position in converted. */
if (len == 0)
return mallocstrcpy(NULL, "");
start_index = actual_x(buf, start_col);
column = strnlenpt(buf, start_index);
assert(column <= start_col);
end_index = actual_x(buf, start_col + len - 1);
alloc_len = strnlenpt(buf, end_index + 1) - column;
if (len > alloc_len + column - start_col)
len = alloc_len + column - start_col;
converted = charalloc(alloc_len + 1);
buf += start_index;
index = 0;
for (; index < alloc_len; buf++) {
if (*buf == '\t')
do {
converted[index++] = ' ';
} while ((column + index) % tabsize);
else if (is_cntrl_char(*buf)) {
converted[index++] = '^';
if (*buf == '\n')
/* Treat newlines embedded in a line as encoded nulls;
* the line in question should be run through unsunder()
* before reaching here. */
converted[index++] = '@';
else if (*buf == NANO_CONTROL_8)
converted[index++] = '?';
else
converted[index++] = *buf + 64;
} else
converted[index++] = *buf;
}
assert(len <= alloc_len + column - start_col);
charmove(converted, converted + start_col - column, len);
null_at(&converted, len);
return charealloc(converted, len + 1);
}
/* Repaint the statusbar when getting a character in nanogetstr(). buf
* should be no longer than COLS - 4.
* should be no longer than max(0, COLS - 4).
*
* Note that we must turn on A_REVERSE here, since do_help() turns it
* off! */
void nanoget_repaint(const char *buf, const char *inputbuf, int x)
void nanoget_repaint(const char *buf, const char *inputbuf, size_t x)
{
int len = strlen(buf) + 2;
int wid = COLS - len;
size_t x_real = strnlenpt(inputbuf, x);
int wid = COLS - strlen(buf) - 2;
assert(wid >= 2);
assert(0 <= x && x <= strlen(inputbuf));
wattron(bottomwin, A_REVERSE);
blank_statusbar();
mvwaddstr(bottomwin, 0, 0, buf);
waddch(bottomwin, ':');
waddch(bottomwin, x < wid ? ' ' : '$');
waddnstr(bottomwin, &inputbuf[wid * (x / wid)], wid);
wmove(bottomwin, 0, (x % wid) + len);
if (COLS > 1)
waddch(bottomwin, x_real < wid ? ' ' : '$');
if (COLS > 2) {
size_t page_start = x_real - x_real % wid;
char *expanded = display_string(inputbuf, page_start, wid);
assert(wid > 0);
assert(strlen(expanded) <= wid);
waddstr(bottomwin, expanded);
free(expanded);
wmove(bottomwin, 0, COLS - wid + x_real - page_start);
} else
wmove(bottomwin, 0, COLS - 1);
wattroff(bottomwin, A_REVERSE);
}
@ -933,23 +1000,34 @@ void reset_cursor(void)
wmove(edit, current_y, x - get_page_start(x));
}
/* edit_add() takes care of the job of actually painting a line into
* the edit window. Called only from update_line(). Expects a
* converted-to-not-have-tabs line. */
void edit_add(const filestruct *fileptr, int yval, int start
#ifndef NANO_SMALL
, int virt_mark_beginx, int virt_cur_x
#endif
)
/* edit_add() takes care of the job of actually painting a line into the
* edit window. fileptr is the line to be painted, at row yval of the
* window. converted is the actual string to be written to the window,
* with tabs and control characters replaced by strings of regular
* characters. start is the column number of the first character
* of this page. That is, the first character of converted corresponds to
* character number actual_x(fileptr->data, start) of the line. */
void edit_add(const filestruct *fileptr, const char *converted,
int yval, size_t start)
{
#ifdef DEBUG
fprintf(stderr, "Painting line %d, current is %d\n", fileptr->lineno,
current->lineno);
#if defined(ENABLE_COLOR) || !defined(NANO_SMALL)
size_t startpos = actual_x(fileptr->data, start);
/* The position in fileptr->data of the leftmost character
* that displays at least partially on the window. */
size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
/* The position in fileptr->data of the first character that is
* completely off the window to the right.
*
* Note that endpos might be beyond the null terminator of the
* string. */
#endif
assert(fileptr != NULL && converted != NULL);
assert(strlen(converted) <= COLS);
/* Just paint the string in any case (we'll add color or reverse on
just the text that needs it */
mvwaddnstr(edit, yval, 0, &fileptr->data[start], COLS);
* just the text that needs it). */
mvwaddstr(edit, yval, 0, converted);
#ifdef ENABLE_COLOR
if (colorstrings != NULL && ISSET(COLOR_SYNTAX)) {
@ -959,16 +1037,16 @@ void edit_add(const filestruct *fileptr, int yval, int start
int x_start;
/* Starting column for mvwaddnstr. Zero-based. */
int paintlen;
/* number of chars to paint on this line. There are COLS
/* Number of chars to paint on this line. There are COLS
* characters on a whole line. */
regmatch_t startmatch; /* match position for start_regexp*/
regmatch_t endmatch; /* match position for end_regexp*/
regmatch_t startmatch; /* match position for start_regexp */
regmatch_t endmatch; /* match position for end_regexp */
if (tmpcolor->bright)
wattron(edit, A_BOLD);
wattron(edit, COLOR_PAIR(tmpcolor->pairnum));
/* Two notes about regexec. Return value 0 means there is a
* match. Also, rm_eo is the first non-matching character
/* Two notes about regexec(). Return value 0 means there is
* 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 (mark_beginbuf->lineno > fileptr->lineno ||
current->lineno > fileptr->lineno)
paintlen = start + COLS;
if (top->lineno < fileptr->lineno || top_x < startpos)
top_x = startpos;
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
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);
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, foo);
free(foo);
waddstr(bottomwin, " ]");
wattroff(bottomwin, A_REVERSE);
wrefresh(bottomwin);
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;
int y = xplustabs();
size_t word_len = strlen(word);
highlight_word =
mallocstrcpy(highlight_word, &current->data[current_x]);
#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;