Compare commits

...

3 Commits

Author SHA1 Message Date
Riley Bruins
d49e41d7ec
Merge 40527a4684 into 02bc40c194 2024-12-19 08:19:54 +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
Riley Bruins
40527a4684 feat(api): add/del folds, get fold information 2024-12-11 23:44:35 -08:00
15 changed files with 431 additions and 63 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

@ -2887,6 +2887,20 @@ nvim__ns_set({ns_id}, {opts}) *nvim__ns_set()*
==============================================================================
Window Functions *api-window*
*nvim_win_add_fold()*
nvim_win_add_fold({window}, {start}, {end}, {opts})
Add a fold to the window from {start} to {end}.
All row arguments are 0-indexed, inclusive.
Only supported for |fold-manual| and |fold-marker|.
Parameters: ~
• {window} Window handle, or 0 for current window.
• {start} Start row of fold.
• {end} End row of fold.
• {opts} Optional parameters. Reserved for future use.
nvim_win_call({window}, {fun}) *nvim_win_call()*
Calls a function with window as temporary current window.
@ -2917,6 +2931,21 @@ nvim_win_close({window}, {force}) *nvim_win_close()*
unwritten changes can be closed. The buffer will become
hidden, even if 'hidden' is not set.
*nvim_win_del_fold()*
nvim_win_del_fold({window}, {start}, {end}, {opts})
Delete a fold from the window from {start} to {end}.
All row arguments are 0-indexed, inclusive.
Only supported for |fold-manual| and |fold-marker|.
Parameters: ~
• {window} Window handle, or 0 for current window.
• {start} Start row of fold.
• {end} End row of fold.
• {opts} Optional parameters:
• recursive: Delete folds recursively
nvim_win_del_var({window}, {name}) *nvim_win_del_var()*
Removes a window-scoped (w:) variable
@ -2947,6 +2976,17 @@ nvim_win_get_cursor({window}) *nvim_win_get_cursor()*
See also: ~
• |getcurpos()|
nvim_win_get_folds({window}, {opts}) *nvim_win_get_folds()*
Get fold information from the window.
All row arguments are 0-indexed, inclusive.
Parameters: ~
• {window} Window handle, or 0 for current window.
• {opts} Optional parameters:
• start_row: get folds from this row
• end_row: get folds up to this row
nvim_win_get_height({window}) *nvim_win_get_height()*
Gets the window height

View File

@ -2341,6 +2341,18 @@ function vim.api.nvim_tabpage_set_var(tabpage, name, value) end
--- @param win integer Window handle, must already belong to {tabpage}
function vim.api.nvim_tabpage_set_win(tabpage, win) end
--- Add a fold to the window from {start} to {end}.
---
--- All row arguments are 0-indexed, inclusive.
---
--- Only supported for `fold-manual` and `fold-marker`.
---
--- @param window integer Window handle, or 0 for current window.
--- @param start integer Start row of fold.
--- @param end_ integer End row of fold.
--- @param opts vim.api.keyset.empty Optional parameters. Reserved for future use.
function vim.api.nvim_win_add_fold(window, start, end_, opts) end
--- Calls a function with window as temporary current window.
---
---
@ -2360,6 +2372,19 @@ function vim.api.nvim_win_call(window, fun) end
--- hidden, even if 'hidden' is not set.
function vim.api.nvim_win_close(window, force) end
--- Delete a fold from the window from {start} to {end}.
---
--- All row arguments are 0-indexed, inclusive.
---
--- Only supported for `fold-manual` and `fold-marker`.
---
--- @param window integer Window handle, or 0 for current window.
--- @param start integer Start row of fold.
--- @param end_ integer End row of fold.
--- @param opts vim.api.keyset.win_del_fold Optional parameters:
--- - recursive: Delete folds recursively
function vim.api.nvim_win_del_fold(window, start, end_, opts) end
--- Removes a window-scoped (w:) variable
---
--- @param window integer Window handle, or 0 for current window
@ -2392,6 +2417,17 @@ function vim.api.nvim_win_get_config(window) end
--- @return integer[] # (row, col) tuple
function vim.api.nvim_win_get_cursor(window) end
--- Get fold information from the window.
---
--- All row arguments are 0-indexed, inclusive.
---
--- @param window integer Window handle, or 0 for current window.
--- @param opts vim.api.keyset.empty Optional parameters:
--- - start_row: get folds from this row
--- - end_row: get folds up to this row
--- @return any[]
function vim.api.nvim_win_get_folds(window, opts) end
--- Gets the window height
---
--- @param window integer Window handle, or 0 for current window

