xref: /vim-8.2.3635/src/testdir/test_popup.vim (revision f08b0eb8)
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  let g:test_is_flaky = 1
669
670  let h = winheight(0)
671  if h < 15
672    return
673  endif
674  let rows = h / 3
675  let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': rows})
676  call term_sendkeys(buf, (h / 3 - 1) . "o\<esc>")
677  " Wait for the nested Vim to exit insert mode, where it will show the ruler.
678  " Need to trigger a redraw.
679  call WaitFor({-> execute("redraw") == "" && term_getline(buf, rows) =~ '\<' . rows . ',.*Bot'})
680
681  call term_sendkeys(buf, "Gi\<c-x>")
682  call term_sendkeys(buf, "\<c-v>")
683  call TermWait(buf, 50)
684  " popup first entry "!" must be at the top
685  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, 1))})
686  exe 'resize +' . (h - 1)
687  call TermWait(buf, 50)
688  redraw!
689  " popup shifted down, first line is now empty
690  call WaitForAssert({-> assert_equal('', term_getline(buf, 1))})
691  sleep 100m
692  " popup is below cursor line and shows first match "!"
693  call WaitForAssert({-> assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0] + 1))})
694  " cursor line also shows !
695  call assert_match('^!\s*$', term_getline(buf, term_getcursor(buf)[0]))
696  bwipe!
697endfunc
698
699func Test_popup_and_preview_autocommand()
700  CheckFeature python
701  CheckFeature quickfix
702  if winheight(0) < 15
703    throw 'Skipped: window height insufficient'
704  endif
705
706  " This used to crash Vim
707  new
708  augroup MyBufAdd
709    au!
710    au BufAdd * nested tab sball
711  augroup END
712  set omnifunc=pythoncomplete#Complete
713  call setline(1, 'import os')
714  " make the line long
715  call setline(2, '                                 os.')
716  $
717  call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
718  call assert_equal("import os", getline(1))
719  call assert_match('                                 os.\(EX_IOERR\|O_CREAT\)$', getline(2))
720  call assert_equal(1, winnr('$'))
721  " previewwindow option is not set
722  call assert_equal(0, &previewwindow)
723  norm! gt
724  call assert_equal(0, &previewwindow)
725  norm! gT
726  call assert_equal(10, tabpagenr('$'))
727  tabonly
728  pclose
729  augroup MyBufAdd
730    au!
731  augroup END
732  augroup! MyBufAdd
733  bw!
734endfunc
735
736func Test_popup_and_previewwindow_dump()
737  CheckScreendump
738  CheckFeature quickfix
739
740  let lines =<< trim END
741    set previewheight=9
742    silent! pedit
743    call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
744    exec "norm! G\<C-E>\<C-E>"
745  END
746  call writefile(lines, 'Xscript')
747  let buf = RunVimInTerminal('-S Xscript', {})
748
749  " wait for the script to finish
750  call TermWait(buf)
751
752  " Test that popup and previewwindow do not overlap.
753  call term_sendkeys(buf, "o")
754  call TermWait(buf, 50)
755  call term_sendkeys(buf, "\<C-X>\<C-N>")
756  call VerifyScreenDump(buf, 'Test_popup_and_previewwindow_01', {})
757
758  call term_sendkeys(buf, "\<Esc>u")
759  call StopVimInTerminal(buf)
760  call delete('Xscript')
761endfunc
762
763func Test_balloon_split()
764  CheckFunction balloon_split
765
766  call assert_equal([
767        \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
768        \ ], balloon_split(
769        \ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
770  call assert_equal([
771        \ 'one two three four one two three four one two thre',
772        \ 'e four',
773        \ ], balloon_split(
774        \ 'one two three four one two three four one two three four'))
775
776  eval 'struct = {one = 1, two = 2, three = 3}'
777        \ ->balloon_split()
778        \ ->assert_equal([
779        \   'struct = {',
780        \   '  one = 1,',
781        \   '  two = 2,',
782        \   '  three = 3}',
783        \ ])
784
785  call assert_equal([
786        \ 'struct = {',
787        \ '  one = 1,',
788        \ '  nested = {',
789        \ '    n1 = "yes",',
790        \ '    n2 = "no"}',
791        \ '  two = 2}',
792        \ ], balloon_split(
793        \ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
794  call assert_equal([
795        \ 'struct = 0x234 {',
796        \ '  long = 2343 "\\"some long string that will be wr',
797        \ 'apped in two\\"",',
798        \ '  next = 123}',
799        \ ], balloon_split(
800        \ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
801  call assert_equal([
802        \ 'Some comment',
803        \ '',
804        \ 'typedef this that;',
805        \ ], balloon_split(
806        \ "Some comment\n\ntypedef this that;"))
807endfunc
808
809func Test_popup_position()
810  CheckScreendump
811
812  let lines =<< trim END
813    123456789_123456789_123456789_a
814    123456789_123456789_123456789_b
815                123
816  END
817  call writefile(lines, 'Xtest')
818  let buf = RunVimInTerminal('Xtest', {})
819  call term_sendkeys(buf, ":vsplit\<CR>")
820
821  " default pumwidth in left window: overlap in right window
822  call term_sendkeys(buf, "GA\<C-N>")
823  call VerifyScreenDump(buf, 'Test_popup_position_01', {'rows': 8})
824  call term_sendkeys(buf, "\<Esc>u")
825
826  " default pumwidth: fill until right of window
827  call term_sendkeys(buf, "\<C-W>l")
828  call term_sendkeys(buf, "GA\<C-N>")
829  call VerifyScreenDump(buf, 'Test_popup_position_02', {'rows': 8})
830
831  " larger pumwidth: used as minimum width
832  call term_sendkeys(buf, "\<Esc>u")
833  call term_sendkeys(buf, ":set pumwidth=30\<CR>")
834  call term_sendkeys(buf, "GA\<C-N>")
835  call VerifyScreenDump(buf, 'Test_popup_position_03', {'rows': 8})
836
837  " completed text wider than the window and 'pumwidth' smaller than available
838  " space
839  call term_sendkeys(buf, "\<Esc>u")
840  call term_sendkeys(buf, ":set pumwidth=20\<CR>")
841  call term_sendkeys(buf, "ggI123456789_\<Esc>")
842  call term_sendkeys(buf, "jI123456789_\<Esc>")
843  call term_sendkeys(buf, "GA\<C-N>")
844  call VerifyScreenDump(buf, 'Test_popup_position_04', {'rows': 10})
845
846  call term_sendkeys(buf, "\<Esc>u")
847  call StopVimInTerminal(buf)
848  call delete('Xtest')
849endfunc
850
851func Test_popup_command()
852  CheckScreendump
853  CheckFeature menu
854
855  menu Test.Foo Foo
856  call assert_fails('popup Test.Foo', 'E336:')
857  call assert_fails('popup Test.Foo.X', 'E327:')
858  call assert_fails('popup Foo', 'E337:')
859  unmenu Test.Foo
860
861  let script =<< trim END
862    func StartTimer()
863      call timer_start(100, {-> ChangeMenu()})
864    endfunc
865    func ChangeMenu()
866      nunmenu PopUp.&Paste
867      nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
868      echomsg 'changed'
869    endfunc
870  END
871  call writefile(script, 'XtimerScript')
872
873  let lines =<< trim END
874	one two three four five
875	and one two Xthree four five
876	one more two three four five
877  END
878  call writefile(lines, 'Xtest')
879  let buf = RunVimInTerminal('-S XtimerScript Xtest', {})
880  call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
881  call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
882  call VerifyScreenDump(buf, 'Test_popup_command_01', {})
883
884  " go to the Paste entry in the menu
885  call term_sendkeys(buf, "jj")
886  call VerifyScreenDump(buf, 'Test_popup_command_02', {})
887
888  " Select a word
889  call term_sendkeys(buf, "j\<CR>")
890  call VerifyScreenDump(buf, 'Test_popup_command_03', {})
891
892  call term_sendkeys(buf, "\<Esc>")
893
894  " Set a timer to change a menu entry while it's displayed.  The text should
895  " not change but the command does.  Making the screendump also verifies that
896  " "changed" shows up, which means the timer triggered
897  call term_sendkeys(buf, "/X\<CR>:call StartTimer() | popup PopUp\<CR>")
898  call VerifyScreenDump(buf, 'Test_popup_command_04', {})
899
900  " Select the Paste entry, executes the changed menu item.
901  call term_sendkeys(buf, "jj\<CR>")
902  call VerifyScreenDump(buf, 'Test_popup_command_05', {})
903
904  call StopVimInTerminal(buf)
905  call delete('Xtest')
906  call delete('XtimerScript')
907endfunc
908
909func Test_popup_complete_backwards()
910  new
911  call setline(1, ['Post', 'Port', 'Po'])
912  let expected=['Post', 'Port', 'Port']
913  call cursor(3,2)
914  call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
915  call assert_equal(expected, getline(1,'$'))
916  bwipe!
917endfunc
918
919func Test_popup_complete_backwards_ctrl_p()
920  new
921  call setline(1, ['Post', 'Port', 'Po'])
922  let expected=['Post', 'Port', 'Port']
923  call cursor(3,2)
924  call feedkeys("A\<C-P>\<C-N>rt\<cr>", 'tx')
925  call assert_equal(expected, getline(1,'$'))
926  bwipe!
927endfunc
928
929func Test_complete_o_tab()
930  let s:o_char_pressed = 0
931
932  fun! s:act_on_text_changed()
933    if s:o_char_pressed
934      let s:o_char_pressed = 0
935      call feedkeys("\<c-x>\<c-n>", 'i')
936    endif
937  endfunc
938
939  set completeopt=menu,noselect
940  new
941  imap <expr> <buffer> <tab> pumvisible() ? "\<c-p>" : "X"
942  autocmd! InsertCharPre <buffer> let s:o_char_pressed = (v:char ==# 'o')
943  autocmd! TextChangedI <buffer> call <sid>act_on_text_changed()
944  call setline(1,  ['hoard', 'hoax', 'hoarse', ''])
945  let l:expected = ['hoard', 'hoax', 'hoarse', 'hoax', 'hoax']
946  call cursor(4,1)
947  call test_override("char_avail", 1)
948  call feedkeys("Ahoa\<tab>\<tab>\<c-y>\<esc>", 'tx')
949  call feedkeys("oho\<tab>\<tab>\<c-y>\<esc>", 'tx')
950  call assert_equal(l:expected, getline(1,'$'))
951
952  call test_override("char_avail", 0)
953  bwipe!
954  set completeopt&
955  delfunc s:act_on_text_changed
956endfunc
957
958func Test_menu_only_exists_in_terminal()
959  CheckCommand tlmenu
960  CheckNotGui
961
962  tlnoremenu  &Edit.&Paste<Tab>"+gP  <C-W>"+
963  aunmenu *
964  try
965    popup Edit
966    call assert_false(1, 'command should have failed')
967  catch
968    call assert_exception('E328:')
969  endtry
970endfunc
971
972func Test_popup_complete_info_01()
973  new
974  inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
975  func s:complTestEval() abort
976    call complete(1, ['aa', 'ab'])
977    return ''
978  endfunc
979  inoremap <buffer><F6> <C-R>=s:complTestEval()<CR>
980  call writefile([
981        \ 'dummy	dummy.txt	1',
982        \], 'Xdummy.txt')
983  setlocal tags=Xdummy.txt
984  setlocal dictionary=Xdummy.txt
985  setlocal thesaurus=Xdummy.txt
986  setlocal omnifunc=syntaxcomplete#Complete
987  setlocal completefunc=syntaxcomplete#Complete
988  setlocal spell
989  for [keys, mode_name] in [
990        \ ["", ''],
991        \ ["\<C-X>", 'ctrl_x'],
992        \ ["\<C-X>\<C-N>", 'keyword'],
993        \ ["\<C-X>\<C-P>", 'keyword'],
994        \ ["\<C-X>\<C-E>", 'scroll'],
995        \ ["\<C-X>\<C-Y>", 'scroll'],
996        \ ["\<C-X>\<C-E>\<C-E>\<C-Y>", 'scroll'],
997        \ ["\<C-X>\<C-Y>\<C-E>\<C-Y>", 'scroll'],
998        \ ["\<C-X>\<C-L>", 'whole_line'],
999        \ ["\<C-X>\<C-F>", 'files'],
1000        \ ["\<C-X>\<C-]>", 'tags'],
1001        \ ["\<C-X>\<C-D>", 'path_defines'],
1002        \ ["\<C-X>\<C-I>", 'path_patterns'],
1003        \ ["\<C-X>\<C-K>", 'dictionary'],
1004        \ ["\<C-X>\<C-T>", 'thesaurus'],
1005        \ ["\<C-X>\<C-V>", 'cmdline'],
1006        \ ["\<C-X>\<C-U>", 'function'],
1007        \ ["\<C-X>\<C-O>", 'omni'],
1008        \ ["\<C-X>s", 'spell'],
1009        \ ["\<F6>", 'eval'],
1010        \]
1011    call feedkeys("i" . keys . "\<F5>\<Esc>", 'tx')
1012    call assert_equal(mode_name, getline('.'))
1013    %d
1014  endfor
1015  call delete('Xdummy.txt')
1016  bwipe!
1017endfunc
1018
1019func UserDefinedComplete(findstart, base)
1020  if a:findstart
1021    return 0
1022  else
1023    return [
1024          \   { 'word': 'Jan', 'menu': 'January' },
1025          \   { 'word': 'Feb', 'menu': 'February' },
1026          \   { 'word': 'Mar', 'menu': 'March' },
1027          \   { 'word': 'Apr', 'menu': 'April' },
1028          \   { 'word': 'May', 'menu': 'May' },
1029          \ ]
1030  endif
1031endfunc
1032
1033func GetCompleteInfo()
1034  if empty(g:compl_what)
1035    let g:compl_info = complete_info()
1036  else
1037    let g:compl_info = g:compl_what->complete_info()
1038  endif
1039  return ''
1040endfunc
1041
1042func Test_popup_complete_info_02()
1043  new
1044  inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR>
1045  setlocal completefunc=UserDefinedComplete
1046
1047  let d = {
1048    \   'mode': 'function',
1049    \   'pum_visible': 1,
1050    \   'items': [
1051    \     {'word': 'Jan', 'menu': 'January', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1052    \     {'word': 'Feb', 'menu': 'February', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1053    \     {'word': 'Mar', 'menu': 'March', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1054    \     {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
1055    \     {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
1056    \   ],
1057    \   'selected': 0,
1058    \ }
1059
1060  let g:compl_what = []
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', 'pum_visible', 'selected']
1065  call remove(d, 'items')
1066  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1067  call assert_equal(d, g:compl_info)
1068
1069  let g:compl_what = ['mode']
1070  call remove(d, 'selected')
1071  call remove(d, 'pum_visible')
1072  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1073  call assert_equal(d, g:compl_info)
1074  bwipe!
1075endfunc
1076
1077func Test_popup_complete_info_no_pum()
1078  new
1079  call assert_false( pumvisible() )
1080  let no_pum_info = complete_info()
1081  let d = {
1082        \   'mode': '',
1083        \   'pum_visible': 0,
1084        \   'items': [],
1085        \   'selected': -1,
1086        \  }
1087  call assert_equal( d, complete_info() )
1088  bwipe!
1089endfunc
1090
1091func Test_CompleteChanged()
1092  new
1093  call setline(1, ['foo', 'bar', 'foobar', ''])
1094  set complete=. completeopt=noinsert,noselect,menuone
1095  function! OnPumChange()
1096    let g:event = copy(v:event)
1097    let g:item = get(v:event, 'completed_item', {})
1098    let g:word = get(g:item, 'word', v:null)
1099  endfunction
1100  augroup AAAAA_Group
1101    au!
1102    autocmd CompleteChanged * :call OnPumChange()
1103  augroup END
1104  call cursor(4, 1)
1105
1106  call feedkeys("Sf\<C-N>", 'tx')
1107  call assert_equal({'completed_item': {}, 'width': 15,
1108        \ 'height': 2, 'size': 2,
1109        \ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
1110  call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
1111  call assert_equal('foo', g:word)
1112  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1113  call assert_equal('foobar', g:word)
1114  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
1115  call assert_equal(v:null, g:word)
1116  call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
1117  call assert_equal('foobar', g:word)
1118
1119  autocmd! AAAAA_Group
1120  set complete& completeopt&
1121  delfunc! OnPumChange
1122  bw!
1123endfunc
1124
1125function! GetPumPosition()
1126  call assert_true( pumvisible() )
1127  let g:pum_pos = pum_getpos()
1128  return ''
1129endfunction
1130
1131func Test_pum_getpos()
1132  new
1133  inoremap <buffer><F5> <C-R>=GetPumPosition()<CR>
1134  setlocal completefunc=UserDefinedComplete
1135
1136  let d = {
1137    \   'height':    5,
1138    \   'width':     15,
1139    \   'row':       1,
1140    \   'col':       0,
1141    \   'size':      5,
1142    \   'scrollbar': v:false,
1143    \ }
1144  call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
1145  call assert_equal(d, g:pum_pos)
1146
1147  call assert_false( pumvisible() )
1148  call assert_equal( {}, pum_getpos() )
1149  bw!
1150  unlet g:pum_pos
1151endfunc
1152
1153" Test for the popup menu with the 'rightleft' option set
1154func Test_pum_rightleft()
1155  CheckFeature rightleft
1156  CheckScreendump
1157
1158  let lines =<< trim END
1159    abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
1160    vim
1161    victory
1162  END
1163  call writefile(lines, 'Xtest1')
1164  let buf = RunVimInTerminal('--cmd "set rightleft" Xtest1', {})
1165  call term_wait(buf)
1166  call term_sendkeys(buf, "Go\<C-P>")
1167  call term_wait(buf)
1168  call VerifyScreenDump(buf, 'Test_pum_rightleft_01', {'rows': 8})
1169  call term_sendkeys(buf, "\<C-P>\<C-Y>")
1170  call term_wait(buf)
1171  redraw!
1172  call assert_match('\s*miv', Screenline(5))
1173
1174  " Test for expanding tabs to spaces in the popup menu
1175  let lines =<< trim END
1176    one	two
1177    one	three
1178    four
1179  END
1180  call writefile(lines, 'Xtest2')
1181  call term_sendkeys(buf, "\<Esc>:e! Xtest2\<CR>")
1182  call term_wait(buf)
1183  call term_sendkeys(buf, "Goone\<C-X>\<C-L>")
1184  call term_wait(buf)
1185  redraw!
1186  call VerifyScreenDump(buf, 'Test_pum_rightleft_02', {'rows': 7})
1187  call term_sendkeys(buf, "\<C-Y>")
1188  call term_wait(buf)
1189  redraw!
1190  call assert_match('\s*eerht     eno', Screenline(4))
1191
1192  call StopVimInTerminal(buf)
1193  call delete('Xtest1')
1194  call delete('Xtest2')
1195endfunc
1196
1197" Test for a popup menu with a scrollbar
1198func Test_pum_scrollbar()
1199  CheckScreendump
1200  let lines =<< trim END
1201    one
1202    two
1203    three
1204  END
1205  call writefile(lines, 'Xtest1')
1206  let buf = RunVimInTerminal('--cmd "set pumheight=2" Xtest1', {})
1207  call term_wait(buf)
1208  call term_sendkeys(buf, "Go\<C-P>\<C-P>\<C-P>")
1209  call term_wait(buf)
1210  call VerifyScreenDump(buf, 'Test_pum_scrollbar_01', {'rows': 7})
1211  call term_sendkeys(buf, "\<C-E>\<Esc>dd")
1212  call term_wait(buf)
1213
1214  if has('rightleft')
1215    call term_sendkeys(buf, ":set rightleft\<CR>")
1216    call term_wait(buf)
1217    call term_sendkeys(buf, "Go\<C-P>\<C-P>\<C-P>")
1218    call term_wait(buf)
1219    call VerifyScreenDump(buf, 'Test_pum_scrollbar_02', {'rows': 7})
1220  endif
1221
1222  call StopVimInTerminal(buf)
1223  call delete('Xtest1')
1224endfunc
1225
1226" vim: shiftwidth=2 sts=2 expandtab
1227