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
parent
00d4a06cc7
commit
9a9f36fca7
16
src/cut.c
16
src/cut.c
|
@ -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. */
|
||||
|
|
14
src/files.c
14
src/files.c
|
@ -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. */
|
||||
|
|
45
src/nano.c
45
src/nano.c
|
@ -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
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
19
src/text.c
19
src/text.c
|
@ -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". */
|
||||
|
|
15
src/winio.c
15
src/winio.c
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue