indicator: rework how the "scrollbar" is computed when softwrapping

Instead of storing for each line the ordinal number of the first chunk
in that line, simply store the number of extra chunks in the line.

It now takes some more computation to actually draw the scrollbar, but
it saves a lot of computation when just inserting or deleting characters
(when using --softwrap and causing a change in chunk count).

This fixes https://savannah.gnu.org/bugs/?58510.

Bug existed since commit 6bccedb3 from two days ago.
master
Benno Schulenberg 2020-06-06 18:57:17 +02:00
parent 00d4a06cc7
commit 9a9f36fca7
8 changed files with 70 additions and 48 deletions

View File

@ -34,7 +34,7 @@ void do_deletion(undo_type action)
int charlen = char_length(openfile->current->data + openfile->current_x);
size_t line_len = strlen(openfile->current->data + openfile->current_x);
#ifndef NANO_TINY
size_t old_amount = 0;
size_t old_amount = openfile->current->extrarows;
/* If the type of action changed or the cursor moved to a different
* line, create a new undo item, otherwise update the existing item. */
@ -43,20 +43,18 @@ void do_deletion(undo_type action)
add_undo(action, NULL);
else
update_undo(action);
if (ISSET(SOFTWRAP))
old_amount = extra_chunks_in(openfile->current);
#endif
/* Move the remainder of the line "in", over the current character. */
memmove(&openfile->current->data[openfile->current_x],
&openfile->current->data[openfile->current_x + charlen],
line_len - charlen + 1);
#ifndef NANO_TINY
/* When softwrapping and the number of chunks in the current line has
* changed, the chunks must be renumbered and the screen refreshed. */
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount) {
renumber_from(openfile->current);
refresh_needed = TRUE;
/* When softwrapping, recompute the number of chunks in the line,
* and schedule a refresh if the number changed. */
if (ISSET(SOFTWRAP)) {
openfile->current->extrarows = extra_chunks_in(openfile->current);
if (openfile->current->extrarows != old_amount)
refresh_needed = TRUE;
}
/* Adjust the mark if it is after the cursor on the current line. */

View File

@ -356,6 +356,16 @@ bool has_valid_path(const char *filename)
return validity;
}
/* Compute and store how many extra rows each line needs when softwrapping. */
void compute_the_extra_rows_per_line(void)
{
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
for (linestruct *ln = openfile->filetop; ln != NULL; ln = ln->next)
ln->extrarows = extra_chunks_in(ln);
#endif
}
/* This does one of three things. If the filename is "", it just creates
* a new empty buffer. When the filename is not empty, it reads that file
* into a new buffer when requested, otherwise into the existing buffer. */
@ -453,6 +463,8 @@ bool open_buffer(const char *filename, bool new_one)
openfile->placewewant = 0;
}
compute_the_extra_rows_per_line();
#ifdef ENABLE_COLOR
/* If a new buffer was opened, check whether a syntax can be applied. */
if (new_one)
@ -527,6 +539,8 @@ void redecorate_after_switch(void)
* or softwrap mode may have been toggled, so make sure that the
* starting column for the first row gets an appropriate value. */
ensure_firstcolumn_is_aligned();
compute_the_extra_rows_per_line();
#endif
/* Update title bar and multiline info to match the current buffer. */

View File

