Skip to content

Commit

Permalink
perf: cache breakindent/showbreak width in win_lbr_chartabsize
Browse files Browse the repository at this point in the history
breakindent was recomputed on every call to win_lbr_charbabsize() when the character
is past the end of the first row of a wrapped line. Even though the function for computing
breakindent cached the last result, reusing the cached value required strcmp of the cached line with the given line.
  • Loading branch information
vanaigr committed Jan 19, 2024
1 parent 77c3d66 commit a9c551e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 34 deletions.
5 changes: 2 additions & 3 deletions src/nvim/drawline.c
Original file line number Diff line number Diff line change
Expand Up @@ -2083,9 +2083,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
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;
// lnum == 0, do not want virtual text to be counted here
init_chartabsize_arg(&cts, wp, 0, wlv.vcol, line, p);
wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
clear_chartabsize_arg(&cts);

Expand Down
64 changes: 37 additions & 27 deletions src/nvim/plines.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ void win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
cts->cts_vcol += win_lbr_chartabsize(cts, NULL);
}
// check for inline virtual text after the end of the line
if (len == MAXCOL && cts->cts_has_virt_text && *cts->cts_ptr == NUL) {
win_lbr_chartabsize(cts, NULL);
if (len == MAXCOL && cts->virt_row >= 0 && *cts->cts_ptr == NUL) {
(void)win_lbr_chartabsize(cts, NULL);
cts->cts_vcol += cts->cts_cur_text_width_left + cts->cts_cur_text_width_right;
}
}
Expand All @@ -129,14 +129,14 @@ void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T
cts->cts_max_head_vcol = 0;
cts->cts_cur_text_width_left = 0;
cts->cts_cur_text_width_right = 0;
cts->cts_has_virt_text = false;
cts->cts_row = lnum - 1;
cts->virt_row = -1;
cts->indent_width = INT_MIN;

