Compare commits

...

3 Commits

Author SHA1 Message Date
glepnir
98daec7036
Merge 5bb11844b3 into 02bc40c194 2024-12-19 08:21:48 +01:00
zeertzjq
02bc40c194
vim-patch:9.1.0945: ComplMatchIns highlight doesn't end after inserted text (#31628)
Problem:  ComplMatchIns highlight doesn't end after inserted text.
Solution: Handle ComplMatchIns highlight more like search highlight.
          Fix off-by-one error. Handle deleting text properly.
          (zeertzjq)

closes: vim/vim#16244

f25d8f9312
2024-12-18 23:59:03 +00:00
glepnir
5bb11844b3 fix(diagnostic): support function type of float in open_float()
Problem: the float field of vim.diagnostic.config can be a function type
but function was ignored in open_float function.

Solution: check global_diagnostic_options.float type before use for funciton type
2024-12-14 18:05:46 +08:00
10 changed files with 239 additions and 23 deletions

View File

@ -60,7 +60,7 @@ hi('PmenuMatch', { link = 'Pmenu' })
hi('PmenuMatchSel', { link = 'PmenuSel' })
hi('PmenuExtra', { link = 'Pmenu' })
hi('PmenuExtraSel', { link = 'PmenuSel' })
hi('ComplMatchIns', { link = 'Normal' })
hi('ComplMatchIns', {})
hi('Substitute', { link = 'Search' })
hi('Whitespace', { link = 'NonText' })
hi('MsgSeparator', { link = 'StatusLine' })

View File

