nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

commit 9a9f36fca7a728dd2c5b66a0f29b203b638c0e25
parent 00d4a06cc7e321f232e3e2420f70eac542a170b5
Author: Benno Schulenberg <bensberg@telfort.nl>
Date:   Sat,  6 Jun 2020 18:57:17 +0200

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.

Diffstat:
Msrc/cut.c | 16+++++++---------
Msrc/files.c | 14++++++++++++++
Msrc/nano.c | 45++++++++++++++++-----------------------------
Msrc/nano.h | 4++--
Msrc/proto.h | 1+
Msrc/search.c | 4++++
Msrc/text.c | 19++++++++++++++++++-
Msrc/winio.c | 15++++++++-------
8 files changed, 70 insertions(+), 48 deletions(-)

diff --git a/src/cut.c b/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. */ diff --git a/src/files.c b/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. */ diff --git a/src/nano.c b/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 diff --git a/src/nano.h b/src/nano.h @@ -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. */ diff --git a/src/proto.h b/src/proto.h @@ -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); diff --git a/src/search.c b/src/search.c @@ -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); diff --git a/src/text.c b/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". */ diff --git a/src/winio.c b/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. */