View File

@ -308,6 +308,9 @@ error('Cannot require a meta file')
--- @field fixed? boolean
--- @field hide? boolean
--- @class vim.api.keyset.win_del_fold
--- @field recursive? boolean
--- @class vim.api.keyset.win_text_height
--- @field start_row? integer
--- @field end_row? integer

View File

@ -227,6 +227,11 @@ typedef struct {
Integer end_vcol;
} Dict(win_text_height);
typedef struct {
OptionalKeys is_set__win_del_fold_;
Boolean recursive;
} Dict(win_del_fold);
typedef struct {
OptionalKeys is_set__clear_autocmds_;
Buffer buffer;

View File

@ -4,6 +4,7 @@
#include <stdlib.h>
#include "nvim/api/keysets_defs.h"
#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
@ -16,6 +17,7 @@
#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/ex_docmd.h"
#include "nvim/fold.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/lua/executor.h"
@ -563,3 +565,114 @@ Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *are
PUT_C(rv, "fill", INTEGER_OBJ(fill));
return rv;
}
/// Add a fold to the window from {start} to {end}.
///
/// All row arguments are 0-indexed, inclusive.
///
/// Only supported for |fold-manual| and |fold-marker|.
///
/// @param window Window handle, or 0 for current window.
/// @param start Start row of fold.
/// @param end End row of fold.
/// @param opts Optional parameters. Reserved for future use.
void nvim_win_add_fold(Window window, Integer start, Integer end, Dict(empty) *opts, Error *err)
FUNC_API_SINCE(11)
{
if (!foldManualAllowed(true)) {
return;
}
win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
}
curwin->w_p_fen = true;
// Rows are zero-indexed.
pos_T start_pos = { start + 1, 1, 0 };
pos_T end_pos = { end + 1, 1, 0 };
foldCreate(win, start_pos, end_pos);
}
/// Delete a fold from the window from {start} to {end}.
///
/// All row arguments are 0-indexed, inclusive.
///
/// Only supported for |fold-manual| and |fold-marker|.
///
/// @param window Window handle, or 0 for current window.
/// @param start Start row of fold.
/// @param end End row of fold.
/// @param opts Optional parameters:
/// - recursive: Delete folds recursively
void nvim_win_del_fold(Window window, Integer start, Integer end, Dict(win_del_fold) *opts, Error *err)
FUNC_API_SINCE(11)
{
if (!foldManualAllowed(false)) {
return;
}
win_T *win = find_window_by_handle(window, err);
if (!win) {
return;
}
// Rows are zero-indexed.
deleteFold(win, start + 1, end + 1, opts->recursive, false);
}
/// Get fold information from the window.
///
/// All row arguments are 0-indexed, inclusive.
///
/// @param window Window handle, or 0 for current window.
/// @param opts Optional parameters:
/// - start_row: get folds from this row
/// - end_row: get folds up to this row
Array nvim_win_get_folds(Window window, Dict(empty) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(11)
{
win_T *win = find_window_by_handle(window, err);
if (!win) {
goto cleanup;
}
garray_T *gap = &win->w_folds;
return folds_to_fold_dict(gap, arena, win, 0);
cleanup:
return (Array)ARRAY_DICT_INIT;
}
static Array folds_to_fold_dict(garray_T *folds, Arena *arena, win_T *wp, int parent_start) {
fold_T *fp = (fold_T *)folds->ga_data;
int fold_count = folds->ga_len;
Array rv = arena_array(arena, fold_count);
for (int i = 0; i < fold_count; i++) {
fold_T fold = fp[i];
// Nested fold positions are relative to the parent
int top = fold.fd_top + parent_start;
Dict fold_dict = arena_dict(arena, 4);
char *state;
switch (fold.fd_flags) {
case FD_CLOSED:
state = "closed";
break;
case FD_OPEN:
state = "open";
break;
case FD_LEVEL:
// BUG: Still does not update for e.g. open nested folds after "zM"
state = foldLevelWin(wp, top) >= wp->w_p_fdl ? "closed" : "open";
break;
}
PUT_C(fold_dict, "state", CSTR_TO_ARENA_OBJ(arena, state));
PUT_C(fold_dict, "start_row", INTEGER_OBJ(top - 1));
PUT_C(fold_dict, "end_row", INTEGER_OBJ(top + fold.fd_len - 2));
Array inner_folds = folds_to_fold_dict(&fold.fd_nested, arena, wp, top);
PUT_C(fold_dict, "children", ARRAY_OBJ(inner_folds));
ADD_C(rv, DICT_OBJ(fold_dict));
}
return rv;
}

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

@ -55,49 +55,6 @@
#include "nvim/undo.h"
#include "nvim/vim_defs.h"
// local declarations. {{{1
// typedef fold_T {{{2
// The toplevel folds for each window are stored in the w_folds growarray.
// Each toplevel fold can contain an array of second level folds in the
// fd_nested growarray.
// The info stored in both growarrays is the same: An array of fold_T.
typedef struct {
linenr_T fd_top; // first line of fold; for nested fold
// relative to parent
linenr_T fd_len; // number of lines in the fold
garray_T fd_nested; // array of nested folds
char fd_flags; // see below
TriState fd_small; // kTrue, kFalse, or kNone: fold smaller than
// 'foldminlines'; kNone applies to nested
// folds too
} fold_T;
enum {
FD_OPEN = 0, // fold is open (nested ones can be closed)
FD_CLOSED = 1, // fold is closed
FD_LEVEL = 2, // depends on 'foldlevel' (nested folds too)
};
#define MAX_LEVEL 20 // maximum fold depth
// Define "fline_T", passed to get fold level for a line. {{{2
typedef struct {
win_T *wp; // window
linenr_T lnum; // current line number
linenr_T off; // offset between lnum and real line number
linenr_T lnum_save; // line nr used by foldUpdateIEMSRecurse()
int lvl; // current level (-1 for undefined)
int lvl_next; // level used for next line
int start; // number of folds that are forced to start at
// this line.
int end; // level of fold that is forced to end below
// this line
int had_end; // level of fold that is forced to end above
// this line (copy of "end" of prev. line)
} fline_T;
// Flag is set when redrawing is needed.
static bool fold_changed;
@ -1086,7 +1043,7 @@ static bool foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
// foldLevelWin() {{{2
/// @return fold level at line number "lnum" in window "wp".
static int foldLevelWin(win_T *wp, linenr_T lnum)
int foldLevelWin(win_T *wp, linenr_T lnum)
{
fold_T *fp;
linenr_T lnum_rel = lnum;

View File

@ -12,6 +12,51 @@
EXTERN int disable_fold_update INIT( = 0);
// local declarations. {{{1
// typedef fold_T {{{2
// The toplevel folds for each window are stored in the w_folds growarray.
// Each toplevel fold can contain an array of second level folds in the
// fd_nested growarray.
// The info stored in both growarrays is the same: An array of fold_T.
typedef struct {
linenr_T fd_top; // first line of fold; for nested fold
// relative to parent
linenr_T fd_len; // number of lines in the fold
garray_T fd_nested; // array of nested folds
char fd_flags; // see below
TriState fd_small; // kTrue, kFalse, or kNone: fold smaller than
// 'foldminlines'; kNone applies to nested
// folds too
} fold_T;
enum {
FD_OPEN = 0, // fold is open (nested ones can be closed)
FD_CLOSED = 1, // fold is closed
FD_LEVEL = 2, // depends on 'foldlevel' (nested folds too)
};
#define MAX_LEVEL 20 // maximum fold depth
// Define "fline_T", passed to get fold level for a line. {{{2
typedef struct {
win_T *wp; // window
linenr_T lnum; // current line number
linenr_T off; // offset between lnum and real line number
linenr_T lnum_save; // line nr used by foldUpdateIEMSRecurse()
int lvl; // current level (-1 for undefined)
int lvl_next; // level used for next line
int start; // number of folds that are forced to start at
// this line.
int end; // level of fold that is forced to end below
// this line
int had_end; // level of fold that is forced to end above
// this line (copy of "end" of prev. line)
} fline_T;
int foldLevelWin(win_T *wp, linenr_T lnum);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fold.h.generated.h"
#endif

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

@ -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