softwrap: make the changes to actually allow the chunk width to vary

get_chunk_row() and get_chunk_leftedge() now become wrappers around
get_chunk(); the latter is only used directly in place_the_cursor()
when we need to get both the row and the leftedge.  get_chunk() now
uses the proper formula to implement varying chunk width.

Since chunk width now varies, place_the_cursor() sets the x position
relative to the leftedge in a different way that works regardless
of chunk width, update_softwrapped_line() loops until it gets all
softwrap breakpoints instead of calculating the full length in
advance and getting one full row at a time, the chunk iterators
now count leftedges instead of rows, and fix_firstcolumn() does a
full recalculation of the chunk that firstcolumn is on instead of
simply shifting it back.

Also, in update_softwrapped_line(), when a line's softwrap breakpoint
is before the last column of the edit window, a ">" is now added to
the end of it.

The workaround in place_the_cursor() for when two-column characters
straddle the edge of the screen is removed, as it's no longer needed
now that chunks end before such characters.

Furthermore, do_home() and do_end() use xplustabs() instead of
placewewant again when calculating the leftedge, since placewewant
refers to a column that may or may not be available (if it's not,
the cursor will be placed wrongly).  Make get_edge_and_target() use
xplustabs() instead of placewewant for the same reason; this also lets
us simplify get_edge_and_target(), since xplustabs() will never be
greater than strlenpt().  Finally, since do_end() now has to calculate
rightedge as well as rightedge_x, use the former to implement the same
time-saving optimizations as in do_home().

The cursor is not yet adjusted when we try to go directly to a column
past the end of a softwrap breakpoint, and placewewant handling in the
vertical movement code is not yet adjusted for varying chunk lengths,
but fixes for these are forthcoming.

This fixes https://savannah.gnu.org/bugs/?49440.
master
David Lawrence Ramsey 2017-02-22 12:44:53 -06:00 committed by Benno Schulenberg
parent e375995d98
commit 8490f4acab
2 changed files with 70 additions and 47 deletions

View File

