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