diff options
-rw-r--r-- | src/nvim/decoration.c | 29 | ||||
-rw-r--r-- | src/nvim/decoration.h | 6 | ||||
-rw-r--r-- | src/nvim/drawline.c | 25 | ||||
-rw-r--r-- | test/functional/ui/decorations_spec.lua | 115 |
4 files changed, 134 insertions, 41 deletions
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index ce1af290c1..81e1cb617c 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -81,7 +81,7 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor) } } - if (decor && decor_virt_pos(*decor)) { + if (decor && decor_virt_pos(decor)) { redraw_buf_line_later(buf, row1 + 1, false); if (decor->virt_text_pos == kVTInline) { changed_line_display_buf(buf); @@ -202,9 +202,9 @@ Decoration get_decor(mtkey_t mark) } /// @return true if decor has a virtual position (virtual text or ui_watched) -static bool decor_virt_pos(Decoration decor) +bool decor_virt_pos(const Decoration *const decor) { - return kv_size(decor.virt_text) || decor.ui_watched; + return kv_size(decor->virt_text) || decor->ui_watched; } bool decor_redraw_start(win_T *wp, int top_row, DecorState *state) @@ -232,7 +232,7 @@ bool decor_redraw_start(win_T *wp, int top_row, DecorState *state) // Exclude start marks if the end mark position is above the top row // Exclude end marks if we have already added the start mark - if ((mt_start(mark) && altpos.row < top_row && !decor_virt_pos(decor)) + if ((mt_start(mark) && altpos.row < top_row && !decor_virt_pos(&decor)) || (mt_end(mark) && altpos.row >= top_row)) { goto next_mark; } @@ -342,7 +342,7 @@ next_mark: bool active = false, keep = true; if (item.end_row < state->row || (item.end_row == state->row && item.end_col <= col)) { - if (!(item.start_row >= state->row && decor_virt_pos(item.decor))) { + if (!(item.start_row >= state->row && decor_virt_pos(&item.decor))) { keep = false; } } else { @@ -372,10 +372,19 @@ next_mark: if (active && item.decor.spell != kNone) { spell = item.decor.spell; } - if ((item.start_row == state->row && item.start_col <= col) - && decor_virt_pos(item.decor) - && item.decor.virt_text_pos == kVTOverlay && item.win_col == -1) { - item.win_col = (item.decor.virt_text_hide && hidden) ? -2 : win_col; + if (item.start_row == state->row && decor_virt_pos(&item.decor) + && item.draw_col != INT_MIN) { + if (item.start_col <= col) { + if (item.decor.virt_text_pos == kVTOverlay && item.draw_col == -1) { + item.draw_col = (item.decor.virt_text_hide && hidden) ? INT_MIN : win_col; + } else if (item.draw_col == -3) { + item.draw_col = -1; + } + } else if (wp->w_p_wrap + && (item.decor.virt_text_pos == kVTRightAlign + || item.decor.virt_text_pos == kVTWinCol)) { + item.draw_col = -3; + } } if (keep) { kv_A(state->active, j++) = item; @@ -550,7 +559,7 @@ bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col) bool has_virttext = false; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange item = kv_A(state->active, i); - if (item.start_row == state->row && decor_virt_pos(item.decor)) { + if (item.start_row == state->row && decor_virt_pos(&item.decor)) { has_virttext = true; } diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index 95c9655742..565279b21b 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -82,7 +82,11 @@ typedef struct { Decoration decor; int attr_id; // cached lookup of decor.hl_id bool virt_text_owned; - int win_col; + /// Screen column to draw the virtual text. + /// When -1, the virtual text may be drawn after deciding where. + /// When -3, the virtual text should be drawn on a later screen line. + /// When INT_MIN, the virtual text should no longer be drawn. + int draw_col; uint64_t ns_id; uint64_t mark_id; } DecorRange; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index c9a27ceedf..723c3e1c2b 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -277,35 +277,34 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int bool do_eol = state->eol_col > -1; for (size_t i = 0; i < kv_size(state->active); i++) { DecorRange *item = &kv_A(state->active, i); - if (!(item->start_row == state->row - && (kv_size(item->decor.virt_text) || item->decor.ui_watched))) { + if (!(item->start_row == state->row && decor_virt_pos(&item->decor))) { continue; } - if (item->win_col == -1) { + if (item->draw_col == -1) { if (item->decor.virt_text_pos == kVTRightAlign) { right_pos -= item->decor.virt_text_width; - item->win_col = right_pos; + item->draw_col = right_pos; } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { - item->win_col = state->eol_col; + item->draw_col = state->eol_col; } else if (item->decor.virt_text_pos == kVTWinCol) { - item->win_col = MAX(item->decor.col + col_off, 0); + item->draw_col = MAX(item->decor.col + col_off, 0); } } - if (item->win_col < 0) { + if (item->draw_col < 0) { continue; } int col = 0; if (item->decor.ui_watched) { // send mark position to UI - col = item->win_col; + col = item->draw_col; WinExtmark m = { (NS)item->ns_id, item->mark_id, win_row, col }; kv_push(win_extmark_arr, m); } if (kv_size(item->decor.virt_text)) { - col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text, - item->decor.hl_mode, max_col, item->win_col - col_off); + col = draw_virt_text_item(buf, item->draw_col, item->decor.virt_text, + item->decor.hl_mode, max_col, item->draw_col - col_off); } - item->win_col = -2; // deactivate + item->draw_col = INT_MIN; // deactivate if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) { state->eol_col = col + 1; } @@ -876,10 +875,10 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t || item->decor.virt_text_pos != kVTInline) { continue; } - if (item->win_col >= -1 && item->start_col == v) { + if (item->draw_col >= -1 && item->start_col == v) { wlv->virt_inline = item->decor.virt_text; wlv->virt_inline_i = 0; - item->win_col = -2; + item->draw_col = INT_MIN; break; } } diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 3ed31033fa..b9080cbcf5 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -940,25 +940,30 @@ describe('extmark decorations', function() ]]} end) - it('can have virtual text of fixed win_col position', function() + it('can have virtual text of right_align and fixed win_col position', function() insert(example_text) feed 'gg' meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'VERY', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'MUCH', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'}) meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_pos='right_align', hl_mode='blend'}) -- empty virt_text should not change anything meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_pos='right_align', hl_mode='blend'}) screen:expect{grid=[[ ^for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_id_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_id_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -971,14 +976,14 @@ describe('extmark decorations', function() feed '3G12|i<cr><esc>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_i {4:Much} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_i {4:Much} {4:MUCH}| ^d_cell ~= nil then | - hl_id = hl_id_cell {4:Error} | + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -990,13 +995,13 @@ describe('extmark decorations', function() feed 'u:<cr>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | - if hl_i^d_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if hl_i^d_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -1009,14 +1014,14 @@ describe('extmark decorations', function() feed '8|i<cr><esc>' screen:expect{grid=[[ for _,item in ipairs(items) do | - local text, hl_id_cell, cou{4:Very} unpack(item) | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| if | - ^hl_id_cell ~= nil then {4:Much} | - hl_id = hl_id_cell {4:Error} | + ^hl_id_cell ~= nil then {4:Much} {4:MUCH}| + hl_id = hl_id_cell {4:Error} {4:ERROR}| end | for _ = 1, (count or 1) do | local cell = line[colpos] | - {1:-} cell.text = text | + {1:-} cell.text = text {1:-}| cell.hl_id = hl_id | colpos = colpos+1 | end | @@ -1024,6 +1029,82 @@ describe('extmark decorations', function() {1:~ }| | ]]} + + feed 'jI-- <esc>..........' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}| + l_id_cell | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + | + ]]} + + feed '.' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- -- -- -- -- -- hl_id | + = hl_id_cell {4:Error} {4:ERROR}| + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + | + ]]} + + command 'set nowrap' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}| + if | + hl_id_cell ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- --{4:Error}- -- -- h{4:ERROR}| + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + | + ]]} + + feed('8zl') + screen:expect{grid=[[ + em in ipairs(items) do | + l text, hl_id_cell, count = unp{4:Very}item) {4:VERY}| + | + ll ~= nil then {4:Much} {4:MUCH}| + --^ -- -- -- -- -- -- -- -- -- -{4:Error}hl_id = h{4:ERROR}| + | + _ = 1, (count or 1) do | + local cell = line[colpos] | + cell{1:-}text = text {1:-}| + cell.hl_id = hl_id | + colpos = colpos+1 | + | + | + {1:~ }| + | + ]]} end) it('can have virtual text which combines foreground and background groups', function() |