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
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
size_t realspan = strlenpt(openfile->current->data);
|
*leftedge = get_chunk_leftedge(openfile->current, xplustabs());
|
||||||
|
*target_column = openfile->placewewant - *leftedge;
|
||||||
if (realspan > openfile->placewewant)
|
|
||||||
realspan = openfile->placewewant;
|
|
||||||
|
|
||||||
*leftedge = get_chunk_leftedge(openfile->current, realspan);
|
|
||||||
*target_column = openfile->placewewant % editwincols;
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -346,15 +341,14 @@ void do_next_word_void(void)
|
||||||
void do_home(bool be_clever)
|
void do_home(bool be_clever)
|
||||||
{
|
{
|
||||||
filestruct *was_current = openfile->current;
|
filestruct *was_current = openfile->current;
|
||||||
size_t was_column = openfile->placewewant;
|
size_t was_column = xplustabs();
|
||||||
bool moved_off_chunk = TRUE;
|
bool moved_off_chunk = TRUE;
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
bool moved = FALSE;
|
bool moved = FALSE;
|
||||||
size_t leftedge_x = 0;
|
size_t leftedge = 0, leftedge_x = 0;
|
||||||
|
|
||||||
if (ISSET(SOFTWRAP)) {
|
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);
|
leftedge_x = actual_x(openfile->current->data, leftedge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,11 +372,11 @@ void do_home(bool be_clever)
|
||||||
if (!moved && ISSET(SOFTWRAP)) {
|
if (!moved && ISSET(SOFTWRAP)) {
|
||||||
/* If already at the left edge of the screen, move fully home.
|
/* If already at the left edge of the screen, move fully home.
|
||||||
* Otherwise, move to the left edge. */
|
* 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;
|
openfile->current_x = 0;
|
||||||
else {
|
else {
|
||||||
openfile->current_x = leftedge_x;
|
openfile->current_x = leftedge_x;
|
||||||
openfile->placewewant = (was_column / editwincols) * editwincols;
|
openfile->placewewant = leftedge;
|
||||||
moved_off_chunk = FALSE;
|
moved_off_chunk = FALSE;
|
||||||
}
|
}
|
||||||
} else if (!moved)
|
} else if (!moved)
|
||||||
|
@ -413,15 +407,26 @@ void do_home_void(void)
|
||||||
void do_end(bool be_clever)
|
void do_end(bool be_clever)
|
||||||
{
|
{
|
||||||
filestruct *was_current = openfile->current;
|
filestruct *was_current = openfile->current;
|
||||||
size_t was_column = openfile->placewewant;
|
size_t was_column = xplustabs();
|
||||||
size_t line_len = strlen(openfile->current->data);
|
size_t line_len = strlen(openfile->current->data);
|
||||||
bool moved_off_chunk = TRUE;
|
bool moved_off_chunk = TRUE;
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
|
bool last_chunk;
|
||||||
size_t leftedge = get_chunk_leftedge(openfile->current, was_column);
|
size_t leftedge = get_chunk_leftedge(openfile->current, was_column);
|
||||||
size_t rightedge_x = actual_x(openfile->current->data,
|
size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
|
||||||
leftedge + (editwincols - 1));
|
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
|
/* If already at the right edge of the screen, move fully to
|
||||||
* the end of the line. Otherwise, move to the right edge. */
|
* 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;
|
openfile->current_x = line_len;
|
||||||
else {
|
else {
|
||||||
openfile->current_x = rightedge_x;
|
openfile->current_x = rightedge_x;
|
||||||
|
openfile->placewewant = rightedge;
|
||||||
moved_off_chunk = FALSE;
|
moved_off_chunk = FALSE;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
openfile->current_x = line_len;
|
openfile->current_x = line_len;
|
||||||
|
|
||||||
|
if (moved_off_chunk)
|
||||||
openfile->placewewant = xplustabs();
|
openfile->placewewant = xplustabs();
|
||||||
|
|
||||||
/* If we changed chunk, we might be offscreen. Otherwise,
|
/* 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
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
filestruct *line = openfile->edittop;
|
filestruct *line = openfile->edittop;
|
||||||
|
size_t leftedge;
|
||||||
|
|
||||||
row -= get_chunk_row(openfile->edittop, openfile->firstcolumn);
|
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. */
|
/* Add the number of wraps in the current line before the cursor. */
|
||||||
row += get_chunk_row(openfile->current, xpt);
|
row += get_chunk(openfile->current, xpt, &leftedge);
|
||||||
col = xpt % editwincols;
|
col = xpt - leftedge;
|
||||||
|
|
||||||
/* If the cursor ought to be in column zero, nudge it there. */
|
|
||||||
if (forreal && openfile->placewewant % editwincols == 0 && col != 0) {
|
|
||||||
row++;
|
|
||||||
col = 0;
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -2745,10 +2740,10 @@ int update_softwrapped_line(filestruct *fileptr)
|
||||||
/* The first row in the edit window that gets updated. */
|
/* The first row in the edit window that gets updated. */
|
||||||
size_t from_col = 0;
|
size_t from_col = 0;
|
||||||
/* The starting column of the current chunk. */
|
/* The starting column of the current chunk. */
|
||||||
|
size_t to_col = 0;
|
||||||
|
/* To which column a line is displayed. */
|
||||||
char *converted;
|
char *converted;
|
||||||
/* The data of the chunk with tabs and control characters expanded. */
|
/* 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)
|
if (fileptr == openfile->edittop)
|
||||||
from_col = openfile->firstcolumn;
|
from_col = openfile->firstcolumn;
|
||||||
|
@ -2768,18 +2763,30 @@ int update_softwrapped_line(filestruct *fileptr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
full_length = strlenpt(fileptr->data);
|
|
||||||
starting_row = row;
|
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);
|
blank_row(edit, row, 0, COLS);
|
||||||
|
|
||||||
/* Convert the chunk to its displayable form and draw it. */
|
/* 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);
|
edit_draw(fileptr, converted, row++, from_col);
|
||||||
free(converted);
|
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);
|
return (row - starting_row);
|
||||||
|
@ -2813,12 +2820,13 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
|
||||||
|
|
||||||
#ifndef NANO_TINY
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
size_t current_chunk = get_chunk_row(*line, *leftedge);
|
size_t current_leftedge = *leftedge;
|
||||||
|
|
||||||
/* Recede through the requested number of chunks. */
|
/* Recede through the requested number of chunks. */
|
||||||
for (i = nrows; i > 0; i--) {
|
for (i = nrows; i > 0; i--) {
|
||||||
if (current_chunk > 0) {
|
if (current_leftedge > 0) {
|
||||||
current_chunk--;
|
current_leftedge = get_chunk_leftedge(*line,
|
||||||
|
current_leftedge - 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2826,12 +2834,12 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
*line = (*line)->prev;
|
*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. */
|
/* Only change leftedge when we actually could move. */
|
||||||
if (i < nrows)
|
if (i < nrows)
|
||||||
*leftedge = current_chunk * editwincols;
|
*leftedge = current_leftedge;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
|
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
|
#ifndef NANO_TINY
|
||||||
if (ISSET(SOFTWRAP)) {
|
if (ISSET(SOFTWRAP)) {
|
||||||
size_t current_chunk = get_chunk_row(*line, *leftedge);
|
size_t current_leftedge = *leftedge;
|
||||||
size_t last_chunk = get_last_chunk_row(*line);
|
size_t last_leftedge = get_last_chunk_leftedge(*line);
|
||||||
|
|
||||||
/* Advance through the requested number of chunks. */
|
/* Advance through the requested number of chunks. */
|
||||||
for (i = nrows; i > 0; i--) {
|
for (i = nrows; i > 0; i--) {
|
||||||
if (current_chunk < last_chunk) {
|
if (current_leftedge < last_leftedge) {
|
||||||
current_chunk++;
|
bool end_of_line;
|
||||||
|
|
||||||
|
current_leftedge = get_softwrap_breakpoint((*line)->data,
|
||||||
|
current_leftedge,
|
||||||
|
&end_of_line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2868,13 +2880,13 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
*line = (*line)->next;
|
*line = (*line)->next;
|
||||||
current_chunk = 0;
|
current_leftedge = 0;
|
||||||
last_chunk = get_last_chunk_row(*line);
|
last_leftedge = get_last_chunk_leftedge(*line);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only change leftedge when we actually could move. */
|
/* Only change leftedge when we actually could move. */
|
||||||
if (i < nrows)
|
if (i < nrows)
|
||||||
*leftedge = current_chunk * editwincols;
|
*leftedge = current_leftedge;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
|
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). */
|
* relative to the first row (zero-based). */
|
||||||
size_t get_chunk_row(filestruct *line, size_t column)
|
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
|
/* Return the leftmost column of the softwrapped chunk of the given line that
|
||||||
* column is on. */
|
* column is on. */
|
||||||
size_t get_chunk_leftedge(filestruct *line, size_t column)
|
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
|
/* 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. */
|
* has changed, because then the width of softwrapped chunks has changed. */
|
||||||
void ensure_firstcolumn_is_aligned(void)
|
void ensure_firstcolumn_is_aligned(void)
|
||||||
{
|
{
|
||||||
if (openfile->firstcolumn % editwincols != 0)
|
openfile->firstcolumn = get_chunk_leftedge(openfile->edittop,
|
||||||
openfile->firstcolumn -= (openfile->firstcolumn % editwincols);
|
openfile->firstcolumn);
|
||||||
|
|
||||||
/* If smooth scrolling is on, make sure the viewport doesn't center. */
|
/* If smooth scrolling is on, make sure the viewport doesn't center. */
|
||||||
focusing = FALSE;
|
focusing = FALSE;
|
||||||
|
|
Loading…
Reference in New Issue