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