Skip to content

Commit

Permalink
Merge pull request neovim#26813 from VanaIgr/screen-pos-speedup
Browse files Browse the repository at this point in the history
perf: make screen size and position calculations more efficient

N/A patches for version.c:
vim-patch:9.1.0037: Calling get_breakindent_win() repeatedly when computing virtcol
vim-patch:9.1.0038: Unnecessary loop in getvcol()
  • Loading branch information
zeertzjq authored Jan 22, 2024
2 parents a25aeee + fd08de4 commit 8c6de91
Show file tree
Hide file tree
Showing 16 changed files with 1,104 additions and 556 deletions.
2 changes: 2 additions & 0 deletions runtime/doc/news.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ The following new APIs and features were added.
• Treesitter highlighting now parses injections incrementally during
screen redraws only for the line range being rendered. This significantly
improves performance in large files with many injections.
'breakindent' performance is significantly improved for wrapped lines.
• Cursor movement, insertion with [count] and |screenpos()| are now faster.

|vim.iter()| provides a generic iterator interface for tables and Lua
iterators |for-in|.
Expand Down
1 change: 1 addition & 0 deletions src/nvim/arabic.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ bool arabic_maycombine(int two)
}

/// Check whether we are dealing with Arabic combining characters.
/// Returns false for negative values.
/// Note: these are NOT really composing characters!
///
/// @param one First character.
Expand Down
21 changes: 11 additions & 10 deletions src/nvim/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,18 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a
}
}

chartabsize_T cts;
init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line);
while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL) {
// Count a tab for what it's worth (if list mode not on)
csize = win_lbr_chartabsize(&cts, &head);
MB_PTR_ADV(cts.cts_ptr);
cts.cts_vcol += csize;
CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, curwin, pos->lnum, line);
StrCharInfo ci = utf_ptr2StrCharInfo(line);
col = 0;
while (col <= wcol && *ci.ptr != NUL) {
CharSize cs = win_charsize(cstype, col, ci.ptr, ci.chr.value, &arg);
csize = cs.width;
head = cs.head;
col += cs.width;
ci = utfc_next(ci);
}
col = cts.cts_vcol;
idx = (int)(cts.cts_ptr - line);
clear_chartabsize_arg(&cts);
idx = (int)(ci.ptr - line);

// Handle all the special cases. The virtual_active() check
// is needed to ensure that a virtual position off the end of
Expand Down
48 changes: 24 additions & 24 deletions src/nvim/drawline.c
Original file line number Diff line number Diff line change
Expand Up @@ -1336,30 +1336,30 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s

if (start_col > 0 && col_rows == 0) {
char *prev_ptr = ptr;
chartabsize_T cts;
int charsize = 0;
int head = 0;

init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr);
cts.cts_max_head_vcol = start_col;
while (cts.cts_vcol < start_col && *cts.cts_ptr != NUL) {
head = 0;
charsize = win_lbr_chartabsize(&cts, &head);
cts.cts_vcol += charsize;
prev_ptr = cts.cts_ptr;
MB_PTR_ADV(cts.cts_ptr);
CharSize cs = { 0 };

CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, wp, lnum, line);
arg.max_head_vcol = start_col;
int vcol = wlv.vcol;
StrCharInfo ci = utf_ptr2StrCharInfo(ptr);
while (vcol < start_col && *ci.ptr != NUL) {
cs = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &arg);
vcol += cs.width;
prev_ptr = ci.ptr;
ci = utfc_next(ci);
if (wp->w_p_list) {
in_multispace = *prev_ptr == ' ' && (*cts.cts_ptr == ' '
in_multispace = *prev_ptr == ' ' && (*ci.ptr == ' '
|| (prev_ptr > line && prev_ptr[-1] == ' '));
if (!in_multispace) {
multispace_pos = 0;
} else if (cts.cts_ptr >= line + leadcol
} else if (ci.ptr >= line + leadcol
&& wp->w_p_lcs_chars.multispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
} else if (cts.cts_ptr < line + leadcol
} else if (ci.ptr < line + leadcol
&& wp->w_p_lcs_chars.leadmultispace != NULL) {
multispace_pos++;
if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
Expand All @@ -1368,9 +1368,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
}
}
}
wlv.vcol = cts.cts_vcol;
ptr = cts.cts_ptr;
clear_chartabsize_arg(&cts);
wlv.vcol = vcol;
ptr = ci.ptr;
int charsize = cs.width;
int head = cs.head;

