softwrap: avoid time-consuming computations, to burden large files less

Whenever softwrap was toggled on or line numbers were toggled on/off or
the window was resized, the extra rows per line needed to be recomputed
for ALL the lines.  For large files with many long lines this was too
costly.

(This change causes the indicator to have an incorrect size when there
are many softwrapped chunks onscreen, but that will be addressed later.)

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

Problem existed since version 5.0, since the indicator was introduced.
This commit is contained in:
Benno Schulenberg 2021-04-21 16:27:36 +02:00
parent bb81932422
commit 49d8b99e4f
9 changed files with 7 additions and 88 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 = openfile->current->extrarows;
size_t old_amount = extra_chunks_in(openfile->current);
/* If the type of action changed or the cursor moved to a different
* line, create a new undo item, otherwise update the existing item. */
@ -52,8 +52,7 @@ void do_deletion(undo_type action)
/* 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)
if (extra_chunks_in(openfile->current) != old_amount)
refresh_needed = TRUE;
}
@ -94,10 +93,6 @@ void do_deletion(undo_type action)
unlink_node(joining);
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
openfile->current->extrarows = extra_chunks_in(openfile->current);
#endif
/* Two lines were joined, so do a renumbering and refresh the screen. */
renumber_from(openfile->current);
refresh_needed = TRUE;
@ -336,9 +331,6 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
#ifndef NANO_TINY
openfile->current->has_anchor = was_anchored;
if (ISSET(SOFTWRAP))
openfile->current->extrarows = extra_chunks_in(openfile->current);
if (post_marked || same_line)
openfile->mark = openfile->current;
if (post_marked)
@ -391,10 +383,6 @@ void ingraft_buffer(linestruct *topline)
}
if (topline != botline) {
#ifndef NANO_TINY
/* First compute the softwrapped chunks for each line in the graft. */
compute_the_extra_rows_per_line_from(topline);
#endif
/* When inserting at end-of-buffer, update the relevant pointer. */
if (line->next == NULL)
openfile->filebot = botline;
@ -427,11 +415,6 @@ void ingraft_buffer(linestruct *topline)
openfile->mark_x += length - xpos;
} else if (mark_follows)
openfile->mark_x += extralen;
if (ISSET(SOFTWRAP)) {
line->extrarows = extra_chunks_in(line);
openfile->current->extrarows = extra_chunks_in(openfile->current);
}
#endif
delete_node(topline);

View File

