aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-09-15 20:30:50 +0800
committerGitHub <noreply@github.com>2023-09-15 20:30:50 +0800
commit35e50d79c630b05f67a840ebe21b4043ba9a6066 (patch)
tree42820f91a941d7d7c928fe1d15c9ac0896db9022
parentf5a09f1b035254f6ee773a1f88f79ab5913b48a0 (diff)
downloadrneovim-35e50d79c630b05f67a840ebe21b4043ba9a6066.tar.gz
rneovim-35e50d79c630b05f67a840ebe21b4043ba9a6066.tar.bz2
rneovim-35e50d79c630b05f67a840ebe21b4043ba9a6066.zip
fix(extmarks): overlay virt_text position after 'showbreak' (#25175)
Also make virt_text_hide work properly.
-rw-r--r--src/nvim/decoration.c31
-rw-r--r--src/nvim/decoration.h1
-rw-r--r--src/nvim/drawline.c36
-rw-r--r--src/nvim/spell.c2
-rw-r--r--test/functional/ui/decorations_spec.lua55
5 files changed, 106 insertions, 19 deletions
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 0181cc8983..f4ca31040a 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -268,6 +268,28 @@ static void decor_add(DecorState *state, int start_row, int start_col, int end_r
kv_A(state->active, index) = range;
}
+/// Initialize the draw_col of a newly-added non-inline virtual text item.
+static void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
+{
+ if (win_col < 0) {
+ item->draw_col = win_col;
+ } else if (item->decor.virt_text_pos == kVTOverlay) {
+ item->draw_col = (item->decor.virt_text_hide && hidden) ? INT_MIN : win_col;
+ } else {
+ item->draw_col = -1;
+ }
+}
+
+void decor_recheck_draw_col(int win_col, bool hidden, DecorState *state)
+{
+ for (size_t i = 0; i < kv_size(state->active); i++) {
+ DecorRange *item = &kv_A(state->active, i);
+ if (item->draw_col == -3) {
+ decor_init_draw_col(win_col, hidden, item);
+ }
+ }
+}
+
int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *state)
{
buf_T *buf = wp->w_buffer;
@@ -349,12 +371,9 @@ next_mark:
spell = item.decor.spell;
}
if (item.start_row == state->row && item.start_col <= col
- && decor_virt_pos(&item.decor) && item.draw_col == -1) {
- if (item.decor.virt_text_pos == kVTOverlay) {
- item.draw_col = (item.decor.virt_text_hide && hidden) ? INT_MIN : win_col;
- } else if (win_col < 0 && item.decor.virt_text_pos != kVTInline) {
- item.draw_col = win_col;
- }
+ && decor_virt_pos(&item.decor) && item.draw_col == -1
+ && item.decor.virt_text_pos != kVTInline) {
+ decor_init_draw_col(win_col, hidden, &item);
}
if (keep) {
kv_A(state->active, j++) = item;
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index dfd26294f3..0f191aa870 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -84,7 +84,6 @@ typedef struct {
bool virt_text_owned;
/// Screen column to draw the virtual text.
/// When -1, the virtual text may be drawn after deciding where.
- /// When -2, the virtual text should be drawn at the start of the screen line.
/// When -3, the virtual text should be drawn on the next screen line.
/// When INT_MIN, the virtual text should no longer be drawn.
int draw_col;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index cd1a5df8de..e1550e0ece 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -282,10 +282,6 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
} else if (item->decor.virt_text_pos == kVTWinCol) {
item->draw_col = MAX(item->decor.col + col_off, 0);
}
- } else if (item->draw_col == -2) {
- item->draw_col = col_off;
- } else if (item->draw_col == -3) {
- item->draw_col = item->decor.virt_text_pos == kVTOverlay ? -2 : -1;
}
if (item->draw_col < 0) {
continue;
@@ -1145,6 +1141,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
bool saved_search_attr_from_match = false;
int win_col_offset = 0; // offset for window columns
+ bool area_active = false; // whether in Visual selection, for virtual text
+ bool decor_need_recheck = false; // call decor_recheck_draw_col() at next char
char buf_fold[FOLD_TEXT_LEN]; // Hold value returned by get_foldtext
@@ -1786,9 +1784,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
if (has_decor && wlv.n_extra == 0) {
- bool selected = (area_highlighting
- && ((wlv.vcol >= wlv.fromcol && wlv.vcol < wlv.tocol)
- || (noinvcur && wlv.vcol == wp->w_virtcol)));
+ // Duplicate the Visual area check after this block,
+ // but don't check inside p_extra here.
+ if (wlv.vcol == wlv.fromcol
+ || (wlv.vcol + 1 == wlv.fromcol
+ && (wlv.n_extra == 0 && utf_ptr2cells(ptr) > 1))
+ || (vcol_prev == fromcol_prev
+ && vcol_prev < wlv.vcol
+ && wlv.vcol < wlv.tocol)) {
+ area_active = true;
+ } else if (area_active
+ && (wlv.vcol == wlv.tocol
+ || (noinvcur && wlv.vcol == wp->w_virtcol))) {
+ area_active = false;
+ }
+
+ bool selected = (area_active || (area_highlighting && noinvcur
+ && wlv.vcol == wp->w_virtcol));
+ if (decor_need_recheck) {
+ decor_recheck_draw_col(wlv.off, selected, &decor_state);
+ decor_need_recheck = false;
+ }
extmark_attr = decor_redraw_col(wp, (colnr_T)v, wlv.off, selected, &decor_state);
if (!has_fold && wp->w_buffer->b_virt_text_inline > 0) {
@@ -1822,10 +1838,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& vcol_prev < wlv.vcol // not at margin
&& wlv.vcol < wlv.tocol)) {
*area_attr_p = vi_attr; // start highlighting
+ area_active = true;
} else if (*area_attr_p != 0
&& (wlv.vcol == wlv.tocol
|| (noinvcur && wlv.vcol == wp->w_virtcol))) {
*area_attr_p = 0; // stop highlighting
+ area_active = false;
}
if (!has_fold && wlv.n_extra == 0) {
@@ -3087,9 +3105,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// At the end of screen line: might need to peek for decorations just after
// this position.
if (!has_fold && wp->w_p_wrap && wlv.n_extra == 0) {
- // FIXME: virt_text_hide doesn't work for overlay virt_text at the next char
- // as it's not easy to check if the next char is inside Visual selection.
decor_redraw_col(wp, (int)(ptr - line), -3, false, &decor_state);
+ // Check position/hiding of virtual text again on next screen line.
+ decor_need_recheck = true;
} else if (has_fold || !wp->w_p_wrap) {
// Without wrapping, we might need to display right_align and win_col
// virt_text for the entire text line.
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 72e21a9130..38e045a08b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1280,7 +1280,7 @@ static TriState decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_ln
decor_redraw_line(wp, lnum - 1, &decor_state);
*decor_lnum = lnum;
}
- decor_redraw_col(wp, col, col, false, &decor_state);
+ decor_redraw_col(wp, col, 0, false, &decor_state);
return decor_state.spell;
}
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 85093566a5..daa4b4bdb3 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -869,7 +869,7 @@ describe('extmark decorations', function()
insert(('ab'):rep(100))
for i = 0, 9 do
meths.buf_set_extmark(0, ns, 0, 42 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay'})
- meths.buf_set_extmark(0, ns, 0, 91 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide = true})
+ meths.buf_set_extmark(0, ns, 0, 91 + i, { virt_text={{tostring(i), 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
end
screen:expect{grid=[[
ababababababababababababababababababababab{4:01234567}|
@@ -880,7 +880,58 @@ describe('extmark decorations', function()
|
]]}
- command('set number')
+ command('set showbreak=++')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}{4:789}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababa^b |
+ |
+ ]]}
+
+ feed('2gkvg0')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}^a{18:babab}ababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('o')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}abababababababababababababababababababa{4:0123456}|
+ {1:++}{18:ababa}^bababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('gk')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}aba^b{18:ababababababababababababababababababababab}|
+ {1:++}{18:a}{4:89}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('o')
+ screen:expect{grid=[[
+ ababababababababababababababababababababab{4:01234567}|
+ {1:++}{4:89}aba{18:bababababababababababababababababababababab}|
+ {1:++}^a{4:89}babababababababababababababababababababababab|
+ {1:++}abababababababababababababababababababababababab|
+ {1:++}ababab |
+ {24:-- VISUAL --} |
+ ]]}
+
+ feed('<Esc>$')
+ command('set number showbreak=')
screen:expect{grid=[[
{2: 1 }ababababababababababababababababababababab{4:0123}|
{2: }{4:456789}abababababababababababababababababababa{4:0}|