xref: /vim-8.2.3635/src/testdir/test_popup.vim (revision 4c295027)
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' tries to open
338" a new window (fails to open window, continues)
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")', 'E565:')
346  call assert_equal(winid, win_getid())
347  call assert_equal('onedef', getline(1))
348  q!
349endfunc
350
351" Test that nothing happens if the 'completefunc' opens
352" a new window (no completion, no crash)
353func DummyCompleteTwo(findstart, base)
354  if a:findstart
355    wincmd n
356    return 0
357  else
358    return ['twodef', 'twoDEF']
359  endif
360endfunc
361
362" Test that nothing happens if the 'completefunc' opens
363" a new window (no completion, no crash)
364func Test_completefunc_opens_new_window_two()
365  new
366  let winid = win_getid()
367  setlocal completefunc=DummyCompleteTwo
368  call setline(1, 'two')
369  /^two
370  call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
371  call assert_equal(winid, win_getid())
372  call assert_equal('twodef', getline(1))
373  q!
374endfunc
375
376func DummyCompleteThree(findstart, base)
377  if a:findstart
378    return 0
379  else
380    return ['threedef', 'threeDEF']
381  endif
382endfunc
383
384:"Test that 'completefunc' works when it's OK.
385func Test_completefunc_works()
386  new
387  let winid = win_getid()
388  setlocal completefunc=DummyCompleteThree
389  call setline(1, 'three')
390  /^three
391  call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")
392  call assert_equal(winid, win_getid())
393  call assert_equal('threeDEF', getline(1))
394  q!
395endfunc
396
397func DummyCompleteFour(findstart, base)
398  if a:findstart
399    return 0
400  else
401    call complete_add('four1')
402    eval 'four2'->complete_add()
403    call complete_check()
404    call complete_add('four3')
405    call complete_add('four4')
406    call complete_check()
407    call complete_add('four5')
408    call complete_add('four6')
409    return []
410  endif
411endfunc
412
413" Test that 'omnifunc' works when it's OK.
414func Test_omnifunc_with_check()
415  new
416  setlocal omnifunc=DummyCompleteFour
417  call setline(1, 'four')
418  /^four
419  call feedkeys("A\<C-X>\<C-O>\<C-N>\<Esc>", "x")
420  call assert_equal('four2', getline(1))
421
422  call setline(1, 'four')
423  /^four
424  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<Esc>", "x")
425  call assert_equal('four3', getline(1))
426
427  call setline(1, 'four')
428  /^four
429  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
430  call assert_equal('four5', getline(1))
431
432  q!
433endfunc
434
435func UndoComplete()
436  call complete(1, ['January', 'February', 'March',
437        \ 'April', 'May', 'June', 'July', 'August', 'September',
438        \ 'October', 'November', 'December'])
439  return ''
440endfunc
441
442" Test that no undo item is created when no completion is inserted
443func Test_complete_no_undo()
444  set completeopt=menu,preview,noinsert,noselect
445  inoremap <Right> <C-R>=UndoComplete()<CR>
446  new
447  call feedkeys("ixxx\<CR>\<CR>yyy\<Esc>k", 'xt')
448  call feedkeys("iaaa\<Esc>0", 'xt')
449  call assert_equal('aaa', getline(2))
450  call feedkeys("i\<Right>\<Esc>", 'xt')
451  call assert_equal('aaa', getline(2))
452  call feedkeys("u", 'xt')
453  call assert_equal('', getline(2))
454
455  call feedkeys("ibbb\<Esc>0", 'xt')
456  call assert_equal('bbb', getline(2))
457  call feedkeys("A\<Right>\<Down>\<CR>\<Esc>", 'xt')
458  call assert_equal('January', getline(2))
459  call feedkeys("u", 'xt')
460  call assert_equal('bbb', getline(2))
461
462  call feedkeys("A\<Right>\<C-N>\<Esc>", 'xt')
463  call assert_equal('January', getline(2))
464  call feedkeys("u", 'xt')
465  call assert_equal('bbb', getline(2))
466
467  iunmap <Right>
468  set completeopt&
469  q!
470endfunc
471
472func DummyCompleteFive(findstart, base)
473  if a:findstart
474    return 0
475  else
476    return [
477          \   { 'word': 'January', 'info': "info1-1\n1-2\n1-3" },
478          \   { 'word': 'February', 'info': "info2-1\n2-2\n2-3" },
479          \   { 'word': 'March', 'info': "info3-1\n3-2\n3-3" },
480          \   { 'word': 'April', 'info': "info4-1\n4-2\n4-3" },
481          \   { 'word': 'May', 'info': "info5-1\n5-2\n5-3" },
482          \ ]
483  endif
484endfunc
485
486" Test that 'completefunc' on Scratch buffer with preview window works when
487" it's OK.
488func Test_completefunc_with_scratch_buffer()
489  CheckFeature quickfix
490
491  new +setlocal\ buftype=nofile\ bufhidden=wipe\ noswapfile
492  set completeopt+=preview
493  setlocal completefunc=DummyCompleteFive
494  call feedkeys("A\<C-X>\<C-U>\<C-N>\<C-N>\<C-N>\<Esc>", "x")
495  call assert_equal(['April'], getline(1, '$'))
496  pclose
497  q!
498  set completeopt&
499endfunc
500
501" <C-E> - select original typed text before the completion started without
502" auto-wrap text.
503func Test_completion_ctrl_e_without_autowrap()
504  new
505  let tw_save = &tw
506  set tw=78
507  let li = [
508        \ '"                                                        zzz',
509        \ '" zzzyyyyyyyyyyyyyyyyyyy']
510  call setline(1, li)
511  0
512  call feedkeys("A\<C-X>\<C-N>\<C-E>\<Esc>", "tx")
513  call assert_equal(li, getline(1, '$'))
514
515  let &tw = tw_save
516  q!
517endfunc
518
519func DummyCompleteSix()
520  call complete(1, ['Hello', 'World'])
521  return ''
522endfunction
523
524" complete() correctly clears the list of autocomplete candidates
525" See #1411
526func Test_completion_clear_candidate_list()
527  new
528  %d
529  " select first entry from the completion popup
530  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
531  call assert_equal('Hello', getline(1))
532  %d
533  " select second entry from the completion popup
534  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
535  call assert_equal('World', getline(1))
536  %d
537  " select original text
538  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
539  call assert_equal('    xxx', getline(1))
540  %d
541  " back at first entry from completion list
542  call feedkeys("a    xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
543  call assert_equal('Hello', getline(1))
544
545  bw!
546endfunc
547
548func Test_completion_respect_bs_option()
549  new
550  let li = ["aaa", "aaa12345", "aaaabcdef", "aaaABC"]
551
552  set bs=indent,eol
553  call setline(1, li)
554  1
555  call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
556  call assert_equal('aaa', getline(1))
557
558  %d
559  set bs=indent,eol,start
560  call setline(1, li)
561  1
562  call feedkeys("A\<C-X>\<C-N>\<C-P>\<BS>\<BS>\<BS>\<Esc>", "tx")
563  call assert_equal('', getline(1))
564
565  bw!
566endfunc
567
568func CompleteUndo() abort
569  call complete(1, g:months)
570  return ''
571endfunc
572
573func Test_completion_can_undo()
574  inoremap <Right> <c-r>=CompleteUndo()<cr>
575  set completeopt+=noinsert,noselect
576
577  new
578  call feedkeys("a\<Right>a\<Esc>", 'xt')
579  call assert_equal('a', getline(1))
580  undo
581  call assert_equal('', getline(1))
582
583  bwipe!
584  set completeopt&
585  iunmap <Right>
586endfunc
587
588func Test_completion_comment_formatting()
589  new
590  setl formatoptions=tcqro
591  call feedkeys("o/*\<cr>\<cr>/\<esc>", 'tx')
592  call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
593  %d
594  call feedkeys("o/*\<cr>foobar\<cr>/\<esc>", 'tx')
595  call assert_equal(['', '/*', ' * foobar', ' */'], getline(1,4))
596  %d
597  try
598    call feedkeys("o/*\<cr>\<cr>\<c-x>\<c-u>/\<esc>", 'tx')
599    call assert_report('completefunc not set, should have failed')
600  catch
601    call assert_exception('E764:')
602  endtry
603  call assert_equal(['', '/*', ' *', ' */'], getline(1,4))
604  bwipe!
605endfunc
606
607func MessCompleteMonths()
608  for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep")
609    call complete_add(m)
610    if complete_check()
611      break
612    endif
613  endfor
614  return []
615endfunc
616
617func MessCompleteMore()
618  call complete(1, split("Oct Nov Dec"))
619  return []
620endfunc
621
622func MessComplete(findstart, base)
623  if a:findstart
624    let line = getline('.')
625    let start = col('.') - 1
626    while start > 0 && line[start - 1] =~ '\a'
627      let start -= 1
628    endwhile
629    return start
630  else
631    call MessCompleteMonths()
632    call MessCompleteMore()
633    return []
634  endif
635endfunc
636
637func Test_complete_func_mess()
638  " Calling complete() after complete_add() in 'completefunc' is wrong, but it
639  " should not crash.
640  set completefunc=MessComplete
641  new
642  call setline(1, 'Ju')
643  call assert_fails('call feedkeys("A\<c-x>\<c-u>/\<esc>", "tx")', 'E578:')
644  call assert_equal('Jan/', getline(1))
645  bwipe!
646  set completefunc=
647endfunc
648
649func Test_complete_CTRLN_startofbuffer()
650  new
651  call setline(1, [ 'organize(cupboard, 3, 2);',
652        \ 'prioritize(bureau, 8, 7);',
653        \ 'realize(bannister, 4, 4);',
654        \ 'moralize(railing, 3,9);'])
655  let expected=['cupboard.organize(3, 2);',
656        \ 'bureau.prioritize(8, 7);',
657        \ 'bannister.realize(4, 4);',
658        \ 'railing.moralize(3,9);']
659  call feedkeys("qai\<c-n>\<c-n>.\<esc>3wdW\<cr>q3@a", 'tx')
660  call assert_equal(expected, getline(1,'$'))
661  bwipe!
662endfunc
663
664func Test_popup_and_window_resize()
665  CheckFeature terminal
666  CheckFeature quickfix
667  CheckNotGui
668
669  let h = winheight(0)
670  if h < 15
671    return
672  endif
673  let rows = h / 3
674  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': rows})
675  call term_sendkeys(buf, (h / 3 - 1) . "o\<esc>")
676  " Wait for the nested Vim to exit insert mode, where it will show the ruler.
677  " Need to trigger a redraw.
678  call WaitFor({-> execute("redraw") == "" && term_getline(buf, rows) =~ '\<' . rows . ',.*Bot'})
679
680  call term_sendkeys(buf, "Gi\<c-x>")
681  call term_sendkeys(buf, "\<c-v>")
682  call TermWait(buf, 50)
683  " popup first entry "!" must be at the top
684  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, 1))})
685  exe 'resize +' . (h - 1)
686  call TermWait(buf, 50)
687  redraw!
688  " popup shifted down, first line is now empty
689  call WaitForAssert({-> assert_equal('', term_getline(buf, 1))})
690  sleep 100m
691  " popup is below cursor line and shows first match "!"
692  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0] + 1))})
693  " cursor line also shows !
694  call assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0]))
695  bwipe!
696endfunc
697
698func Test_popup_and_preview_autocommand()
699  CheckFeature python
700  CheckFeature quickfix
701  if winheight(0) < 15
702    throw 'Skipped: window height insufficient'
703  endif
704
705  " This used to crash Vim
706  new
707  augroup MyBufAdd
708    au!
709    au BufAdd * nested tab sball
710  augroup END
711  set omnifunc=pythoncomplete#Complete
712  call setline(1, 'import os')
713  " make the line long
714  call setline(2, '                                 os.')
715  $
716  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
717  call assert_equal("import os", getline(1))
718  call assert_match('                                 os.\(EX_IOERR\|O_CREAT\)$', getline(2))
719  call assert_equal(1, winnr('$'))
720  " previewwindow option is not set
721  call assert_equal(0, &previewwindow)
722  norm! gt
723  call assert_equal(0, &previewwindow)
724  norm! gT
725  call assert_equal(10, tabpagenr('$'))
726  tabonly
727  pclose
728  augroup MyBufAdd
729    au!
730  augroup END
731  augroup! MyBufAdd
732  bw!
733endfunc
734
735func Test_popup_and_previewwindow_dump()
736  CheckScreendump
737  CheckFeature quickfix
738
739  let lines =<< trim END
740    set previewheight=9
741    silent! pedit
742    call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
743    exec "norm! G\<C-E>\<C-E>"
744  END
745  call writefile(lines, 'Xscript')
746  let buf = RunVimInTerminal('-S Xscript', {})
747
748  " wait for the script to finish
749  call TermWait(buf)
750
751  " Test that popup and previewwindow do not overlap.
752  call term_sendkeys(buf, "o")
753  call TermWait(buf, 50)
754  call term_sendkeys(buf, "\<C-X>\<C-N>")
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  menu Test.Foo Foo
855  call assert_fails('popup Test.Foo', 'E336:')
856  call assert_fails('popup Test.Foo.X', 'E327:')
857  call assert_fails('popup Foo', 'E337:')
858  unmenu Test.Foo
859
860  let script =<< trim END
861    func StartTimer()
862      call timer_start(100, {-> ChangeMenu()})
863    endfunc
864    func ChangeMenu()
865      nunmenu PopUp.&Paste
866      nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
867      echomsg 'changed'
868    endfunc
869  END
870  call writefile(script, 'XtimerScript')
871
872  let lines =<< trim END
873	one two three four five
874	and one two Xthree four five
875	one more two three four five
876  END
877  call writefile(lines, 'Xtest')
878  let buf = RunVimInTerminal('-S XtimerScript Xtest', {})
879  call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
880  call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
881  call VerifyScreenDump(buf, 'Test_popup_command_01', {})
882
883  " go to the Paste entry in the menu
884  call term_sendkeys(buf, "jj")
885  call VerifyScreenDump(buf, 'Test_popup_command_02', {})
886
887  " Select a word
888  call term_sendkeys(buf, "j\<CR>")
889  call VerifyScreenDump(buf, 'Test_popup_command_03', {})
890
891  call term_sendkeys(buf, "\<Esc>")
892
893  " Set a timer to change a menu entry while it's displayed.  The text should
894  " not change but the command does.  Making the screendump also verifies that
895  " "changed" shows up, which means the timer triggered
896  call term_sendkeys(buf, "/X\<CR>:call StartTimer() | popup PopUp\<CR>")
897  call VerifyScreenDump(buf, 'Test_popup_command_04', {})
898
899  " Select the Paste entry, executes the changed menu item.
900  call term_sendkeys(buf, "jj\<CR>")
901  call VerifyScreenDump(buf, 'Test_popup_command_05', {})
902
903  call StopVimInTerminal(buf)
904  call delete('Xtest')
905  call delete('XtimerScript')
906endfunc
907
908func Test_popup_complete_backwards()
909  new
910  call setline(1, ['Post', 'Port', 'Po'])
911  let expected=['Post', 'Port', 'Port']
912  call cursor(3,2)
913  call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
914  call assert_equal(expected, getline(1,'$'))
915  bwipe!
916endfunc
917
918func Test_popup_complete_backwards_ctrl_p()
919  new
920  call setline(1, ['Post', 'Port', 'Po'])
921  let expected=['Post', 'Port', 'Port']
922  call cursor(3,2)
923  call feedkeys("A\<C-P>\<C-N>rt\<cr>", 'tx')
924  call assert_equal(expected, getline(1,'$'))
925  bwipe!
926endfunc
927
928func Test_complete_o_tab()
929  let s:o_char_pressed = 0
930
931  fun! s:act_on_text_changed()
932    if s:o_char_pressed
933      let s:o_char_pressed = 0
934      call feedkeys("\<c-x>\<c-n>", 'i')
935    endif
936  endfunc
937
938  set completeopt=menu,noselect
939  new
940  imap <expr> <buffer> <tab> pumvisible() ? "\<c-p>" : "X"
941  autocmd! InsertCharPre <buffer> let s:o_char_pressed = (v:char ==# 'o')
942  autocmd! TextChangedI <buffer> call <sid>act_on_text_changed()
943  call setline(1,  ['hoard', 'hoax', 'hoarse', ''])
944  let l:expected = ['hoard', 'hoax', 'hoarse', 'hoax', 'hoax']
945  call cursor(4,1)
946  call test_override("char_avail", 1)
947  call feedkeys("Ahoa\<tab>\<tab>\<c-y>\<esc>", 'tx')
948  call feedkeys("oho\<tab>\<tab>\<c-y>\<esc>", 'tx')
949  call assert_equal(l:expected, getline(1,'$'))
950
951  call test_override("char_avail", 0)
952  bwipe!
953  set completeopt&
954  delfunc s:act_on_text_changed
955endfunc
956
957func Test_menu_only_exists_in_terminal()
958  CheckCommand tlmenu
959  CheckNotGui
960
961  tlnoremenu  &Edit.&Paste<Tab>"+gP  <C-W>"+
962  aunmenu *
963  try
964    popup Edit
965    call assert_false(1, 'command should have failed')
966  catch
967    call assert_exception('E328:')
968  endtry
969endfunc
970
971func Test_popup_complete_info_01()
972  new
973  inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
974  func s:complTestEval() abort
975    call complete(1, ['aa', 'ab'])
976    return ''
977  endfunc
978  inoremap <buffer><F6> <C-R>=s:complTestEval()<CR>
979  call writefile([
980        \ 'dummy	dummy.txt	1',
981        \], 'Xdummy.txt')
982  setlocal tags=Xdummy.txt
983  setlocal dictionary=Xdummy.txt
984  setlocal thesaurus=Xdummy.txt
985  setlocal omnifunc=syntaxcomplete#Complete
986  setlocal completefunc=syntaxcomplete#Complete
987  setlocal spell
988  for [keys, mode_name] in [
989        \ ["", ''],
990        \ ["\<C-X>", 'ctrl_x'],
991        \ ["\<C-X>\<C-N>", 'keyword'],
992        \ ["\<C-X>\<C-P>", 'keyword'],
993        \ ["\<C-X>\<C-L>", 'whole_line'],
994        \ ["\<C-X>\<C-F>", 'files'],
995        \ ["\<C-X>\<C-]>", 'tags'],
996        \ ["\<C-X>\<C-D>", 'path_defines'],
997        \ ["\<C-X>\<C-I>", 'path_patterns'],
998        \ ["\<C-X>\<C-K>", 'dictionary'],
999        \ ["\<C-X>\<C-T>", 'thesaurus'],
1000        \ ["\<C-X>\<C-V>", 'cmdline'],
1001        \ ["\<C-X>\<C-U>", 'function'],
1002        \ ["\<C-X>\<C-O>", 'omni'],
1003        \ ["\<C-X>s", 'spell'],
1004        \ ["\<F6>", 'eval'],
1005        \]
1006    call feedkeys("i" . keys . "\<F5>\<Esc>", 'tx')
1007    call assert_equal(mode_name, getline('.'))
1008    %d
1009  endfor
1010  call delete('Xdummy.txt')
1011  bwipe!
1012endfunc
1013
1014func UserDefinedComplete(findstart, base)
1015  if a:findstart
1016    return 0
1017  else
1018    return [
1019          \   { 'word': 'Jan', 'menu': 'January' },
1020          \   { 'word': 'Feb', 'menu': 'February' },
1021          \   { 'word': 'Mar', 'menu': 'March' },
1022          \   { 'word': 'Apr', 'menu': 'April' },
1023          \   { 'word': 'May', 'menu': 'May' },
1024          \ ]
1025  endif
1026endfunc
1027
1028func GetCompleteInfo()
1029  if empty(g:compl_what)
1030    let g:compl_info = complete_info()
1031  else
1032    let g:compl_info = g:compl_what->complete_info()
1033  endif
1034  return ''
1035endfunc
1036
1037func Test_popup_complete_info_02()
1038  new
1039  inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR>
1040  setlocal completefunc=UserDefinedComplete
1041
1042  let d = {
1043    \   'mode': 'function',
1044    \   'pum_visible': 1,
1045    \   'items': [
1046    \     {'word': 'Jan', 'menu': 'January', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1047    \     {'word': 'Feb', 'menu': 'February', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1048    \     {'word': 'Mar', 'menu': 'March', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1049    \     {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1050    \     {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
1051    \   ],
1052    \   'selected': 0,
1053    \ }
1054
1055  let g:compl_what = []
1056  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1057  call assert_equal(d, g:compl_info)
1058
1059  let g:compl_what = ['mode', 'pum_visible', 'selected']
1060  call remove(d, 'items')
1061  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1062  call assert_equal(d, g:compl_info)
1063
1064  let g:compl_what = ['mode']
1065  call remove(d, 'selected')
1066  call remove(d, 'pum_visible')
1067  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1068  call assert_equal(d, g:compl_info)
1069  bwipe!
1070endfunc
1071
1072func Test_popup_complete_info_no_pum()
1073  new
1074  call assert_false( pumvisible() )
1075  let no_pum_info = complete_info()
1076  let d = {
1077        \   'mode': '',
1078        \   'pum_visible': 0,
1079        \   'items': [],
1080        \   'selected': -1,
1081        \  }
1082  call assert_equal( d, complete_info() )
1083  bwipe!
1084endfunc
1085
1086func Test_CompleteChanged()
1087  new
1088  call setline(1, ['foo', 'bar', 'foobar', ''])
1089  set complete=. completeopt=noinsert,noselect,menuone
1090  function! OnPumChange()
1091    let g:event = copy(v:event)
1092    let g:item = get(v:event, 'completed_item', {})
1093    let g:word = get(g:item, 'word', v:null)
1094  endfunction
1095  augroup AAAAA_Group
1096    au!
1097    autocmd CompleteChanged * :call OnPumChange()
1098  augroup END
1099  call cursor(4, 1)
1100
1101  call feedkeys("Sf\<C-N>", 'tx')
1102  call assert_equal({'completed_item': {}, 'width': 15,
1103        \ 'height': 2, 'size': 2,
1104        \ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
1105  call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
1106  call assert_equal('foo', g:word)
1107  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1108  call assert_equal('foobar', g:word)
1109  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1110  call assert_equal(v:null, g:word)
1111  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
1112  call assert_equal('foobar', g:word)
1113
1114  autocmd! AAAAA_Group
1115  set complete& completeopt&
1116  delfunc! OnPumChange
1117  bw!
1118endfunc
1119
1120function! GetPumPosition()
1121  call assert_true( pumvisible() )
1122  let g:pum_pos = pum_getpos()
1123  return ''
1124endfunction
1125
1126func Test_pum_getpos()
1127  new
1128  inoremap <buffer><F5> <C-R>=GetPumPosition()<CR>
1129  setlocal completefunc=UserDefinedComplete
1130
1131  let d = {
1132    \   'height':    5,
1133    \   'width':     15,
1134    \   'row':       1,
1135    \   'col':       0,
1136    \   'size':      5,
1137    \   'scrollbar': v:false,
1138    \ }
1139  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1140  call assert_equal(d, g:pum_pos)
1141
1142  call assert_false( pumvisible() )
1143  call assert_equal( {}, pum_getpos() )
1144  bw!
1145  unlet g:pum_pos
1146endfunc
1147
1148" vim: shiftwidth=2 sts=2 expandtab
1149