view src/testdir/test_cmdline.vim @ 33521:1f9b1def80c8 v9.0.2009

patch 9.0.2009: cmdline-completion for comma-separated options wrong Commit: https://github.com/vim/vim/commit/54844857fd6933fa4f6678e47610c4b9c9f7a091 Author: Yee Cheng Chin <ychin.git@gmail.com> Date: Mon Oct 9 18:12:31 2023 +0200 patch 9.0.2009: cmdline-completion for comma-separated options wrong Problem: cmdline-completion for comma-separated options wrong Solution: Fix command-line expansions for options with filenames with commas Fix command-line expansions for options with filenames with commas Cmdline expansion for option values that take a comma-separated list of file names is currently not handling file names with commas as the commas are not escaped. For such options, the commas in file names need to be escaped (to differentiate from a comma that delimit the list items). The escaped comma is unescaped in `copy_option_part()` during option parsing. Fix as follows: - Cmdline completion for option values with comma-separated file/folder names will not start a new match when seeing `\\,` and will instead consider it as one value. - File/folder regex matching will strip the `\\` when seeing `\\,` to make sure it can match the correct files/folders. - The expanded value will escape `,` with `\\,`, similar to how spaces are escaped to make sure the option value is correct on the cmdline. This fix also takes into account the fact that Win32 Vim handles file name escaping differently. Typing '\,' for a file name results in it being handled literally but in other platforms '\,' is interpreted as a simple ',' and commas need to be escaped using '\\,' instead. Also, make sure this new logic only applies to comma-separated options like 'path'. Non-list options like 'set makeprg=<Tab>' and regular ex commands like `:edit <Tab>` do not require escaping and will continue to work. Also fix up documentation to be clearer. The original docs are slightly misleading in how it discusses triple slashes for 'tags'. closes: #13303 related: #13301 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
author Christian Brabandt <cb@256bit.org>
date Mon, 09 Oct 2023 18:30:04 +0200
parents 55fefd9848e3
children 46d449fd4fe4
line wrap: on
line source

" Tests for editing the command line.

source check.vim
source screendump.vim
source view_util.vim
source shared.vim
import './vim9.vim' as v9

func SetUp()
  func SaveLastScreenLine()
    let g:Sline = Screenline(&lines - 1)
    return ''
  endfunc
  cnoremap <expr> <F4> SaveLastScreenLine()
endfunc

func TearDown()
  delfunc SaveLastScreenLine
  cunmap <F4>
endfunc

func Test_complete_tab()
  call writefile(['testfile'], 'Xtestfile', 'D')
  call feedkeys(":e Xtest\t\r", "tx")
  call assert_equal('testfile', getline(1))

  " Pressing <Tab> after '%' completes the current file, also on MS-Windows
  call feedkeys(":e %\t\r", "tx")
  call assert_equal('e Xtestfile', @:)
endfunc

