aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVanaIgr <vanaigranov@gmail.com>2023-12-13 13:25:48 -0600
committerVanaIgr <vanaigranov@gmail.com>2024-01-18 21:30:47 -0600
commita9c551e5e38f484e9055a930b3feaa9ac65d07be (patch)
tree14a0465de0e425a06f9107918965d28a533bdc26 /src
parent77c3d66be9a2ee2c06a2eac049de94c16e92436a (diff)
downloadrneovim-a9c551e5e38f484e9055a930b3feaa9ac65d07be.tar.gz
rneovim-a9c551e5e38f484e9055a930b3feaa9ac65d07be.tar.bz2
rneovim-a9c551e5e38f484e9055a930b3feaa9ac65d07be.zip
perf: cache breakindent/showbreak width in win_lbr_chartabsize
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.
Diffstat (limited to 'src')
-rw-r--r--src/nvim/drawline.c5
-rw-r--r--src/nvim/plines.c64
-rw-r--r--src/nvim/plines.h9
3 files changed, 44 insertions, 34 deletions
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index cead63b88d..cc0fa441ca 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -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);
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index c2cf3796a7..48c43e155e 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -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;
}
}
@@ -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;
}
}
}
@@ -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);
}
@@ -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);
}
@@ -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)) {
@@ -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);
@@ -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;
@@ -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.
@@ -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);
@@ -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);
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
index 38024e622e..86ee7ef53c 100644
--- a/src/nvim/plines.h
+++ b/src/nvim/plines.h
@@ -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