if (cts->cts_row >= 0 && wp->w_buffer->b_virt_text_inline > 0) {
marktree_itr_get(wp->w_buffer->b_marktree, cts->cts_row, 0, cts->cts_iter);
if (lnum > 0 && wp->w_buffer->b_virt_text_inline > 0) {
marktree_itr_get(wp->w_buffer->b_marktree, lnum - 1, 0, cts->cts_iter);
MTKey mark = marktree_itr_current(cts->cts_iter);
if (mark.pos.row == cts->cts_row) {
cts->cts_has_virt_text = true;
if (mark.pos.row == lnum - 1) {
cts->virt_row = lnum - 1;
}
}
}
Expand All @@ -154,7 +154,7 @@ void clear_chartabsize_arg(chartabsize_T *cts)
int lbr_chartabsize(chartabsize_T *cts)
{
if (!curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL
&& !curwin->w_p_bri && !cts->cts_has_virt_text) {
&& !curwin->w_p_bri && cts->virt_row < 0) {
if (curwin->w_p_wrap) {
return win_nolbr_chartabsize(cts, NULL);
}
Expand Down Expand Up @@ -199,9 +199,11 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
cts->cts_cur_text_width_left = 0;
cts->cts_cur_text_width_right = 0;

char *const sbr = get_showbreak_value(wp);

// No 'linebreak', 'showbreak' and 'breakindent': return quickly.
if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL
&& !cts->cts_has_virt_text) {
if (!wp->w_p_lbr && !wp->w_p_bri && *sbr == NUL
&& cts->virt_row < 0) {
if (wp->w_p_wrap) {
return win_nolbr_chartabsize(cts, headp);
}
Expand All @@ -217,12 +219,12 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
}
bool is_doublewidth = size == 2 && MB_BYTE2LEN((uint8_t)(*s)) > 1;

if (cts->cts_has_virt_text) {
if (cts->virt_row >= 0) {
int tab_size = size;
int col = (int)(s - line);
while (true) {
MTKey mark = marktree_itr_current(cts->cts_iter);
if (mark.pos.row != cts->cts_row || mark.pos.col > col) {
if (mark.pos.row != cts->virt_row || mark.pos.col > col) {
break;
} else if (mark.pos.col == col) {
if (!mt_end(mark) && mark.flags & (MT_FLAG_DECOR_VIRT_TEXT_INLINE)) {
Expand Down Expand Up @@ -260,7 +262,6 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// May have to add something for 'breakindent' and/or 'showbreak'
// string at the start of a screen line.
int head = mb_added;
char *const sbr = get_showbreak_value(wp);
// When "size" is 0, no new screen line is started.
if (size > 0 && wp->w_p_wrap && (*sbr != NUL || wp->w_p_bri)) {
int col_off_prev = win_col_off(wp);
Expand All @@ -277,11 +278,16 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
if (wcol >= width2 && width2 > 0) {
wcol %= width2;
}
if (*sbr != NUL) {
head_prev += vim_strsize(sbr);
}
if (wp->w_p_bri) {
head_prev += get_breakindent_win(wp, line);
head_prev = cts->indent_width;
if (head_prev == INT_MIN) {
head_prev = 0;
if (*sbr != NUL) {
head_prev += vim_strsize(sbr);
}
if (wp->w_p_bri) {
head_prev += get_breakindent_win(wp, line);
}
cts->indent_width = head_prev;
}
if (wcol < head_prev) {
head_prev -= wcol;
Expand All @@ -298,12 +304,16 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)

if (wcol + size > wp->w_width) {
// cells taken by 'showbreak'/'breakindent' halfway current char
int head_mid = 0;
if (*sbr != NUL) {
head_mid += vim_strsize(sbr);
}
if (wp->w_p_bri) {
head_mid += get_breakindent_win(wp, line);
int head_mid = cts->indent_width;
if (head_mid == INT_MIN) {
head_mid = 0;
if (*sbr != NUL) {
head_mid += vim_strsize(sbr);
}
if (wp->w_p_bri) {
head_mid += get_breakindent_win(wp, line);
}
cts->indent_width = head_mid;
}
if (head_mid > 0 && wcol + size > wp->w_width_inner) {
// Calculate effective window width.
Expand Down Expand Up @@ -520,7 +530,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
&& !wp->w_p_lbr
&& *get_showbreak_value(wp) == NUL
&& !wp->w_p_bri
&& !cts.cts_has_virt_text) {
&& cts.virt_row < 0) {
while (true) {
head = 0;
int c = (uint8_t)(*ptr);
Expand Down Expand Up @@ -800,7 +810,7 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
char *s = ml_get_buf(wp->w_buffer, lnum);
chartabsize_T cts;
init_chartabsize_arg(&cts, wp, lnum, 0, s, s);
if (*s == NUL && !cts.cts_has_virt_text) {
if (*s == NUL && cts.virt_row < 0) {
return 1; // be quick for an empty line
}
win_linetabsize_cts(&cts, (colnr_T)MAXCOL);
Expand Down
9 changes: 5 additions & 4 deletions src/nvim/plines.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ typedef struct {
win_T *cts_win;
char *cts_line; ///< start of the line
char *cts_ptr; ///< current position in line
int cts_row;
int cts_vcol; ///< virtual column at current position
int indent_width; ///< width of showbreak and breakindent on wrapped lines
/// INT_MIN if not yet calculated

bool cts_has_virt_text; ///< true if if there is inline virtual text
int virt_row; ///< line number, -1 if no virtual text
int cts_cur_text_width_left; ///< width of virtual text left of cursor
int cts_cur_text_width_right; ///< width of virtual text right of cursor
MarkTreeIter cts_iter[1];

int cts_vcol; ///< virtual column at current position
int cts_max_head_vcol; ///< see win_lbr_chartabsize()
MarkTreeIter cts_iter[1];
} chartabsize_T;

#ifdef INCLUDE_GENERATED_DECLARATIONS
Expand Down

0 comments on commit a9c551e

Please sign in to comment.