@ -1824,10 +1824,13 @@ function M.open_float(opts, ...)
-- Resolve options with user settings from vim.diagnostic.config
-- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float`
-- does not have a dedicated table for configuration options; instead, the options are mixed in
-- with its `opts` table which also includes "keyword" parameters. So we create a dedicated
-- options table that inherits missing keys from the global configuration before resolving.
local t = global_diagnostic_options.float
local float_opts = vim.tbl_extend('keep', opts, type(t) == 'table' and t or {})
-- with its `opts` table. We create a dedicated options table (`float_opts`) that inherits
-- missing keys from the global configuration (`global_diagnostic_options.float`), which can
-- be a table or a function.
local o = global_diagnostic_options
local t = type(o.float) == 'table' and o.float
or (type(o.float) == 'function' and o.float(0, bufnr) or {})
local float_opts = vim.tbl_extend('keep', opts, t)
opts = get_resolved_options({ float = float_opts }, nil, bufnr).float
end

View File

@ -955,7 +955,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
bool area_highlighting = false; // Visual or incsearch highlighting in this line
int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by highlighting
int search_attr = 0; // attributes desired by 'hlsearch'
int search_attr = 0; // attributes desired by 'hlsearch' or ComplMatchIns
int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
int decor_attr = 0; // attributes desired by syntax and extmarks
bool has_syntax = false; // this buffer has syntax highl.
@ -969,7 +969,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int spell_attr = 0; // attributes desired by spelling
int word_end = 0; // last byte with same spell_attr
int cur_checked_col = 0; // checked column for current line
bool extra_check = 0; // has syntax or linebreak
bool extra_check = false; // has extra highlighting
int multi_attr = 0; // attributes desired by multibyte
int mb_l = 1; // multi-byte byte length
int mb_c = 0; // decoded multi-byte character
@ -1495,6 +1495,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
ptr = line + v; // "line" may have been updated
}
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
area_highlighting = true;
}
win_line_start(wp, &wlv);
bool draw_cols = true;
int leftcols_width = 0;
@ -1740,6 +1744,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (*ptr == NUL) {
has_match_conc = 0;
}
// Check if ComplMatchIns highlight is needed.
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
search_attr = hl_combine_attr(search_attr, ins_match_attr);
}
}
}
if (wlv.diff_hlf != (hlf_T)0) {
@ -1787,16 +1799,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
// Apply ComplMatchIns highlight if needed.
if (wlv.filler_todo <= 0
&& (State & MODE_INSERT) && in_curline && ins_compl_active()) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
char_attr_pri = hl_combine_attr(char_attr_pri, ins_match_attr);
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
}
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1;

View File

@ -173,7 +173,7 @@ static const char *highlight_init_both[] = {
"default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel",
"default link PmenuSbar Pmenu",
"default link ComplMatchIns Normal",
"default link ComplMatchIns NONE",
"default link Substitute Search",
"default link StatusLineTerm StatusLine",
"default link StatusLineTermNC StatusLineNC",

View File

@ -958,7 +958,7 @@ static void ins_compl_insert_bytes(char *p, int len)
}
assert(len >= 0);
ins_bytes_len(p, (size_t)len);
compl_ins_end_col = curwin->w_cursor.col - 1;
compl_ins_end_col = curwin->w_cursor.col;
}
/// Checks if the column is within the currently inserted completion text
@ -2147,6 +2147,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
&& pum_visible()) {
word = xstrdup(compl_shown_match->cp_str);
retval = true;
// May need to remove ComplMatchIns highlight.
redrawWinline(curwin, curwin->w_cursor.lnum);
}
// CTRL-E means completion is Ended, go back to the typed text.
@ -3648,6 +3650,7 @@ void ins_compl_delete(bool new_leader)
return;
}
backspace_until_column(col);
compl_ins_end_col = curwin->w_cursor.col;
}
// TODO(vim): is this sufficient for redrawing? Redrawing everything

View File

@ -1750,6 +1750,19 @@ describe('vim.diagnostic', function()
return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
end)
)
--`float` option defined as a function.
eq(
true,
exec_lua(function()
vim.diagnostic.config({
float = function(_, _)
return { border = 'rounded' }
end,
})
return type(vim.diagnostic.config().float) == 'function'
end)
)
end)
it('can use functions for config values', function()
@ -2501,6 +2514,37 @@ describe('vim.diagnostic', function()
)
end)
it('', function()
eq(
{ { 'Diagnostics:', '1. syntax error' }, '', '' },
exec_lua(function()
local diagnostics = {
_G.make_error('syntax error', 0, 1, 0, 3),
}
vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
vim.diagnostic.config({
float = function(_, bufnr)
return { border = bufnr == _G.diagnostic_bufnr and 'rounded' or 'single' }
end,
})
local float_bufnr, winnr = vim.diagnostic.open_float()
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
local border1 = vim.api.nvim_win_get_config(winnr).border
vim.api.nvim_win_close(winnr, true)
local other_bufnr = vim.api.nvim_create_buf(true, true)
vim.api.nvim_win_set_buf(0, other_bufnr)
vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, diagnostics)
local _, winnr1 = vim.diagnostic.open_float()
local border2 = vim.api.nvim_win_get_config(winnr1).border
vim.api.nvim_win_close(winnr1, true)
return { lines, border1[1], border2[1] }
end)
)
end)
it('can show diagnostics from the whole buffer', function()
eq(
{ '1. Syntax error', '2. Some warning' },

View File

@ -94,7 +94,7 @@ describe('ui mode_change event', function()
}
end)
-- oldtest: Test_indent_norm_with_gq()
-- oldtest: Test_mouse_shape_indent_norm_with_gq()
it('is restored to Normal mode after "gq" indents using :normal #12309', function()
screen:try_resize(60, 6)
n.exec([[

View File

@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red },
[9] = { foreground = Screen.colors.Yellow, background = Screen.colors.Green },
[10] = { foreground = Screen.colors.White, background = Screen.colors.Green },
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
@ -5625,6 +5627,114 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} |
]])
feed('<Esc>')
-- text after the inserted text shouldn't be highlighted
feed('0ea <C-X><C-O>')
screen:expect([[
αβγ {8:foo}^ foo |
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-P>')
screen:expect([[
αβγ ^ foo |
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{8:Back at original} |
]])
feed('<C-P>')
screen:expect([[
αβγ {8:}^ foo |
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{s: }{1: }|
{1:~ }|*15
{2:-- }{5:match 3 of 3} |
]])
feed('<C-Y>')
screen:expect([[
αβγ ^ foo |
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
end)
-- oldtest: Test_pum_matchins_highlight_combine()
it('with ComplMatchIns, Normal and CursorLine highlights', function()
exec([[
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi Normal guibg=blue
hi CursorLine guibg=green guifg=white
set cursorline
call setline(1, 'aaa bbb')
]])
-- when ComplMatchIns is not set, CursorLine applies normally
feed('0ea <C-X><C-O>')
screen:expect([[
{10:aaa foo^ bbb }|
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-E>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<BS><Esc>')
-- when ComplMatchIns is set, it is applied over CursorLine
command('hi ComplMatchIns guifg=Yellow')
feed('0ea <C-X><C-O>')
screen:expect([[
{10:aaa }{9:foo}{10:^ bbb }|
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-P>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{8:Back at original} |
]])
feed('<C-P>')
screen:expect([[
{10:aaa }{9:}{10:^ bbb }|
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{s: }{1: }|
{1:~ }|*15
{2:-- }{5:match 3 of 3} |
]])
feed('<C-E>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
end)
end
end

View File

@ -308,7 +308,7 @@ endfunc
" Test that mouse shape is restored to Normal mode after using "gq" when
" 'indentexpr' executes :normal.
func Test_indent_norm_with_gq()
func Test_mouse_shape_indent_norm_with_gq()
CheckFeature mouseshape
CheckCanRunGui

View File

@ -1747,13 +1747,67 @@ func Test_pum_matchins_highlight()
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call term_sendkeys(buf, "\<Esc>")
" restore after cancel completion
call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call term_sendkeys(buf, "\<Esc>")
" text after the inserted text shouldn't be highlighted
call TermWait(buf)
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_07', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_08', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_09', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_10', {})
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
endfunc
func Test_pum_matchins_highlight_combine()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi Normal ctermbg=blue
hi CursorLine cterm=underline ctermbg=green
set cursorline
call setline(1, 'aaa bbb')
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
" when ComplMatchIns is not set, CursorLine applies normally
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_01', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_02', {})
call term_sendkeys(buf, "\<BS>\<Esc>")
" when ComplMatchIns is set, it is applied over CursorLine
call TermWait(buf)
call term_sendkeys(buf, ":hi ComplMatchIns ctermbg=red ctermfg=yellow\<CR>")
call TermWait(buf)
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_03', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_04', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_05', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_06', {})
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
endfunc