@ -53,13 +53,8 @@ void get_edge_and_target(size_t *leftedge, size_t *target_column)
{
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
size_t realspan = strlenpt(openfile->current->data);
if (realspan > openfile->placewewant)
realspan = openfile->placewewant;
*leftedge = get_chunk_leftedge(openfile->current, realspan);
*target_column = openfile->placewewant % editwincols;
*leftedge = get_chunk_leftedge(openfile->current, xplustabs());
*target_column = openfile->placewewant - *leftedge;
} else
#endif
{
@ -346,15 +341,14 @@ void do_next_word_void(void)
void do_home(bool be_clever)
{
filestruct *was_current = openfile->current;
size_t was_column = openfile->placewewant;
size_t was_column = xplustabs();
bool moved_off_chunk = TRUE;
#ifndef NANO_TINY
bool moved = FALSE;
size_t leftedge_x = 0;
size_t leftedge = 0, leftedge_x = 0;
if (ISSET(SOFTWRAP)) {
size_t leftedge = get_chunk_leftedge(openfile->current, was_column);
leftedge = get_chunk_leftedge(openfile->current, was_column);
leftedge_x = actual_x(openfile->current->data, leftedge);
}
@ -378,11 +372,11 @@ void do_home(bool be_clever)
if (!moved && ISSET(SOFTWRAP)) {
/* If already at the left edge of the screen, move fully home.
* Otherwise, move to the left edge. */
if (was_column % editwincols == 0 && be_clever)
if (openfile->current_x == leftedge_x && be_clever)
openfile->current_x = 0;
else {
openfile->current_x = leftedge_x;
openfile->placewewant = (was_column / editwincols) * editwincols;
openfile->placewewant = leftedge;
moved_off_chunk = FALSE;
}
} else if (!moved)
@ -413,15 +407,26 @@ void do_home_void(void)
void do_end(bool be_clever)
{
filestruct *was_current = openfile->current;
size_t was_column = openfile->placewewant;
size_t was_column = xplustabs();
size_t line_len = strlen(openfile->current->data);
bool moved_off_chunk = TRUE;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool last_chunk;
size_t leftedge = get_chunk_leftedge(openfile->current, was_column);
size_t rightedge_x = actual_x(openfile->current->data,
leftedge + (editwincols - 1));
size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
leftedge,
&last_chunk);
size_t rightedge_x;
/* If we're on the last chunk, we're already at the end of the line.
* Otherwise, we're one column past the end of the line. Shifting
* backwards one column might put us in the middle of a multi-column
* character, but actual_x() will fix that. */
if (!last_chunk)
rightedge--;
rightedge_x = actual_x(openfile->current->data, rightedge);
/* If already at the right edge of the screen, move fully to
* the end of the line. Otherwise, move to the right edge. */
@ -429,12 +434,14 @@ void do_end(bool be_clever)
openfile->current_x = line_len;
else {
openfile->current_x = rightedge_x;
openfile->placewewant = rightedge;
moved_off_chunk = FALSE;
}
} else
#endif
openfile->current_x = line_len;
if (moved_off_chunk)
openfile->placewewant = xplustabs();
/* If we changed chunk, we might be offscreen. Otherwise,

View File

@ -2294,6 +2294,7 @@ void place_the_cursor(bool forreal)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
filestruct *line = openfile->edittop;
size_t leftedge;
row -= get_chunk_row(openfile->edittop, openfile->firstcolumn);
@ -2304,14 +2305,8 @@ void place_the_cursor(bool forreal)
}
/* Add the number of wraps in the current line before the cursor. */
row += get_chunk_row(openfile->current, xpt);
col = xpt % editwincols;
/* If the cursor ought to be in column zero, nudge it there. */
if (forreal && openfile->placewewant % editwincols == 0 && col != 0) {
row++;
col = 0;
}
row += get_chunk(openfile->current, xpt, &leftedge);
col = xpt - leftedge;
} else
#endif
{
@ -2745,10 +2740,10 @@ int update_softwrapped_line(filestruct *fileptr)
/* The first row in the edit window that gets updated. */
size_t from_col = 0;
/* The starting column of the current chunk. */
size_t to_col = 0;
/* To which column a line is displayed. */
char *converted;
/* The data of the chunk with tabs and control characters expanded. */
size_t full_length;
/* The length of the expanded line. */
if (fileptr == openfile->edittop)
from_col = openfile->firstcolumn;
@ -2768,18 +2763,30 @@ int update_softwrapped_line(filestruct *fileptr)
return 0;
}
full_length = strlenpt(fileptr->data);
starting_row = row;
while (from_col <= full_length && row < editwinrows) {
while (row < editwinrows) {
bool end_of_line;
to_col = get_softwrap_breakpoint(fileptr->data, from_col, &end_of_line);
blank_row(edit, row, 0, COLS);
/* Convert the chunk to its displayable form and draw it. */
converted = display_string(fileptr->data, from_col, editwincols, TRUE);
converted = display_string(fileptr->data, from_col, to_col - from_col,
TRUE);
edit_draw(fileptr, converted, row++, from_col);
free(converted);
from_col += editwincols;
if (end_of_line)
break;
/* If the line is softwrapped before its last column, add a ">" just
* after its softwrap breakpoint. */
if (to_col - from_col < editwincols)
mvwaddch(edit, row - 1, to_col - from_col, '>');
from_col = to_col;
}
return (row - starting_row);
@ -2813,12 +2820,13 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
size_t current_chunk = get_chunk_row(*line, *leftedge);
size_t current_leftedge = *leftedge;
/* Recede through the requested number of chunks. */
for (i = nrows; i > 0; i--) {
if (current_chunk > 0) {
current_chunk--;
if (current_leftedge > 0) {
current_leftedge = get_chunk_leftedge(*line,
current_leftedge - 1);
continue;
}
@ -2826,12 +2834,12 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
break;
*line = (*line)->prev;
current_chunk = get_last_chunk_row(*line);
current_leftedge = get_last_chunk_leftedge(*line);
}
/* Only change leftedge when we actually could move. */
if (i < nrows)
*leftedge = current_chunk * editwincols;
*leftedge = current_leftedge;
} else
#endif
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
@ -2854,13 +2862,17 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
size_t current_chunk = get_chunk_row(*line, *leftedge);
size_t last_chunk = get_last_chunk_row(*line);
size_t current_leftedge = *leftedge;
size_t last_leftedge = get_last_chunk_leftedge(*line);
/* Advance through the requested number of chunks. */
for (i = nrows; i > 0; i--) {
if (current_chunk < last_chunk) {
current_chunk++;
if (current_leftedge < last_leftedge) {
bool end_of_line;
current_leftedge = get_softwrap_breakpoint((*line)->data,
current_leftedge,
&end_of_line);
continue;
}
@ -2868,13 +2880,13 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge)
break;
*line = (*line)->next;
current_chunk = 0;
last_chunk = get_last_chunk_row(*line);
current_leftedge = 0;
last_leftedge = get_last_chunk_leftedge(*line);
}
/* Only change leftedge when we actually could move. */
if (i < nrows)
*leftedge = current_chunk * editwincols;
*leftedge = current_leftedge;
} else
#endif
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
@ -3043,14 +3055,18 @@ size_t get_chunk(filestruct *line, size_t column, size_t *leftedge)
* relative to the first row (zero-based). */
size_t get_chunk_row(filestruct *line, size_t column)
{
return strnlenpt(line->data, column) / editwincols;
return get_chunk(line, column, NULL);
}
/* Return the leftmost column of the softwrapped chunk of the given line that
* column is on. */
size_t get_chunk_leftedge(filestruct *line, size_t column)
{
return (strnlenpt(line->data, column) / editwincols) * editwincols;
size_t leftedge;
get_chunk(line, column, &leftedge);
return leftedge;
}
/* Return the row of the last softwrapped chunk of the given line, relative to
@ -3072,8 +3088,8 @@ size_t get_last_chunk_leftedge(filestruct *line)
* has changed, because then the width of softwrapped chunks has changed. */
void ensure_firstcolumn_is_aligned(void)
{
if (openfile->firstcolumn % editwincols != 0)
openfile->firstcolumn -= (openfile->firstcolumn % editwincols);
openfile->firstcolumn = get_chunk_leftedge(openfile->edittop,
openfile->firstcolumn);
/* If smooth scrolling is on, make sure the viewport doesn't center. */
focusing = FALSE;