Compare commits

...

4 Commits

Author SHA1 Message Date
Maria José Solano
1e1263ffc5
Merge 9a2662d24a into 02bc40c194 2024-12-18 22:22:45 -08: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
luukvbaal
160cbd0ef4
test(cursor_spec): global highlight definitions (#31613) 2024-12-18 19:06:16 +00:00
Maria José Solano
9a2662d24a feat(snippet): support multiple sessions 2024-06-14 15:17:15 -07:00
11 changed files with 226 additions and 52 deletions

View File

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

View File

@ -306,7 +306,7 @@ function Session:set_group_gravity(index, right_gravity)
end end
end end
local M = { session = nil } local M = { _sessions = {} }
--- Displays the choices for the given tabstop as completion items. --- Displays the choices for the given tabstop as completion items.
--- ---
@ -397,7 +397,7 @@ local function setup_autocmds(bufnr)
local cursor_row, cursor_col = cursor_pos() local cursor_row, cursor_col = cursor_pos()
-- The cursor left the snippet region. -- The cursor left the snippet region.
local snippet_range = get_extmark_range(bufnr, M._session.extmark_id) local snippet_range = get_extmark_range(bufnr, M._current_session.extmark_id)
if if
cursor_row < snippet_range[1] cursor_row < snippet_range[1]
or (cursor_row == snippet_range[1] and cursor_col < snippet_range[2]) or (cursor_row == snippet_range[1] and cursor_col < snippet_range[2])
@ -408,7 +408,7 @@ local function setup_autocmds(bufnr)
return true return true
end end
for tabstop_index, tabstops in pairs(M._session.tabstops) do for tabstop_index, tabstops in pairs(M._current_session.tabstops) do
for _, tabstop in ipairs(tabstops) do for _, tabstop in ipairs(tabstops) do
local range = tabstop:get_range() local range = tabstop:get_range()
if if
@ -434,7 +434,7 @@ local function setup_autocmds(bufnr)
buffer = bufnr, buffer = bufnr,
callback = function() callback = function()
-- Check that the snippet hasn't been deleted. -- Check that the snippet hasn't been deleted.
local snippet_range = get_extmark_range(M._session.bufnr, M._session.extmark_id) local snippet_range = get_extmark_range(M._current_session.bufnr, M._current_session.extmark_id)
if if
(snippet_range[1] == snippet_range[3] and snippet_range[2] == snippet_range[4]) (snippet_range[1] == snippet_range[3] and snippet_range[2] == snippet_range[4])
or snippet_range[3] + 1 > vim.fn.line('$') or snippet_range[3] + 1 > vim.fn.line('$')
@ -447,9 +447,9 @@ local function setup_autocmds(bufnr)
end end
-- Sync the tabstops in the current group. -- Sync the tabstops in the current group.
local current_tabstop = M._session.current_tabstop local current_tabstop = M._current_session.current_tabstop
local current_text = current_tabstop:get_text() local current_text = current_tabstop:get_text()
for _, tabstop in ipairs(M._session.tabstops[current_tabstop.index]) do for _, tabstop in ipairs(M._current_session.tabstops[current_tabstop.index]) do
if tabstop.extmark_id ~= current_tabstop.extmark_id then if tabstop.extmark_id ~= current_tabstop.extmark_id then
tabstop:set_text(current_text) tabstop:set_text(current_text)
end end
@ -594,7 +594,8 @@ function M.expand(input)
right_gravity = false, right_gravity = false,
end_right_gravity = true, end_right_gravity = true,
}) })
M._session = Session.new(bufnr, snippet_extmark, tabstop_data) M._current_session = Session.new(bufnr, snippet_extmark, tabstop_data)
table.insert(M._sessions, M._current_session)
-- Jump to the first tabstop. -- Jump to the first tabstop.
M.jump(1) M.jump(1)
@ -619,13 +620,13 @@ end
--- @param direction (vim.snippet.Direction) Navigation direction. -1 for previous, 1 for next. --- @param direction (vim.snippet.Direction) Navigation direction. -1 for previous, 1 for next.
function M.jump(direction) function M.jump(direction)
-- Get the tabstop index to jump to. -- Get the tabstop index to jump to.
local dest_index = M._session and M._session:get_dest_index(direction) local dest_index = M._current_session and M._current_session:get_dest_index(direction)
if not dest_index then if not dest_index then
return return
end end
-- Find the tabstop with the lowest range. -- Find the tabstop with the lowest range.
local tabstops = M._session.tabstops[dest_index] local tabstops = M._current_session.tabstops[dest_index]
local dest = tabstops[1] local dest = tabstops[1]
for _, tabstop in ipairs(tabstops) do for _, tabstop in ipairs(tabstops) do
local dest_range, range = dest:get_range(), tabstop:get_range() local dest_range, range = dest:get_range(), tabstop:get_range()
@ -635,19 +636,19 @@ function M.jump(direction)
end end
-- Clear the autocommands so that we can move the cursor freely while selecting the tabstop. -- Clear the autocommands so that we can move the cursor freely while selecting the tabstop.
vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._current_session.bufnr })
-- Deactivate expansion of the current tabstop. -- Deactivate expansion of the current tabstop.
M._session:set_group_gravity(M._session.current_tabstop.index, true) M._current_session:set_group_gravity(M._current_session.current_tabstop.index, true)
M._session.current_tabstop = dest M._current_session.current_tabstop = dest
select_tabstop(dest) select_tabstop(dest)
-- Activate expansion of the destination tabstop. -- Activate expansion of the destination tabstop.
M._session:set_group_gravity(dest.index, false) M._current_session:set_group_gravity(dest.index, false)
-- Restore the autocommands. -- Restore the autocommands.
setup_autocmds(M._session.bufnr) setup_autocmds(M._current_session.bufnr)
end end
--- @class vim.snippet.ActiveFilter --- @class vim.snippet.ActiveFilter
@ -673,11 +674,11 @@ end
--- can be jumped in the given direction. --- can be jumped in the given direction.
--- @return boolean --- @return boolean
function M.active(filter) function M.active(filter)
local active = M._session ~= nil and M._session.bufnr == vim.api.nvim_get_current_buf() local active = M._current_session ~= nil and M._current_session.bufnr == vim.api.nvim_get_current_buf()
local in_direction = true local in_direction = true
if active and filter and filter.direction then if active and filter and filter.direction then
in_direction = M._session:get_dest_index(filter.direction) ~= nil in_direction = M._current_session:get_dest_index(filter.direction) ~= nil
end end
return active and in_direction return active and in_direction
@ -689,12 +690,15 @@ function M.stop()
return return
end end
M._session:restore_keymaps() if #M._sessions == 1 then
M._current_session:restore_keymaps()
vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._current_session.bufnr })
vim.api.nvim_buf_clear_namespace(M._session.bufnr, snippet_ns, 0, -1) vim.api.nvim_buf_clear_namespace(M._current_session.bufnr, snippet_ns, 0, -1)
end
M._session = nil table.remove(M._sessions)
M._current_session = #M._sessions > 0 and M._sessions[#M._sessions] or nil
end end
return M return M

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 bool area_highlighting = false; // Visual or incsearch highlighting in this line
int vi_attr = 0; // attributes for Visual and incsearch highlighting int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by 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 vcol_save_attr = 0; // saved attr for 'cursorcolumn'
int decor_attr = 0; // attributes desired by syntax and extmarks int decor_attr = 0; // attributes desired by syntax and extmarks
bool has_syntax = false; // this buffer has syntax highl. 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 spell_attr = 0; // attributes desired by spelling
int word_end = 0; // last byte with same spell_attr int word_end = 0; // last byte with same spell_attr
int cur_checked_col = 0; // checked column for current line 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 multi_attr = 0; // attributes desired by multibyte
int mb_l = 1; // multi-byte byte length int mb_l = 1; // multi-byte byte length
int mb_c = 0; // decoded multi-byte character 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 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); win_line_start(wp, &wlv);
bool draw_cols = true; bool draw_cols = true;
int leftcols_width = 0; 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) { if (*ptr == NUL) {
has_match_conc = 0; 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) { 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); 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) { if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
const int v = (int)(ptr - line); const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1; 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 PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel", "default link PmenuKindSel PmenuSel",
"default link PmenuSbar Pmenu", "default link PmenuSbar Pmenu",
"default link ComplMatchIns Normal", "default link ComplMatchIns NONE",
"default link Substitute Search", "default link Substitute Search",
"default link StatusLineTerm StatusLine", "default link StatusLineTerm StatusLine",
"default link StatusLineTermNC StatusLineNC", "default link StatusLineTermNC StatusLineNC",

View File

@ -958,7 +958,7 @@ static void ins_compl_insert_bytes(char *p, int len)
} }
assert(len >= 0); assert(len >= 0);
ins_bytes_len(p, (size_t)len); 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 /// 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()) { && pum_visible()) {
word = xstrdup(compl_shown_match->cp_str); word = xstrdup(compl_shown_match->cp_str);
retval = true; 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. // CTRL-E means completion is Ended, go back to the typed text.
@ -3648,6 +3650,7 @@ void ins_compl_delete(bool new_leader)
return; return;
} }
backspace_until_column(col); backspace_until_column(col);
compl_ins_end_col = curwin->w_cursor.col;
} }
// TODO(vim): is this sufficient for redrawing? Redrawing everything // TODO(vim): is this sufficient for redrawing? Redrawing everything

