commit 8490f4acab53ed38c3b083871654a073e293e02c
parent e375995d98bbb6313b16220e7ecd34ac1a54e3c4
Author: David Lawrence Ramsey <pooka109@gmail.com>
Date: Wed, 22 Feb 2017 12:44:53 -0600
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.
Diffstat:
M | src/move.c | | | 41 | ++++++++++++++++++++++++----------------- |
M | src/winio.c | | | 76 | ++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
2 files changed, 70 insertions(+), 47 deletions(-)
diff --git 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
@@ -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;