// When:
// - 'cuc' is set, or
Expand Down Expand Up @@ -2081,13 +2082,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
&& vim_isbreak(mb_c) && !vim_isbreak((uint8_t)(*ptr))) {
int mb_off = utf_head_off(line, ptr - 1);
char *p = ptr - (mb_off + 1);
chartabsize_T cts;

init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p);
// do not want virtual text to be counted here
cts.cts_has_virt_text = false;
wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
clear_chartabsize_arg(&cts);
CharsizeArg arg;
// lnum == 0, do not want virtual text to be counted here
CSType cstype = init_charsize_arg(&arg, wp, 0, line);
wlv.n_extra = win_charsize(cstype, wlv.vcol, p, utf_ptr2CharInfo(p).value,
&arg).width - 1;

if (on_last_col && mb_c != TAB) {
// Do not continue search/match highlighting over the
Expand Down
91 changes: 44 additions & 47 deletions src/nvim/edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1679,33 +1679,37 @@ void change_indent(int type, int amount, int round, int replaced, bool call_chan
} else {
// Compute the screen column where the cursor should be.
vcol = get_indent() - vcol;
curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
int const end_vcol = (colnr_T)((vcol < 0) ? 0 : vcol);
curwin->w_virtcol = end_vcol;

// Advance the cursor until we reach the right screen column.
int last_vcol = 0;
char *ptr = get_cursor_line_ptr();
chartabsize_T cts;
init_chartabsize_arg(&cts, curwin, 0, 0, ptr, ptr);
while (cts.cts_vcol <= (int)curwin->w_virtcol) {
last_vcol = cts.cts_vcol;
if (cts.cts_vcol > 0) {
MB_PTR_ADV(cts.cts_ptr);
}
if (*cts.cts_ptr == NUL) {
break;
new_cursor_col = 0;
char *const line = get_cursor_line_ptr();
vcol = 0;
if (*line != NUL) {
CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, curwin, 0, line);
StrCharInfo ci = utf_ptr2StrCharInfo(line);
while (true) {
int next_vcol = vcol + win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &arg).width;
if (next_vcol > end_vcol) {
break;
}
vcol = next_vcol;
ci = utfc_next(ci);
if (*ci.ptr == NUL) {
break;
}
}
cts.cts_vcol += lbr_chartabsize(&cts);
new_cursor_col = (int)(ci.ptr - line);
}
vcol = last_vcol;
new_cursor_col = (int)(cts.cts_ptr - cts.cts_line);
clear_chartabsize_arg(&cts);

// May need to insert spaces to be able to position the cursor on
// the right screen column.
if (vcol != (int)curwin->w_virtcol) {
curwin->w_cursor.col = (colnr_T)new_cursor_col;
size_t i = (size_t)(curwin->w_virtcol - vcol);
ptr = xmallocz(i);
char *ptr = xmallocz(i);
memset(ptr, ' ', i);
new_cursor_col += (int)i;
ins_str(ptr);
Expand Down Expand Up @@ -4347,14 +4351,16 @@ static bool ins_tab(void)
getvcol(curwin, cursor, &want_vcol, NULL, NULL);

char *tab = "\t";
chartabsize_T cts;
init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab);
int32_t tab_v = (uint8_t)(*tab);

CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, curwin, 0, tab);

// Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
// and 'linebreak' adding extra virtual columns.
while (ascii_iswhite(*ptr)) {
int i = lbr_chartabsize(&cts);
if (cts.cts_vcol + i > want_vcol) {
int i = win_charsize(cstype, vcol, tab, tab_v, &arg).width;
if (vcol + i > want_vcol) {
break;
}
if (*ptr != TAB) {
Expand All @@ -4369,23 +4375,18 @@ static bool ins_tab(void)
}
fpos.col++;
ptr++;
cts.cts_vcol += i;
vcol += i;
}
vcol = cts.cts_vcol;
clear_chartabsize_arg(&cts);

if (change_col >= 0) {
int repl_off = 0;
// Skip over the spaces we need.
init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, ptr);
while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ') {
cts.cts_vcol += lbr_chartabsize(&cts);
cts.cts_ptr++;
cstype = init_charsize_arg(&arg, curwin, 0, ptr);
while (vcol < want_vcol && *ptr == ' ') {
vcol += win_charsize(cstype, vcol, ptr, (uint8_t)(' '), &arg).width;
ptr++;
repl_off++;
}
ptr = cts.cts_ptr;
vcol = cts.cts_vcol;
clear_chartabsize_arg(&cts);

if (vcol > want_vcol) {
// Must have a char with 'showbreak' just before it.
Expand Down Expand Up @@ -4556,33 +4557,29 @@ static int ins_digraph(void)
// Returns the char to be inserted, or NUL if none found.
int ins_copychar(linenr_T lnum)
{
char *ptr;

if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
vim_beep(BO_COPY);
return NUL;
}

// try to advance to the cursor column
validate_virtcol();
int const end_vcol = curwin->w_virtcol;
char *line = ml_get(lnum);
char *prev_ptr = line;

chartabsize_T cts;
init_chartabsize_arg(&cts, curwin, lnum, 0, line, line);
while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL) {
prev_ptr = cts.cts_ptr;
cts.cts_vcol += lbr_chartabsize_adv(&cts);
}

if (cts.cts_vcol > curwin->w_virtcol) {
ptr = prev_ptr;
} else {
ptr = cts.cts_ptr;
CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, curwin, lnum, line);
StrCharInfo ci = utf_ptr2StrCharInfo(line);
int vcol = 0;
while (vcol < end_vcol && *ci.ptr != NUL) {
vcol += win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &arg).width;
if (vcol > end_vcol) {
break;
}
ci = utfc_next(ci);
}
clear_chartabsize_arg(&cts);

int c = utf_ptr2char(ptr);
int c = ci.chr.value < 0 ? (uint8_t)(*ci.ptr) : ci.chr.value;
if (c == NUL) {
vim_beep(BO_COPY);
}
Expand Down
22 changes: 12 additions & 10 deletions src/nvim/getchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -2502,20 +2502,22 @@ static int vgetorpeek(bool advance)
// we are expecting to truncate the trailing
// white-space, so find the last non-white
// character -- webb
if (did_ai
&& *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) {
if (did_ai && *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) {
curwin->w_wcol = 0;
ptr = get_cursor_line_ptr();
chartabsize_T cts;
init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0, ptr, ptr);
while (cts.cts_ptr < ptr + curwin->w_cursor.col) {
if (!ascii_iswhite(*cts.cts_ptr)) {
curwin->w_wcol = cts.cts_vcol;
char *endptr = ptr + curwin->w_cursor.col;

CharsizeArg arg;
CSType cstype = init_charsize_arg(&arg, curwin, curwin->w_cursor.lnum, ptr);
StrCharInfo ci = utf_ptr2StrCharInfo(ptr);
int vcol = 0;
while (ci.ptr < endptr) {
if (!ascii_iswhite(ci.chr.value)) {
curwin->w_wcol = vcol;
}
cts.cts_vcol += lbr_chartabsize(&cts);
cts.cts_ptr += utfc_ptr2len(cts.cts_ptr);
vcol += win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &arg).width;
ci = utfc_next(ci);
}
clear_chartabsize_arg(&cts);

curwin->w_wrow = curwin->w_cline_row
+ curwin->w_wcol / curwin->w_width_inner;
Expand Down
Loading

0 comments on commit 8c6de91

Please sign in to comment.