From 8490f4acab53ed38c3b083871654a073e293e02c Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Wed, 22 Feb 2017 12:44:53 -0600 Subject: [PATCH] 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. --- src/move.c | 41 +++++++++++++++++------------ src/winio.c | 76 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/src/move.c b/src/move.c index 69181b45..883e41b3 100644 --- a/src/move.c +++ b/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,13 +434,15 @@ 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; - openfile->placewewant = xplustabs(); + if (moved_off_chunk) + openfile->placewewant = xplustabs(); /* If we changed chunk, we might be offscreen. Otherwise, * update current if the mark is on or we changed "page". */ diff --git a/src/winio.c b/src/winio.c index df571583..e1adccb1 100644 --- a/src/winio.c +++ b/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;