@ -438,10 +438,6 @@ typedef struct linestruct {
/* The text of this line. */
ssize_t lineno;
/* The number of this line. */
#ifndef NANO_TINY
ssize_t extrarows;
/* The extra rows that this line occupies when softwrapping. */
#endif
struct linestruct *next;
/* Next node. */
struct linestruct *prev;

View File

@ -545,9 +545,8 @@ void redecorate_after_switch(void)
#ifndef NANO_TINY
/* While in a different buffer, the effective width of the screen may
* have changed, so make sure that the softwrapped chunks per line and
* have changed, so make sure that
* the starting column for the first row get corresponding values. */
compute_the_extra_rows_per_line_from(openfile->filetop);
ensure_firstcolumn_is_aligned();
#endif

View File

@ -76,7 +76,6 @@ linestruct *make_new_node(linestruct *prevnode)
#endif
newnode->lineno = (prevnode) ? prevnode->lineno + 1 : 1;
#ifndef NANO_TINY
newnode->extrarows = -2; /* Bad value, to make it easier to find bugs. */
newnode->has_anchor = FALSE;
#endif
@ -152,7 +151,6 @@ linestruct *copy_node(const linestruct *src)
#endif
dst->lineno = src->lineno;
#ifndef NANO_TINY
dst->extrarows = src->extrarows;
dst->has_anchor = FALSE;
#endif
@ -1006,14 +1004,6 @@ void handle_sigwinch(int signal)
the_window_resized = TRUE;
}
/* Compute and store how many extra rows each line needs when softwrapping. */
void compute_the_extra_rows_per_line_from(linestruct *fromline)
{
if (ISSET(SOFTWRAP))
for (linestruct *line = fromline; line != NULL; line = line->next)
line->extrarows = extra_chunks_in(line);
}
/* Reinitialize and redraw the screen completely. */
void regenerate_screen(void)
{
@ -1056,7 +1046,6 @@ void regenerate_screen(void)
/* If we have an open buffer, redraw the contents of the subwindows. */
if (openfile) {
compute_the_extra_rows_per_line_from(openfile->filetop);
ensure_firstcolumn_is_aligned();
draw_all_subwindows();
}
@ -1082,9 +1071,7 @@ void do_toggle(int flag)
break;
#endif
case SOFTWRAP:
if (ISSET(SOFTWRAP))
compute_the_extra_rows_per_line_from(openfile->filetop);
else
if (!ISSET(SOFTWRAP))
openfile->firstcolumn = 0;
refresh_needed = TRUE;
break;
@ -1246,9 +1233,7 @@ void confirm_margin(void)
editwincols = COLS - margin - thebar;
#ifndef NANO_TINY
/* Recompute the softwrapped chunks for each line in the buffer,
* and ensure a proper starting column for the first screen row. */
compute_the_extra_rows_per_line_from(openfile->filetop);
/* Ensure a proper starting column for the first screen row. */
ensure_firstcolumn_is_aligned();
focusing = keep_focus;
#endif
@ -1414,7 +1399,7 @@ void inject(char *burst, size_t count)
linestruct *thisline = openfile->current;
size_t datalen = strlen(thisline->data);
#ifndef NANO_TINY
size_t old_amount = openfile->current->extrarows;
size_t old_amount = extra_chunks_in(openfile->current);
size_t original_row = 0;
if (ISSET(SOFTWRAP)) {
@ -1484,8 +1469,7 @@ void inject(char *burst, size_t count)
* 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 ||
if (extra_chunks_in(openfile->current) != old_amount ||
(openfile->current_y == editwinrows - 1 &&
chunk_for(xplustabs(), openfile->current) > original_row)) {
refresh_needed = TRUE;

View File

@ -409,7 +409,6 @@ void block_sigwinch(bool blockit);
#endif
#ifndef NANO_TINY
void handle_sigwinch(int signal);
void compute_the_extra_rows_per_line_from(linestruct *fromline);
void regenerate_screen(void);
void do_toggle(int flag);
#endif

View File

@ -665,10 +665,6 @@ 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
set_modified();
as_an_at = TRUE;
numreplaced++;

View File

@ -103,9 +103,6 @@ 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;
@ -234,9 +231,6 @@ 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);
}
@ -426,10 +420,6 @@ void do_comment(void)
* store undo data when a line changed. */
for (line = top; line != bot->next; line = line->next) {
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, "");
}
}
@ -573,8 +563,6 @@ void do_undo(void)
break;
}
line->data[u->tail_x] = '\0';
if (ISSET(SOFTWRAP))
line->extrarows = extra_chunks_in(line);
intruder = make_new_node(line);
intruder->data = copy_of(u->strdata);
splice_node(line, intruder);
@ -676,9 +664,6 @@ 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". */
@ -725,8 +710,6 @@ void do_redo(void)
case ENTER:
redidmsg = _("line break");
line->data[u->head_x] = '\0';
if (ISSET(SOFTWRAP))
line->extrarows = extra_chunks_in(line);
intruder = make_new_node(line);
intruder->data = copy_of(u->strdata);
splice_node(line, intruder);
@ -841,9 +824,6 @@ 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". */
@ -907,11 +887,6 @@ void do_enter(void)
openfile->mark = newnode;
openfile->mark_x += extra - openfile->current_x;
}
if (ISSET(SOFTWRAP)) {
openfile->current->extrarows = extra_chunks_in(openfile->current);
newnode->extrarows = extra_chunks_in(newnode);
}
#endif
/* Insert the newly created line after the current one and renumber. */

View File

@ -429,9 +429,6 @@ void new_magicline(void)
openfile->filebot->next = make_new_node(openfile->filebot);
openfile->filebot->next->data = copy_of("");
openfile->filebot = openfile->filebot->next;
#ifndef NANO_TINY
openfile->filebot->extrarows = 0;
#endif
openfile->totsize++;
}

View File

@ -3057,16 +3057,6 @@ void draw_scrollbar(void)
{
int totalrows = openfile->filebot->lineno;
int first_row = openfile->edittop->lineno;
if (ISSET(SOFTWRAP)) {
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;
int highest = lowest + (editwinrows * editwinrows) / totalrows;