func Test_complete_list()
  " We can't see the output, but at least we check the code runs properly.
  call feedkeys(":e test\<C-D>\r", "tx")
  call assert_equal('test', expand('%:t'))

  " If a command doesn't support completion, then CTRL-D should be literally
  " used.
  call feedkeys(":chistory \<C-D>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"chistory \<C-D>", @:)

  " Test for displaying the tail of the completion matches
  set wildmode=longest,full
  call mkdir('Xtest', 'R')
  call writefile([], 'Xtest/a.c')
  call writefile([], 'Xtest/a.h')
  let g:Sline = ''
  call feedkeys(":e Xtest/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('a.c  a.h', g:Sline)
  call assert_equal('"e Xtest/', @:)
  if has('win32')
    " Test for 'completeslash'
    set completeslash=backslash
    call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest\', @:)
    call feedkeys(":e Xtest/\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest\a.', @:)
    set completeslash=slash
    call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest/', @:)
    call feedkeys(":e Xtest\\\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest/a.', @:)
    set completeslash&
  endif

  " Test for displaying the tail with wildcards
  let g:Sline = ''
  call feedkeys(":e Xtes?/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('Xtest/a.c  Xtest/a.h', g:Sline)
  call assert_equal('"e Xtes?/', @:)
  let g:Sline = ''
  call feedkeys(":e Xtes*/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('Xtest/a.c  Xtest/a.h', g:Sline)
  call assert_equal('"e Xtes*/', @:)
  let g:Sline = ''
  call feedkeys(":e Xtes[/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal(':e Xtes[/', g:Sline)
  call assert_equal('"e Xtes[/', @:)

  set wildmode&
endfunc

func Test_complete_wildmenu()
  call mkdir('Xwilddir1/Xdir2', 'pR')
  call writefile(['testfile1'], 'Xwilddir1/Xtestfile1')
  call writefile(['testfile2'], 'Xwilddir1/Xtestfile2')
  call writefile(['testfile3'], 'Xwilddir1/Xdir2/Xtestfile3')
  call writefile(['testfile3'], 'Xwilddir1/Xdir2/Xtestfile4')
  set wildmenu

  " Pressing <Tab> completes, and moves to next files when pressing again.
  call feedkeys(":e Xwilddir1/\<Tab>\<Tab>\<CR>", 'tx')
  call assert_equal('testfile1', getline(1))
  call feedkeys(":e Xwilddir1/\<Tab>\<Tab>\<Tab>\<CR>", 'tx')
  call assert_equal('testfile2', getline(1))

  " <S-Tab> is like <Tab> but begin with the last match and then go to
  " previous.
  call feedkeys(":e Xwilddir1/Xtest\<S-Tab>\<CR>", 'tx')
  call assert_equal('testfile2', getline(1))
  call feedkeys(":e Xwilddir1/Xtest\<S-Tab>\<S-Tab>\<CR>", 'tx')
  call assert_equal('testfile1', getline(1))

  " <Left>/<Right> to move to previous/next file.
  call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<CR>", 'tx')
  call assert_equal('testfile1', getline(1))
  call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<Right>\<CR>", 'tx')
  call assert_equal('testfile2', getline(1))
  call feedkeys(":e Xwilddir1/\<Tab>\<Right>\<Right>\<Left>\<CR>", 'tx')
  call assert_equal('testfile1', getline(1))

  " <Up>/<Down> to go up/down directories.
  call feedkeys(":e Xwilddir1/\<Tab>\<Down>\<CR>", 'tx')
  call assert_equal('testfile3', getline(1))
  call feedkeys(":e Xwilddir1/\<Tab>\<Down>\<Up>\<Right>\<CR>", 'tx')
  call assert_equal('testfile1', getline(1))

  " this fails in some Unix GUIs, not sure why
  if !has('unix') || !has('gui_running')
    " <C-J>/<C-K> mappings to go up/down directories when 'wildcharm' is
    " different than 'wildchar'.
    set wildcharm=<C-Z>
    cnoremap <C-J> <Down><C-Z>
    cnoremap <C-K> <Up><C-Z>
    call feedkeys(":e Xwilddir1/\<Tab>\<C-J>\<CR>", 'tx')
    call assert_equal('testfile3', getline(1))
    call feedkeys(":e Xwilddir1/\<Tab>\<C-J>\<C-K>\<CR>", 'tx')
    call assert_equal('testfile1', getline(1))
    set wildcharm=0
    cunmap <C-J>
    cunmap <C-K>
  endif

  " Test for canceling the wild menu by adding a character
  redrawstatus
  call feedkeys(":e Xwilddir1/\<Tab>x\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xwilddir1/Xdir2/x', @:)

  " Completion using a relative path
  cd Xwilddir1/Xdir2
  call feedkeys(":e ../\<Tab>\<Right>\<Down>\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"e Xtestfile3 Xtestfile4', @:)
  cd -

  " test for wildmenumode()
  cnoremap <expr> <F2> wildmenumode()
  call feedkeys(":cd Xwilddir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"cd Xwilddir1/0', @:)
  call feedkeys(":e Xwilddir1/\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"e Xwilddir1/Xdir2/1', @:)
  cunmap <F2>

  " Test for canceling the wild menu by pressing <PageDown> or <PageUp>.
  " After this pressing <Left> or <Right> should not change the selection.
  call feedkeys(":sign \<Tab>\<PageDown>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sign define', @:)
  call histadd('cmd', 'TestWildMenu')
  call feedkeys(":sign \<Tab>\<PageUp>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"TestWildMenu', @:)

  " cleanup
  %bwipe
  set nowildmenu
endfunc

func Test_wildmenu_screendump()
  CheckScreendump

  let lines =<< trim [SCRIPT]
    set wildmenu hlsearch
  [SCRIPT]
  call writefile(lines, 'XTest_wildmenu', 'D')

  let buf = RunVimInTerminal('-S XTest_wildmenu', {'rows': 8})
  call term_sendkeys(buf, ":vim\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_1', {})

  call term_sendkeys(buf, "\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_2', {})

  call term_sendkeys(buf, "\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_3', {})

  call term_sendkeys(buf, "\<Tab>\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_4', {})
  call term_sendkeys(buf, "\<Esc>")

  " clean up
  call StopVimInTerminal(buf)
endfunc

func Test_redraw_in_autocmd()
  CheckScreendump

  let lines =<< trim END
      set cmdheight=2
      autocmd CmdlineChanged * redraw
  END
  call writefile(lines, 'XTest_redraw', 'D')

  let buf = RunVimInTerminal('-S XTest_redraw', {'rows': 8})
  call term_sendkeys(buf, ":for i in range(3)\<CR>")
  call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_1', {})

  call term_sendkeys(buf, "let i =")
  call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_2', {})

  " clean up
  call term_sendkeys(buf, "\<CR>")
  call StopVimInTerminal(buf)
endfunc

func Test_redrawstatus_in_autocmd()
  CheckScreendump

  let lines =<< trim END
      set laststatus=2
      set statusline=%=:%{getcmdline()}
      autocmd CmdlineChanged * redrawstatus
  END
  call writefile(lines, 'XTest_redrawstatus', 'D')

  let buf = RunVimInTerminal('-S XTest_redrawstatus', {'rows': 8})
  " :redrawstatus is postponed if messages have scrolled
  call term_sendkeys(buf, ":echo \"one\\ntwo\\nthree\\nfour\"\<CR>")
  call term_sendkeys(buf, ":foobar")
  call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_1', {})
  " it is not postponed if messages have not scrolled
  call term_sendkeys(buf, "\<Esc>:for in in range(3)")
  call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_2', {})
  " with cmdheight=1 messages have scrolled when typing :endfor
  call term_sendkeys(buf, "\<CR>:endfor")
  call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_3', {})
  call term_sendkeys(buf, "\<CR>:set cmdheight=2\<CR>")
  " with cmdheight=2 messages haven't scrolled when typing :for or :endfor
  call term_sendkeys(buf, ":for in in range(3)")
  call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_4', {})
  call term_sendkeys(buf, "\<CR>:endfor")
  call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_5', {})

  " clean up
  call term_sendkeys(buf, "\<CR>")
  call StopVimInTerminal(buf)
endfunc

func Test_changing_cmdheight()
  CheckScreendump

  let lines =<< trim END
      set cmdheight=1 laststatus=2
      func EchoTwo()
        set laststatus=2
        set cmdheight=5
        echo 'foo'
        echo 'bar'
        set cmdheight=1
      endfunc
  END
  call writefile(lines, 'XTest_cmdheight', 'D')

  let buf = RunVimInTerminal('-S XTest_cmdheight', {'rows': 8})
  call term_sendkeys(buf, ":resize -3\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_1', {})

  " using the space available doesn't change the status line
  call term_sendkeys(buf, ":set cmdheight+=3\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_2', {})

  " using more space moves the status line up
  call term_sendkeys(buf, ":set cmdheight+=1\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_3', {})

  " reducing cmdheight moves status line down
  call term_sendkeys(buf, ":set cmdheight-=2\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_4', {})

  " reducing window size and then setting cmdheight
  call term_sendkeys(buf, ":resize -1\<CR>")
  call term_sendkeys(buf, ":set cmdheight=1\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_5', {})

  " setting 'cmdheight' works after outputting two messages
  call term_sendkeys(buf, ":call EchoTwo()\<CR>")
  call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {})

  " clean up
  call StopVimInTerminal(buf)
endfunc

func Test_cmdheight_tabline()
  CheckScreendump

  let buf = RunVimInTerminal('-c "set ls=2" -c "set stal=2" -c "set cmdheight=1"', {'rows': 6})
  call VerifyScreenDump(buf, 'Test_cmdheight_tabline_1', {})

  " clean up
  call StopVimInTerminal(buf)
endfunc

func Test_map_completion()
  call feedkeys(":map <unique> <si\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <unique> <silent>', getreg(':'))
  call feedkeys(":map <script> <un\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <script> <unique>', getreg(':'))
  call feedkeys(":map <expr> <sc\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <expr> <script>', getreg(':'))
  call feedkeys(":map <buffer> <e\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <buffer> <expr>', getreg(':'))
  call feedkeys(":map <nowait> <b\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <nowait> <buffer>', getreg(':'))
  call feedkeys(":map <special> <no\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <special> <nowait>', getreg(':'))
  call feedkeys(":map <silent> <sp\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <silent> <special>', getreg(':'))

  map <Middle>x middle

  map ,f commaf
  map ,g commaf
  map <Left> left
  map <A-Left>x shiftleft
  call feedkeys(":map ,\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map ,f', getreg(':'))
  call feedkeys(":map ,\<Tab>\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map ,g', getreg(':'))
  call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <Left>', getreg(':'))
  call feedkeys(":map <A-Left>\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal("\"map <A-Left>\<Tab>", getreg(':'))
  call feedkeys(":map <M-Left>\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal("\"map <M-Left>x", getreg(':'))
  unmap ,f
  unmap ,g
  unmap <Left>
  unmap <A-Left>x

  set cpo-=< cpo-=k
  map <Left> left
  call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <Left>', getreg(':'))
  call feedkeys(":map <M\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal("\"map <M\<Tab>", getreg(':'))
  call feedkeys(":map \<C-V>\<C-V><M\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal("\"map \<C-V><Middle>x", getreg(':'))
  unmap <Left>

  set cpo+=<
  map <Left> left
  exe "set t_k6=\<Esc>[17~"
  call feedkeys(":map \<Esc>[17~x f6x\<CR>", 'xt')
  call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <Left>', getreg(':'))
  if !has('gui_running')
    call feedkeys(":map \<Esc>[17~\<Tab>\<Home>\"\<CR>", 'xt')
    call assert_equal("\"map <F6>x", getreg(':'))
  endif
  unmap <Left>
  call feedkeys(":unmap \<Esc>[17~x\<CR>", 'xt')
  set cpo-=<

  set cpo+=B
  map <Left> left
  call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <Left>', getreg(':'))
  unmap <Left>
  set cpo-=B

  set cpo+=k
  map <Left> left
  call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"map <Left>', getreg(':'))
  unmap <Left>
  set cpo-=k

  call assert_fails('call feedkeys(":map \\\\%(\<Tab>\<Home>\"\<CR>", "xt")', 'E53:')

  unmap <Middle>x
  set cpo&vim
endfunc

func Test_match_completion()
  hi Aardig ctermfg=green
  call feedkeys(":match \<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"match Aardig', @:)
  call feedkeys(":match \<S-Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"match none', @:)
  call feedkeys(":match | chist\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"match | chistory', @:)
endfunc

func Test_highlight_completion()
  hi Aardig ctermfg=green
  call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi Aardig', getreg(':'))
  call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi default Aardig', getreg(':'))
  call feedkeys(":hi clear Aa\<Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi clear Aardig', getreg(':'))
  call feedkeys(":hi li\<S-Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi link', getreg(':'))
  call feedkeys(":hi d\<S-Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi default', getreg(':'))
  call feedkeys(":hi c\<S-Tab>\<Home>\"\<CR>", 'xt')
  call assert_equal('"hi clear', getreg(':'))
  call feedkeys(":hi clear Aardig Aard\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"hi clear Aardig Aardig', getreg(':'))
  call feedkeys(":hi Aardig \<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"hi Aardig \t", getreg(':'))

  " A cleared group does not show up in completions.
  hi Anders ctermfg=green
  call assert_equal(['Aardig', 'Anders'], getcompletion('A', 'highlight'))
  hi clear Aardig
  call assert_equal(['Anders'], getcompletion('A', 'highlight'))
  hi clear Anders
  call assert_equal([], getcompletion('A', 'highlight'))
endfunc

" Test for command-line expansion of "hi Ni " (easter egg)
func Test_highlight_easter_egg()
  call test_override('ui_delay', 1)
  call feedkeys(":hi Ni \<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"hi Ni \<Tab>", @:)
  call test_override('ALL', 0)
endfunc

func Test_getcompletion()
  let groupcount = len(getcompletion('', 'event'))
  call assert_true(groupcount > 0)
  let matchcount = len('File'->getcompletion('event'))
  call assert_true(matchcount > 0)
  call assert_true(groupcount > matchcount)

  if has('menu')
    source $VIMRUNTIME/menu.vim
    let matchcount = len(getcompletion('', 'menu'))
    call assert_true(matchcount > 0)
    call assert_equal(['File.'], getcompletion('File', 'menu'))
    call assert_true(matchcount > 0)
    let matchcount = len(getcompletion('File.', 'menu'))
    call assert_true(matchcount > 0)
    source $VIMRUNTIME/delmenu.vim
  endif

  let l = getcompletion('v:n', 'var')
  call assert_true(index(l, 'v:null') >= 0)
  let l = getcompletion('v:notexists', 'var')
  call assert_equal([], l)

  args a.c b.c
  let l = getcompletion('', 'arglist')
  call assert_equal(['a.c', 'b.c'], l)
  let l = getcompletion('a.', 'buffer')
  call assert_equal(['a.c'], l)
  %argdelete

  let l = getcompletion('', 'augroup')
  call assert_true(index(l, 'END') >= 0)
  let l = getcompletion('blahblah', 'augroup')
  call assert_equal([], l)

  let l = getcompletion('', 'behave')
  call assert_true(index(l, 'mswin') >= 0)
  let l = getcompletion('not', 'behave')
  call assert_equal([], l)

  let l = getcompletion('', 'color')
  call assert_true(index(l, 'default') >= 0)
  let l = getcompletion('dirty', 'color')
  call assert_equal([], l)

  let l = getcompletion('', 'command')
  call assert_true(index(l, 'sleep') >= 0)
  let l = getcompletion('awake', 'command')
  call assert_equal([], l)

  let l = getcompletion('', 'dir')
  call assert_true(index(l, 'samples/') >= 0)
  let l = getcompletion('NoMatch', 'dir')
  call assert_equal([], l)

  if glob('~/*') !=# ''
    let l = getcompletion('~/', 'dir')
    call assert_true(l[0][0] ==# '~')
  endif

  let l = getcompletion('exe', 'expression')
  call assert_true(index(l, 'executable(') >= 0)
  let l = getcompletion('kill', 'expression')
  call assert_equal([], l)

  let l = getcompletion('tag', 'function')
  call assert_true(index(l, 'taglist(') >= 0)
  let l = getcompletion('paint', 'function')
  call assert_equal([], l)

  if !has('ruby')
    " global_functions[] has an entry but it doesn't have an implementation
    let l = getcompletion('ruby', 'function')
    call assert_equal([], l)
  endif

  let Flambda = {-> 'hello'}
  let l = getcompletion('', 'function')
  let l = filter(l, {i, v -> v =~ 'lambda'})
  call assert_equal([], l)

  let l = getcompletion('run', 'file')
  call assert_true(index(l, 'runtest.vim') >= 0)
  let l = getcompletion('walk', 'file')
  call assert_equal([], l)
  set wildignore=*.vim
  let l = getcompletion('run', 'file', 1)
  call assert_true(index(l, 'runtest.vim') < 0)
  set wildignore&
  " Directory name with space character
  call mkdir('Xdir with space', 'D')
  call assert_equal(['Xdir with space/'], getcompletion('Xdir\ w', 'shellcmd'))
  call assert_equal(['./Xdir with space/'], getcompletion('./Xdir', 'shellcmd'))

  let l = getcompletion('ha', 'filetype')
  call assert_true(index(l, 'hamster') >= 0)
  let l = getcompletion('horse', 'filetype')
  call assert_equal([], l)

  let l = getcompletion('z', 'syntax')
  call assert_true(index(l, 'zimbu') >= 0)
  let l = getcompletion('emacs', 'syntax')
  call assert_equal([], l)

  let l = getcompletion('jikes', 'compiler')
  call assert_true(index(l, 'jikes') >= 0)
  let l = getcompletion('break', 'compiler')
  call assert_equal([], l)

  let l = getcompletion('last', 'help')
  call assert_true(index(l, ':tablast') >= 0)
  let l = getcompletion('giveup', 'help')
  call assert_equal([], l)

  let l = getcompletion('time', 'option')
  call assert_true(index(l, 'timeoutlen') >= 0)
  let l = getcompletion('space', 'option')
  call assert_equal([], l)

  let l = getcompletion('er', 'highlight')
  call assert_true(index(l, 'ErrorMsg') >= 0)
  let l = getcompletion('dark', 'highlight')
  call assert_equal([], l)

  let l = getcompletion('', 'messages')
  call assert_true(index(l, 'clear') >= 0)
  let l = getcompletion('not', 'messages')
  call assert_equal([], l)

  let l = getcompletion('', 'mapclear')
  call assert_true(index(l, '<buffer>') >= 0)
  let l = getcompletion('not', 'mapclear')
  call assert_equal([], l)

  let l = getcompletion('.', 'shellcmd')
  call assert_equal(['./', '../'], filter(l, 'v:val =~ "\\./"'))
  call assert_equal(-1, match(l[2:], '^\.\.\?/$'))
  let root = has('win32') ? 'C:\\' : '/'
  let l = getcompletion(root, 'shellcmd')
  let expected = map(filter(glob(root . '*', 0, 1),
        \ 'isdirectory(v:val) || executable(v:val)'), 'isdirectory(v:val) ? v:val . ''/'' : v:val')
  call assert_equal(expected, l)

  if has('cscope')
    let l = getcompletion('', 'cscope')
    let cmds = ['add', 'find', 'help', 'kill', 'reset', 'show']
    call assert_equal(cmds, l)
    " using cmdline completion must not change the result
    call feedkeys(":cscope find \<c-d>\<c-c>", 'xt')
    let l = getcompletion('', 'cscope')
    call assert_equal(cmds, l)
    let keys = ['a', 'c', 'd', 'e', 'f', 'g', 'i', 's', 't']
    let l = getcompletion('find ', 'cscope')
    call assert_equal(keys, l)
  endif

  if has('signs')
    sign define Testing linehl=Comment
    let l = getcompletion('', 'sign')
    let cmds = ['define', 'jump', 'list', 'place', 'undefine', 'unplace']
    call assert_equal(cmds, l)
    " using cmdline completion must not change the result
    call feedkeys(":sign list \<c-d>\<c-c>", 'xt')
    let l = getcompletion('', 'sign')
    call assert_equal(cmds, l)
    let l = getcompletion('list ', 'sign')
    call assert_equal(['Testing'], l)
    let l = getcompletion('de*', 'sign')
    call assert_equal(['define'], l)
    let l = getcompletion('p?', 'sign')
    call assert_equal(['place'], l)
    let l = getcompletion('j.', 'sign')
    call assert_equal(['jump'], l)
  endif

  " Command line completion tests
  let l = getcompletion('cd ', 'cmdline')
  call assert_true(index(l, 'samples/') >= 0)
  let l = getcompletion('cd NoMatch', 'cmdline')
  call assert_equal([], l)
  let l = getcompletion('let v:n', 'cmdline')
  call assert_true(index(l, 'v:null') >= 0)
  let l = getcompletion('let v:notexists', 'cmdline')
  call assert_equal([], l)
  let l = getcompletion('call tag', 'cmdline')
  call assert_true(index(l, 'taglist(') >= 0)
  let l = getcompletion('call paint', 'cmdline')
  call assert_equal([], l)
  let l = getcompletion('autocmd BufEnter * map <bu', 'cmdline')
  call assert_equal(['<buffer>'], l)

  func T(a, c, p)
    let g:cmdline_compl_params = [a:a, a:c, a:p]
    return "oneA\noneB\noneC"
  endfunc
  command -nargs=1 -complete=custom,T MyCmd
  let l = getcompletion('MyCmd ', 'cmdline')
  call assert_equal(['oneA', 'oneB', 'oneC'], l)
  call assert_equal(['', 'MyCmd ', 6], g:cmdline_compl_params)

  delcommand MyCmd
  delfunc T
  unlet g:cmdline_compl_params

  " For others test if the name is recognized.
  let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
  if has('cmdline_hist')
    call add(names, 'history')
  endif
  if has('gettext')
    call add(names, 'locale')
  endif
  if has('profile')
    call add(names, 'syntime')
  endif

  set tags=Xtags
  call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", "word\tfile\tcmd"], 'Xtags', 'D')

  for name in names
    let matchcount = len(getcompletion('', name))
    call assert_true(matchcount >= 0, 'No matches for ' . name)
  endfor

  set tags&

  edit a~b
  enew
  call assert_equal(['a~b'], getcompletion('a~', 'buffer'))
  bw a~b

  if has('unix')
    edit Xtest\
    enew
    call assert_equal(['Xtest\'], getcompletion('Xtest\', 'buffer'))
    bw Xtest\
  endif

  call assert_fails("call getcompletion('\\\\@!\\\\@=', 'buffer')", 'E871:')
  call assert_fails('call getcompletion("", "burp")', 'E475:')
  call assert_fails('call getcompletion("abc", [])', 'E1174:')
endfunc

func Test_multibyte_expression()
  " Get a dialog in the GUI
  CheckNotGui

  " This was using uninitialized memory.
  let lines =<< trim END
      set verbose=6
      norm @=ٷ
      qall!
  END
  call writefile(lines, 'XmultiScript', 'D')
  call RunVim('', '', '-u NONE -n -e -s -S XmultiScript')
endfunc

" Test for getcompletion() with "fuzzy" in 'wildoptions'
func Test_getcompletion_wildoptions()
  let save_wildoptions = &wildoptions
  set wildoptions&
  let l = getcompletion('space', 'option')
  call assert_equal([], l)
  let l = getcompletion('ier', 'command')
  call assert_equal([], l)
  set wildoptions=fuzzy
  let l = getcompletion('space', 'option')
  call assert_true(index(l, 'backspace') >= 0)
  let l = getcompletion('ier', 'command')
  call assert_true(index(l, 'compiler') >= 0)
  let &wildoptions = save_wildoptions
endfunc

func Test_complete_autoload_error()
  let save_rtp = &rtp
  let lines =<< trim END
      vim9script
      export def Complete(..._): string
        return 'match'
      enddef
      echo this will cause an error
  END
  call mkdir('Xdir/autoload', 'pR')
  call writefile(lines, 'Xdir/autoload/script.vim')
  exe 'set rtp+=' .. getcwd() .. '/Xdir'

  let lines =<< trim END
      vim9script
      import autoload 'script.vim'
      command -nargs=* -complete=custom,script.Complete Cmd eval 0 + 0
      &wildcharm = char2nr("\<Tab>")
      feedkeys(":Cmd \<Tab>", 'xt')
  END
  call v9.CheckScriptFailure(lines, 'E121: Undefined variable: this')

  let &rtp = save_rtp
endfunc

func Test_fullcommand()
  let tests = {
        \ '':           '',
        \ ':':          '',
        \ ':::':        '',
        \ ':::5':       '',
        \ 'not_a_cmd':  '',
        \ 'Check':      '',
        \ 'syntax':     'syntax',
        \ ':syntax':    'syntax',
        \ '::::syntax': 'syntax',
        \ 'sy':         'syntax',
        \ 'syn':        'syntax',
        \ 'synt':       'syntax',
        \ ':sy':        'syntax',
        \ '::::sy':     'syntax',
        \ 'match':      'match',
        \ '2match':     'match',
        \ '3match':     'match',
        \ 'aboveleft':  'aboveleft',
        \ 'abo':        'aboveleft',
        \ 'en':         'endif',
        \ 'end':        'endif',
        \ 'endi':        'endif',
        \ 's':          'substitute',
        \ '5s':         'substitute',
        \ ':5s':        'substitute',
        \ "'<,'>s":     'substitute',
        \ ":'<,'>s":    'substitute',
        \ 'CheckLin':   'CheckLinux',
        \ 'CheckLinux': 'CheckLinux',
  \ }

  for [in, want] in items(tests)
    call assert_equal(want, fullcommand(in))
  endfor
  call assert_equal('', fullcommand(test_null_string()))

  call assert_equal('syntax', 'syn'->fullcommand())

  command -buffer BufferLocalCommand :
  command GlobalCommand :
  call assert_equal('GlobalCommand', fullcommand('GlobalCom'))
  call assert_equal('BufferLocalCommand', fullcommand('BufferL'))
  delcommand BufferLocalCommand
  delcommand GlobalCommand
endfunc

func Test_shellcmd_completion()
  let save_path = $PATH

  call mkdir('Xpathdir/Xpathsubdir', 'pR')
  call writefile([''], 'Xpathdir/Xfile.exe')
  call setfperm('Xpathdir/Xfile.exe', 'rwx------')

  " Set PATH to example directory without trailing slash.
  let $PATH = getcwd() . '/Xpathdir'

  " Test for the ":!<TAB>" case.  Previously, this would include subdirs of
  " dirs in the PATH, even though they won't be executed.  We check that only
  " subdirs of the PWD and executables from the PATH are included in the
  " suggestions.
  let actual = getcompletion('X', 'shellcmd')
  let expected = map(filter(glob('*', 0, 1), 'isdirectory(v:val) && v:val[0] == "X"'), 'v:val . "/"')
  call insert(expected, 'Xfile.exe')
  call assert_equal(expected, actual)

  let $PATH = save_path
endfunc

func Test_expand_star_star()
  call mkdir('a/b/c', 'pR')
  call writefile(['asdfasdf'], 'a/b/c/fileXname')
  call feedkeys(":find a/**/fileXname\<Tab>\<CR>", 'xt')
  call assert_equal('find a/b/c/fileXname', @:)
  bwipe!
endfunc

func Test_cmdline_paste()
  let @a = "def"
  call feedkeys(":abc \<C-R>a ghi\<C-B>\"\<CR>", 'tx')
  call assert_equal('"abc def ghi', @:)

  new
  call setline(1, 'asdf.x /tmp/some verylongword a;b-c*d ')

  call feedkeys(":aaa \<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
  call assert_equal('"aaa asdf bbb', @:)

  call feedkeys("ft:aaa \<C-R>\<C-F> bbb\<C-B>\"\<CR>", 'tx')
  call assert_equal('"aaa /tmp/some bbb', @:)

  call feedkeys(":aaa \<C-R>\<C-L> bbb\<C-B>\"\<CR>", 'tx')
  call assert_equal('"aaa '.getline(1).' bbb', @:)

  set incsearch
  call feedkeys("fy:aaa veryl\<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
  call assert_equal('"aaa verylongword bbb', @:)

  call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
  call assert_equal('"aaa a;b-c*d bbb', @:)

  call feedkeys(":\<C-\>etoupper(getline(1))\<CR>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"ASDF.X /TMP/SOME VERYLONGWORD A;B-C*D ', @:)
  bwipe!

  " Error while typing a command used to cause that it was not executed
  " in the end.
  new
  try
    call feedkeys(":file \<C-R>%Xtestfile\<CR>", 'tx')
  catch /^Vim\%((\a\+)\)\=:E32/
    " ignore error E32
  endtry
  call assert_equal("Xtestfile", bufname("%"))

  " Try to paste an invalid register using <C-R>
  call feedkeys(":\"one\<C-R>\<C-X>two\<CR>", 'xt')
  call assert_equal('"onetwo', @:)

  " Test for pasting register containing CTRL-H using CTRL-R and CTRL-R CTRL-R
  let @a = "xy\<C-H>z"
  call feedkeys(":\"\<C-R>a\<CR>", 'xt')
  call assert_equal('"xz', @:)
  call feedkeys(":\"\<C-R>\<C-R>a\<CR>", 'xt')
  call assert_equal("\"xy\<C-H>z", @:)
  call feedkeys(":\"\<C-R>\<C-O>a\<CR>", 'xt')
  call assert_equal("\"xy\<C-H>z", @:)

  " Test for pasting register containing CTRL-V using CTRL-R and CTRL-R CTRL-R
  let @a = "xy\<C-V>z"
  call feedkeys(":\"\<C-R>=@a\<CR>\<cr>", 'xt')
  call assert_equal('"xyz', @:)
  call feedkeys(":\"\<C-R>\<C-R>=@a\<CR>\<cr>", 'xt')
  call assert_equal("\"xy\<C-V>z", @:)

  call assert_beeps('call feedkeys(":\<C-R>=\<C-R>=\<Esc>", "xt")')

  bwipe!
endfunc

func Test_cmdline_remove_char()
  let encoding_save = &encoding

  for e in ['utf8', 'latin1']
    exe 'set encoding=' . e

    call feedkeys(":abc def\<S-Left>\<Del>\<C-B>\"\<CR>", 'tx')
    call assert_equal('"abc ef', @:, e)

    call feedkeys(":abc def\<S-Left>\<BS>\<C-B>\"\<CR>", 'tx')
    call assert_equal('"abcdef', @:)

    call feedkeys(":abc def ghi\<S-Left>\<C-W>\<C-B>\"\<CR>", 'tx')
    call assert_equal('"abc ghi', @:, e)

    call feedkeys(":abc def\<S-Left>\<C-U>\<C-B>\"\<CR>", 'tx')
    call assert_equal('"def', @:, e)

    " This was going before the start in latin1.
    call feedkeys(": \<C-W>\<CR>", 'tx')
  endfor

  let &encoding = encoding_save
endfunc

func Test_cmdline_keymap_ctrl_hat()
  CheckFeature keymap

  set keymap=esperanto
  call feedkeys(":\"Jxauxdo \<C-^>Jxauxdo \<C-^>Jxauxdo\<CR>", 'tx')
  call assert_equal('"Jxauxdo Ĵaŭdo Jxauxdo', @:)
  set keymap=
endfunc

func Test_illegal_address1()
  new
  2;'(
  2;')
  quit
endfunc

func Test_illegal_address2()
  call writefile(['c', 'x', '  x', '.', '1;y'], 'Xtest.vim', 'D')
  new
  source Xtest.vim
  " Trigger calling validate_cursor()
  diffsp Xtest.vim
  quit!
  bwipe!
endfunc

func Test_mark_from_line_zero()
  " this was reading past the end of the first (empty) line
  new
  norm oxxxx
  call assert_fails("0;'(", 'E20:')
  bwipe!
endfunc

func Test_cmdline_complete_wildoptions()
  help
  call feedkeys(":tag /\<c-a>\<c-b>\"\<cr>", 'tx')
  let a = join(sort(split(@:)),' ')
  set wildoptions=tagfile
  call feedkeys(":tag /\<c-a>\<c-b>\"\<cr>", 'tx')
  let b = join(sort(split(@:)),' ')
  call assert_equal(a, b)
  bw!
endfunc

func Test_cmdline_complete_user_cmd()
  command! -complete=color -nargs=1 Foo :
  call feedkeys(":Foo \<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"Foo blue', @:)
  call feedkeys(":Foo b\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"Foo blue', @:)
  call feedkeys(":Foo a b\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"Foo a blue', @:)
  call feedkeys(":Foo b\\\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"Foo b\', @:)
  call feedkeys(":Foo b\\x\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"Foo b\x', @:)
  delcommand Foo

  redraw
  call assert_equal('~', Screenline(&lines - 1))
  command! FooOne :
  command! FooTwo :

  set nowildmenu
  call feedkeys(":Foo\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"FooOne', @:)
  call assert_equal('~', Screenline(&lines - 1))

  call feedkeys(":Foo\<S-Tab>\<Home>\"\<cr>", 'tx')
  call assert_equal('"FooTwo', @:)
  call assert_equal('~', Screenline(&lines - 1))

  delcommand FooOne
  delcommand FooTwo
  set wildmenu&
endfunc

func Test_complete_user_cmd()
  command FooBar echo 'global'
  command -buffer FooBar echo 'local'
  call feedkeys(":Foo\<C-A>\<Home>\"\<CR>", 'tx')
  call assert_equal('"FooBar', @:)

  delcommand -buffer FooBar
  delcommand FooBar
endfunc

func s:ScriptLocalFunction()
  echo 'yes'
endfunc

func Test_cmdline_complete_user_func()
  call feedkeys(":func Test_cmdline_complete_user\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_match('"func Test_cmdline_complete_user_', @:)
  call feedkeys(":func s:ScriptL\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_match('"func <SNR>\d\+_ScriptLocalFunction', @:)

  " g: prefix also works
  call feedkeys(":echo g:Test_cmdline_complete_user_f\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_match('"echo g:Test_cmdline_complete_user_func', @:)

  " using g: prefix does not result in just "g:" matches from a lambda
  let Fx = { a ->  a }
  call feedkeys(":echo g:\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_match('"echo g:[A-Z]', @:)

  " existence of script-local dict function does not break user function name
  " completion
  function s:a_dict_func() dict
  endfunction
  call feedkeys(":call Test_cmdline_complete_user\<Tab>\<Home>\"\<cr>", 'tx')
  call assert_match('"call Test_cmdline_complete_user_', @:)
  delfunction s:a_dict_func
endfunc

func Test_cmdline_complete_user_names()
  if has('unix') && executable('whoami')
    let whoami = systemlist('whoami')[0]
    let first_letter = whoami[0]
    if len(first_letter) > 0
      " Trying completion of  :e ~x  where x is the first letter of
      " the user name should complete to at least the user name.
      call feedkeys(':e ~' . first_letter . "\<c-a>\<c-B>\"\<cr>", 'tx')
      call assert_match('^"e \~.*\<' . whoami . '\>', @:)
    endif
  elseif has('win32')
    " Just in case: check that the system has an Administrator account.
    let names = system('net user')
    if names =~ 'Administrator'
      " Trying completion of  :e ~A  should complete to Administrator.
      " There could be other names starting with "A" before Administrator.
      call feedkeys(':e ~A' . "\<c-a>\<c-B>\"\<cr>", 'tx')
      call assert_match('^"e \~.*Administrator', @:)
    endif
  else
    throw 'Skipped: does not work on this platform'
  endif
endfunc

func Test_cmdline_complete_bang()
  CheckExecutable whoami
  call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_match('^".*\<whoami\>', @:)
endfunc

func Test_cmdline_complete_languages()
  let lang = substitute(execute('language time'), '.*"\(.*\)"$', '\1', '')
  call assert_equal(lang, v:lc_time)

  let lang = substitute(execute('language ctype'), '.*"\(.*\)"$', '\1', '')
  call assert_equal(lang, v:ctype)

  let lang = substitute(execute('language collate'), '.*"\(.*\)"$', '\1', '')
  call assert_equal(lang, v:collate)

  let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '')
  call assert_equal(lang, v:lang)

  call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx')
  call assert_match('^"language .*\<collate\>.*\<ctype\>.*\<messages\>.*\<time\>', @:)

  call assert_match('^"language .*\<' . lang . '\>', @:)

  call feedkeys(":language messages \<c-a>\<c-b>\"\<cr>", 'tx')
  call assert_match('^"language .*\<' . lang . '\>', @:)

  call feedkeys(":language ctype \<c-a>\<c-b>\"\<cr>", 'tx')
  call assert_match('^"language .*\<' . lang . '\>', @:)

  call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx')
  call assert_match('^"language .*\<' . lang . '\>', @:)

  call feedkeys(":language collate \<c-a>\<c-b>\"\<cr>", 'tx')
  call assert_match('^"language .*\<' . lang . '\>', @:)
endfunc

func Test_cmdline_complete_env_variable()
  let $X_VIM_TEST_COMPLETE_ENV = 'foo'
  call feedkeys(":edit $X_VIM_TEST_COMPLETE_E\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_match('"edit $X_VIM_TEST_COMPLETE_ENV', @:)
  unlet $X_VIM_TEST_COMPLETE_ENV
endfunc

func Test_cmdline_complete_expression()
  let g:SomeVar = 'blah'
  for cmd in ['exe', 'echo', 'echon', 'echomsg']
    call feedkeys(":" .. cmd .. " SomeV\<Tab>\<C-B>\"\<CR>", 'tx')
    call assert_match('"' .. cmd .. ' SomeVar', @:)
    call feedkeys(":" .. cmd .. " foo SomeV\<Tab>\<C-B>\"\<CR>", 'tx')
    call assert_match('"' .. cmd .. ' foo SomeVar', @:)
  endfor
  unlet g:SomeVar
endfunc

" Unique function name for completion below
func s:WeirdFunc()
  echo 'weird'
endfunc

" Test for various command-line completion
func Test_cmdline_complete_various()
  " completion for a command starting with a comment
  call feedkeys(": :|\"\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\" :|\"\<C-A>", @:)

  " completion for a range followed by a comment
  call feedkeys(":1,2\"\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"1,2\"\<C-A>", @:)

  " completion for :k command
  call feedkeys(":ka\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"ka\<C-A>", @:)

  " completion for short version of the :s command
  call feedkeys(":sI \<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"sI \<C-A>", @:)

  " completion for :write command
  call mkdir('Xcwdir', 'R')
  call writefile(['one'], 'Xcwdir/Xfile1')
  let save_cwd = getcwd()
  cd Xcwdir
  call feedkeys(":w >> \<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"w >> Xfile1", @:)
  call chdir(save_cwd)

  " completion for :w ! and :r ! commands
  call feedkeys(":w !invalid_xyz_cmd\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"w !invalid_xyz_cmd", @:)
  call feedkeys(":r !invalid_xyz_cmd\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"r !invalid_xyz_cmd", @:)

  " completion for :>> and :<< commands
  call feedkeys(":>>>\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\">>>\<C-A>", @:)
  call feedkeys(":<<<\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"<<<\<C-A>", @:)

  " completion for command with +cmd argument
  call feedkeys(":buffer +/pat Xabc\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"buffer +/pat Xabc", @:)
  call feedkeys(":buffer +/pat\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"buffer +/pat\<C-A>", @:)

  " completion for a command with a trailing comment
  call feedkeys(":ls \" comment\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"ls \" comment\<C-A>", @:)

  " completion for a command with a trailing command
  call feedkeys(":ls | ls\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"ls | ls", @:)

  " completion for a command with an CTRL-V escaped argument
  call feedkeys(":ls \<C-V>\<C-V>a\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"ls \<C-V>a\<C-A>", @:)

  " completion for a command that doesn't take additional arguments
  call feedkeys(":all abc\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"all abc\<C-A>", @:)

  " completion for :wincmd with :horizontal modifier
  call feedkeys(":horizontal wincm\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"horizontal wincmd", @:)

  " completion for a command with a command modifier
  call feedkeys(":topleft new\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"topleft new", @:)

  " completion for vim9 and legacy commands
  call feedkeys(":vim9 call strle\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"vim9 call strlen(", @:)
  call feedkeys(":legac call strle\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"legac call strlen(", @:)

  " completion for the :disassemble command
  call feedkeys(":disas deb\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"disas debug", @:)
  call feedkeys(":disas pro\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"disas profile", @:)
  call feedkeys(":disas debug Test_cmdline_complete_var\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"disas debug Test_cmdline_complete_various", @:)
  call feedkeys(":disas profile Test_cmdline_complete_var\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"disas profile Test_cmdline_complete_various", @:)
  call feedkeys(":disas Test_cmdline_complete_var\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"disas Test_cmdline_complete_various", @:)

  call feedkeys(":disas s:WeirdF\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_match('"disas <SNR>\d\+_WeirdFunc', @:)

  call feedkeys(":disas \<S-Tab>\<C-B>\"\<CR>", 'xt')
  call assert_match('"disas <SNR>\d\+_', @:)
  call feedkeys(":disas debug \<S-Tab>\<C-B>\"\<CR>", 'xt')
  call assert_match('"disas debug <SNR>\d\+_', @:)

  " completion for the :match command
  call feedkeys(":match Search /pat/\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"match Search /pat/\<C-A>", @:)

  " completion for the :doautocmd command
  call feedkeys(":doautocmd User MyCmd a.c\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"doautocmd User MyCmd a.c\<C-A>", @:)

  " completion of autocmd group after comma
  call feedkeys(":doautocmd BufNew,BufEn\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"doautocmd BufNew,BufEnter", @:)

  " completion of file name in :doautocmd
  call writefile([], 'Xvarfile1', 'D')
  call writefile([], 'Xvarfile2', 'D')
  call feedkeys(":doautocmd BufEnter Xvarfi\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"doautocmd BufEnter Xvarfile1 Xvarfile2", @:)

  " completion for the :augroup command
  augroup XTest.test
  augroup END
  call feedkeys(":augroup X\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"augroup XTest.test", @:)

  " group name completion in :autocmd
  call feedkeys(":au X\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"au XTest.test", @:)
  call feedkeys(":au XTest.test\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"au XTest.test", @:)

  augroup! XTest.test

  " autocmd pattern completion
  call feedkeys(":au BufEnter *.py\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"au BufEnter *.py\t", @:)

  " completion for the :unlet command
  call feedkeys(":unlet one two\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"unlet one two", @:)

  " completion for the :buffer command with curlies
  " FIXME: what should happen on MS-Windows?
  if !has('win32')
    edit \{someFile}
    call feedkeys(":buf someFile\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal("\"buf {someFile}", @:)
    bwipe {someFile}
  endif

  " completion for the :bdelete command
  call feedkeys(":bdel a b c\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"bdel a b c", @:)

  " completion for the :mapclear command
  call feedkeys(":mapclear \<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"mapclear <buffer>", @:)

  " completion for user defined commands with menu names
  menu Test.foo :ls<CR>
  com -nargs=* -complete=menu MyCmd
  call feedkeys(":MyCmd Te\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd Test.', @:)
  delcom MyCmd
  unmenu Test

  " completion for user defined commands with mappings
  mapclear
  map <F3> :ls<CR>
  com -nargs=* -complete=mapping MyCmd
  call feedkeys(":MyCmd <F\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd <F3> <F4>', @:)
  mapclear
  delcom MyCmd

  " Prepare for path completion
  call mkdir('Xa b c', 'D')
  defer delete('Xcomma,foobar.txt')
  call writefile([], 'Xcomma,foobar.txt')

  " completion for :set path= with multiple backslashes
  call feedkeys(':set path=Xa\\\ b' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"set path=Xa\\\ b\\\ c/', @:)
  set path&

  " completion for :set dir= with a backslash
  call feedkeys(':set dir=Xa\ b' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"set dir=Xa\ b\ c/', @:)
  set dir&

  " completion for :set tags= / set dictionary= with escaped commas
  if has('win32')
    " In Windows backslashes are rounded up, so both '\,' and '\\,' escape to
    " '\,'
    call feedkeys(':set dictionary=Xcomma\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set dictionary=Xcomma\,foobar.txt', @:)

    call feedkeys(':set tags=Xcomma\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set tags=Xcomma\,foobar.txt', @:)

    call feedkeys(':set tags=Xcomma\\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set tags=Xcomma\\\,foo', @:) " Didn't find a match

    " completion for :set dictionary= with escaped commas (same behavior, but
    " different internal code path from 'set tags=' for escaping the output)
    call feedkeys(':set tags=Xcomma\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set tags=Xcomma\,foobar.txt', @:)
  else
    " In other platforms, backslashes are rounded down (since '\,' itself will
    " be escaped into ','). As a result '\\,' and '\\\,' escape to '\,'.
    call feedkeys(':set tags=Xcomma\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set tags=Xcomma\,foo', @:) " Didn't find a match

    call feedkeys(':set tags=Xcomma\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set tags=Xcomma\\,foobar.txt', @:)

    call feedkeys(':set dictionary=Xcomma\\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set dictionary=Xcomma\\,foobar.txt', @:)

    " completion for :set dictionary= with escaped commas (same behavior, but
    " different internal code path from 'set tags=' for escaping the output)
    call feedkeys(':set dictionary=Xcomma\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set dictionary=Xcomma\\,foobar.txt', @:)
  endif
  set tags&
  set dictionary&

  " completion for :set makeprg= with no escaped commas
  call feedkeys(':set makeprg=Xcomma,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"set makeprg=Xcomma,foobar.txt', @:)

  if !has('win32')
    " Cannot create file with backslash in file name in Windows, so only test
    " this elsewhere.
    defer delete('Xcomma\,fooslash.txt')
    call writefile([], 'Xcomma\,fooslash.txt')
    call feedkeys(':set makeprg=Xcomma\\,foo' .. "\<C-A>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"set makeprg=Xcomma\\,fooslash.txt', @:)
  endif
  set makeprg&

  " completion for the :py3 commands
  call feedkeys(":py3\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"py3 py3do py3file', @:)

  " completion for the :vim9 commands
  call feedkeys(":vim9\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"vim9cmd vim9script', @:)

  " redir @" is not the start of a comment. So complete after that
  call feedkeys(":redir @\" | cwin\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"redir @" | cwindow', @:)

  " completion after a backtick
  call feedkeys(":e `a1b2c\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e `a1b2c', @:)

  " completion for :language command with an invalid argument
  call feedkeys(":language dummy \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"language dummy \t", @:)

  " completion for commands after a :global command
  call feedkeys(":g/a\\xb/clearj\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"g/a\xb/clearjumps', @:)

  " completion with ambiguous user defined commands
  com TCmd1 echo 'TCmd1'
  com TCmd2 echo 'TCmd2'
  call feedkeys(":TCmd \t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"TCmd ', @:)
  delcom TCmd1
  delcom TCmd2

  " completion after a range followed by a pipe (|) character
  call feedkeys(":1,10 | chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"1,10 | chistory', @:)

  " completion after a :global command
  call feedkeys(":g/a/chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"g/a/chistory', @:)
  call feedkeys(":g/a\\/chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"g/a\\/chist\t", @:)

  " use <Esc> as the 'wildchar' for completion
  set wildchar=<Esc>
  call feedkeys(":g/a\\xb/clearj\<Esc>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"g/a\xb/clearjumps', @:)
  " pressing <esc> twice should cancel the command
  call feedkeys(":chist\<Esc>\<Esc>", 'xt')
  call assert_equal('"g/a\xb/clearjumps', @:)
  set wildchar&

  if has('unix')
    " should be able to complete a file name that starts with a '~'.
    call writefile([], '~Xtest')
    call feedkeys(":e \\~X\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e \~Xtest', @:)
    call delete('~Xtest')

    " should be able to complete a file name that has a '*'
    call writefile([], 'Xx*Yy')
    call feedkeys(":e Xx\*\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xx\*Yy', @:)
    call delete('Xx*Yy')

    " use a literal star
    call feedkeys(":e \\*\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e \*', @:)
  endif

  call feedkeys(":py3f\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"py3file', @:)
endfunc

" Test that expanding a pattern doesn't interfere with cmdline completion.
func Test_expand_during_cmdline_completion()
  func ExpandStuff()
    badd <script>:p:h/README.*
    call assert_equal(expand('<script>:p:h') .. '/README.txt', bufname('$'))
    $bwipe
    call assert_equal('README.txt', expand('README.*'))
    call assert_equal(['README.txt'], getcompletion('README.*', 'file'))
  endfunc
  augroup test_CmdlineChanged
    autocmd!
    autocmd CmdlineChanged * call ExpandStuff()
  augroup END

  call feedkeys(":sign \<Tab>\<Tab>\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"sign place', @:)

  augroup test_CmdlineChanged
    au!
  augroup END
  augroup! test_CmdlineChanged
  delfunc ExpandStuff
endfunc

" Test for 'wildignorecase'
func Test_cmdline_wildignorecase()
  CheckUnix
  call writefile([], 'XTEST', 'D')
  set wildignorecase
  call feedkeys(":e xt\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e XTEST', @:)
  call assert_equal(['XTEST'], getcompletion('xt', 'file'))
  let g:Sline = ''
  call feedkeys(":e xt\<C-d>\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e xt', @:)
  call assert_equal('XTEST', g:Sline)
  set wildignorecase&
endfunc

func Test_cmdline_write_alternatefile()
  new
  call setline('.', ['one', 'two'])
  f foo.txt
  new
  f #-A
  call assert_equal('foo.txt-A', expand('%'))
  f #<-B.txt
  call assert_equal('foo-B.txt', expand('%'))
  f %<
  call assert_equal('foo-B', expand('%'))
  new
  call assert_fails('f #<', 'E95:')
  bw!
  f foo-B.txt
  f %<-A
  call assert_equal('foo-B-A', expand('%'))
  bw!
  bw!
endfunc

func Test_cmdline_expand_cur_alt_file()
  enew
  file http://some.com/file.txt
  call feedkeys(":e %\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e http://some.com/file.txt', @:)
  edit another
  call feedkeys(":e #\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e http://some.com/file.txt', @:)
  bwipe
  bwipe http://some.com/file.txt
endfunc

" using a leading backslash here
set cpo+=C

func Test_cmdline_search_range()
  new
  call setline(1, ['a', 'b', 'c', 'd'])
  /d
  1,\/s/b/B/
  call assert_equal('B', getline(2))

  /a
  $
  \?,4s/c/C/
  call assert_equal('C', getline(3))

  call setline(1, ['a', 'b', 'c', 'd'])
  %s/c/c/
  1,\&s/b/B/
  call assert_equal('B', getline(2))

  let @/ = 'apple'
  call assert_fails('\/print', ['E486:.*apple'])

  bwipe!
endfunc

" Test for the tick mark (') in an excmd range
func Test_tick_mark_in_range()
  " If only the tick is passed as a range and no command is specified, there
  " should not be an error
  call feedkeys(":'\<CR>", 'xt')
  call assert_equal("'", @:)
  call assert_fails("',print", 'E78:')
endfunc

" Test for using a line number followed by a search pattern as range
func Test_lnum_and_pattern_as_range()
  new
  call setline(1, ['foo 1', 'foo 2', 'foo 3'])
  let @" = ''
  2/foo/yank
  call assert_equal("foo 3\n", @")
  call assert_equal(1, line('.'))
  close!
endfunc

" Tests for getcmdline(), getcmdpos() and getcmdtype()
func Check_cmdline(cmdtype)
  call assert_equal('MyCmd a', getcmdline())
  call assert_equal(8, getcmdpos())
  call assert_equal(a:cmdtype, getcmdtype())
  return ''
endfunc

set cpo&

func Test_getcmdtype()
  call feedkeys(":MyCmd a\<C-R>=Check_cmdline(':')\<CR>\<Esc>", "xt")

  let cmdtype = ''
  debuggreedy
  call feedkeys(":debug echo 'test'\<CR>", "t")
  call feedkeys("let cmdtype = \<C-R>=string(getcmdtype())\<CR>\<CR>", "t")
  call feedkeys("cont\<CR>", "xt")
  0debuggreedy
  call assert_equal('>', cmdtype)

  call feedkeys("/MyCmd a\<C-R>=Check_cmdline('/')\<CR>\<Esc>", "xt")
  call feedkeys("?MyCmd a\<C-R>=Check_cmdline('?')\<CR>\<Esc>", "xt")

  call feedkeys(":call input('Answer?')\<CR>", "t")
  call feedkeys("MyCmd a\<C-R>=Check_cmdline('@')\<CR>\<C-C>", "xt")

  call feedkeys(":insert\<CR>MyCmd a\<C-R>=Check_cmdline('-')\<CR>\<Esc>", "xt")

  cnoremap <expr> <F6> Check_cmdline('=')
  call feedkeys("a\<C-R>=MyCmd a\<F6>\<Esc>\<Esc>", "xt")
  cunmap <F6>

  call assert_equal('', getcmdline())
endfunc

func Test_verbosefile()
  set verbosefile=Xlog
  echomsg 'foo'
  echomsg 'bar'
  set verbosefile=
  let log = readfile('Xlog')
  call assert_match("foo\nbar", join(log, "\n"))
  call delete('Xlog')

  call mkdir('Xdir', 'D')
  call assert_fails('set verbosefile=Xdir', ['E484:.*Xdir', 'E474:'])
endfunc

func Test_verbose_option()
  CheckScreendump

  let lines =<< trim [SCRIPT]
    command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v
    call feedkeys("\r", 't') " for the hit-enter prompt
    set verbose=20
  [SCRIPT]
  call writefile(lines, 'XTest_verbose', 'D')

  let buf = RunVimInTerminal('-S XTest_verbose', {'rows': 12})
  call TermWait(buf, 50)
  call term_sendkeys(buf, ":DoSomething\<CR>")
  call VerifyScreenDump(buf, 'Test_verbose_option_1', {})

  " clean up
  call StopVimInTerminal(buf)
endfunc

func Test_setcmdpos()
  func InsertTextAtPos(text, pos)
    call assert_equal(0, setcmdpos(a:pos))
    return a:text
  endfunc

  " setcmdpos() with position in the middle of the command line.
  call feedkeys(":\"12\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
  call assert_equal('"1ab2', @:)

  call feedkeys(":\"12\<C-R>\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
  call assert_equal('"1b2a', @:)

  " setcmdpos() with position beyond the end of the command line.
  call feedkeys(":\"12\<C-B>\<C-R>=InsertTextAtPos('a', 10)\<CR>b\<CR>", 'xt')
  call assert_equal('"12ab', @:)

  " setcmdpos() returns 1 when not editing the command line.
  call assert_equal(1, 3->setcmdpos())
endfunc

func Test_cmdline_overstrike()
  let encodings = ['latin1', 'utf8']
  let encoding_save = &encoding

  for e in encodings
    exe 'set encoding=' . e

    " Test overstrike in the middle of the command line.
    call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
    call assert_equal('"0ab1cd4', @:, e)

    " Test overstrike going beyond end of command line.
    call feedkeys(":\"01234\<home>\<right>\<right>ab\<right>\<insert>cdefgh\<enter>", 'xt')
    call assert_equal('"0ab1cdefgh', @:, e)

    " Test toggling insert/overstrike a few times.
    call feedkeys(":\"01234\<home>\<right>ab\<right>\<insert>cd\<right>\<insert>ef\<enter>", 'xt')
    call assert_equal('"ab0cd3ef4', @:, e)
  endfor

  " Test overstrike with multi-byte characters.
  call feedkeys(":\"テキストエディタ\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
  call assert_equal('"テabキcdエディタ', @:, e)

  let &encoding = encoding_save
endfunc

func Test_buffers_lastused()
  " check that buffers are sorted by time when wildmode has lastused
  call test_settime(1550020000)	  " middle
  edit bufa
  enew
  call test_settime(1550030000)	  " newest
  edit bufb
  enew
  call test_settime(1550010000)	  " oldest
  edit bufc
  enew
  call test_settime(0)
  enew

  call assert_equal(['bufa', 'bufb', 'bufc'],
	\ getcompletion('', 'buffer'))

  let save_wildmode = &wildmode
  set wildmode=full:lastused

  let cap = "\<c-r>=execute('let X=getcmdline()')\<cr>"
  call feedkeys(":b \<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufb', X)
  call feedkeys(":b \<tab>\<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufa', X)
  call feedkeys(":b \<tab>\<tab>\<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufc', X)
  enew

  edit other
  call feedkeys(":b \<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufb', X)
  call feedkeys(":b \<tab>\<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufa', X)
  call feedkeys(":b \<tab>\<tab>\<tab>" .. cap .. "\<esc>", 'xt')
  call assert_equal('b bufc', X)
  enew

  let &wildmode = save_wildmode

  bwipeout bufa
  bwipeout bufb
  bwipeout bufc
endfunc

func Test_cmdlineclear_tabenter()
  CheckScreendump

  let lines =<< trim [SCRIPT]
    call setline(1, range(30))
  [SCRIPT]

  call writefile(lines, 'XtestCmdlineClearTabenter', 'D')
  let buf = RunVimInTerminal('-S XtestCmdlineClearTabenter', #{rows: 10})
  call TermWait(buf, 25)
  " in one tab make the command line higher with CTRL-W -
  call term_sendkeys(buf, ":tabnew\<cr>\<C-w>-\<C-w>-gtgt")
  call VerifyScreenDump(buf, 'Test_cmdlineclear_tabenter', {})

  call StopVimInTerminal(buf)
endfunc

" Test for expanding special keywords in cmdline
func Test_cmdline_expand_special()
  %bwipe!
  call assert_fails('e #', 'E194:')
  call assert_fails('e <afile>', 'E495:')
  call assert_fails('e <abuf>', 'E496:')
  call assert_fails('e <amatch>', 'E497:')

  call writefile([], 'Xfile.cpp', 'D')
  call writefile([], 'Xfile.java', 'D')
  new Xfile.cpp
  call feedkeys(":e %:r\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xfile.cpp Xfile.java', @:)
  close
endfunc

" Test for backtick expression in the command line
func Test_cmd_backtick()
  %argd
  argadd `=['a', 'b', 'c']`
  call assert_equal(['a', 'b', 'c'], argv())
  %argd

  argadd `echo abc def`
  call assert_equal(['abc def'], argv())
  %argd
endfunc

" Test for the :! command
func Test_cmd_bang()
  CheckUnix

  let lines =<< trim [SCRIPT]
    " Test for no previous command
    call assert_fails('!!', 'E34:')
    set nomore
    " Test for cmdline expansion with :!
    call setline(1, 'foo!')
    silent !echo <cWORD> > Xfile.out
    call assert_equal(['foo!'], readfile('Xfile.out'))
    " Test for using previous command
    silent !echo \! !
    call assert_equal(['! echo foo!'], readfile('Xfile.out'))
    call writefile(v:errors, 'Xresult')
    call delete('Xfile.out')
    qall!
  [SCRIPT]
  call writefile(lines, 'Xscript', 'D')
  if RunVim([], [], '--clean -S Xscript')
    call assert_equal([], readfile('Xresult'))
  endif
  call delete('Xresult')
endfunc

" Test error: "E135: *Filter* Autocommands must not change current buffer"
func Test_cmd_bang_E135()
  new
  call setline(1, ['a', 'b', 'c', 'd'])
  augroup test_cmd_filter_E135
    au!
    autocmd FilterReadPost * help
  augroup END
  call assert_fails('2,3!echo "x"', 'E135:')

  augroup test_cmd_filter_E135
    au!
  augroup END
  augroup! test_cmd_filter_E135
  %bwipe!
endfunc

func Test_cmd_bang_args()
  new
  :.!
  call assert_equal(0, v:shell_error)

  " Note that below there is one space char after the '!'.  This caused a
  " shell error in the past, see https://github.com/vim/vim/issues/11495.
  :.! 
  call assert_equal(0, v:shell_error)
  bwipe!

  CheckUnix
  :.!pwd
  call assert_equal(0, v:shell_error)
  :.! pwd
  call assert_equal(0, v:shell_error)

  " Note there is one space after 'pwd'.
  :.! pwd 
  call assert_equal(0, v:shell_error)

  " Note there are two spaces after 'pwd'.
  :.!  pwd  
  call assert_equal(0, v:shell_error)
  :.!ls ~
  call assert_equal(0, v:shell_error)

  " Note there is one space char after '~'.
  :.!ls  ~ 
  call assert_equal(0, v:shell_error)

  " Note there are two spaces after '~'.
  :.!ls  ~  
  call assert_equal(0, v:shell_error)

  :.!echo "foo"
  call assert_equal(getline('.'), "foo")
  :.!echo "foo  "
  call assert_equal(getline('.'), "foo  ")
  :.!echo " foo  "
  call assert_equal(getline('.'), " foo  ")
  :.!echo  " foo  "
  call assert_equal(getline('.'), " foo  ")

  %bwipe!
endfunc

" Test for using ~ for home directory in cmdline completion matches
func Test_cmdline_expand_home()
  call mkdir('Xexpdir', 'R')
  call writefile([], 'Xexpdir/Xfile1')
  call writefile([], 'Xexpdir/Xfile2')
  cd Xexpdir
  let save_HOME = $HOME
  let $HOME = getcwd()
  call feedkeys(":e ~/\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ~/Xfile1 ~/Xfile2', @:)
  let $HOME = save_HOME
  cd ..
endfunc

" Test for using CTRL-\ CTRL-G in the command line to go back to normal mode
" or insert mode (when 'insertmode' is set)
func Test_cmdline_ctrl_g()
  new
  call setline(1, 'abc')
  call cursor(1, 3)
  " If command line is entered from insert mode, using C-\ C-G should back to
  " insert mode
  call feedkeys("i\<C-O>:\<C-\>\<C-G>xy", 'xt')
  call assert_equal('abxyc', getline(1))
  call assert_equal(4, col('.'))

  " If command line is entered in 'insertmode', using C-\ C-G should back to
  " 'insertmode'
  call feedkeys(":set im\<cr>\<C-L>:\<C-\>\<C-G>12\<C-L>:set noim\<cr>", 'xt')
  call assert_equal('ab12xyc', getline(1))
  close!
endfunc

" Test for 'wildmode'
func Wildmode_tests()
  func T(a, c, p)
    return "oneA\noneB\noneC"
  endfunc
  command -nargs=1 -complete=custom,T MyCmd

  set nowildmenu
  set wildmode=full,list
  let g:Sline = ''
  call feedkeys(":MyCmd \t\t\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('oneA  oneB  oneC', g:Sline)
  call assert_equal('"MyCmd oneA', @:)

  set wildmode=longest,full
  call feedkeys(":MyCmd o\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd one', @:)
  call feedkeys(":MyCmd o\t\t\t\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd oneC', @:)

  set wildmode=longest
  call feedkeys(":MyCmd one\t\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd one', @:)

  set wildmode=list:longest
  let g:Sline = ''
  call feedkeys(":MyCmd \t\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('oneA  oneB  oneC', g:Sline)
  call assert_equal('"MyCmd one', @:)

  set wildmode=""
  call feedkeys(":MyCmd \t\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd oneA', @:)

  " Test for wildmode=longest with 'fileignorecase' set
  set wildmode=longest
  set fileignorecase
  argadd AAA AAAA AAAAA
  call feedkeys(":buffer a\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"buffer AAA', @:)
  set fileignorecase&

  " Test for listing files with wildmode=list
  set wildmode=list
  let g:Sline = ''
  call feedkeys(":b A\t\t\<F4>\<C-B>\"\<CR>", 'xt')
  call assert_equal('AAA    AAAA   AAAAA', g:Sline)
  call assert_equal('"b A', @:)

  " when using longest completion match, matches shorter than the argument
  " should be ignored (happens with :help)
  set wildmode=longest,full
  set wildmenu
  call feedkeys(":help a*\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"help a', @:)
  " non existing file
  call feedkeys(":e a1b2y3z4\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e a1b2y3z4', @:)
  set wildmenu&

  " Test for longest file name completion with 'fileignorecase'
  " On MS-Windows, file names are case insensitive.
  if has('unix')
    call writefile([], 'XTESTfoo', 'D')
    call writefile([], 'Xtestbar', 'D')
    set nofileignorecase
    call feedkeys(":e XT\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e XTESTfoo', @:)
    call feedkeys(":e Xt\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtestbar', @:)
    set fileignorecase
    call feedkeys(":e XT\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest', @:)
    call feedkeys(":e Xt\<Tab>\<C-B>\"\<CR>", 'xt')
    call assert_equal('"e Xtest', @:)
    set fileignorecase&
  endif

  %argdelete
  delcommand MyCmd
  delfunc T
  set wildmode&
  %bwipe!
endfunc

func Test_wildmode()
  " Test with utf-8 encoding
  call Wildmode_tests()

  " Test with latin1 encoding
  let save_encoding = &encoding
  set encoding=latin1
  call Wildmode_tests()
  let &encoding = save_encoding
endfunc

func Test_custom_complete_autoload()
  call mkdir('Xcustdir/autoload', 'pR')
  let save_rtp = &rtp
  exe 'set rtp=' .. getcwd() .. '/Xcustdir'
  let lines =<< trim END
      func vim8#Complete(a, c, p)
        return "oneA\noneB\noneC"
      endfunc
  END
  call writefile(lines, 'Xcustdir/autoload/vim8.vim')

  command -nargs=1 -complete=custom,vim8#Complete MyCmd
  set nowildmenu
  set wildmode=full,list
  call feedkeys(":MyCmd \<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"MyCmd oneA oneB oneC', @:)

  let &rtp = save_rtp
  set wildmode& wildmenu&
  delcommand MyCmd
endfunc

" Test for interrupting the command-line completion
func Test_interrupt_compl()
  func F(lead, cmdl, p)
    if a:lead =~ 'tw'
      call interrupt()
      return
    endif
    return "one\ntwo\nthree"
  endfunc
  command -nargs=1 -complete=custom,F Tcmd

  set nowildmenu
  set wildmode=full
  let interrupted = 0
  try
    call feedkeys(":Tcmd tw\<Tab>\<C-B>\"\<CR>", 'xt')
  catch /^Vim:Interrupt$/
    let interrupted = 1
  endtry
  call assert_equal(1, interrupted)

  let interrupted = 0
  try
    call feedkeys(":Tcmd tw\<C-d>\<C-B>\"\<CR>", 'xt')
  catch /^Vim:Interrupt$/
    let interrupted = 1
  endtry
  call assert_equal(1, interrupted)

  delcommand Tcmd
  delfunc F
  set wildmode&
endfunc

" Test for moving the cursor on the : command line
func Test_cmdline_edit()
  let str = ":one two\<C-U>"
  let str ..= "one two\<C-W>\<C-W>"
  let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
  let str ..= "\<Left>five\<Right>"
  let str ..= "\<Home>two "
  let str ..= "\<C-Left>one "
  let str ..= "\<C-Right> three"
  let str ..= "\<End>\<S-Left>four "
  let str ..= "\<S-Right> six"
  let str ..= "\<C-B>\"\<C-E> seven\<CR>"
  call feedkeys(str, 'xt')
  call assert_equal("\"one two three four five six seven", @:)
endfunc

" Test for moving the cursor on the / command line in 'rightleft' mode
func Test_cmdline_edit_rightleft()
  CheckFeature rightleft
  set rightleft
  set rightleftcmd=search
  let str = "/one two\<C-U>"
  let str ..= "one two\<C-W>\<C-W>"
  let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
  let str ..= "\<Right>five\<Left>"
  let str ..= "\<Home>two "
  let str ..= "\<C-Right>one "
  let str ..= "\<C-Left> three"
  let str ..= "\<End>\<S-Right>four "
  let str ..= "\<S-Left> six"
  let str ..= "\<C-B>\"\<C-E> seven\<CR>"
  call assert_fails("call feedkeys(str, 'xt')", 'E486:')
  call assert_equal("\"one two three four five six seven", @/)
  set rightleftcmd&
  set rightleft&
endfunc

" Test for using <C-\>e in the command line to evaluate an expression
func Test_cmdline_expr()
  " Evaluate an expression from the beginning of a command line
  call feedkeys(":abc\<C-B>\<C-\>e\"\\\"hello\"\<CR>\<CR>", 'xt')
  call assert_equal('"hello', @:)

  " Use an invalid expression for <C-\>e
  call assert_beeps('call feedkeys(":\<C-\>einvalid\<CR>", "tx")')

  " Insert literal <CTRL-\> in the command line
  call feedkeys(":\"e \<C-\>\<C-Y>\<CR>", 'xt')
  call assert_equal("\"e \<C-\>\<C-Y>", @:)
endfunc

" This was making the insert position negative
func Test_cmdline_expr_register()
  exe "sil! norm! ?\<C-\>e0\<C-R>0\<Esc>?\<C-\>e0\<CR>"
endfunc

" Test for 'imcmdline' and 'imsearch'
" This test doesn't actually test the input method functionality.
func Test_cmdline_inputmethod()
  new
  call setline(1, ['', 'abc', ''])
  set imcmdline

  call feedkeys(":\"abc\<CR>", 'xt')
  call assert_equal("\"abc", @:)
  call feedkeys(":\"\<C-^>abc\<C-^>\<CR>", 'xt')
  call assert_equal("\"abc", @:)
  call feedkeys("/abc\<CR>", 'xt')
  call assert_equal([2, 1], [line('.'), col('.')])
  call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
  call assert_equal([2, 1], [line('.'), col('.')])

  set imsearch=2
  call cursor(1, 1)
  call feedkeys("/abc\<CR>", 'xt')
  call assert_equal([2, 1], [line('.'), col('.')])
  call cursor(1, 1)
  call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
  call assert_equal([2, 1], [line('.'), col('.')])
  set imdisable
  call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
  call assert_equal([2, 1], [line('.'), col('.')])
  set imdisable&
  set imsearch&

  set imcmdline&
  %bwipe!
endfunc

" Test for using CTRL-_ in the command line with 'allowrevins'
func Test_cmdline_revins()
  CheckNotMSWindows
  CheckFeature rightleft
  call feedkeys(":\"abc\<c-_>\<cr>", 'xt')
  call assert_equal("\"abc\<c-_>", @:)
  set allowrevins
  call feedkeys(":\"abc\<c-_>xyz\<c-_>\<CR>", 'xt')
  call assert_equal('"abcñèæ', @:)
  set allowrevins&
endfunc

" Test for typing UTF-8 composing characters in the command line
func Test_cmdline_composing_chars()
  call feedkeys(":\"\<C-V>u3046\<C-V>u3099\<CR>", 'xt')
  call assert_equal('"ゔ', @:)
endfunc

" test that ";" works to find a match at the start of the first line
func Test_zero_line_search()
  new
  call setline(1, ["1, pattern", "2, ", "3, pattern"])
  call cursor(1,1)
  0;/pattern/d
  call assert_equal(["2, ", "3, pattern"], getline(1,'$'))
  q!
endfunc

func Test_read_shellcmd()
  CheckUnix
  if executable('ls')
    " There should be ls in the $PATH
    call feedkeys(":r! l\<c-a>\<c-b>\"\<cr>", 'tx')
    call assert_match('^"r! .*\<ls\>', @:)
  endif

  if executable('rm')
    call feedkeys(":r! ++enc=utf-8 r\<c-a>\<c-b>\"\<cr>", 'tx')
    call assert_notmatch('^"r!.*\<runtest.vim\>', @:)
    call assert_match('^"r!.*\<rm\>', @:)

    call feedkeys(":r ++enc=utf-8 !rm\<c-a>\<c-b>\"\<cr>", 'tx')
    call assert_notmatch('^"r.*\<runtest.vim\>', @:)
    call assert_match('^"r ++enc\S\+ !.*\<rm\>', @:)
  endif
endfunc

" Test for going up and down the directory tree using 'wildmenu'
func Test_wildmenu_dirstack()
  CheckUnix
  %bw!
  call mkdir('Xwildmenu/dir2/dir3/dir4', 'pR')
  call writefile([], 'Xwildmenu/file1_1.txt')
  call writefile([], 'Xwildmenu/file1_2.txt')
  call writefile([], 'Xwildmenu/dir2/file2_1.txt')
  call writefile([], 'Xwildmenu/dir2/file2_2.txt')
  call writefile([], 'Xwildmenu/dir2/dir3/file3_1.txt')
  call writefile([], 'Xwildmenu/dir2/dir3/file3_2.txt')
  call writefile([], 'Xwildmenu/dir2/dir3/dir4/file4_1.txt')
  call writefile([], 'Xwildmenu/dir2/dir3/dir4/file4_2.txt')
  set wildmenu

  cd Xwildmenu/dir2/dir3/dir4
  call feedkeys(":e \<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e file4_1.txt', @:)
  call feedkeys(":e \<Tab>\<Up>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ../dir4/', @:)
  call feedkeys(":e \<Tab>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ../../dir3/', @:)
  call feedkeys(":e \<Tab>\<Up>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ../../../dir2/', @:)
  call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ../../dir3/dir4/', @:)
  call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e ../../dir3/dir4/file4_1.txt', @:)
  cd -
  call feedkeys(":e Xwildmenu/\<Tab>\<Down>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xwildmenu/dir2/dir3/dir4/file4_1.txt', @:)

  set wildmenu&
endfunc

" Test for recalling newer or older cmdline from history with <Up>, <Down>,
" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <kPageUp>, <kPageDown>, <C-p>, or
" <C-n>.
func Test_recalling_cmdline()
  CheckFeature cmdline_hist

  let g:cmdlines = []
  cnoremap <Plug>(save-cmdline) <Cmd>let g:cmdlines += [getcmdline()]<CR>

  let histories = [
  \  #{name: 'cmd',    enter: ':',                    exit: "\<Esc>"},
  \  #{name: 'search', enter: '/',                    exit: "\<Esc>"},
  \  #{name: 'expr',   enter: ":\<C-r>=",             exit: "\<Esc>\<Esc>"},
  \  #{name: 'input',  enter: ":call input('')\<CR>", exit: "\<CR>"},
  "\ TODO: {'name': 'debug', ...}
  \]
  let keypairs = [
  \  #{older: "\<Up>",     newer: "\<Down>",     prefixmatch: v:true},
  \  #{older: "\<S-Up>",   newer: "\<S-Down>",   prefixmatch: v:false},
  \  #{older: "\<PageUp>", newer: "\<PageDown>", prefixmatch: v:false},
  \  #{older: "\<kPageUp>", newer: "\<kPageDown>", prefixmatch: v:false},
  \  #{older: "\<C-p>",    newer: "\<C-n>",      prefixmatch: v:false},
  \]
  let prefix = 'vi'
  for h in histories
    call histadd(h.name, 'vim')
    call histadd(h.name, 'virtue')
    call histadd(h.name, 'Virgo')
    call histadd(h.name, 'vogue')
    call histadd(h.name, 'emacs')
    for k in keypairs
      let g:cmdlines = []
      let keyseqs = h.enter
      \          .. prefix
      \          .. repeat(k.older .. "\<Plug>(save-cmdline)", 2)
      \          .. repeat(k.newer .. "\<Plug>(save-cmdline)", 2)
      \          .. h.exit
      call feedkeys(keyseqs, 'xt')
      call histdel(h.name, -1) " delete the history added by feedkeys above
      let expect = k.prefixmatch
      \          ? ['virtue', 'vim',   'virtue', prefix]
      \          : ['emacs',  'vogue', 'emacs',  prefix]
      call assert_equal(expect, g:cmdlines)
    endfor
  endfor

  unlet g:cmdlines
  cunmap <Plug>(save-cmdline)
endfunc

func Test_cmd_map_cmdlineChanged()
  let g:log = []
  cnoremap <F1> l<Cmd><CR>s
  augroup test_CmdlineChanged
    autocmd!
    autocmd CmdlineChanged : let g:log += [getcmdline()]
  augroup END

  call feedkeys(":\<F1>\<CR>", 'xt')
  call assert_equal(['l', 'ls'], g:log)

  let @b = 'b'
  cnoremap <F1> a<C-R>b
  let g:log = []
  call feedkeys(":\<F1>\<CR>", 'xt')
  call assert_equal(['a', 'ab'], g:log)

  unlet g:log
  cunmap <F1>
  augroup test_CmdlineChanged
    autocmd!
  augroup END
  augroup! test_CmdlineChanged
endfunc

" Test for the 'suffixes' option
func Test_suffixes_opt()
  call writefile([], 'Xsuffile', 'D')
  call writefile([], 'Xsuffile.c', 'D')
  call writefile([], 'Xsuffile.o', 'D')
  set suffixes=
  call feedkeys(":e Xsuffi*\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile Xsuffile.c Xsuffile.o', @:)
  call feedkeys(":e Xsuffi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile.c', @:)
  set suffixes=.c
  call feedkeys(":e Xsuffi*\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile Xsuffile.o Xsuffile.c', @:)
  call feedkeys(":e Xsuffi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile.o', @:)
  set suffixes=,,
  call feedkeys(":e Xsuffi*\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile.c Xsuffile.o Xsuffile', @:)
  call feedkeys(":e Xsuffi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"e Xsuffile.o', @:)
  set suffixes&
  " Test for getcompletion() with different patterns
  call assert_equal(['Xsuffile', 'Xsuffile.c', 'Xsuffile.o'], getcompletion('Xsuffile', 'file'))
  call assert_equal(['Xsuffile'], getcompletion('Xsuffile$', 'file'))
endfunc

" Test for using a popup menu for the command line completion matches
" (wildoptions=pum)
func Test_wildmenu_pum()
  CheckRunVimInTerminal

  let commands =<< trim [CODE]
    set wildmenu
    set wildoptions=pum
    set shm+=I
    set noruler
    set noshowcmd

    func CmdCompl(a, b, c)
      return repeat(['aaaa'], 120)
    endfunc
    command -nargs=* -complete=customlist,CmdCompl Tcmd

    func MyStatusLine() abort
      return 'status'
    endfunc
    func SetupStatusline()
      set statusline=%!MyStatusLine()
      set laststatus=2
    endfunc

    func MyTabLine()
      return 'my tab line'
    endfunc
    func SetupTabline()
      set statusline=
      set tabline=%!MyTabLine()
      set showtabline=2
    endfunc

    func DoFeedKeys()
      let &wildcharm = char2nr("\t")
      call feedkeys(":edit $VIMRUNTIME/\<Tab>\<Left>\<C-U>ab\<Tab>")
    endfunc
  [CODE]
  call writefile(commands, 'Xtest', 'D')

  let buf = RunVimInTerminal('-S Xtest', #{rows: 10})

  call term_sendkeys(buf, ":sign \<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_01', {})

  " going down the popup menu using <Down>
  call term_sendkeys(buf, "\<Down>\<Down>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_02', {})

  " going down the popup menu using <C-N>
  call term_sendkeys(buf, "\<C-N>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_03', {})

  " going up the popup menu using <C-P>
  call term_sendkeys(buf, "\<C-P>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_04', {})

  " going up the popup menu using <Up>
  call term_sendkeys(buf, "\<Up>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_05', {})

  " pressing <C-E> should end completion and go back to the original match
  call term_sendkeys(buf, "\<C-E>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_06', {})

  " pressing <C-Y> should select the current match and end completion
  call term_sendkeys(buf, "\<Tab>\<C-P>\<C-P>\<C-Y>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_07', {})

  " With 'wildmode' set to 'longest,full', completing a match should display
  " the longest match, the wildmenu should not be displayed.
  call term_sendkeys(buf, ":\<C-U>set wildmode=longest,full\<CR>")
  call TermWait(buf)
  call term_sendkeys(buf, ":sign u\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_08', {})

  " pressing <Tab> should display the wildmenu
  call term_sendkeys(buf, "\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_09', {})

  " pressing <Tab> second time should select the next entry in the menu
  call term_sendkeys(buf, "\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_10', {})

  call term_sendkeys(buf, ":\<C-U>set wildmode=full\<CR>")
  " showing popup menu in different columns in the cmdline
  call term_sendkeys(buf, ":sign define \<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_11', {})

  call term_sendkeys(buf, " \<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_12', {})

  call term_sendkeys(buf, " \<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_13', {})

  " Directory name completion
  call mkdir('Xnamedir/XdirA/XdirB', 'pR')
  call writefile([], 'Xnamedir/XfileA')
  call writefile([], 'Xnamedir/XdirA/XfileB')
  call writefile([], 'Xnamedir/XdirA/XdirB/XfileC')

  call term_sendkeys(buf, "\<C-U>e Xnamedi\<Tab>\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_14', {})

  " Pressing <Right> on a directory name should go into that directory
  call term_sendkeys(buf, "\<Right>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_15', {})

  " Pressing <Left> on a directory name should go to the parent directory
  call term_sendkeys(buf, "\<Left>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_16', {})

  " Pressing <C-A> when the popup menu is displayed should list all the
  " matches but the popup menu should still remain
  call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-A>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_17', {})

  " Pressing <C-D> when the popup menu is displayed should remove the popup
  " menu
  call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-D>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_18', {})

  " Pressing <S-Tab> should open the popup menu with the last entry selected
  call term_sendkeys(buf, "\<C-U>\<CR>:sign \<S-Tab>\<C-P>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_19', {})

  " Pressing <Esc> should close the popup menu and cancel the cmd line
  call term_sendkeys(buf, "\<C-U>\<CR>:sign \<Tab>\<Esc>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_20', {})

  " Typing a character when the popup is open, should close the popup
  call term_sendkeys(buf, ":sign \<Tab>x")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_21', {})

  " When the popup is open, entering the cmdline window should close the popup
  call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-F>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_22', {})
  call term_sendkeys(buf, ":q\<CR>")

  " After the last popup menu item, <C-N> should show the original string
  call term_sendkeys(buf, ":sign u\<Tab>\<C-N>\<C-N>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_23', {})

  " Use the popup menu for the command name
  call term_sendkeys(buf, "\<C-U>bu\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_24', {})

  " Pressing the left arrow should remove the popup menu
  call term_sendkeys(buf, "\<Left>\<Left>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_25', {})

  " Pressing <BS> should remove the popup menu and erase the last character
  call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<BS>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_26', {})

  " Pressing <C-W> should remove the popup menu and erase the previous word
  call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-W>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_27', {})

  " Pressing <C-U> should remove the popup menu and erase the entire line
  call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-U>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_28', {})

  " Using <C-E> to cancel the popup menu and then pressing <Up> should recall
  " the cmdline from history
  call term_sendkeys(buf, "sign xyz\<Esc>:sign \<Tab>\<C-E>\<Up>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_29', {})

  " Check "list" still works
  call term_sendkeys(buf, "\<C-U>set wildmode=longest,list\<CR>")
  call term_sendkeys(buf, ":cn\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_30', {})
  call term_sendkeys(buf, "s")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_31', {})

  " Tests a directory name contained full-width characters.
  call mkdir('Xnamedir/あいう', 'p')
  call writefile([], 'Xnamedir/あいう/abc')
  call writefile([], 'Xnamedir/あいう/xyz')
  call writefile([], 'Xnamedir/あいう/123')

  call term_sendkeys(buf, "\<C-U>set wildmode&\<CR>")
  call term_sendkeys(buf, ":\<C-U>e Xnamedir/あいう/\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_32', {})

  " Pressing <C-A> when the popup menu is displayed should list all the
  " matches and pressing a key after that should remove the popup menu
  call term_sendkeys(buf, "\<C-U>set wildmode=full\<CR>")
  call term_sendkeys(buf, ":sign \<Tab>\<C-A>x")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_33', {})

  " Pressing <C-A> when the popup menu is displayed should list all the
  " matches and pressing <Left> after that should move the cursor
  call term_sendkeys(buf, "\<C-U>abc\<Esc>")
  call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<Left>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_34', {})

  " When <C-A> displays a lot of matches (screen scrolls), all the matches
  " should be displayed correctly on the screen.
  call term_sendkeys(buf, "\<End>\<C-U>Tcmd \<Tab>\<C-A>\<Left>\<Left>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_35', {})

  " After using <C-A> to expand all the filename matches, pressing <Up>
  " should not open the popup menu again.
  call term_sendkeys(buf, "\<C-E>\<C-U>:cd Xnamedir/XdirA\<CR>")
  call term_sendkeys(buf, ":e \<Tab>\<C-A>\<Up>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_36', {})
  call term_sendkeys(buf, "\<C-E>\<C-U>:cd -\<CR>")

  " After using <C-A> to expand all the matches, pressing <S-Tab> used to
  " crash Vim
  call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<S-Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_37', {})

  " After removing the pum the command line is redrawn
  call term_sendkeys(buf, ":edit foo\<CR>")
  call term_sendkeys(buf, ":edit bar\<CR>")
  call term_sendkeys(buf, ":ls\<CR>")
  call term_sendkeys(buf, ":com\<Tab> ")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_38', {})
  call term_sendkeys(buf, "\<C-U>\<CR>")

  " Esc still works to abort the command when 'statusline' is set
  call term_sendkeys(buf, ":call SetupStatusline()\<CR>")
  call term_sendkeys(buf, ":si\<Tab>")
  call term_sendkeys(buf, "\<Esc>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_39', {})

  " Esc still works to abort the command when 'tabline' is set
  call term_sendkeys(buf, ":call SetupTabline()\<CR>")
  call term_sendkeys(buf, ":si\<Tab>")
  call term_sendkeys(buf, "\<Esc>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_40', {})

  " popup is cleared also when 'lazyredraw' is set
  call term_sendkeys(buf, ":set showtabline=1 laststatus=1 lazyredraw\<CR>")
  call term_sendkeys(buf, ":call DoFeedKeys()\<CR>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {})
  call term_sendkeys(buf, "\<Esc>")

  " Pressing <PageDown> should scroll the menu downward
  call term_sendkeys(buf, ":sign \<Tab>\<PageDown>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_42', {})
  call term_sendkeys(buf, "\<PageDown>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_43', {})
  call term_sendkeys(buf, "\<PageDown>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_44', {})
  call term_sendkeys(buf, "\<PageDown>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_45', {})
  call term_sendkeys(buf, "\<C-U>sign \<Tab>\<Down>\<Down>\<PageDown>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_46', {})

  " Pressing <PageUp> should scroll the menu upward
  call term_sendkeys(buf, "\<C-U>sign \<Tab>\<PageUp>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_47', {})
  call term_sendkeys(buf, "\<PageUp>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_48', {})
  call term_sendkeys(buf, "\<PageUp>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_49', {})
  call term_sendkeys(buf, "\<PageUp>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_50', {})

  call term_sendkeys(buf, "\<C-U>\<CR>")
  call StopVimInTerminal(buf)
endfunc

" Test for wildmenumode() with the cmdline popup menu
func Test_wildmenumode_with_pum()
  set wildmenu
  set wildoptions=pum
  cnoremap <expr> <F2> wildmenumode()
  call feedkeys(":sign \<Tab>\<F2>\<F2>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"sign define10', @:)
  call feedkeys(":sign \<Tab>\<C-A>\<F2>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"sign define jump list place undefine unplace0', @:)
  call feedkeys(":sign \<Tab>\<C-E>\<F2>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"sign 0', @:)
  call feedkeys(":sign \<Tab>\<C-Y>\<F2>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"sign define0', @:)
  set nowildmenu wildoptions&
  cunmap <F2>
endfunc

func Test_wildmenu_with_pum_foldexpr()
  CheckRunVimInTerminal

  let lines =<< trim END
      call setline(1, ['folded one', 'folded two', 'some more text'])
      func MyFoldText()
        return 'foo'
      endfunc
      set foldtext=MyFoldText() wildoptions=pum
      normal ggzfj
  END
  call writefile(lines, 'Xpumfold', 'D')
  let buf = RunVimInTerminal('-S Xpumfold', #{rows: 10})
  call term_sendkeys(buf, ":set\<Tab>")
  call VerifyScreenDump(buf, 'Test_wildmenu_with_pum_foldexpr_1', {})

  call term_sendkeys(buf, "\<Esc>")
  call VerifyScreenDump(buf, 'Test_wildmenu_with_pum_foldexpr_2', {})

  call StopVimInTerminal(buf)
endfunc

" Test for opening the cmdline completion popup menu from the terminal window.
" The popup menu should be positioned correctly over the status line of the
" bottom-most window.
func Test_wildmenu_pum_from_terminal()
  CheckRunVimInTerminal
  let python = PythonProg()
  call CheckPython(python)

  %bw!
  let cmds = ['set wildmenu wildoptions=pum']
  let pcmd = python .. ' -c "import sys; sys.stdout.write(sys.stdin.read())"'
  call add(cmds, "call term_start('" .. pcmd .. "')")
  call writefile(cmds, 'Xtest', 'D')
  let buf = RunVimInTerminal('-S Xtest', #{rows: 10})
  call term_sendkeys(buf, "\r\r\r")
  call term_wait(buf)
  call term_sendkeys(buf, "\<C-W>:sign \<Tab>")
  call term_wait(buf)
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_term_01', {})
  call term_wait(buf)
  call StopVimInTerminal(buf)
endfunc

func Test_wildmenu_pum_clear_entries()
  CheckRunVimInTerminal

  " This was using freed memory.  Run in a terminal to get the pum to update.
  let lines =<< trim END
    set wildoptions=pum
    set wildchar=<C-E>
  END
  call writefile(lines, 'XwildmenuTest', 'D')
  let buf = RunVimInTerminal('-S XwildmenuTest', #{rows: 10})

  call term_sendkeys(buf, ":\<C-E>\<C-E>")
  call VerifyScreenDump(buf, 'Test_wildmenu_pum_clear_entries_1', {})

  set wildoptions& wildchar&
endfunc

" Test for completion after a :substitute command followed by a pipe (|)
" character
func Test_cmdline_complete_substitute()
  call feedkeys(":s | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s | \t", @:)
  call feedkeys(":s/ | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/ | \t", @:)
  call feedkeys(":s/one | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one | \t", @:)
  call feedkeys(":s/one/ | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one/ | \t", @:)
  call feedkeys(":s/one/two | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one/two | \t", @:)
  call feedkeys(":s/one/two/ | chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"s/one/two/ | chistory', @:)
  call feedkeys(":s/one/two/g \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one/two/g \t", @:)
  call feedkeys(":s/one/two/g | chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one/two/g | chistory", @:)
  call feedkeys(":s/one/t\\/ | \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"s/one/t\\/ | \t", @:)
  call feedkeys(":s/one/t\"o/ | chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"s/one/t"o/ | chistory', @:)
  call feedkeys(":s/one/t|o/ | chist\t\<C-B>\"\<CR>", 'xt')
  call assert_equal('"s/one/t|o/ | chistory', @:)
  call feedkeys(":&\t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"&\t", @:)
endfunc

" Test for the :dlist command completion
func Test_cmdline_complete_dlist()
  call feedkeys(":dlist 10 /pat/ a\<C-A>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"dlist 10 /pat/ a\<C-A>", @:)
  call feedkeys(":dlist 10 /pat/ \t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"dlist 10 /pat/ \t", @:)
  call feedkeys(":dlist 10 /pa\\t/\t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"dlist 10 /pa\\t/\t", @:)
  call feedkeys(":dlist 10 /pat\\\t\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"dlist 10 /pat\\\t", @:)
  call feedkeys(":dlist 10 /pat/ | chist\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal("\"dlist 10 /pat/ | chistory", @:)
endfunc

" argument list (only for :argdel) fuzzy completion
func Test_fuzzy_completion_arglist()
  argadd change.py count.py charge.py
  set wildoptions&
  call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"argdel cge', @:)
  set wildoptions=fuzzy
  call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"argdel change.py charge.py', @:)
  %argdelete
  set wildoptions&
endfunc

" autocmd group name fuzzy completion
func Test_fuzzy_completion_autocmd()
  set wildoptions&
  augroup MyFuzzyGroup
  augroup END
  call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"augroup mfg', @:)
  call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"augroup MyFuzzyGroup', @:)
  set wildoptions=fuzzy
  call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"augroup MyFuzzyGroup', @:)
  call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"augroup My*p', @:)
  augroup! MyFuzzyGroup
  set wildoptions&
endfunc

" buffer name fuzzy completion
func Test_fuzzy_completion_bufname()
  set wildoptions&
  " Use a long name to reduce the risk of matching a random directory name
  edit SomeRandomFileWithLetters.txt
  enew
  call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"b SRFWL', @:)
  call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"b SomeRandomFileWithLetters.txt', @:)
  set wildoptions=fuzzy
  call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"b SomeRandomFileWithLetters.txt', @:)
  call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"b S*FileWithLetters.txt', @:)
  %bw!
  set wildoptions&
endfunc

" buffer name (full path) fuzzy completion
func Test_fuzzy_completion_bufname_fullpath()
  CheckUnix
  set wildoptions&
  call mkdir('Xcmd/Xstate/Xfile.js', 'pR')
  edit Xcmd/Xstate/Xfile.js
  cd Xcmd/Xstate
  enew
  call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"b CmdStateFile', @:)
  set wildoptions=fuzzy
  call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_match('Xcmd/Xstate/Xfile.js$', @:)
  cd -
  set wildoptions&
endfunc

" :behave suboptions fuzzy completion
func Test_fuzzy_completion_behave()
  set wildoptions&
  call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"behave xm', @:)
  call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"behave xterm', @:)
  set wildoptions=fuzzy
  call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"behave xterm', @:)
  call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"behave xt*m', @:)
  let g:Sline = ''
  call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx')
  call assert_equal('mswin', g:Sline)
  call assert_equal('"behave win', @:)
  set wildoptions&
endfunc

" " colorscheme name fuzzy completion - NOT supported
" func Test_fuzzy_completion_colorscheme()
" endfunc

" built-in command name fuzzy completion
func Test_fuzzy_completion_cmdname()
  set wildoptions&
  call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sbwin', @:)
  call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sbrewind', @:)
  set wildoptions=fuzzy
  call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sbrewind', @:)
  call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sbr*d', @:)
  set wildoptions&
endfunc

" " compiler name fuzzy completion - NOT supported
" func Test_fuzzy_completion_compiler()
" endfunc

" :cscope suboptions fuzzy completion
func Test_fuzzy_completion_cscope()
  CheckFeature cscope
  set wildoptions&
  call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"cscope ret', @:)
  call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"cscope reset', @:)
  set wildoptions=fuzzy
  call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"cscope reset', @:)
  call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"cscope re*t', @:)
  set wildoptions&
endfunc

" :diffget/:diffput buffer name fuzzy completion
func Test_fuzzy_completion_diff()
  new SomeBuffer
  diffthis
  new OtherBuffer
  diffthis
  set wildoptions&
  call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"diffget sbuf', @:)
  call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"diffput sbuf', @:)
  set wildoptions=fuzzy
  call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"diffget SomeBuffer', @:)
  call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"diffput SomeBuffer', @:)
  %bw!
  set wildoptions&
endfunc

" " directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_dirname()
" endfunc

" environment variable name fuzzy completion
func Test_fuzzy_completion_env()
  set wildoptions&
  call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"echo $VUT', @:)
  set wildoptions=fuzzy
  call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"echo $VIMRUNTIME', @:)
  set wildoptions&
endfunc

" autocmd event fuzzy completion
func Test_fuzzy_completion_autocmd_event()
  set wildoptions&
  call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"autocmd BWout', @:)
  set wildoptions=fuzzy
  call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"autocmd BufWipeout', @:)
  set wildoptions&
endfunc

" vim expression fuzzy completion
func Test_fuzzy_completion_expr()
  let g:PerPlaceCount = 10
  set wildoptions&
  call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"let c = ppc', @:)
  set wildoptions=fuzzy
  call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"let c = PerPlaceCount', @:)
  set wildoptions&
endfunc

" " file name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filename()
" endfunc

" " files in path fuzzy completion - NOT supported
" func Test_fuzzy_completion_filesinpath()
" endfunc

" " filetype name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filetype()
" endfunc

" user defined function name completion
func Test_fuzzy_completion_userdefined_func()
  set wildoptions&
  call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"call Test_f_u_f', @:)
  set wildoptions=fuzzy
  call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"call Test_fuzzy_completion_userdefined_func()', @:)
  set wildoptions&
endfunc

" <SNR> functions should be sorted to the end
func Test_fuzzy_completion_userdefined_snr_func()
  func s:Sendmail()
  endfunc
  func SendSomemail()
  endfunc
  func S1e2n3dmail()
  endfunc
  set wildoptions=fuzzy
  call feedkeys(":call sendmail\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_match('"call SendSomemail() S1e2n3dmail() <SNR>\d\+_Sendmail()', @:)
  set wildoptions&
  delfunc s:Sendmail
  delfunc SendSomemail
  delfunc S1e2n3dmail
endfunc

" user defined command name completion
func Test_fuzzy_completion_userdefined_cmd()
  set wildoptions&
  call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"MsFeat', @:)
  set wildoptions=fuzzy
  call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"MissingFeature', @:)
  set wildoptions&
endfunc

" " :help tag fuzzy completion - NOT supported
" func Test_fuzzy_completion_helptag()
" endfunc

" highlight group name fuzzy completion
func Test_fuzzy_completion_hlgroup()
  set wildoptions&
  call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"highlight SKey', @:)
  call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"highlight SpecialKey', @:)
  set wildoptions=fuzzy
  call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"highlight SpecialKey', @:)
  call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"highlight Sp*Key', @:)
  set wildoptions&
endfunc

" :history suboptions fuzzy completion
func Test_fuzzy_completion_history()
  set wildoptions&
  call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"history dg', @:)
  call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"history search', @:)
  set wildoptions=fuzzy
  call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"history debug', @:)
  call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"history se*h', @:)
  set wildoptions&
endfunc

" :language locale name fuzzy completion
func Test_fuzzy_completion_lang()
  CheckUnix
  set wildoptions&
  call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"lang psx', @:)
  set wildoptions=fuzzy
  call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"lang POSIX', @:)
  set wildoptions&
endfunc

" :mapclear buffer argument fuzzy completion
func Test_fuzzy_completion_mapclear()
  set wildoptions&
  call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"mapclear buf', @:)
  set wildoptions=fuzzy
  call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"mapclear <buffer>', @:)
  set wildoptions&
endfunc

" map name fuzzy completion
func Test_fuzzy_completion_mapname()
  " test regex completion works
  set wildoptions=fuzzy
  call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"cnoremap <expr> <esc> \<Tab>", @:)
  nmap <plug>MyLongMap :p<CR>
  call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap <Plug>MyLongMap", @:)
  call feedkeys(":nmap MLM \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap MLM \t", @:)
  call feedkeys(":nmap <F2> one two \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap <F2> one two \t", @:)
  " duplicate entries should be removed
  vmap <plug>MyLongMap :<C-U>#<CR>
  call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap <Plug>MyLongMap", @:)
  nunmap <plug>MyLongMap
  vunmap <plug>MyLongMap
  call feedkeys(":nmap ABC\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap ABC\t", @:)
  " results should be sorted by best match
  nmap <Plug>format :
  nmap <Plug>goformat :
  nmap <Plug>TestFOrmat :
  nmap <Plug>fendoff :
  nmap <Plug>state :
  nmap <Plug>FendingOff :
  call feedkeys(":nmap <Plug>fo\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"nmap <Plug>format <Plug>TestFOrmat <Plug>FendingOff <Plug>goformat <Plug>fendoff", @:)
  nunmap <Plug>format
  nunmap <Plug>goformat
  nunmap <Plug>TestFOrmat
  nunmap <Plug>fendoff
  nunmap <Plug>state
  nunmap <Plug>FendingOff
  set wildoptions&
endfunc

" abbreviation fuzzy completion
func Test_fuzzy_completion_abbr()
  set wildoptions=fuzzy
  call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"iabbr <nowait>", @:)
  iabbr WaitForCompletion WFC
  call feedkeys(":iabbr fcl\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"iabbr WaitForCompletion", @:)
  call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"iabbr a1z\t", @:)

  iunabbrev WaitForCompletion
  set wildoptions&
endfunc

" menu name fuzzy completion
func Test_fuzzy_completion_menu()
  CheckFeature menu

  source $VIMRUNTIME/menu.vim
  set wildoptions&
  call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"menu pup', @:)
  set wildoptions=fuzzy
  call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"menu PopUp.', @:)

  set wildoptions&
  source $VIMRUNTIME/delmenu.vim
endfunc

" :messages suboptions fuzzy completion
func Test_fuzzy_completion_messages()
  set wildoptions&
  call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"messages clr', @:)
  set wildoptions=fuzzy
  call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"messages clear', @:)
  set wildoptions&
endfunc

" :set option name fuzzy completion
func Test_fuzzy_completion_option()
  set wildoptions&
  call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set brkopt', @:)
  set wildoptions=fuzzy
  call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set breakindentopt', @:)
  set wildoptions&
  call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set fixendofline', @:)
  set wildoptions=fuzzy
  call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set fixendofline', @:)
  set wildoptions&
endfunc

" :set <term_option>
func Test_fuzzy_completion_term_option()
  set wildoptions&
  call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set t_EC', @:)
  call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set <t_EC>', @:)
  set wildoptions=fuzzy
  call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set t_EC', @:)
  call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"set <t_EC>', @:)
  set wildoptions&
endfunc

" " :packadd directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_packadd()
" endfunc

" " shell command name fuzzy completion - NOT supported
" func Test_fuzzy_completion_shellcmd()
" endfunc

" :sign suboptions fuzzy completion
func Test_fuzzy_completion_sign()
  set wildoptions&
  call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sign ufe', @:)
  set wildoptions=fuzzy
  call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"sign undefine', @:)
  set wildoptions&
endfunc

" :syntax suboptions fuzzy completion
func Test_fuzzy_completion_syntax_cmd()
  set wildoptions&
  call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntax kwd', @:)
  set wildoptions=fuzzy
  call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntax keyword', @:)
  set wildoptions&
endfunc

" syntax group name fuzzy completion
func Test_fuzzy_completion_syntax_group()
  set wildoptions&
  call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntax list mpar', @:)
  set wildoptions=fuzzy
  call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntax list MatchParen', @:)
  set wildoptions&
endfunc

" :syntime suboptions fuzzy completion
func Test_fuzzy_completion_syntime()
  CheckFeature profile
  set wildoptions&
  call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntime clr', @:)
  set wildoptions=fuzzy
  call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"syntime clear', @:)
  set wildoptions&
endfunc

" " tag name fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagname()
" endfunc

" " tag name and file fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagfile()
" endfunc

" " user names fuzzy completion - how to test this functionality?
" func Test_fuzzy_completion_username()
" endfunc

" user defined variable name fuzzy completion
func Test_fuzzy_completion_userdefined_var()
  let g:SomeVariable=10
  set wildoptions&
  call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"let SVar', @:)
  set wildoptions=fuzzy
  call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"let SomeVariable', @:)
  set wildoptions&
endfunc

" Test for sorting the results by the best match
func Test_fuzzy_completion_cmd_sort_results()
  %bw!
  command T123format :
  command T123goformat :
  command T123TestFOrmat :
  command T123fendoff :
  command T123state :
  command T123FendingOff :
  set wildoptions=fuzzy
  call feedkeys(":T123fo\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"T123format T123TestFOrmat T123FendingOff T123goformat T123fendoff', @:)
  delcommand T123format
  delcommand T123goformat
  delcommand T123TestFOrmat
  delcommand T123fendoff
  delcommand T123state
  delcommand T123FendingOff
  %bw
  set wildoptions&
endfunc

" Test for fuzzy completion of a command with lower case letters and a number
func Test_fuzzy_completion_cmd_alnum()
  command Foo2Bar :
  set wildoptions=fuzzy
  call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"Foo2Bar', @:)
  call feedkeys(":foo\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"Foo2Bar', @:)
  call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"Foo2Bar', @:)
  delcommand Foo2Bar
  set wildoptions&
endfunc

" Test for command completion for a command starting with 'k'
func Test_fuzzy_completion_cmd_k()
  command KillKillKill :
  set wildoptions&
  call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"killkill\<Tab>", @:)
  set wildoptions=fuzzy
  call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"KillKillKill', @:)
  delcom KillKillKill
  set wildoptions&
endfunc

" Test for fuzzy completion for user defined custom completion function
func Test_fuzzy_completion_custom_func()
  func Tcompl(a, c, p)
    return "format\ngoformat\nTestFOrmat\nfendoff\nstate"
  endfunc
  command -nargs=* -complete=custom,Tcompl Fuzzy :
  set wildoptions&
  call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy format", @:)
  call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy xy", @:)
  call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy ttt", @:)
  set wildoptions=fuzzy
  call feedkeys(":Fuzzy \<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy format goformat TestFOrmat fendoff state", @:)
  call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy format TestFOrmat goformat fendoff", @:)
  call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy xy", @:)
  call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"Fuzzy TestFOrmat", @:)
  delcom Fuzzy
  set wildoptions&
endfunc

" Test for :breakadd argument completion
func Test_cmdline_complete_breakadd()
  call feedkeys(":breakadd \<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd expr file func here", @:)
  call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd expr", @:)
  call feedkeys(":breakadd    \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd    expr", @:)
  call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd here", @:)
  call feedkeys(":breakadd    he\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd    here", @:)
  call feedkeys(":breakadd abc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd abc", @:)
  call assert_equal(['expr', 'file', 'func', 'here'], getcompletion('', 'breakpoint'))
  let l = getcompletion('not', 'breakpoint')
  call assert_equal([], l)

  " Test for :breakadd file [lnum] <file>
  call writefile([], 'Xscript', 'D')
  call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file Xscript", @:)
  call feedkeys(":breakadd   file   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd   file   Xscript", @:)
  call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file 20 Xscript", @:)
  call feedkeys(":breakadd   file   20   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd   file   20   Xscript", @:)
  call feedkeys(":breakadd file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file 20x Xsc\t", @:)
  call feedkeys(":breakadd file 20\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file 20\t", @:)
  call feedkeys(":breakadd file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file 20x\t", @:)
  call feedkeys(":breakadd file Xscript  \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file Xscript  ", @:)
  call feedkeys(":breakadd file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd file X1B2C3", @:)

  " Test for :breakadd func [lnum] <function>
  func Xbreak_func()
  endfunc
  call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func Xbreak_func", @:)
  call feedkeys(":breakadd    func    Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd    func    Xbreak_func", @:)
  call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func 20 Xbreak_func", @:)
  call feedkeys(":breakadd   func   20   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd   func   20   Xbreak_func", @:)
  call feedkeys(":breakadd func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func 20x Xbr\t", @:)
  call feedkeys(":breakadd func 20\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func 20\t", @:)
  call feedkeys(":breakadd func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func 20x\t", @:)
  call feedkeys(":breakadd func Xbreak_func  \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func Xbreak_func  ", @:)
  call feedkeys(":breakadd func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd func X1B2C3", @:)
  delfunc Xbreak_func

  " Test for :breakadd expr <expression>
  let g:Xtest_var = 10
  call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd expr Xtest_var", @:)
  call feedkeys(":breakadd    expr    Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd    expr    Xtest_var", @:)
  call feedkeys(":breakadd expr Xtest_var  \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd expr Xtest_var  ", @:)
  call feedkeys(":breakadd expr X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd expr X1B2C3", @:)
  unlet g:Xtest_var

  " Test for :breakadd here
  call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd here Xtest", @:)
  call feedkeys(":breakadd   here   Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd   here   Xtest", @:)
  call feedkeys(":breakadd here \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakadd here ", @:)
endfunc

" Test for :breakdel argument completion
func Test_cmdline_complete_breakdel()
  call feedkeys(":breakdel \<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file func here", @:)
  call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file", @:)
  call feedkeys(":breakdel    \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel    file", @:)
  call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel here", @:)
  call feedkeys(":breakdel    he\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel    here", @:)
  call feedkeys(":breakdel abc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel abc", @:)

  " Test for :breakdel file [lnum] <file>
  call writefile([], 'Xscript', 'D')
  call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file Xscript", @:)
  call feedkeys(":breakdel   file   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel   file   Xscript", @:)
  call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file 20 Xscript", @:)
  call feedkeys(":breakdel   file   20   Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel   file   20   Xscript", @:)
  call feedkeys(":breakdel file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file 20x Xsc\t", @:)
  call feedkeys(":breakdel file 20\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file 20\t", @:)
  call feedkeys(":breakdel file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file 20x\t", @:)
  call feedkeys(":breakdel file Xscript  \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file Xscript  ", @:)
  call feedkeys(":breakdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel file X1B2C3", @:)

  " Test for :breakdel func [lnum] <function>
  func Xbreak_func()
  endfunc
  call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func Xbreak_func", @:)
  call feedkeys(":breakdel   func   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel   func   Xbreak_func", @:)
  call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func 20 Xbreak_func", @:)
  call feedkeys(":breakdel   func   20   Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel   func   20   Xbreak_func", @:)
  call feedkeys(":breakdel func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func 20x Xbr\t", @:)
  call feedkeys(":breakdel func 20\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func 20\t", @:)
  call feedkeys(":breakdel func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func 20x\t", @:)
  call feedkeys(":breakdel func Xbreak_func  \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func Xbreak_func  ", @:)
  call feedkeys(":breakdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel func X1B2C3", @:)
  delfunc Xbreak_func

  " Test for :breakdel here
  call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel here Xtest", @:)
  call feedkeys(":breakdel   here   Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel   here   Xtest", @:)
  call feedkeys(":breakdel here \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"breakdel here ", @:)
endfunc

" Test for :scriptnames argument completion
func Test_cmdline_complete_scriptnames()
  set wildmenu
  call writefile(['let a = 1'], 'Xa1b2c3.vim', 'D')
  source Xa1b2c3.vim
  call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
  call assert_match("\"script .*Xa1b2c3.vim$", @:)
  call feedkeys(":script    \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
  call assert_match("\"script .*Xa1b2c3.vim$", @:)
  call feedkeys(":script b2c3\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"script b2c3", @:)
  call feedkeys(":script 2\<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_match("\"script 2\<Tab>$", @:)
  call feedkeys(":script \<Tab>\<Left>\<Left> \<Tab>\<C-B>\"\<CR>", 'tx')
  call assert_match("\"script .*Xa1b2c3.vim $", @:)
  call feedkeys(":script \<Tab>\<Left>\<C-B>\"\<CR>", 'tx')
  call assert_equal("\"script ", @:)
  call assert_match('Xa1b2c3.vim$', getcompletion('.*Xa1b2.*', 'scriptnames')[0])
  call assert_equal([], getcompletion('Xa1b2', 'scriptnames'))
  new
  call feedkeys(":script \<Tab>\<Left>\<Left>\<CR>", 'tx')
  call assert_equal('Xa1b2c3.vim', fnamemodify(@%, ':t'))
  bw!
  set wildmenu&
endfunc

" this was going over the end of IObuff
func Test_report_error_with_composing()
  let caught = 'no'
  try
    exe repeat('0', 987) .. "0\xdd\x80\xdd\x80\xdd\x80\xdd\x80"
  catch /E492:/
    let caught = 'yes'
  endtry
  call assert_equal('yes', caught)
endfunc

" Test for expanding 2-letter and 3-letter :substitute command arguments.
" These commands don't accept an argument.
func Test_cmdline_complete_substitute_short()
  for cmd in ['sc', 'sce', 'scg', 'sci', 'scI', 'scn', 'scp', 'scl',
        \ 'sgc', 'sge', 'sg', 'sgi', 'sgI', 'sgn', 'sgp', 'sgl', 'sgr',
        \ 'sic', 'sie', 'si', 'siI', 'sin', 'sip', 'sir',
        \ 'sIc', 'sIe', 'sIg', 'sIi', 'sI', 'sIn', 'sIp', 'sIl', 'sIr',
        \ 'src', 'srg', 'sri', 'srI', 'srn', 'srp', 'srl', 'sr']
    call feedkeys(':' .. cmd .. " \<Tab>\<C-B>\"\<CR>", 'tx')
    call assert_equal('"' .. cmd .. " \<Tab>", @:)
  endfor
endfunc

" Test for :! shell command argument completion
func Test_cmdline_complete_bang_cmd_argument()
  set wildoptions=fuzzy
  call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"!vim test_cmdline.vim', @:)
  set wildoptions&
  call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
  call assert_equal('"!vim test_cmdline.vim', @:)
endfunc

func Call_cmd_funcs()
  return string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()])
endfunc

func Test_screenpos_and_completion()
  call assert_equal(0, getcmdpos())
  call assert_equal(0, getcmdscreenpos())
  call assert_equal('', getcmdcompltype())

  cnoremap <expr> <F2> string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()])
  call feedkeys(":let a\<F2>\<C-B>\"\<CR>", "xt")
  call assert_equal("\"let a[6, 7, 'var']", @:)
  call feedkeys(":quit \<F2>\<C-B>\"\<CR>", "xt")
  call assert_equal("\"quit [6, 7, '']", @:)
  call feedkeys(":nosuchcommand \<F2>\<C-B>\"\<CR>", "xt")
  call assert_equal("\"nosuchcommand [15, 16, '']", @:)
  cunmap <F2>
endfunc

func Test_recursive_register()
  let @= = ''
  silent! ?e/
  let caught = 'no'
  try
    normal // 
  catch /E169:/
    let caught = 'yes'
  endtry
  call assert_equal('yes', caught)
endfunc

func Test_long_error_message()
  " the error should be truncated, not overrun IObuff
  silent! norm Q00000000000000     000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                                                                                                                                                                        
endfunc

func Test_cmdline_redraw_tabline()
  CheckRunVimInTerminal

  let lines =<< trim END
      set showtabline=2
      autocmd CmdlineEnter * set tabline=foo
  END
  call writefile(lines, 'Xcmdline_redraw_tabline', 'D')
  let buf = RunVimInTerminal('-S Xcmdline_redraw_tabline', #{rows: 6})
  call term_sendkeys(buf, ':')
  call WaitForAssert({-> assert_match('^foo', term_getline(buf, 1))})

  call StopVimInTerminal(buf)
endfunc

func Test_wildmenu_pum_disable_while_shown()
  set wildoptions=pum
  set wildmenu
  cnoremap <F2> <Cmd>set nowildmenu<CR>
  call feedkeys(":sign \<Tab>\<F2>\<Esc>", 'tx')
  call assert_equal(0, pumvisible())
  cunmap <F2>
  set wildoptions& wildmenu&
endfunc

func Test_setcmdline()
  func SetText(text, pos)
    call assert_equal(0, setcmdline(test_null_string()))
    call assert_equal('', getcmdline())
    call assert_equal(1, getcmdpos())

    call assert_equal(0, setcmdline(''[: -1]))
    call assert_equal('', getcmdline())
    call assert_equal(1, getcmdpos())

    autocmd CmdlineChanged * let g:cmdtype = expand('<afile>')
    call assert_equal(0, setcmdline(a:text))
    call assert_equal(a:text, getcmdline())
    call assert_equal(len(a:text) + 1, getcmdpos())
    call assert_equal(getcmdtype(), g:cmdtype)
    unlet g:cmdtype
    autocmd! CmdlineChanged

    call assert_equal(0, setcmdline(a:text, a:pos))
    call assert_equal(a:text, getcmdline())
    call assert_equal(a:pos, getcmdpos())

    call assert_fails('call setcmdline("' .. a:text .. '", -1)', 'E487:')
    call assert_fails('call setcmdline({}, 0)', 'E1174:')
    call assert_fails('call setcmdline("' .. a:text .. '", {})', 'E1210:')

    return ''
  endfunc

  call feedkeys(":\<C-R>=SetText('set rtp?', 2)\<CR>\<CR>", 'xt')
  call assert_equal('set rtp?', @:)

  call feedkeys(":let g:str = input('? ')\<CR>", 't')
  call feedkeys("\<C-R>=SetText('foo', 4)\<CR>\<CR>", 'xt')
  call assert_equal('foo', g:str)
  unlet g:str

  delfunc SetText

  " setcmdline() returns 1 when not editing the command line.
  call assert_equal(1, 'foo'->setcmdline())

  " Called in custom function
  func CustomComplete(A, L, P)
    call assert_equal(0, setcmdline("DoCmd "))
    return "January\nFebruary\nMars\n"
  endfunc

  com! -nargs=* -complete=custom,CustomComplete DoCmd :
  call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
  call assert_equal('"DoCmd January February Mars', @:)
  delcom DoCmd
  delfunc CustomComplete

  " Called in <expr>
  cnoremap <expr>a setcmdline('let foo=')
  call feedkeys(":a\<CR>", 'tx')
  call assert_equal('let foo=0', @:)
  cunmap a
endfunc

func Test_rulerformat_position()
  CheckScreendump

  let buf = RunVimInTerminal('', #{rows: 2, cols: 20})
  call term_sendkeys(buf, ":set ruler rulerformat=longish\<CR>")
  call term_sendkeys(buf, ":set laststatus=0 winwidth=1\<CR>")
  call term_sendkeys(buf, "\<C-W>v\<C-W>|\<C-W>p")
  call VerifyScreenDump(buf, 'Test_rulerformat_position', {})

  " clean up
  call StopVimInTerminal(buf)
endfunc

func Test_getcompletion_usercmd()
  command! -nargs=* -complete=command TestCompletion echo <q-args>

  call assert_equal(getcompletion('', 'cmdline'),
        \ getcompletion('TestCompletion ', 'cmdline'))
  call assert_equal(['<buffer>'],
        \ getcompletion('TestCompletion map <bu', 'cmdline'))

  delcom TestCompletion
endfunc

func Test_custom_completion()
  func CustomComplete1(lead, line, pos)
    return "a\nb\nc"
  endfunc
  func CustomComplete2(lead, line, pos)
    return ['a', 'b']->filter({ _, val -> val->stridx(a:lead) == 0 })
  endfunc
  func Check_custom_completion()
    call assert_equal('custom,CustomComplete1', getcmdcompltype())
    return ''
  endfunc
  func Check_customlist_completion()
    call assert_equal('customlist,CustomComplete2', getcmdcompltype())
    return ''
  endfunc

  command -nargs=1 -complete=custom,CustomComplete1 Test1 echo
  command -nargs=1 -complete=customlist,CustomComplete2 Test2 echo

  call feedkeys(":Test1 \<C-R>=Check_custom_completion()\<CR>\<Esc>", "xt")
  call feedkeys(":Test2 \<C-R>=Check_customlist_completion()\<CR>\<Esc>", "xt")

  call assert_fails("call getcompletion('', 'custom')", 'E475:')
  call assert_fails("call getcompletion('', 'customlist')", 'E475:')

  call assert_equal(getcompletion('', 'custom,CustomComplete1'), ['a', 'b', 'c'])
  call assert_equal(getcompletion('', 'customlist,CustomComplete2'), ['a', 'b'])
  call assert_equal(getcompletion('b', 'customlist,CustomComplete2'), ['b'])

  delcom Test1
  delcom Test2

  delfunc CustomComplete1
  delfunc CustomComplete2
  delfunc Check_custom_completion
  delfunc Check_customlist_completion
endfunc

func Test_custom_completion_with_glob()
  func TestGlobComplete(A, L, P)
    return split(glob('Xglob*'), "\n")
  endfunc

  command -nargs=* -complete=customlist,TestGlobComplete TestGlobComplete :
  call writefile([], 'Xglob1', 'D')
  call writefile([], 'Xglob2', 'D')

  call feedkeys(":TestGlobComplete \<Tab> \<Tab>\<C-N> \<Tab>\<C-P>;\<C-B>\"\<CR>", 'xt')
  call assert_equal('"TestGlobComplete Xglob1 Xglob2 ;', @:)

  delcommand TestGlobComplete
  delfunc TestGlobComplete
endfunc

" vim: shiftwidth=2 sts=2 expandtab