View File

@ -309,4 +309,18 @@ describe('vim.snippet', function()
feed('<Esc>O<cr><Tab>') feed('<Esc>O<cr><Tab>')
eq({ '' }, buf_lines(0)) eq({ '' }, buf_lines(0))
end) end)
it('supports multiple snippet sessions', function()
test_expand_success({ 'func $1($3) {', ' $2', '}' }, { 'func () {', ' ', '}' })
feed('foo<Tab>')
test_expand_success({ 'var x = $1 + $2' }, { 'func foo() {', ' var x = + ', '}' })
feed('a<Tab>b')
feed('<Tab><Tab>a, b')
eq({ 'func foo(a, b) {', ' var x = a + b', '}' }, buf_lines(0))
end)
end) end)

View File

@ -373,12 +373,6 @@ describe('buffer cursor position is correct in terminal without number column',
}, { }, {
cols = 70, cols = 70,
}) })
screen:set_default_attr_ids({
[1] = { foreground = 253, background = 11 },
[2] = { reverse = true },
[3] = { bold = true },
[4] = { background = 11 },
})
-- Also check for real cursor position, as it is used for stuff like input methods -- Also check for real cursor position, as it is used for stuff like input methods
screen._handle_busy_start = function() end screen._handle_busy_start = function() end
screen._handle_busy_stop = function() end screen._handle_busy_stop = function() end
@ -690,13 +684,6 @@ describe('buffer cursor position is correct in terminal with number column', fun
}, { }, {
cols = 70, cols = 70,
}) })
screen:set_default_attr_ids({
[1] = { foreground = 253, background = 11 },
[2] = { reverse = true },
[3] = { bold = true },
[4] = { background = 11 },
[7] = { foreground = 130 },
})
-- Also check for real cursor position, as it is used for stuff like input methods -- Also check for real cursor position, as it is used for stuff like input methods
screen._handle_busy_start = function() end screen._handle_busy_start = function() end
screen._handle_busy_stop = function() end screen._handle_busy_stop = function() end

View File

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

View File

@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red }, [6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search [7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red }, [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 }, ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 }, kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
@ -5625,6 +5627,114 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} | {2:-- INSERT --} |
]]) ]])
feed('<Esc>') 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 end
end end

View File

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

View File

@ -1747,13 +1747,67 @@ func Test_pum_matchins_highlight()
call TermWait(buf) call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>") call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {}) call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>") call term_sendkeys(buf, "\<Esc>")
" restore after cancel completion " restore after cancel completion
call TermWait(buf) call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>") call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {}) 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) call StopVimInTerminal(buf)
endfunc endfunc