xref: /vim-8.2.3635/src/testdir/test_popup.vim (revision 1a928c20)
1" Test for completion menu
2
3source shared.vim
4source screendump.vim
5source check.vim
6
7let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
8let g:setting = ''
9
10func ListMonths()
11  if g:setting != ''
12    exe ":set" g:setting
13  endif
14  let mth = copy(g:months)
15  let entered = strcharpart(getline('.'),0,col('.'))
16  if !empty(entered)
17    let mth = filter(mth, 'v:val=~"^".entered')
18  endif
19  call complete(1, mth)
20  return ''
21endfunc
22
23func Test_popup_complete2()
24  " Although the popupmenu is not visible, this does not mean completion mode
25  " has ended. After pressing <f5> to complete the currently typed char, Vim
26  " still stays in the first state of the completion (:h ins-completion-menu),
27  " although the popupmenu wasn't shown <c-e> will remove the inserted
28  " completed text (:h complete_CTRL-E), while the following <c-e> will behave
29  " like expected (:h i_CTRL-E)
30  new
31  inoremap <f5> <c-r>=ListMonths()<cr>
32  call append(1, ["December2015"])
33  :1
34  call feedkeys("aD\<f5>\<C-E>\<C-E>\<C-E>\<C-E>\<enter>\<esc>", 'tx')
35  call assert_equal(["Dece", "", "December2015"], getline(1,3))
36  %d
37  bw!
38endfunc
39
40func Test_popup_complete()
41  new
42  inoremap <f5> <c-r>=ListMonths()<cr>
43
44  " <C-E> - select original typed text before the completion started
45  call feedkeys("aJu\<f5>\<down>\<c-e>\<esc>", 'tx')
46  call assert_equal(["Ju"], getline(1,2))
47  %d
48
49  " <C-Y> - accept current match
50  call feedkeys("a\<f5>". repeat("\<down>",7). "\<c-y>\<esc>", 'tx')
51  call assert_equal(["August"], getline(1,2))
52  %d
53
54  " <BS> - Delete one character from the inserted text (state: 1)
55  " TODO: This should not end the completion, but it does.
56  " This should according to the documentation:
57  " January
58  " but instead, this does
59  " Januar
60  " (idea is, C-L inserts the match from the popup menu
61  " but if the menu is closed, it will insert the character <c-l>
62  call feedkeys("aJ\<f5>\<bs>\<c-l>\<esc>", 'tx')
63  call assert_equal(["Januar"], getline(1,2))
64  %d
65
66  " any-non special character: Stop completion without changing the match
67  " and insert the typed character
68  call feedkeys("a\<f5>20", 'tx')
69  call assert_equal(["January20"], getline(1,2))
70  %d
71
72  " any-non printable, non-white character: Add this character and
73  " reduce number of matches
74  call feedkeys("aJu\<f5>\<c-p>l\<c-y>", 'tx')
75  call assert_equal(["Jul"], getline(1,2))
76  %d
77
78  " any-non printable, non-white character: Add this character and
79  " reduce number of matches
80  call feedkeys("aJu\<f5>\<c-p>l\<c-n>\<c-y>", 'tx')
81  call assert_equal(["July"], getline(1,2))
82  %d
83
84  " any-non printable, non-white character: Add this character and
85  " reduce number of matches
86  call feedkeys("aJu\<f5>\<c-p>l\<c-e>", 'tx')
87  call assert_equal(["Jul"], getline(1,2))
88  %d
89
90  " <BS> - Delete one character from the inserted text (state: 2)
91  call feedkeys("a\<f5>\<c-n>\<bs>", 'tx')
92  call assert_equal(["Februar"], getline(1,2))
93  %d
94
95  " <c-l> - Insert one character from the current match
96  call feedkeys("aJ\<f5>".repeat("\<c-n>",3)."\<c-l>\<esc>", 'tx')
97  call assert_equal(["J"], getline(1,2))
98  %d
99
100  " <c-l> - Insert one character from the current match
101  call feedkeys("aJ\<f5>".repeat("\<c-n>",4)."\<c-l>\<esc>", 'tx')
102  call assert_equal(["January"], getline(1,2))
103  %d
104
105  " <c-y> - Accept current selected match
106  call feedkeys("aJ\<f5>\<c-y>\<esc>", 'tx')
107  call assert_equal(["January"], getline(1,2))
108  %d
109
110  " <c-e> - End completion, go back to what was there before selecting a match
111  call feedkeys("aJu\<f5>\<c-e>\<esc>", 'tx')
112  call assert_equal(["Ju"], getline(1,2))
113  %d
114
115  " <PageUp> - Select a match several entries back
116  call feedkeys("a\<f5>\<PageUp>\<c-y>\<esc>", 'tx')
117  call assert_equal([""], getline(1,2))
118  %d
119
120  " <PageUp><PageUp> - Select a match several entries back
121  call feedkeys("a\<f5>\<PageUp>\<PageUp>\<c-y>\<esc>", 'tx')
122  call assert_equal(["December"], getline(1,2))
123  %d
124
125  " <PageUp><PageUp><PageUp> - Select a match several entries back
126  call feedkeys("a\<f5>\<PageUp>\<PageUp>\<PageUp>\<c-y>\<esc>", 'tx')
127  call assert_equal(["February"], getline(1,2))
128  %d
129
130  " <PageDown> - Select a match several entries further
131  call feedkeys("a\<f5>\<PageDown>\<c-y>\<esc>", 'tx')
132  call assert_equal(["November"], getline(1,2))
133  %d
134
135  " <PageDown><PageDown> - Select a match several entries further
136  call feedkeys("a\<f5>\<PageDown>\<PageDown>\<c-y>\<esc>", 'tx')
137  call assert_equal(["December"], getline(1,2))
138  %d
139
140  " <PageDown><PageDown><PageDown> - Select a match several entries further
141  call feedkeys("a\<f5>\<PageDown>\<PageDown>\<PageDown>\<c-y>\<esc>", 'tx')
142  call assert_equal([""], getline(1,2))
143  %d
144
145  " <PageDown><PageDown><PageDown><PageDown> - Select a match several entries further
146  call feedkeys("a\<f5>".repeat("\<PageDown>",4)."\<c-y>\<esc>", 'tx')
147  call assert_equal(["October"], getline(1,2))
148  %d
149
150  " <Up> - Select a match don't insert yet
151  call feedkeys("a\<f5>\<Up>\<c-y>\<esc>", 'tx')
152  call assert_equal([""], getline(1,2))
153  %d
154
155  " <Up><Up> - Select a match don't insert yet
156  call feedkeys("a\<f5>\<Up>\<Up>\<c-y>\<esc>", 'tx')
157  call assert_equal(["December"], getline(1,2))
158  %d
159
160  " <Up><Up><Up> - Select a match don't insert yet
161  call feedkeys("a\<f5>\<Up>\<Up>\<Up>\<c-y>\<esc>", 'tx')
162  call assert_equal(["November"], getline(1,2))
163  %d
164
165  " <Tab> - Stop completion and insert the match
166  call feedkeys("a\<f5>\<Tab>\<c-y>\<esc>", 'tx')
167  call assert_equal(["January	"], getline(1,2))
168  %d
169
170  " <Space> - Stop completion and insert the match
171  call feedkeys("a\<f5>".repeat("\<c-p>",5)." \<esc>", 'tx')
172  call assert_equal(["September "], getline(1,2))
173  %d
174
175  " <Enter> - Use the text and insert line break (state: 1)
176  call feedkeys("a\<f5>\<enter>\<esc>", 'tx')
177  call assert_equal(["January", ''], getline(1,2))
178  %d
179
180  " <Enter> - Insert the current selected text (state: 2)
181  call feedkeys("a\<f5>".repeat("\<Up>",5)."\<enter>\<esc>", 'tx')
182  call assert_equal(["September"], getline(1,2))
183  %d
184
185  " Insert match immediately, if there is only one match
186  " <c-y> selects a character from the line above
187  call append(0, ["December2015"])
188  call feedkeys("aD\<f5>\<C-Y>\<C-Y>\<C-Y>\<C-Y>\<enter>\<esc>", 'tx')
189  call assert_equal(["December2015", "December2015", ""], getline(1,3))
190  %d
191
192  " use menuone for 'completeopt'
193  " Since for the first <c-y> the menu is still shown, will only select
194  " three letters from the line above
195  set completeopt&vim
196  set completeopt+=menuone
197  call append(0, ["December2015"])
198  call feedkeys("aD\<f5>\<C-Y>\<C-Y>\<C-Y>\<C-Y>\<enter>\<esc>", 'tx')
199  call assert_equal(["December2015", "December201", ""], getline(1,3))
200  %d
201
202  " use longest for 'completeopt'
203  set completeopt&vim
204  call feedkeys("aM\<f5>\<C-N>\<C-P>\<c-e>\<enter>\<esc>", 'tx')
205  set completeopt+=longest
206  call feedkeys("aM\<f5>\<C-N>\<C-P>\<c-e>\<enter>\<esc>", 'tx')
207  call assert_equal(["M", "Ma", ""], getline(1,3))
208  %d
209
210  " use noselect/noinsert for 'completeopt'
211  set completeopt&vim
212  call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
213  set completeopt+=noselect
214  call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
215  set completeopt-=noselect completeopt+=noinsert
216  call feedkeys("aM\<f5>\<enter>\<esc>", 'tx')
217  call assert_equal(["March", "M", "March"], getline(1,4))
218  %d
219endfunc
220
221
222func Test_popup_completion_insertmode()
223  new
224  inoremap <F5> <C-R>=ListMonths()<CR>
225
226  call feedkeys("a\<f5>\<down>\<enter>\<esc>", 'tx')
227  call assert_equal('February', getline(1))
228  %d
229  " Set noinsertmode
230  let g:setting = 'noinsertmode'
231  call feedkeys("a\<f5>\<down>\<enter>\<esc>", 'tx')
232  call assert_equal('February', getline(1))
233  call assert_false(pumvisible())
234  %d
235  " Go through all matches, until none is selected
236  let g:setting = ''
237  call feedkeys("a\<f5>". repeat("\<c-n>",12)."\<enter>\<esc>", 'tx')
238  call assert_equal('', getline(1))
239  %d
240  " select previous entry
241  call feedkeys("a\<f5>\<c-p>\<enter>\<esc>", 'tx')
242  call assert_equal('', getline(1))
243  %d
244  " select last entry
245  call feedkeys("a\<f5>\<c-p>\<c-p>\<enter>\<esc>", 'tx')
246  call assert_equal('December', getline(1))
247
248  iunmap <F5>
249endfunc
250
251func Test_noinsert_complete()
252  func! s:complTest1() abort
253    eval ['source', 'soundfold']->complete(1)
254    return ''
255  endfunc
256
257  func! s:complTest2() abort
258    call complete(1, ['source', 'soundfold'])
259    return ''
260  endfunc
261
262  new
263  set completeopt+=noinsert
264  inoremap <F5>  <C-R>=s:complTest1()<CR>
265  call feedkeys("i\<F5>soun\<CR>\<CR>\<ESC>.", 'tx')
266  call assert_equal('soundfold', getline(1))
267  call assert_equal('soundfold', getline(2))
268  bwipe!
269
270  new
271  inoremap <F5>  <C-R>=s:complTest2()<CR>
272  call feedkeys("i\<F5>\<CR>\<ESC>", 'tx')
273  call assert_equal('source', getline(1))
274  bwipe!
275
276  set completeopt-=noinsert
277  iunmap <F5>
278endfunc
279
280func Test_complete_no_filter()
281  func! s:complTest1() abort
282    call complete(1, [{'word': 'foobar'}])
283    return ''
284  endfunc
285  func! s:complTest2() abort
286    call complete(1, [{'word': 'foobar', 'equal': 1}])
287    return ''
288  endfunc
289
290  let completeopt = &completeopt
291
292  " without equal=1
293  new
294  set completeopt=menuone,noinsert,menu
295  inoremap <F5>  <C-R>=s:complTest1()<CR>
296  call feedkeys("i\<F5>z\<CR>\<CR>\<ESC>.", 'tx')
297  call assert_equal('z', getline(1))
298  bwipe!
299
300  " with equal=1
301  new
302  set completeopt=menuone,noinsert,menu
303  inoremap <F5>  <C-R>=s:complTest2()<CR>
304  call feedkeys("i\<F5>z\<CR>\<CR>\<ESC>.", 'tx')
305  call assert_equal('foobar', getline(1))
306  bwipe!
307
308  let &completeopt = completeopt
309  iunmap <F5>
310endfunc
311
312func Test_compl_vim_cmds_after_register_expr()
313  func! s:test_func()
314    return 'autocmd '
315  endfunc
316  augroup AAAAA_Group
317    au!
318  augroup END
319
320  new
321  call feedkeys("i\<c-r>=s:test_func()\<CR>\<C-x>\<C-v>\<Esc>", 'tx')
322  call assert_equal('autocmd AAAAA_Group', getline(1))
323  autocmd! AAAAA_Group
324  augroup! AAAAA_Group
325  bwipe!
326endfunc
327
328func DummyCompleteOne(findstart, base)
329  if a:findstart
330    return 0
331  else
332    wincmd n
333    return ['onedef', 'oneDEF']
334  endif
335endfunc
336
337" Test that nothing happens if the 'completefunc' opens
338" a new window (no completion, no crash)
339func Test_completefunc_opens_new_window_one()
340  new
341  let winid = win_getid()
342  setlocal completefunc=DummyCompleteOne
343  call setline(1, 'one')
344  /^one
345  call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E839:')
346  call assert_notequal(winid, win_getid())
347  q!
348  call assert_equal(winid, win_getid())
349  call assert_equal('', getline(1))
350  q!
351endfunc
352
353" Test that nothing happens if the 'completefunc' opens
354" a new window (no completion, no crash)
355func DummyCompleteTwo(findstart, base)
356  if a:findstart
357    wincmd n
358    return 0
359  else
360    return ['twodef', 'twoDEF']
361  endif
362endfunc
363
364" Test that nothing happens if the 'completefunc' opens
365" a new window (no completion, no crash)
366func Test_completefunc_opens_new_window_two()
367  new
368  let winid = win_getid()
369  setlocal completefunc=DummyCompleteTwo
370  call setline(1, 'two')
371  /^two
372  call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E764:')
373  call assert_notequal(winid, win_getid())
374  q!
375  call assert_equal(winid, win_getid())
376  call assert_equal('two', getline(1))
377  q!
378endfunc
379
380func DummyCompleteThree(findstart, base)
381  if a:findstart
382    return 0
383  else
384    return ['threedef', 'threeDEF']
385  endif
386endfunc
387
388:"Test that 'completefunc' works when it's OK.
389func Test_completefunc_works()
390  new
391  let winid = win_getid()
392  setlocal completefunc=DummyCompleteThree
393  call setline(1, 'three')
394  /^three
395  call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")
396  call assert_equal(winid, win_getid())
397  call assert_equal('threeDEF', getline(1))
398  q!
399endfunc
400
401func DummyCompleteFour(findstart, base)
402  if a:findstart
403    return 0
404  else
405    call complete_add('four1')
406    eval 'four2'->complete_add()
407    call complete_check()
408    call complete_add('four3')
409    call complete_add('four4')
410    call complete_check()
411    call complete_add('four5')
412    call complete_add('four6')
413    return []
414  endif
415endfunc
416
417" Test that 'omnifunc' works when it's OK.
418func Test_omnifunc_with_check()
419  new
420  setlocal omnifunc=DummyCompleteFour
421  call setline(1, 'four')
422  /^four
423  call feedkeys("A\<C-X>\<C-O>\<C-N>\<Esc>", "x")
424  call assert_equal('four2', getline(1))
425
426  call setline(1, 'four')
427  /^four
428  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<Esc>", "x")
429  call assert_equal('four3', getline(1))
430
431  call setline(1, 'four')
432  /^four
433  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
434  call assert_equal('four5', getline(1))
435
436  q!
437endfunc
438
439func UndoComplete()
440  call complete(1, ['January', 'February', 'March',
441        \ 'April', 'May', 'June', 'July', 'August', 'September',
442        \ 'October', 'November', 'December'])
443  return ''
444endfunc
445
446" Test that no undo item is created when no completion is inserted
447func Test_complete_no_undo()
448  set completeopt=menu,preview,noinsert,noselect
449  inoremap <Right> <C-R>=UndoComplete()<CR>
450  new
451  call feedkeys("ixxx\<CR>\<CR>yyy\<Esc>k", 'xt')
452  call feedkeys("iaaa\<Esc>0", 'xt')
453  call assert_equal('aaa', getline(2))
454  call feedkeys("i\<Right>\<Esc>", 'xt')
455  call assert_equal('aaa', getline(2))
456  call feedkeys("u", 'xt')
457  call assert_equal('', getline(2))
458
459  call feedkeys("ibbb\<Esc>0", 'xt')
460  call assert_equal('bbb', getline(2))
461  call feedkeys("A\<Right>\<Down>\<CR>\<Esc>", 'xt')
462  call assert_equal('January', getline(2))
463  call feedkeys("u", 'xt')
464  call assert_equal('bbb', getline(2))
465
466  call feedkeys("A\<Right>\<C-N>\<Esc>", 'xt')
467  call assert_equal('January', getline(2))
468  call feedkeys("u", 'xt')
469  call assert_equal('bbb', getline(2))
470
471  iunmap <Right>
472  set completeopt&
473  q!
474endfunc
475
476func DummyCompleteFive(findstart, base)
477  if a:findstart
478    return 0
479  else
480    return [
481          \   { 'word': 'January', 'info': "info1-1\n1-2\n1-3" },
482          \   { 'word': 'February', 'info': "info2-1\n2-2\n2-3" },
483          \   { 'word': 'March', 'info': "info3-1\n3-2\n3-3" },
484          \   { 'word': 'April', 'info': "info4-1\n4-2\n4-3" },
485          \   { 'word': 'May', 'info': "info5-1\n5-2\n5-3" },
486          \ ]
487  endif
488endfunc
489
490" Test that 'completefunc' on Scratch buffer with preview window works when
491" it's OK.
492func Test_completefunc_with_scratch_buffer()
493  CheckFeature quickfix
494
495  new +setlocal\ buftype=nofile\ bufhidden=wipe\ noswapfile
496  set completeopt+=preview
497  setlocal completefunc=DummyCompleteFive
498  call feedkeys("A\<C-X>\<C-U>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
499  call assert_equal(['April'], getline(1, '$'))
500  pclose
501  q!
502  set completeopt&
503endfunc
504
505" <C-E> - select original typed text before the completion started without
506" auto-wrap text.
507func Test_completion_ctrl_e_without_autowrap()
508  new
509  let tw_save = &tw
510  set tw=78
511  let li = [
512        \ '"                                                        zzz',
513        \ '" zzzyyyyyyyyyyyyyyyyyyy']
514  call setline(1, li)
515  0
516  call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
517  call assert_equal(li, getline(1, '$'))
518
519  let &tw = tw_save
520  q!
521endfunc
522
523func DummyCompleteSix()
524  call complete(1, ['Hello', 'World'])
525  return ''
526endfunction
527
528" complete() correctly clears the list of autocomplete candidates
529" See #1411
530func Test_completion_clear_candidate_list()
531  new
532  %d
533  " select first entry from the completion popup
534  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
535  call assert_equal('Hello', getline(1))
536  %d
537  " select second entry from the completion popup
538  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
539  call assert_equal('World', getline(1))
540  %d
541  " select original text
542  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
543  call assert_equal('    xxx', getline(1))
544  %d
545  " back at first entry from completion list
546  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
547  call assert_equal('Hello', getline(1))
548
549  bw!
550endfunc
551
552func Test_completion_respect_bs_option()
553  new
554  let li = ["aaa", "aaa12345", "aaaabcdef", "aaaABC"]
555
556  set bs=indent,eol
557  call setline(1, li)
558  1
559  call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
560  call assert_equal('aaa', getline(1))
561
562  %d
563  set bs=indent,eol,start
564  call setline(1, li)
565  1
566  call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
567  call assert_equal('', getline(1))
568
569  bw!
570endfunc
571
572func CompleteUndo() abort
573  call complete(1, g:months)
574  return ''
575endfunc
576
577func Test_completion_can_undo()
578  inoremap <Right> <c-r>=CompleteUndo()<cr>
579  set completeopt+=noinsert,noselect
580
581  new
582  call feedkeys("a\<Right>a\<Esc>", 'xt')
583  call assert_equal('a', getline(1))
584  undo
585  call assert_equal('', getline(1))
586
587  bwipe!
588  set completeopt&
589  iunmap <Right>
590endfunc
591
592func Test_completion_comment_formatting()
593  new
594  setl formatoptions=tcqro
595  call feedkeys("o/*\<cr>\<cr>/\<esc>", 'tx')
596  call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
597  %d
598  call feedkeys("o/*\<cr>foobar\<cr>/\<esc>", 'tx')
599  call assert_equal(['', '/*', ' * foobar', ' */'], getline(1,4))
600  %d
601  try
602    call feedkeys("o/*\<cr>\<cr>\<c-x>\<c-u>/\<esc>", 'tx')
603    call assert_report('completefunc not set, should have failed')
604  catch
605    call assert_exception('E764:')
606  endtry
607  call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
608  bwipe!
609endfunc
610
611func MessCompleteMonths()
612  for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep")
613    call complete_add(m)
614    if complete_check()
615      break
616    endif
617  endfor
618  return []
619endfunc
620
621func MessCompleteMore()
622  call complete(1, split("Oct Nov Dec"))
623  return []
624endfunc
625
626func MessComplete(findstart, base)
627  if a:findstart
628    let line = getline('.')
629    let start = col('.') - 1
630    while start > 0 && line[start - 1] =~ '\a'
631      let start -= 1
632    endwhile
633    return start
634  else
635    call MessCompleteMonths()
636    call MessCompleteMore()
637    return []
638  endif
639endfunc
640
641func Test_complete_func_mess()
642  " Calling complete() after complete_add() in 'completefunc' is wrong, but it
643  " should not crash.
644  set completefunc=MessComplete
645  new
646  call setline(1, 'Ju')
647  call feedkeys("A\<c-x>\<c-u>/\<esc>", 'tx')
648  call assert_equal('Oct/Oct', getline(1))
649  bwipe!
650  set completefunc=
651endfunc
652
653func Test_complete_CTRLN_startofbuffer()
654  new
655  call setline(1, [ 'organize(cupboard, 3, 2);',
656        \ 'prioritize(bureau, 8, 7);',
657        \ 'realize(bannister, 4, 4);',
658        \ 'moralize(railing, 3,9);'])
659  let expected=['cupboard.organize(3, 2);',
660        \ 'bureau.prioritize(8, 7);',
661        \ 'bannister.realize(4, 4);',
662        \ 'railing.moralize(3,9);']
663  call feedkeys("qai\<c-n>\<c-n>.\<esc>3wdW\<cr>q3@a", 'tx')
664  call assert_equal(expected, getline(1,'$'))
665  bwipe!
666endfunc
667
668func Test_popup_and_window_resize()
669  CheckFeature terminal
670  CheckFeature quickfix
671  CheckNotGui
672
673  let h = winheight(0)
674  if h < 15
675    return
676  endif
677  let rows = h / 3
678  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': rows})
679  call term_sendkeys(buf, (h / 3 - 1) . "o\<esc>")
680  " Wait for the nested Vim to exit insert mode, where it will show the ruler.
681  " Need to trigger a redraw.
682  call WaitFor({-> execute("redraw") == "" && term_getline(buf, rows) =~ '\<' . rows . ',.*Bot'})
683
684  call term_sendkeys(buf, "Gi\<c-x>")
685  call term_sendkeys(buf, "\<c-v>")
686  call term_wait(buf, 100)
687  " popup first entry "!" must be at the top
688  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, 1))})
689  exe 'resize +' . (h - 1)
690  call term_wait(buf, 100)
691  redraw!
692  " popup shifted down, first line is now empty
693  call WaitForAssert({-> assert_equal('', term_getline(buf, 1))})
694  sleep 100m
695  " popup is below cursor line and shows first match "!"
696  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0] + 1))})
697  " cursor line also shows !
698  call assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0]))
699  bwipe!
700endfunc
701
702func Test_popup_and_preview_autocommand()
703  CheckFeature python
704  CheckFeature quickfix
705  if winheight(0) < 15
706    throw 'Skipped: window height insufficient'
707  endif
708
709  " This used to crash Vim
710  new
711  augroup MyBufAdd
712    au!
713    au BufAdd * nested tab sball
714  augroup END
715  set omnifunc=pythoncomplete#Complete
716  call setline(1, 'import os')
717  " make the line long
718  call setline(2, '                                 os.')
719  $
720  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
721  call assert_equal("import os", getline(1))
722  call assert_match('                                 os.\(EX_IOERR\|O_CREAT\)$', getline(2))
723  call assert_equal(1, winnr('$'))
724  " previewwindow option is not set
725  call assert_equal(0, &previewwindow)
726  norm! gt
727  call assert_equal(0, &previewwindow)
728  norm! gT
729  call assert_equal(10, tabpagenr('$'))
730  tabonly
731  pclose
732  augroup MyBufAdd
733    au!
734  augroup END
735  augroup! MyBufAdd
736  bw!
737endfunc
738
739func Test_popup_and_previewwindow_dump()
740  CheckScreendump
741  CheckFeature quickfix
742
743  let lines =<< trim END
744    set previewheight=9
745    silent! pedit
746    call setline(1, map(repeat(["ab"], 10), "v:val. v:key"))
747    exec "norm! G\<C-E>\<C-E>"
748  END
749  call writefile(lines, 'Xscript')
750  let buf = RunVimInTerminal('-S Xscript', {})
751
752  " Test that popup and previewwindow do not overlap.
753  call term_sendkeys(buf, "o\<C-X>\<C-N>")
754  sleep 100m
755  call VerifyScreenDump(buf, 'Test_popup_and_previewwindow_01', {})
756
757  call term_sendkeys(buf, "\<Esc>u")
758  call StopVimInTerminal(buf)
759  call delete('Xscript')
760endfunc
761
762func Test_balloon_split()
763  CheckFunction balloon_split
764
765  call assert_equal([
766        \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
767        \ ], balloon_split(
768        \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
769  call assert_equal([
770        \ 'one two three four one two three four one two thre',
771        \ 'e four',
772        \ ], balloon_split(
773        \ 'one two three four one two three four one two three four'))
774
775  eval 'struct = {one = 1, two = 2, three = 3}'
776        \ ->balloon_split()
777        \ ->assert_equal([
778        \   'struct = {',
779        \   '  one = 1,',
780        \   '  two = 2,',
781        \   '  three = 3}',
782        \ ])
783
784  call assert_equal([
785        \ 'struct = {',
786        \ '  one = 1,',
787        \ '  nested = {',
788        \ '    n1 = "yes",',
789        \ '    n2 = "no"}',
790        \ '  two = 2}',
791        \ ], balloon_split(
792        \ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
793  call assert_equal([
794        \ 'struct = 0x234 {',
795        \ '  long = 2343 "\\"some long string that will be wr',
796        \ 'apped in two\\"",',
797        \ '  next = 123}',
798        \ ], balloon_split(
799        \ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
800  call assert_equal([
801        \ 'Some comment',
802        \ '',
803        \ 'typedef this that;',
804        \ ], balloon_split(
805        \ "Some comment\n\ntypedef this that;"))
806endfunc
807
808func Test_popup_position()
809  CheckScreendump
810
811  let lines =<< trim END
812    123456789_123456789_123456789_a
813    123456789_123456789_123456789_b
814                123
815  END
816  call writefile(lines, 'Xtest')
817  let buf = RunVimInTerminal('Xtest', {})
818  call term_sendkeys(buf, ":vsplit\<CR>")
819
820  " default pumwidth in left window: overlap in right window
821  call term_sendkeys(buf, "GA\<C-N>")
822  call VerifyScreenDump(buf, 'Test_popup_position_01', {'rows': 8})
823  call term_sendkeys(buf, "\<Esc>u")
824
825  " default pumwidth: fill until right of window
826  call term_sendkeys(buf, "\<C-W>l")
827  call term_sendkeys(buf, "GA\<C-N>")
828  call VerifyScreenDump(buf, 'Test_popup_position_02', {'rows': 8})
829
830  " larger pumwidth: used as minimum width
831  call term_sendkeys(buf, "\<Esc>u")
832  call term_sendkeys(buf, ":set pumwidth=30\<CR>")
833  call term_sendkeys(buf, "GA\<C-N>")
834  call VerifyScreenDump(buf, 'Test_popup_position_03', {'rows': 8})
835
836  " completed text wider than the window and 'pumwidth' smaller than available
837  " space
838  call term_sendkeys(buf, "\<Esc>u")
839  call term_sendkeys(buf, ":set pumwidth=20\<CR>")
840  call term_sendkeys(buf, "ggI123456789_\<Esc>")
841  call term_sendkeys(buf, "jI123456789_\<Esc>")
842  call term_sendkeys(buf, "GA\<C-N>")
843  call VerifyScreenDump(buf, 'Test_popup_position_04', {'rows': 10})
844
845  call term_sendkeys(buf, "\<Esc>u")
846  call StopVimInTerminal(buf)
847  call delete('Xtest')
848endfunc
849
850func Test_popup_command()
851  CheckScreendump
852  CheckFeature menu
853
854  let lines =<< trim END
855	one two three four five
856	and one two Xthree four five
857	one more two three four five
858  END
859  call writefile(lines, 'Xtest')
860  let buf = RunVimInTerminal('Xtest', {})
861  call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
862  call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
863  call VerifyScreenDump(buf, 'Test_popup_command_01', {})
864
865  " Select a word
866  call term_sendkeys(buf, "jj")
867  call VerifyScreenDump(buf, 'Test_popup_command_02', {})
868
869  " Select a word
870  call term_sendkeys(buf, "j\<CR>")
871  call VerifyScreenDump(buf, 'Test_popup_command_03', {})
872
873  call term_sendkeys(buf, "\<Esc>")
874  call StopVimInTerminal(buf)
875  call delete('Xtest')
876endfunc
877
878func Test_popup_complete_backwards()
879  new
880  call setline(1, ['Post', 'Port', 'Po'])
881  let expected=['Post', 'Port', 'Port']
882  call cursor(3,2)
883  call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
884  call assert_equal(expected, getline(1,'$'))
885  bwipe!
886endfunc
887
888func Test_popup_complete_backwards_ctrl_p()
889  new
890  call setline(1, ['Post', 'Port', 'Po'])
891  let expected=['Post', 'Port', 'Port']
892  call cursor(3,2)
893  call feedkeys("A\<C-P>\<C-N>rt\<cr>", 'tx')
894  call assert_equal(expected, getline(1,'$'))
895  bwipe!
896endfunc
897
898func Test_complete_o_tab()
899  let s:o_char_pressed = 0
900
901  fun! s:act_on_text_changed()
902    if s:o_char_pressed
903      let s:o_char_pressed = 0
904      call feedkeys("\<c-x>\<c-n>", 'i')
905    endif
906  endfunc
907
908  set completeopt=menu,noselect
909  new
910  imap <expr> <buffer> <tab> pumvisible() ? "\<c-p>" : "X"
911  autocmd! InsertCharPre <buffer> let s:o_char_pressed = (v:char ==# 'o')
912  autocmd! TextChangedI <buffer> call <sid>act_on_text_changed()
913  call setline(1,  ['hoard', 'hoax', 'hoarse', ''])
914  let l:expected = ['hoard', 'hoax', 'hoarse', 'hoax', 'hoax']
915  call cursor(4,1)
916  call test_override("char_avail", 1)
917  call feedkeys("Ahoa\<tab>\<tab>\<c-y>\<esc>", 'tx')
918  call feedkeys("oho\<tab>\<tab>\<c-y>\<esc>", 'tx')
919  call assert_equal(l:expected, getline(1,'$'))
920
921  call test_override("char_avail", 0)
922  bwipe!
923  set completeopt&
924  delfunc s:act_on_text_changed
925endfunc
926
927func Test_menu_only_exists_in_terminal()
928  CheckCommand tlmenu
929  CheckNotGui
930
931  tlnoremenu  &Edit.&Paste<Tab>"+gP  <C-W>"+
932  aunmenu *
933  try
934    popup Edit
935    call assert_false(1, 'command should have failed')
936  catch
937    call assert_exception('E328:')
938  endtry
939endfunc
940
941func Test_popup_complete_info_01()
942  new
943  inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
944  func s:complTestEval() abort
945    call complete(1, ['aa', 'ab'])
946    return ''
947  endfunc
948  inoremap <buffer><F6> <C-R>=s:complTestEval()<CR>
949  call writefile([
950        \ 'dummy	dummy.txt	1',
951        \], 'Xdummy.txt')
952  setlocal tags=Xdummy.txt
953  setlocal dictionary=Xdummy.txt
954  setlocal thesaurus=Xdummy.txt
955  setlocal omnifunc=syntaxcomplete#Complete
956  setlocal completefunc=syntaxcomplete#Complete
957  setlocal spell
958  for [keys, mode_name] in [
959        \ ["", ''],
960        \ ["\<C-X>", 'ctrl_x'],
961        \ ["\<C-X>\<C-N>", 'keyword'],
962        \ ["\<C-X>\<C-P>", 'keyword'],
963        \ ["\<C-X>\<C-L>", 'whole_line'],
964        \ ["\<C-X>\<C-F>", 'files'],
965        \ ["\<C-X>\<C-]>", 'tags'],
966        \ ["\<C-X>\<C-D>", 'path_defines'],
967        \ ["\<C-X>\<C-I>", 'path_patterns'],
968        \ ["\<C-X>\<C-K>", 'dictionary'],
969        \ ["\<C-X>\<C-T>", 'thesaurus'],
970        \ ["\<C-X>\<C-V>", 'cmdline'],
971        \ ["\<C-X>\<C-U>", 'function'],
972        \ ["\<C-X>\<C-O>", 'omni'],
973        \ ["\<C-X>s", 'spell'],
974        \ ["\<F6>", 'eval'],
975        \]
976    call feedkeys("i" . keys . "\<F5>\<Esc>", 'tx')
977    call assert_equal(mode_name, getline('.'))
978    %d
979  endfor
980  call delete('Xdummy.txt')
981  bwipe!
982endfunc
983
984func UserDefinedComplete(findstart, base)
985  if a:findstart
986    return 0
987  else
988    return [
989          \   { 'word': 'Jan', 'menu': 'January' },
990          \   { 'word': 'Feb', 'menu': 'February' },
991          \   { 'word': 'Mar', 'menu': 'March' },
992          \   { 'word': 'Apr', 'menu': 'April' },
993          \   { 'word': 'May', 'menu': 'May' },
994          \ ]
995  endif
996endfunc
997
998func GetCompleteInfo()
999  if empty(g:compl_what)
1000    let g:compl_info = complete_info()
1001  else
1002    let g:compl_info = g:compl_what->complete_info()
1003  endif
1004  return ''
1005endfunc
1006
1007func Test_popup_complete_info_02()
1008  new
1009  inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR>
1010  setlocal completefunc=UserDefinedComplete
1011
1012  let d = {
1013    \   'mode': 'function',
1014    \   'pum_visible': 1,
1015    \   'items': [
1016    \     {'word': 'Jan', 'menu': 'January', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1017    \     {'word': 'Feb', 'menu': 'February', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1018    \     {'word': 'Mar', 'menu': 'March', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1019    \     {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1020    \     {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
1021    \   ],
1022    \   'selected': 0,
1023    \ }
1024
1025  let g:compl_what = []
1026  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1027  call assert_equal(d, g:compl_info)
1028
1029  let g:compl_what = ['mode', 'pum_visible', 'selected']
1030  call remove(d, 'items')
1031  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1032  call assert_equal(d, g:compl_info)
1033
1034  let g:compl_what = ['mode']
1035  call remove(d, 'selected')
1036  call remove(d, 'pum_visible')
1037  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1038  call assert_equal(d, g:compl_info)
1039  bwipe!
1040endfunc
1041
1042func Test_popup_complete_info_no_pum()
1043  new
1044  call assert_false( pumvisible() )
1045  let no_pum_info = complete_info()
1046  let d = {
1047        \   'mode': '',
1048        \   'pum_visible': 0,
1049        \   'items': [],
1050        \   'selected': -1,
1051        \  }
1052  call assert_equal( d, complete_info() )
1053  bwipe!
1054endfunc
1055
1056func Test_CompleteChanged()
1057  new
1058  call setline(1, ['foo', 'bar', 'foobar', ''])
1059  set complete=. completeopt=noinsert,noselect,menuone
1060  function! OnPumChange()
1061    let g:event = copy(v:event)
1062    let g:item = get(v:event, 'completed_item', {})
1063    let g:word = get(g:item, 'word', v:null)
1064  endfunction
1065  augroup AAAAA_Group
1066    au!
1067    autocmd CompleteChanged * :call OnPumChange()
1068  augroup END
1069  call cursor(4, 1)
1070
1071  call feedkeys("Sf\<C-N>", 'tx')
1072  call assert_equal({'completed_item': {}, 'width': 15,
1073        \ 'height': 2, 'size': 2,
1074        \ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
1075  call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
1076  call assert_equal('foo', g:word)
1077  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1078  call assert_equal('foobar', g:word)
1079  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1080  call assert_equal(v:null, g:word)
1081  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
1082  call assert_equal('foobar', g:word)
1083
1084  autocmd! AAAAA_Group
1085  set complete& completeopt&
1086  delfunc! OnPumChange
1087  bw!
1088endfunc
1089
1090function! GetPumPosition()
1091  call assert_true( pumvisible() )
1092  let g:pum_pos = pum_getpos()
1093  return ''
1094endfunction
1095
1096func Test_pum_getpos()
1097  new
1098  inoremap <buffer><F5> <C-R>=GetPumPosition()<CR>
1099  setlocal completefunc=UserDefinedComplete
1100
1101  let d = {
1102    \   'height':    5,
1103    \   'width':     15,
1104    \   'row':       1,
1105    \   'col':       0,
1106    \   'size':      5,
1107    \   'scrollbar': v:false,
1108    \ }
1109  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1110  call assert_equal(d, g:pum_pos)
1111
1112  call assert_false( pumvisible() )
1113  call assert_equal( {}, pum_getpos() )
1114  bw!
1115  unlet g:pum_pos
1116endfunc
1117
1118" vim: shiftwidth=2 sts=2 expandtab
1119