@ -76,9 +76,7 @@ linestruct *make_new_node(linestruct *prevnode)
#endif
newnode->lineno = (prevnode) ? prevnode->lineno + 1 : 1;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
newnode->chunk_nr = (prevnode) ?
prevnode->chunk_nr + extra_chunks_in(prevnode) + 1 : 1;
newnode->extrarows = -2; /* Bad value, to make it easier to find bugs. */
newnode->has_anchor = FALSE;
#endif
@ -154,7 +152,7 @@ linestruct *copy_node(const linestruct *src)
#endif
dst->lineno = src->lineno;
#ifndef NANO_TINY
dst->chunk_nr = src->chunk_nr;
dst->extrarows = src->extrarows;
dst->has_anchor = FALSE;
#endif
@ -190,21 +188,8 @@ void renumber_from(linestruct *line)
{
ssize_t number = (line->prev == NULL) ? 0 : line->prev->lineno;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP) && line->prev == NULL) {
line->lineno = ++number;
line->chunk_nr = 1;
line = line->next;
}
#endif
while (line != NULL) {
line->lineno = ++number;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
line->chunk_nr = line->prev->chunk_nr +
extra_chunks_in(line->prev) + 1;
#endif
line = line->next;
}
}
@ -1095,7 +1080,7 @@ void do_toggle(int flag)
break;
case SOFTWRAP:
if (ISSET(SOFTWRAP))
renumber_from(openfile->filetop);
compute_the_extra_rows_per_line();
else
openfile->firstcolumn = 0;
refresh_needed = TRUE;
@ -1426,12 +1411,12 @@ void inject(char *burst, size_t count)
linestruct *thisline = openfile->current;
size_t datalen = strlen(thisline->data);
#ifndef NANO_TINY
size_t original_row = 0, old_amount = 0;
size_t old_amount = openfile->current->extrarows;
size_t original_row = 0;
if (ISSET(SOFTWRAP)) {
if (openfile->current_y == editwinrows - 1)
original_row = chunk_for(xplustabs(), thisline);
old_amount = extra_chunks_in(thisline);
}
#endif
@ -1492,15 +1477,17 @@ void inject(char *burst, size_t count)
#endif
#ifndef NANO_TINY
/* If we were on the last row of the edit window and moved to a new chunk,
* or if the number of chunks that the current softwrapped line occupies
* changed, we need a full refresh. */
if (ISSET(SOFTWRAP) && ((openfile->current_y == editwinrows - 1 &&
chunk_for(xplustabs(), openfile->current) > original_row) ||
extra_chunks_in(openfile->current) != old_amount)) {
renumber_from(openfile->current);
refresh_needed = TRUE;
focusing = FALSE;
/* When softwrapping and the number of chunks in the current line changed,
* or we were on the last row of the edit window and moved to a new chunk,
* we need a full refresh. */
if (ISSET(SOFTWRAP)) {
openfile->current->extrarows = extra_chunks_in(openfile->current);
if (openfile->current->extrarows != old_amount ||
(openfile->current_y == editwinrows - 1 &&
chunk_for(xplustabs(), openfile->current) > original_row)) {
refresh_needed = TRUE;
focusing = FALSE;
}
}
#endif

View File

@ -285,8 +285,8 @@ typedef struct linestruct {
ssize_t lineno;
/* The number of this line. */
#ifndef NANO_TINY
ssize_t chunk_nr;
/* The ordinal number of the first chunk in this line. */
ssize_t extrarows;
/* The extra rows that this line occupies when softwrapping. */
#endif
struct linestruct *next;
/* Next node. */

View File

@ -283,6 +283,7 @@ void make_new_buffer(void);
#ifndef NANO_TINY
bool delete_lockfile(const char *lockfilename);
#endif
void compute_the_extra_rows_per_line(void);
bool open_buffer(const char *filename, bool new_buffer);
void set_modified(void);
void prepare_for_display(void);

View File

@ -654,6 +654,10 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
free(openfile->current->data);
openfile->current->data = copy;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
openfile->current->extrarows = extra_chunks_in(openfile->current);
#endif
#ifdef ENABLE_COLOR
/* Check whether the replacement requires a change in the coloring. */
check_the_multis(openfile->current);

View File

@ -102,6 +102,9 @@ void indent_a_line(linestruct *line, char *indentation)
openfile->totsize += indent_len;
if (ISSET(SOFTWRAP))
line->extrarows = extra_chunks_in(line);
/* Compensate for the change in the current line. */
if (line == openfile->mark && openfile->mark_x > 0)
openfile->mark_x += indent_len;
@ -230,6 +233,9 @@ void unindent_a_line(linestruct *line, size_t indent_len)
openfile->totsize -= indent_len;
if (ISSET(SOFTWRAP))
line->extrarows = extra_chunks_in(line);
/* Adjust the positions of mark and cursor, when they are affected. */
compensate_leftward(line, indent_len);
}
@ -418,8 +424,13 @@ void do_comment(void)
/* Comment/uncomment each of the selected lines when possible, and
* store undo data when a line changed. */
for (line = top; line != bot->next; line = line->next) {
if (comment_line(action, line, comment_seq))
if (comment_line(action, line, comment_seq)) {
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
line->extrarows = extra_chunks_in(line);
#endif
update_multiline_undo(line->lineno, "");
}
}
set_modified();
@ -660,6 +671,9 @@ void do_undo(void)
openfile->mark = NULL;
openfile->placewewant = xplustabs();
if (ISSET(SOFTWRAP))
openfile->current->extrarows = extra_chunks_in(openfile->current);
openfile->totsize = u->wassize;
/* When at the point where the file was last saved, unset "Modified". */
@ -818,6 +832,9 @@ void do_redo(void)
openfile->mark = NULL;
openfile->placewewant = xplustabs();
if (ISSET(SOFTWRAP))
openfile->current->extrarows = extra_chunks_in(openfile->current);
openfile->totsize = u->newsize;
/* When at the point where the file was last saved, unset "Modified". */

View File

@ -2957,10 +2957,12 @@ void draw_scrollbar(void)
int first_row = openfile->edittop->lineno;
if (ISSET(SOFTWRAP)) {
totalrows = openfile->filebot->chunk_nr +
extra_chunks_in(openfile->filebot);
first_row = openfile->edittop->chunk_nr +
chunk_for(openfile->firstcolumn, openfile->edittop);
for (linestruct *ln = openfile->filetop; ln != openfile->edittop; ln = ln->next)
first_row += ln->extrarows;
first_row += chunk_for(openfile->firstcolumn, openfile->edittop);
for (linestruct *ln = openfile->filetop; ln != NULL; ln = ln->next)
totalrows += ln->extrarows;
}
int lowest = ((first_row - 1) * editwinrows) / totalrows;
@ -3142,11 +3144,10 @@ size_t leftedge_for(size_t column, linestruct *line)
* has changed, because then the width of softwrapped chunks has changed. */
void ensure_firstcolumn_is_aligned(void)
{
if (ISSET(SOFTWRAP)) {
if (ISSET(SOFTWRAP))
openfile->firstcolumn = leftedge_for(openfile->firstcolumn,
openfile->edittop);
renumber_from(openfile->filetop);
} else
else
openfile->firstcolumn = 0;
/* If smooth scrolling is on, make sure the viewport doesn't center. */