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
parent
e375995d98
commit
8490f4acab
39
src/move.c
39
src/move.c
|
@ -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,
|
||||
|
|
76
src/winio.c
76
src/winio.c
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue