123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356 |
- 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, ok = n.eval, t.eq, t.neq, t.ok
- 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
- local exec_lua = n.exec_lua
- describe('completion', function()
- local screen
- before_each(function()
- clear()
- screen = Screen.new(60, 8)
- screen:add_extra_attr_ids {
- [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow },
- [101] = { background = Screen.colors.Gray0 },
- }
- 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('ifoo<ESC>o<C-x><C-n>')
- screen:expect([[
- foo |
- foo^ |
- {1:~ }|*5
- {5:-- Keyword Local completion (^N^P) The only match} |
- ]])
- feed('<C-e>')
- screen:expect([[
- foo |
- ^ |
- {1:~ }|*5
- {5:-- INSERT --} |
- ]])
- feed('<ESC>')
- eq({}, eval('v:completed_item'))
- end)
- it('returns expected dict in normal completion', function()
- feed('ifoo<ESC>o<C-x><C-n>')
- 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('ifoo<ESC>o<C-x><C-n><ESC>')
- 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<C-x><C-o>')
- eq('foo', eval('getline(1)'))
- screen:expect([[
- foo^ |
- {12:bar foobaz baz }{1: }|
- {4:abbr kind menu }{1: }|
- {1:~ }|*4
- {5:-- Omni completion (^O^N^P) }{6: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('ifoo<ESC>o')
- screen:expect([[
- foo |
- ^ |
- {1:~ }|*5
- {5:-- INSERT --} |
- ]])
- feed('<C-x>')
- -- the ^X prompt, only test this once
- screen:expect([[
- foo |
- ^ |
- {1:~ }|*5
- {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} |
- ]])
- feed('<C-n>')
- screen:expect([[
- foo |
- foo^ |
- {12:foo }{1: }|
- {1:~ }|*4
- {5:-- Keyword Local completion (^N^P) The only match} |
- ]])
- feed('bar<ESC>')
- eq('foobar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>')
- screen:expect([[
- foo |
- foobar |
- foo^ |
- {12:foo }{1: }|
- {1:~ }|*3
- {5:-- INSERT --} |
- ]])
- eq('foo', eval('getline(3)'))
- end)
- it('selects the first candidate if noinsert', function()
- feed_command('set completeopt+=menuone,noinsert')
- feed('ifoo<ESC>o<C-x><C-n>')
- screen:expect([[
- foo |
- ^ |
- {12:foo }{1: }|
- {1:~ }|*4
- {5:-- Keyword Local completion (^N^P) The only match} |
- ]])
- feed('<C-y>')
- screen:expect([[
- foo |
- foo^ |
- {1:~ }|*5
- {5:-- INSERT --} |
- ]])
- feed('<ESC>')
- eq('foo', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>')
- screen:expect([[
- foo |*2
- ^ |
- {12:foo }{1: }|
- {1:~ }|*3
- {5:-- INSERT --} |
- ]])
- feed('<C-y><ESC>')
- eq('foo', eval('getline(3)'))
- end)
- it('does not insert the first candidate if noselect', function()
- feed_command('set completeopt+=menuone,noselect')
- feed('ifoo<ESC>o<C-x><C-n>')
- screen:expect([[
- foo |
- ^ |
- {4:foo }{1: }|
- {1:~ }|*4
- {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
- ]])
- feed('b')
- screen:expect([[
- foo |
- b^ |
- {1:~ }|*5
- {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
- ]])
- feed('ar<ESC>')
- eq('bar', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>')
- screen:expect([[
- foo |
- bar |
- ^ |
- {4:foo }{1: }|
- {1:~ }|*3
- {5:-- INSERT --} |
- ]])
- feed('bar<ESC>')
- 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('ifoo<ESC>o<C-x><C-n>')
- screen:expect([[
- foo |
- ^ |
- {4:foo }{1: }|
- {1:~ }|*4
- {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
- ]])
- feed('<ESC>')
- screen:expect([[
- foo |
- ^ |
- {1:~ }|*5
- |
- ]])
- eq('', eval('getline(2)'))
- feed('o<C-r>=TestComplete()<CR>')
- screen:expect([[
- foo |
- |
- ^ |
- {4:foo }{1: }|
- {1:~ }|*3
- {5:-- INSERT --} |
- ]])
- feed('<ESC>')
- screen:expect([[
- foo |
- |
- ^ |
- {1:~ }|*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<C-r>=TestComplete()<CR><ESC>')
- 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<C-r>=TestComplete()<CR><ESC>')
- 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 <right> <c-r>=TestComplete()<cr>')
- end)
- local tests = {
- ['<up>, <down>, <cr>'] = { '<down><cr>', '<up><cr>' },
- ['<c-n>, <c-p>, <c-y>'] = { '<c-n><c-y>', '<c-p><c-y>' },
- }
- for name, seq in pairs(tests) do
- it('using ' .. name, function()
- feed('iaaa<esc>')
- feed('A<right>' .. seq[1] .. '<esc>')
- feed('A<right><esc>A<right><esc>')
- feed('A<cr>bbb<esc>')
- feed('A<right>' .. seq[2] .. '<esc>')
- feed('A<right><esc>A<right><esc>')
- feed('A<cr>ccc<esc>')
- feed('A<right>' .. seq[1] .. '<esc>')
- feed('A<right><esc>A<right><esc>')
- 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('<c-r>')
- end
- eq(expected[i], eval('getline(1, "$")'))
- end
- end)
- end
- end)
- describe('with refresh:always and noselect', 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<C-x><C-u>')
- screen:expect([[
- ^ |
- {4:January }{101: }{1: }|
- {4:February }{101: }{1: }|
- {4:March }{101: }{1: }|
- {4:April }{12: }{1: }|
- {4:May }{12: }{1: }|
- {4:June }{12: }{1: }|
- {5:-- User defined completion (^U^N^P) }{19:Back at original} |
- ]])
- feed('u')
- screen:expect([[
- u^ |
- {4:January }{1: }|
- {4:February }{1: }|
- {4:June }{1: }|
- {4:July }{1: }|
- {4:August }{1: }|
- {1:~ }|
- {5:-- User defined completion (^U^N^P) }{19:Back at original} |
- ]])
- feed('g')
- screen:expect([[
- ug^ |
- {4:August }{1: }|
- {1:~ }|*5
- {5:-- User defined completion (^U^N^P) }{19:Back at original} |
- ]])
- feed('<Down>')
- screen:expect([[
- ug^ |
- {12:August }{1: }|
- {1:~ }|*5
- {5:-- User defined completion (^U^N^P) The only match} |
- ]])
- feed('<C-y>')
- screen:expect([[
- August^ |
- {1:~ }|*6
- {5:-- INSERT --} |
- ]])
- expect('August')
- end)
- it('repeats correctly after backspace #2674', function()
- feed('o<C-x><C-u>Ja')
- screen:expect([[
- |
- Ja^ |
- {4:January }{1: }|
- {1:~ }|*4
- {5:-- User defined completion (^U^N^P) }{19:Back at original} |
- ]])
- feed('<BS>')
- screen:expect([[
- |
- J^ |
- {4:January }{1: }|
- {4:June }{1: }|
- {4:July }{1: }|
- {1:~ }|*2
- {5:-- User defined completion (^U^N^P) }{19:Back at original} |
- ]])
- feed('<C-n>')
- screen:expect([[
- |
- January^ |
- {12:January }{1: }|
- {4:June }{1: }|
- {4:July }{1: }|
- {1:~ }|*2
- {5:-- User defined completion (^U^N^P) }{6:match 1 of 3} |
- ]])
- feed('<C-n>')
- screen:expect([[
- |
- June^ |
- {4:January }{1: }|
- {12:June }{1: }|
- {4:July }{1: }|
- {1:~ }|*2
- {5:-- User defined completion (^U^N^P) }{6:match 2 of 3} |
- ]])
- feed('<Esc>')
- screen:expect([[
- |
- Jun^e |
- {1:~ }|*5
- |
- ]])
- feed('.')
- screen:expect([[
- |
- June |
- Jun^e |
- {1:~ }|*4
- |
- ]])
- expect([[
- June
- June]])
- end)
- it('Enter does not select original text', function()
- feed('iJ<C-x><C-u>')
- poke_eventloop()
- feed('u')
- poke_eventloop()
- feed('<CR>')
- expect([[
- Ju
- ]])
- feed('J<C-x><C-u>')
- poke_eventloop()
- feed('<CR>')
- expect([[
- Ju
- J
- ]])
- end)
- end)
- describe('with noselect but not 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}
- endif
- endfunction
- set completeopt=menuone,noselect
- set completefunc=TestCompletion
- ]])
- end)
- it('Enter selects original text after adding leader', function()
- feed('iJ<C-x><C-u>')
- poke_eventloop()
- feed('u')
- poke_eventloop()
- feed('<CR>')
- expect('Ju')
- feed('<Esc>')
- poke_eventloop()
- -- The behavior should be the same when completion has been interrupted,
- -- which can happen interactively if the completion function is slow.
- feed('SJ<C-x><C-u>u<CR>')
- expect('Ju')
- 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<C-r>=TestComplete()<CR>')
- screen:expect([[
- ^ |
- {4:0 }{101: }{1: }|
- {4:1 }{12: }{1: }|
- {4:2 }{12: }{1: }|
- {4:3 }{12: }{1: }|
- {4:4 }{12: }{1: }|
- {4:5 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('7')
- screen:expect([[
- 7^ |
- {4:7 }{101: }{1: }|
- {4:70 }{101: }{1: }|
- {4:71 }{101: }{1: }|
- {4:72 }{12: }{1: }|
- {4:73 }{12: }{1: }|
- {4:74 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<c-n>')
- screen:expect([[
- 7^ |
- {12:7 }{101: }{1: }|
- {4:70 }{101: }{1: }|
- {4:71 }{101: }{1: }|
- {4:72 }{12: }{1: }|
- {4:73 }{12: }{1: }|
- {4:74 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<c-n>')
- screen:expect([[
- 70^ |
- {4:7 }{101: }{1: }|
- {12:70 }{101: }{1: }|
- {4:71 }{101: }{1: }|
- {4:72 }{12: }{1: }|
- {4:73 }{12: }{1: }|
- {4:74 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- end)
- it('can be navigated with <PageDown>, <PageUp>', function()
- feed('i<C-r>=TestComplete()<CR>')
- screen:expect([[
- ^ |
- {4:0 }{101: }{1: }|
- {4:1 }{12: }{1: }|
- {4:2 }{12: }{1: }|
- {4:3 }{12: }{1: }|
- {4:4 }{12: }{1: }|
- {4:5 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageDown>')
- screen:expect([[
- ^ |
- {4:0 }{101: }{1: }|
- {4:1 }{12: }{1: }|
- {4:2 }{12: }{1: }|
- {12:3 }{1: }|
- {4:4 }{12: }{1: }|
- {4:5 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageDown>')
- screen:expect([[
- ^ |
- {4:5 }{101: }{1: }|
- {4:6 }{12: }{1: }|
- {12:7 }{1: }|
- {4:8 }{12: }{1: }|
- {4:9 }{12: }{1: }|
- {4:10 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<Down>')
- screen:expect([[
- ^ |
- {4:5 }{101: }{1: }|
- {4:6 }{12: }{1: }|
- {4:7 }{12: }{1: }|
- {12:8 }{1: }|
- {4:9 }{12: }{1: }|
- {4:10 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageUp>')
- screen:expect([[
- ^ |
- {4:2 }{101: }{1: }|
- {4:3 }{12: }{1: }|
- {12:4 }{1: }|
- {4:5 }{12: }{1: }|
- {4:6 }{12: }{1: }|
- {4:7 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageUp>') -- stop on first item
- screen:expect([[
- ^ |
- {12:0 }{101: }{1: }|
- {4:1 }{12: }{1: }|
- {4:2 }{12: }{1: }|
- {4:3 }{12: }{1: }|
- {4:4 }{12: }{1: }|
- {4:5 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageUp>') -- when on first item, unselect
- screen:expect([[
- ^ |
- {4:0 }{101: }{1: }|
- {4:1 }{12: }{1: }|
- {4:2 }{12: }{1: }|
- {4:3 }{12: }{1: }|
- {4:4 }{12: }{1: }|
- {4:5 }{12: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageUp>') -- when unselected, select last item
- screen:expect([[
- ^ |
- {4:95 }{12: }{1: }|
- {4:96 }{12: }{1: }|
- {4:97 }{12: }{1: }|
- {4:98 }{12: }{1: }|
- {4:99 }{12: }{1: }|
- {12:100 }{101: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<PageUp>')
- screen:expect([[
- ^ |
- {4:94 }{12: }{1: }|
- {4:95 }{12: }{1: }|
- {12:96 }{1: }|
- {4:97 }{12: }{1: }|
- {4:98 }{12: }{1: }|
- {4:99 }{101: }{1: }|
- {5:-- INSERT --} |
- ]])
- feed('<cr>')
- screen:expect([[
- 96^ |
- {1:~ }|*6
- {5:-- 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<CR>')
- -- Does not indent when "ind" is typed.
- feed('in<C-X><C-N>')
- -- Completion list is generated incorrectly if we send everything at once
- -- via nvim_input(). So poke_eventloop() before sending <BS>. #8480
- poke_eventloop()
- feed('<BS>d')
- screen:expect([[
- inc uninc indent unindent |
- ind^ |
- {12:indent }{1: }|
- {1:~ }|*4
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
- ]])
- -- Indents when the item is selected
- feed('<C-Y>')
- screen:expect([[
- inc uninc indent unindent |
- indent^ |
- {1:~ }|*5
- {5:-- INSERT --} |
- ]])
- -- Indents when completion is exited using ESC.
- feed('<CR>in<C-N><BS>d<Esc>')
- screen:expect([[
- inc uninc indent unindent |
- indent |
- in^d |
- {1:~ }|*4
- |
- ]])
- -- Works for unindenting too.
- feed('ounin<C-X><C-N>')
- poke_eventloop()
- feed('<BS>d')
- screen:expect([[
- inc uninc indent unindent |
- indent |
- ind |
- unind^ |
- {1:~ }{12: unindent }{1: }|
- {1:~ }|*2
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
- ]])
- -- Works when going back and forth.
- feed('<BS>c')
- screen:expect([[
- inc uninc indent unindent |
- indent |
- ind |
- uninc^ |
- {1:~ }{12: uninc }{1: }|
- {1:~ }|*2
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
- ]])
- feed('<BS>d')
- screen:expect([[
- inc uninc indent unindent |
- indent |
- ind |
- unind^ |
- {1:~ }{12: unindent }{1: }|
- {1:~ }|*2
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
- ]])
- feed('<C-N><C-N><C-Y><Esc>')
- screen:expect([[
- inc uninc indent unindent |
- indent |
- ind |
- uninden^t |
- {1:~ }|*3
- |
- ]])
- end)
- it('disables folding during completion', function()
- feed_command('set foldmethod=indent')
- feed('i<Tab>foo<CR><Tab>bar<Esc>gg')
- screen:expect([[
- ^foo |
- bar |
- {1:~ }|*5
- |
- ]])
- feed('A<C-x><C-l>')
- screen:expect([[
- foo^ |
- bar |
- {1:~ }|*5
- {5:-- Whole line completion (^L^N^P) }{9:Pattern not found} |
- ]])
- eq(-1, eval('foldclosed(1)'))
- end)
- it('popupmenu is not interrupted by events', function()
- feed_command('set complete=.')
- feed('ifoobar fooegg<cr>f<c-p>')
- screen:expect([[
- foobar fooegg |
- fooegg^ |
- {4:foobar }{1: }|
- {12:fooegg }{1: }|
- {1:~ }|*3
- {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
- ]])
- assert_alive()
- -- popupmenu still visible
- screen:expect {
- grid = [[
- foobar fooegg |
- fooegg^ |
- {4:foobar }{1: }|
- {12:fooegg }{1: }|
- {1:~ }|*3
- {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
- ]],
- unchanged = true,
- }
- feed('<c-p>')
- -- Didn't restart completion: old matches still used
- screen:expect([[
- foobar fooegg |
- foobar^ |
- {12:foobar }{1: }|
- {4:fooegg }{1: }|
- {1:~ }|*3
- {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
- ]])
- end)
- describe('lua completion', function()
- it('expands when there is only one match', function()
- feed(':lua CURRENT_TESTING_VAR = 1<CR>')
- feed(':lua CURRENT_TESTING_<TAB>')
- screen:expect {
- grid = [[
- |
- {1:~ }|*6
- :lua CURRENT_TESTING_VAR^ |
- ]],
- }
- end)
- it('expands when there is only one match', function()
- feed(':lua CURRENT_TESTING_FOO = 1<CR>')
- feed(':lua CURRENT_TESTING_BAR = 1<CR>')
- feed(':lua CURRENT_TESTING_<TAB>')
- screen:expect {
- grid = [[
- |
- {1:~ }|*5
- {100:CURRENT_TESTING_BAR}{3: CURRENT_TESTING_FOO }|
- :lua CURRENT_TESTING_BAR^ |
- ]],
- unchanged = true,
- }
- end)
- it('prefix is not included in completion for cmdline mode', function()
- feed(':lua math.a<Tab>')
- screen:expect([[
- |
- {1:~ }|*5
- {100:abs}{3: acos asin atan atan2 }|
- :lua math.abs^ |
- ]])
- feed('<Tab>')
- screen:expect([[
- |
- {1:~ }|*5
- {3:abs }{100:acos}{3: asin atan atan2 }|
- :lua math.acos^ |
- ]])
- end)
- it('prefix is not included in completion for i_CTRL-X_CTRL-V #19623', function()
- feed('ilua math.a<C-X><C-V>')
- screen:expect([[
- lua math.abs^ |
- {1:~ }{12: abs }{1: }|
- {1:~ }{4: acos }{1: }|
- {1:~ }{4: asin }{1: }|
- {1:~ }{4: atan }{1: }|
- {1:~ }{4: atan2 }{1: }|
- {1:~ }|
- {5:-- Command-line completion (^V^N^P) }{6:match 1 of 5} |
- ]])
- feed('<C-V>')
- screen:expect([[
- lua math.acos^ |
- {1:~ }{4: abs }{1: }|
- {1:~ }{12: acos }{1: }|
- {1:~ }{4: asin }{1: }|
- {1:~ }{4: atan }{1: }|
- {1:~ }{4: atan2 }{1: }|
- {1:~ }|
- {5:-- Command-line completion (^V^N^P) }{6:match 2 of 5} |
- ]])
- end)
- it('works when cursor is in the middle of cmdline #29586', function()
- feed(':lua math.a(); 1<Left><Left><Left><Left><Left><Tab>')
- screen:expect([[
- |
- {1:~ }|*5
- {100:abs}{3: acos asin atan atan2 }|
- :lua math.abs^(); 1 |
- ]])
- 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'))
- eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('math.a', 'lua'))
- eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('lua math.a', 'cmdline'))
- -- 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)
- it('cmdline completion for -complete does not contain spaces', function()
- for _, str in ipairs(fn.getcompletion('command -complete=', 'cmdline')) do
- ok(not str:find(' '), 'string without spaces', str)
- end
- end)
- describe('from the commandline window', function()
- it('is cleared after CTRL-C', function()
- feed('q:')
- feed('ifoo faa fee f')
- screen:expect([[
- |
- {2:[No Name] }|
- {1::}foo faa fee f^ |
- {1:~ }|*3
- {3:[Command Line] }|
- {5:-- INSERT --} |
- ]])
- feed('<c-x><c-n>')
- screen:expect([[
- |
- {2:[No Name] }|
- {1::}foo faa fee foo^ |
- {1:~ }{12: foo }{1: }|
- {1:~ }{4: faa }{1: }|
- {1:~ }{4: fee }{1: }|
- {3:[Command Line] }|
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} |
- ]])
- feed('<c-c>')
- screen:expect([[
- |
- {2:[No Name] }|
- {1::}foo faa fee foo |
- {1:~ }|*3
- {3:[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<C-r>=TestComplete()<CR>')
- screen:expect([[
- ^ |
- {4:1 3 2 }{1: }|
- {1:~ }|*5
- {5:-- INSERT --} |
- ]])
- end)
- end)
- it("'ignorecase' 'infercase' CTRL-X CTRL-N #6451", function()
- feed_command('set ignorecase infercase')
- feed_command('edit runtime/doc/credits.txt')
- feed('oX<C-X><C-N>')
- screen:expect {
- grid = [[
- *credits.txt* Nvim |
- Xvi^ |
- {12:Xvi }{101: } |
- {4:Xvim }{101: } |
- {4:X11 }{12: } NVIM REFERENCE MANUAL |
- {4:Xnull }{12: } |
- {4:Xoxomoon }{12: } |
- {5:-- Keyword Local completion (^N^P) }{6:match 1 of 10} |
- ]],
- }
- 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<C-N>')
- screen:expect({
- grid = [[
- foo |
- bar |
- foobar |
- f^ |
- {1:~ }|*3
- {5:-- Keyword completion (^N^P) }{19: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^ |
- {1:~ }|*3
- {5:-- Keyword completion (^N^P) }{19: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('<Esc>')
- screen:set_option('ext_popupmenu', false)
- feed('Sf<C-N>')
- screen:expect([[
- foo |
- bar |
- foobar |
- f^ |
- {4:foo }{1: }|
- {4:foobar }{1: }|
- {1:~ }|
- {5:-- Keyword completion (^N^P) }{19:Back at original} |
- ]])
- eq(
- { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false },
- eval('g:event')
- )
- feed('<C-N>')
- screen:expect([[
- foo |
- bar |
- foobar |
- foo^ |
- {12:foo }{1: }|
- {4:foobar }{1: }|
- {1:~ }|
- {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
- ]])
- eq('foo', eval('g:word'))
- feed('<C-N>')
- screen:expect([[
- foo |
- bar |
- foobar |
- foobar^ |
- {4:foo }{1: }|
- {12:foobar }{1: }|
- {1:~ }|
- {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
- ]])
- eq('foobar', eval('g:word'))
- feed('<up>')
- screen:expect([[
- foo |
- bar |
- foobar |
- foobar^ |
- {12:foo }{1: }|
- {4:foobar }{1: }|
- {1:~ }|
- {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
- ]])
- eq('foo', eval('g:word'))
- feed('<down>')
- screen:expect([[
- foo |
- bar |
- foobar |
- foobar^ |
- {4:foo }{1: }|
- {12:foobar }{1: }|
- {1:~ }|
- {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
- ]])
- eq('foobar', eval('g:word'))
- feed('<esc>')
- end)
- it('is stopped by :stopinsert from timer #12976', function()
- screen:try_resize(32, 14)
- command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]])
- feed('Gah<c-x><c-n>')
- screen:expect([[
- hello |
- hullo |
- heeee |
- hello^ |
- {12:hello }{1: }|
- {4:hullo }{1: }|
- {4:heeee }{1: }|
- {1:~ }|*6
- {5:-- }{6: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 |
- {1:~ }|*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\<cr>\<c-p>")
- ]])
- screen:expect([[
- ii |
- ii^ |
- {12:ii }{1: }|
- {1:~ }|*4
- {5:-- 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#<C-X><C-U>')
- assert_alive()
- end)
- it('no crash using i_CTRL-X_CTRL-V to complete non-existent colorscheme', function()
- feed('icolorscheme NOSUCHCOLORSCHEME<C-X><C-V>')
- 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<C-n>')
- screen:expect {
- grid = [[
- foo^ |
- {12:foo }{1: }|
- {4:bar }{1: }|
- {4:foa }{1: }|
- {4:.hidden }{1: }|
- {1:~ }|*3
- {5:-- }{6:match 1 of 4} |
- ]],
- }
- feed('<Esc>ccf<C-n>')
- screen:expect {
- grid = [[
- foo^ |
- {12:foo }{1: }|
- {4:foa }{1: }|
- {1:~ }|*5
- {5:-- }{6: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 <C-x> <C-r>=Complete()<CR>
- function Complete() abort
- call complete(1, [{ 'word': 'aaaaa' }])
- return ''
- endfunction
- ]])
- feed('A<C-X><C-E><Esc>')
- eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
- feed('A<C-N>')
- eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
- feed('<Esc>0Yppia<Esc>ggI<C-N>')
- screen:expect([[
- aaaa{9:^aa}aa |
- {12:aaaa } |
- {4:aaaaa } |
- {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
- ]])
- feed('<C-N><C-N><Esc>')
- eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
- feed('A<C-N>')
- eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
- feed('<C-N>')
- screen:expect([[
- aaaaa^ |
- {4:aaaa } |
- {12:aaaaa } |
- {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
- ]])
- feed('<C-E>')
- screen:expect([[
- {9:aa}aa^ |
- aaaa |
- aaaaa |
- {5:-- INSERT --} |
- ]])
- -- Also when completion leader is changed #31384
- feed('<Esc>hi<C-N><C-P>a')
- screen:expect({
- grid = [[
- {9:aa}a^aa |
- {4:aaaa } |
- {4:aaaaa } |
- {5:-- Keyword completion (^N^P) }{19:Back at original} |
- ]],
- })
- -- But still grows with end_right_gravity #31437
- command(
- "call nvim_buf_set_extmark(0, ns_id, 1, 0, { 'end_col':2, 'hl_group':'Error', 'end_right_gravity': 1 })"
- )
- feed('<Esc>ji<C-N>a')
- screen:expect({
- grid = [[
- {9:aa}aaa |
- {9:aaa}^aa |
- aaaaa |
- {5:-- INSERT --} |
- ]],
- })
- end)
- describe('nvim__complete_set', function()
- it("fails when 'completeopt' does not include popup", function()
- exec_lua([[
- function _G.omni_test(findstart, base)
- if findstart == 1 then
- return vim.fn.col('.') - 1
- end
- return { { word = 'one' } }
- end
- vim.api.nvim_create_autocmd('CompleteChanged', {
- callback = function()
- local ok, err = pcall(vim.api.nvim__complete_set, 0, { info = '1info' })
- if not ok then
- vim.g.err_msg = err
- end
- end,
- })
- vim.opt.completeopt = 'menu,menuone'
- vim.opt.omnifunc = 'v:lua.omni_test'
- ]])
- feed('S<C-X><C-O>')
- eq('completeopt option does not include popup', api.nvim_get_var('err_msg'))
- end)
- end)
- end)
|