local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local assert_alive = n.assert_alive local clear, feed = n.clear, n.feed local eval, eq, neq = n.eval, t.eq, t.neq local feed_command, source, expect = n.feed_command, n.source, n.expect local fn = n.fn local command = n.command local api = n.api local poke_eventloop = n.poke_eventloop describe('completion', function() local screen before_each(function() clear() screen = Screen.new(60, 8) screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { background = Screen.colors.LightMagenta }, [2] = { background = Screen.colors.Grey }, [3] = { bold = true }, [4] = { bold = true, foreground = Screen.colors.SeaGreen }, [5] = { foreground = Screen.colors.Red }, [6] = { background = Screen.colors.Black }, [7] = { foreground = Screen.colors.White, background = Screen.colors.Red }, [8] = { reverse = true }, [9] = { bold = true, reverse = true }, [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, }) end) describe('v:completed_item', function() it('is empty dict until completion', function() eq({}, eval('v:completed_item')) end) it('is empty dict if the candidate is not inserted', function() feed('ifooo') screen:expect([[ foo | foo^ | {0:~ }|*5 {3:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | ^ | {0:~ }|*5 {3:-- INSERT --} | ]]) feed('') eq({}, eval('v:completed_item')) end) it('returns expected dict in normal completion', function() feed('ifooo') eq('foo', eval('getline(2)')) eq( { word = 'foo', abbr = '', menu = '', info = '', kind = '', user_data = '' }, eval('v:completed_item') ) end) it('is readonly', function() screen:try_resize(80, 8) feed('ifooo') feed_command('let v:completed_item.word = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') feed_command('let v:completed_item.abbr = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') feed_command('let v:completed_item.menu = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') feed_command('let v:completed_item.info = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') feed_command('let v:completed_item.kind = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') feed_command('let v:completed_item.user_data = "bar"') neq(nil, string.find(eval('v:errmsg'), '^E46: ')) feed_command('let v:errmsg = ""') end) it('returns expected dict in omni completion', function() source([[ function! TestOmni(findstart, base) abort return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar', \ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'}, \ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', \ 'info': 'info', 'kind': 'kind'}] endfunction setlocal omnifunc=TestOmni ]]) feed('i') eq('foo', eval('getline(1)')) screen:expect([[ foo^ | {2:bar foobaz baz }{0: }| {1:abbr kind menu }{0: }| {0:~ }|*4 {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | ]]) eq({ word = 'foo', abbr = 'bar', menu = 'baz', info = 'foobar', kind = 'foobaz', user_data = '', }, eval('v:completed_item')) end) end) describe('completeopt', function() before_each(function() source([[ function! TestComplete() abort call complete(1, ['foo']) return '' endfunction ]]) end) it('inserts the first candidate if default', function() feed_command('set completeopt+=menuone') feed('ifooo') screen:expect([[ foo | ^ | {0:~ }|*5 {3:-- INSERT --} | ]]) feed('') -- the ^X prompt, only test this once screen:expect([[ foo | ^ | {0:~ }|*5 {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | ]]) feed('') screen:expect([[ foo | foo^ | {2:foo }{0: }| {0:~ }|*4 {3:-- Keyword Local completion (^N^P) The only match} | ]]) feed('bar') eq('foobar', eval('getline(2)')) feed('o=TestComplete()') screen:expect([[ foo | foobar | foo^ | {2:foo }{0: }| {0:~ }|*3 {3:-- INSERT --} | ]]) eq('foo', eval('getline(3)')) end) it('selects the first candidate if noinsert', function() feed_command('set completeopt+=menuone,noinsert') feed('ifooo') screen:expect([[ foo | ^ | {2:foo }{0: }| {0:~ }|*4 {3:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | foo^ | {0:~ }|*5 {3:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(2)')) feed('o=TestComplete()') screen:expect([[ foo |*2 ^ | {2:foo }{0: }| {0:~ }|*3 {3:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(3)')) end) it('does not insert the first candidate if noselect', function() feed_command('set completeopt+=menuone,noselect') feed('ifooo') screen:expect([[ foo | ^ | {1:foo }{0: }| {0:~ }|*4 {3:-- Keyword Local completion (^N^P) }{5:Back at original} | ]]) feed('b') screen:expect([[ foo | b^ | {0:~ }|*5 {3:-- Keyword Local completion (^N^P) }{5:Back at original} | ]]) feed('ar') eq('bar', eval('getline(2)')) feed('o=TestComplete()') screen:expect([[ foo | bar | ^ | {1:foo }{0: }| {0:~ }|*3 {3:-- INSERT --} | ]]) feed('bar') eq('bar', eval('getline(3)')) end) it('does not select/insert the first candidate if noselect and noinsert', function() feed_command('set completeopt+=menuone,noselect,noinsert') feed('ifooo') screen:expect([[ foo | ^ | {1:foo }{0: }| {0:~ }|*4 {3:-- Keyword Local completion (^N^P) }{5:Back at original} | ]]) feed('') screen:expect([[ foo | ^ | {0:~ }|*5 | ]]) eq('', eval('getline(2)')) feed('o=TestComplete()') screen:expect([[ foo | | ^ | {1:foo }{0: }| {0:~ }|*3 {3:-- INSERT --} | ]]) feed('') screen:expect([[ foo | | ^ | {0:~ }|*4 | ]]) eq('', eval('getline(3)')) end) it('does not change modified state if noinsert', function() feed_command('set completeopt+=menuone,noinsert') feed_command('setlocal nomodified') feed('i=TestComplete()') eq(0, eval('&l:modified')) end) it('does not change modified state if noselect', function() feed_command('set completeopt+=menuone,noselect') feed_command('setlocal nomodified') feed('i=TestComplete()') eq(0, eval('&l:modified')) end) end) describe('completeopt+=noinsert does not add blank undo items', function() before_each(function() source([[ function! TestComplete() abort call complete(1, ['foo', 'bar']) return '' endfunction ]]) feed_command('set completeopt+=noselect,noinsert') feed_command('inoremap =TestComplete()') end) local tests = { [', , '] = { '', '' }, [', , '] = { '', '' }, } for name, seq in pairs(tests) do it('using ' .. name, function() feed('iaaa') feed('A' .. seq[1] .. '') feed('AA') feed('Abbb') feed('A' .. seq[2] .. '') feed('AA') feed('Accc') feed('A' .. seq[1] .. '') feed('AA') local expected = { { 'foo', 'bar', 'foo' }, { 'foo', 'bar', 'ccc' }, { 'foo', 'bar' }, { 'foo', 'bbb' }, { 'foo' }, { 'aaa' }, { '' }, } for i = 1, #expected do if i > 1 then feed('u') end eq(expected[i], eval('getline(1, "$")')) end for i = #expected, 1, -1 do if i < #expected then feed('') end eq(expected[i], eval('getline(1, "$")')) end end) end end) describe('refresh:always', function() before_each(function() source([[ function! TestCompletion(findstart, base) abort if a:findstart let line = getline('.') let start = col('.') - 1 while start > 0 && line[start - 1] =~ '\a' let start -= 1 endwhile return start else let ret = [] for m in split("January February March April May June July August September October November December") if m =~ a:base " match by regex call add(ret, m) endif endfor return {'words':ret, 'refresh':'always'} endif endfunction set completeopt=menuone,noselect set completefunc=TestCompletion ]]) end) it('completes on each input char', function() feed('i') screen:expect([[ ^ | {1:January }{6: }{0: }| {1:February }{6: }{0: }| {1:March }{6: }{0: }| {1:April }{2: }{0: }| {1:May }{2: }{0: }| {1:June }{2: }{0: }| {3:-- User defined completion (^U^N^P) }{5:Back at original} | ]]) feed('u') screen:expect([[ u^ | {1:January }{0: }| {1:February }{0: }| {1:June }{0: }| {1:July }{0: }| {1:August }{0: }| {0:~ }| {3:-- User defined completion (^U^N^P) }{5:Back at original} | ]]) feed('g') screen:expect([[ ug^ | {1:August }{0: }| {0:~ }|*5 {3:-- User defined completion (^U^N^P) }{5:Back at original} | ]]) feed('') screen:expect([[ ug^ | {2:August }{0: }| {0:~ }|*5 {3:-- User defined completion (^U^N^P) The only match} | ]]) feed('') screen:expect([[ August^ | {0:~ }|*6 {3:-- INSERT --} | ]]) expect('August') end) it('repeats correctly after backspace #2674', function() feed('oJa') screen:expect([[ | Ja^ | {1:January }{0: }| {0:~ }|*4 {3:-- User defined completion (^U^N^P) }{5:Back at original} | ]]) feed('') screen:expect([[ | J^ | {1:January }{0: }| {1:June }{0: }| {1:July }{0: }| {0:~ }|*2 {3:-- User defined completion (^U^N^P) }{5:Back at original} | ]]) feed('') screen:expect([[ | January^ | {2:January }{0: }| {1:June }{0: }| {1:July }{0: }| {0:~ }|*2 {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} | ]]) feed('') screen:expect([[ | June^ | {1:January }{0: }| {2:June }{0: }| {1:July }{0: }| {0:~ }|*2 {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} | ]]) feed('') screen:expect([[ | Jun^e | {0:~ }|*5 | ]]) feed('.') screen:expect([[ | June | Jun^e | {0:~ }|*4 | ]]) expect([[ June June]]) end) end) describe('with a lot of items', function() before_each(function() source([[ function! TestComplete() abort call complete(1, map(range(0,100), "string(v:val)")) return '' endfunction ]]) feed_command('set completeopt=menuone,noselect') end) it('works', function() feed('i=TestComplete()') screen:expect([[ ^ | {1:0 }{6: }{0: }| {1:1 }{2: }{0: }| {1:2 }{2: }{0: }| {1:3 }{2: }{0: }| {1:4 }{2: }{0: }| {1:5 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('7') screen:expect([[ 7^ | {1:7 }{6: }{0: }| {1:70 }{6: }{0: }| {1:71 }{6: }{0: }| {1:72 }{2: }{0: }| {1:73 }{2: }{0: }| {1:74 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ 7^ | {2:7 }{6: }{0: }| {1:70 }{6: }{0: }| {1:71 }{6: }{0: }| {1:72 }{2: }{0: }| {1:73 }{2: }{0: }| {1:74 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ 70^ | {1:7 }{6: }{0: }| {2:70 }{6: }{0: }| {1:71 }{6: }{0: }| {1:72 }{2: }{0: }| {1:73 }{2: }{0: }| {1:74 }{2: }{0: }| {3:-- INSERT --} | ]]) end) it('can be navigated with , ', function() feed('i=TestComplete()') screen:expect([[ ^ | {1:0 }{6: }{0: }| {1:1 }{2: }{0: }| {1:2 }{2: }{0: }| {1:3 }{2: }{0: }| {1:4 }{2: }{0: }| {1:5 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | {1:0 }{6: }{0: }| {1:1 }{2: }{0: }| {1:2 }{2: }{0: }| {2:3 }{0: }| {1:4 }{2: }{0: }| {1:5 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | {1:5 }{6: }{0: }| {1:6 }{2: }{0: }| {2:7 }{0: }| {1:8 }{2: }{0: }| {1:9 }{2: }{0: }| {1:10 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | {1:5 }{6: }{0: }| {1:6 }{2: }{0: }| {1:7 }{2: }{0: }| {2:8 }{0: }| {1:9 }{2: }{0: }| {1:10 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | {1:2 }{6: }{0: }| {1:3 }{2: }{0: }| {2:4 }{0: }| {1:5 }{2: }{0: }| {1:6 }{2: }{0: }| {1:7 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') -- stop on first item screen:expect([[ ^ | {2:0 }{6: }{0: }| {1:1 }{2: }{0: }| {1:2 }{2: }{0: }| {1:3 }{2: }{0: }| {1:4 }{2: }{0: }| {1:5 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') -- when on first item, unselect screen:expect([[ ^ | {1:0 }{6: }{0: }| {1:1 }{2: }{0: }| {1:2 }{2: }{0: }| {1:3 }{2: }{0: }| {1:4 }{2: }{0: }| {1:5 }{2: }{0: }| {3:-- INSERT --} | ]]) feed('') -- when unselected, select last item screen:expect([[ ^ | {1:95 }{2: }{0: }| {1:96 }{2: }{0: }| {1:97 }{2: }{0: }| {1:98 }{2: }{0: }| {1:99 }{2: }{0: }| {2:100 }{6: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | {1:94 }{2: }{0: }| {1:95 }{2: }{0: }| {2:96 }{0: }| {1:97 }{2: }{0: }| {1:98 }{2: }{0: }| {1:99 }{6: }{0: }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ 96^ | {0:~ }|*6 {3:-- INSERT --} | ]]) end) end) it('does not indent until an item is selected #8345', function() -- Indents on "ind", unindents on "unind". source([[ function! TestIndent() let line = getline(v:lnum) if (line =~ '^\s*ind') return indent(v:lnum-1) + shiftwidth() elseif (line =~ '^\s*unind') return indent(v:lnum-1) - shiftwidth() else return indent(v:lnum-1) endif endfunction set indentexpr=TestIndent() set indentkeys=o,O,!^F,=ind,=unind set completeopt+=menuone ]]) -- Give some words to complete. feed('iinc uninc indent unindent') -- Does not indent when "ind" is typed. feed('in') -- Completion list is generated incorrectly if we send everything at once -- via nvim_input(). So poke_eventloop() before sending . #8480 poke_eventloop() feed('d') screen:expect([[ inc uninc indent unindent | ind^ | {2:indent }{0: }| {0:~ }|*4 {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | ]]) -- Indents when the item is selected feed('') screen:expect([[ inc uninc indent unindent | indent^ | {0:~ }|*5 {3:-- INSERT --} | ]]) -- Indents when completion is exited using ESC. feed('ind') screen:expect([[ inc uninc indent unindent | indent | in^d | {0:~ }|*4 | ]]) -- Works for unindenting too. feed('ounin') poke_eventloop() feed('d') screen:expect([[ inc uninc indent unindent | indent | ind | unind^ | {0:~ }{2: unindent }{0: }| {0:~ }|*2 {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | ]]) -- Works when going back and forth. feed('c') screen:expect([[ inc uninc indent unindent | indent | ind | uninc^ | {0:~ }{2: uninc }{0: }| {0:~ }|*2 {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | ]]) feed('d') screen:expect([[ inc uninc indent unindent | indent | ind | unind^ | {0:~ }{2: unindent }{0: }| {0:~ }|*2 {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | ]]) feed('') screen:expect([[ inc uninc indent unindent | indent | ind | uninden^t | {0:~ }|*3 | ]]) end) it('disables folding during completion', function() feed_command('set foldmethod=indent') feed('ifoobargg') screen:expect([[ ^foo | bar | {0:~ }|*5 | ]]) feed('A') screen:expect([[ foo^ | bar | {0:~ }|*5 {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} | ]]) eq(-1, eval('foldclosed(1)')) end) it('popupmenu is not interrupted by events', function() feed_command('set complete=.') feed('ifoobar fooeggf') screen:expect([[ foobar fooegg | fooegg^ | {1:foobar }{0: }| {2:fooegg }{0: }| {0:~ }|*3 {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | ]]) assert_alive() -- popupmenu still visible screen:expect { grid = [[ foobar fooegg | fooegg^ | {1:foobar }{0: }| {2:fooegg }{0: }| {0:~ }|*3 {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | ]], unchanged = true, } feed('') -- Didn't restart completion: old matches still used screen:expect([[ foobar fooegg | foobar^ | {2:foobar }{0: }| {1:fooegg }{0: }| {0:~ }|*3 {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | ]]) end) describe('lua completion', function() it('expands when there is only one match', function() feed(':lua CURRENT_TESTING_VAR = 1') feed(':lua CURRENT_TESTING_') screen:expect { grid = [[ | {0:~ }|*6 :lua CURRENT_TESTING_VAR^ | ]], } end) it('expands when there is only one match', function() feed(':lua CURRENT_TESTING_FOO = 1') feed(':lua CURRENT_TESTING_BAR = 1') feed(':lua CURRENT_TESTING_') screen:expect { grid = [[ | {0:~ }|*5 {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| :lua CURRENT_TESTING_BAR^ | ]], unchanged = true, } end) it('provides completion from `getcompletion()`', function() eq({ 'vim' }, fn.getcompletion('vi', 'lua')) eq({ 'api' }, fn.getcompletion('vim.ap', 'lua')) eq({ 'tbl_filter' }, fn.getcompletion('vim.tbl_fil', 'lua')) eq({ 'vim' }, fn.getcompletion('print(vi', 'lua')) -- fuzzy completion is not supported, so the result should be the same command('set wildoptions+=fuzzy') eq({ 'vim' }, fn.getcompletion('vi', 'lua')) end) end) it('cmdline completion supports various string options', function() eq('auto', fn.getcompletion('set foldcolumn=', 'cmdline')[2]) eq({ 'nosplit', 'split' }, fn.getcompletion('set inccommand=', 'cmdline')) eq({ 'ver:3,hor:6', 'hor:', 'ver:' }, fn.getcompletion('set mousescroll=', 'cmdline')) eq('BS', fn.getcompletion('set termpastefilter=', 'cmdline')[2]) eq('SpecialKey', fn.getcompletion('set winhighlight=', 'cmdline')[1]) eq('SpecialKey', fn.getcompletion('set winhighlight=NonText:', 'cmdline')[1]) end) describe('from the commandline window', function() it('is cleared after CTRL-C', function() feed('q:') feed('ifoo faa fee f') screen:expect([[ | {8:[No Name] }| {0::}foo faa fee f^ | {0:~ }|*3 {9:[Command Line] }| {3:-- INSERT --} | ]]) feed('') screen:expect([[ | {8:[No Name] }| {0::}foo faa fee foo^ | {0:~ }{2: foo }{0: }| {0:~ }{1: faa }{0: }| {0:~ }{1: fee }{0: }| {9:[Command Line] }| {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} | ]]) feed('') screen:expect([[ | {8:[No Name] }| {0::}foo faa fee foo | {0:~ }|*3 {9:[Command Line] }| :foo faa fee foo^ | ]]) end) end) describe('with numeric items', function() before_each(function() source([[ function! TestComplete() abort call complete(1, g:_complist) return '' endfunction ]]) api.nvim_set_option_value('completeopt', 'menuone,noselect', {}) api.nvim_set_var('_complist', { { word = 0, abbr = 1, menu = 2, kind = 3, info = 4, icase = 5, dup = 6, empty = 7, }, }) end) it('shows correct variant as word', function() feed('i=TestComplete()') screen:expect([[ ^ | {1:1 3 2 }{0: }| {0:~ }|*5 {3:-- INSERT --} | ]]) end) end) it("'ignorecase' 'infercase' CTRL-X CTRL-N #6451", function() feed_command('set ignorecase infercase') feed_command('edit runtime/doc/backers.txt') feed('oX') screen:expect { grid = [[ *backers.txt* Nvim | Xnull^ | {2:Xnull }{6: } | {1:Xoxomoon }{6: } | {1:Xu }{6: } NVIM REFERENCE MANUAL | {1:Xpayn }{2: } | {1:Xinity }{2: } | {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} | ]], } end) it('CompleteChanged autocommand', function() api.nvim_buf_set_lines(0, 0, 1, false, { 'foo', 'bar', 'foobar', '' }) source([[ set complete=. completeopt=noinsert,noselect,menuone function! OnPumChange() let g:event = copy(v:event) let g:item = get(v:event, 'completed_item', {}) let g:word = get(g:item, 'word', v:null) endfunction autocmd! CompleteChanged * :call OnPumChange() call cursor(4, 1) ]]) -- v:event.size should be set with ext_popupmenu #20646 screen:set_option('ext_popupmenu', true) feed('Sf') screen:expect({ grid = [[ foo | bar | foobar | f^ | {0:~ }|*3 {3:-- Keyword completion (^N^P) }{5:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, items = { { 'foo', '', '', '' }, { 'foobar', '', '', '' } }, pos = -1, }, }) eq( { completed_item = {}, width = 0, height = 2, size = 2, col = 0, row = 4, scrollbar = false }, eval('g:event') ) feed('oob') screen:expect({ grid = [[ foo | bar | foobar | foob^ | {0:~ }|*3 {3:-- Keyword completion (^N^P) }{5:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, items = { { 'foobar', '', '', '' } }, pos = -1, }, }) eq( { completed_item = {}, width = 0, height = 1, size = 1, col = 0, row = 4, scrollbar = false }, eval('g:event') ) feed('') screen:set_option('ext_popupmenu', false) feed('Sf') screen:expect([[ foo | bar | foobar | f^ | {1:foo }{0: }| {1:foobar }{0: }| {0:~ }| {3:-- Keyword completion (^N^P) }{5:Back at original} | ]]) eq( { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false }, eval('g:event') ) feed('') screen:expect([[ foo | bar | foobar | foo^ | {2:foo }{0: }| {1:foobar }{0: }| {0:~ }| {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') screen:expect([[ foo | bar | foobar | foobar^ | {1:foo }{0: }| {2:foobar }{0: }| {0:~ }| {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') screen:expect([[ foo | bar | foobar | foobar^ | {2:foo }{0: }| {1:foobar }{0: }| {0:~ }| {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') screen:expect([[ foo | bar | foobar | foobar^ | {1:foo }{0: }| {2:foobar }{0: }| {0:~ }| {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') end) it('is stopped by :stopinsert from timer #12976', function() screen:try_resize(32, 14) command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]]) feed('Gah') screen:expect([[ hello | hullo | heeee | hello^ | {2:hello }{0: }| {1:hullo }{0: }| {1:heeee }{0: }| {0:~ }|*6 {3:-- }{4:match 1 of 3} | ]]) command([[call timer_start(100, { -> execute('stopinsert') })]]) vim.uv.sleep(200) feed('k') -- cursor should move up in Normal mode screen:expect([[ hello | hullo | heee^e | hello | {0:~ }|*9 | ]]) end) -- oldtest: Test_complete_changed_complete_info() it('no crash calling complete_info() in CompleteChanged', function() source([[ set completeopt=menuone autocmd CompleteChanged * call complete_info(['items']) call feedkeys("iii\\") ]]) screen:expect([[ ii | ii^ | {2:ii }{0: }| {0:~ }|*4 {3:-- Keyword completion (^N^P) The only match} | ]]) assert_alive() end) it('no crash if text changed by first call to complete function #17489', function() source([[ func Complete(findstart, base) abort if a:findstart let col = col('.') call complete_add('#') return col - 1 else return [] endif endfunc set completeopt=longest set completefunc=Complete ]]) feed('ifoo#') assert_alive() end) it('no crash using i_CTRL-X_CTRL-V to complete non-existent colorscheme', function() feed('icolorscheme NOSUCHCOLORSCHEME') expect('colorscheme NOSUCHCOLORSCHEME') assert_alive() end) it('complete with f flag #25598', function() screen:try_resize(20, 9) command('set complete+=f | edit foo | edit bar |edit foa |edit .hidden') feed('i') screen:expect { grid = [[ foo^ | {2:foo }{0: }| {1:bar }{0: }| {1:foa }{0: }| {1:.hidden }{0: }| {0:~ }|*3 {3:-- }{4:match 1 of 4} | ]], } feed('ccf') screen:expect { grid = [[ foo^ | {2:foo }{0: }| {1:foa }{0: }| {0:~ }|*5 {3:-- }{4:match 1 of 2} | ]], } end) it('restores extmarks if original text is restored #23653', function() screen:try_resize(screen._width, 4) command([[ call setline(1, ['aaaa']) let ns_id = nvim_create_namespace('extmark') let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error'}) let mark = nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 }) inoremap =Complete() function Complete() abort call complete(1, [{ 'word': 'aaaaa' }]) return '' endfunction ]]) feed('A') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('A') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('0YppiaggI') screen:expect([[ aaaa{7:^aa}aa | {2:aaaa } | {1:aaaaa } | {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | ]]) feed('') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('A') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('') screen:expect([[ aaaaa^ | {1:aaaa } | {2:aaaaa } | {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | ]]) feed('') screen:expect([[ {7:aa}aa^ | aaaa | aaaaa | {3:-- INSERT --} | ]]) end) end)