test_ex_mode.vim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. " Test editing line in Ex mode (see :help Q and :help gQ).
  2. source check.vim
  3. source shared.vim
  4. " Helper function to test editing line in Q Ex mode
  5. func Ex_Q(cmd)
  6. " Is there a simpler way to test editing Ex line?
  7. call feedkeys("Q"
  8. \ .. "let s:test_ex =<< END\<CR>"
  9. \ .. a:cmd .. "\<CR>"
  10. \ .. "END\<CR>"
  11. \ .. "visual\<CR>", 'tx')
  12. return s:test_ex[0]
  13. endfunc
  14. " Helper function to test editing line in gQ Ex mode
  15. func Ex_gQ(cmd)
  16. call feedkeys("gQ" .. a:cmd .. "\<C-b>\"\<CR>", 'tx')
  17. let ret = @:[1:] " Remove leading quote.
  18. call feedkeys("visual\<CR>", 'tx')
  19. return ret
  20. endfunc
  21. " Helper function to test editing line with both Q and gQ Ex mode.
  22. func Ex(cmd)
  23. return [Ex_Q(a:cmd), Ex_gQ(a:cmd)]
  24. endfunc
  25. " Test editing line in Ex mode (both Q and gQ)
  26. func Test_ex_mode()
  27. throw 'Skipped: Nvim only supports Vim Ex mode'
  28. let encoding_save = &encoding
  29. set sw=2
  30. for e in ['utf8', 'latin1']
  31. exe 'set encoding=' . e
  32. call assert_equal(['bar', 'bar'], Ex("foo bar\<C-u>bar"), e)
  33. call assert_equal(["1\<C-u>2", "1\<C-u>2"], Ex("1\<C-v>\<C-u>2"), e)
  34. call assert_equal(["1\<C-b>2\<C-e>3", '213'], Ex("1\<C-b>2\<C-e>3"), e)
  35. call assert_equal(['0123', '2013'], Ex("01\<Home>2\<End>3"), e)
  36. call assert_equal(['0123', '0213'], Ex("01\<Left>2\<Right>3"), e)
  37. call assert_equal(['01234', '0342'], Ex("012\<Left>\<Left>\<Insert>3\<Insert>4"), e)
  38. call assert_equal(["foo bar\<C-w>", 'foo '], Ex("foo bar\<C-w>"), e)
  39. call assert_equal(['foo', 'foo'], Ex("fooba\<Del>\<Del>"), e)
  40. call assert_equal(["foo\tbar", 'foobar'], Ex("foo\<Tab>bar"), e)
  41. call assert_equal(["abbrev\t", 'abbreviate'], Ex("abbrev\<Tab>"), e)
  42. call assert_equal([' 1', "1\<C-t>\<C-t>"], Ex("1\<C-t>\<C-t>"), e)
  43. call assert_equal([' 1', "1\<C-t>\<C-t>"], Ex("1\<C-t>\<C-t>\<C-d>"), e)
  44. call assert_equal([' foo', ' foo'], Ex(" foo\<C-d>"), e)
  45. call assert_equal(['foo', ' foo0'], Ex(" foo0\<C-d>"), e)
  46. call assert_equal(['foo', ' foo^'], Ex(" foo^\<C-d>"), e)
  47. call assert_equal(['foo', 'foo'],
  48. \ Ex("\<BS>\<C-H>\<Del>\<kDel>foo"), e)
  49. " default wildchar <Tab> interferes with this test
  50. set wildchar=<c-e>
  51. call assert_equal(["a\tb", "a\tb"], Ex("a\t\t\<C-H>b"), e)
  52. call assert_equal(["\t mn", "\tm\<C-T>n"], Ex("\tm\<C-T>n"), e)
  53. set wildchar&
  54. endfor
  55. set sw&
  56. let &encoding = encoding_save
  57. endfunc
  58. " Test substitute confirmation prompt :%s/pat/str/c in Ex mode
  59. func Test_Ex_substitute()
  60. CheckRunVimInTerminal
  61. let buf = RunVimInTerminal('', {'rows': 6})
  62. call term_sendkeys(buf, ":call setline(1, repeat(['foo foo'], 4))\<CR>")
  63. call term_sendkeys(buf, ":set number\<CR>")
  64. call term_sendkeys(buf, "gQ")
  65. call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
  66. call term_sendkeys(buf, "%s/foo/bar/gc\<CR>")
  67. call WaitForAssert({-> assert_match(' 1 foo foo', term_getline(buf, 5))},
  68. \ 1000)
  69. call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
  70. call term_sendkeys(buf, "N\<CR>")
  71. call term_wait(buf)
  72. call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
  73. call term_sendkeys(buf, "n\<CR>")
  74. call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))},
  75. \ 1000)
  76. call term_sendkeys(buf, "y\<CR>")
  77. call term_sendkeys(buf, "q\<CR>")
  78. call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
  79. " Pressing enter in ex mode should print the current line
  80. call term_sendkeys(buf, "\<CR>")
  81. call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 5))}, 1000)
  82. call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
  83. " The printed line should overwrite the colon
  84. call term_sendkeys(buf, "\<CR>")
  85. call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 4))}, 1000)
  86. call WaitForAssert({-> assert_match(' 4 foo foo', term_getline(buf, 5))}, 1000)
  87. call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
  88. call term_sendkeys(buf, ":vi\<CR>")
  89. call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
  90. call StopVimInTerminal(buf)
  91. endfunc
  92. " Test for displaying lines from an empty buffer in Ex mode
  93. func Test_Ex_emptybuf()
  94. new
  95. call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E749:')
  96. call setline(1, "abc")
  97. call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E501:')
  98. call assert_fails('call feedkeys("Q%d\<CR>", "xt")', 'E749:')
  99. close!
  100. endfunc
  101. " Test for the :open command
  102. func Test_open_command()
  103. throw 'Skipped: Nvim does not have :open'
  104. new
  105. call setline(1, ['foo foo', 'foo bar', 'foo baz'])
  106. call feedkeys("Qopen\<CR>j", 'xt')
  107. call assert_equal('foo bar', getline('.'))
  108. call feedkeys("Qopen /bar/\<CR>", 'xt')
  109. call assert_equal(5, col('.'))
  110. call assert_fails('call feedkeys("Qopen /baz/\<CR>", "xt")', 'E479:')
  111. close!
  112. endfunc
  113. func Test_open_command_flush_line()
  114. throw 'Skipped: Nvim does not have :open'
  115. " this was accessing freed memory: the regexp match uses a pointer to the
  116. " current line which becomes invalid when searching for the ') mark.
  117. new
  118. call setline(1, ['one', 'two. three'])
  119. s/one/ONE
  120. try
  121. open /\%')/
  122. catch /E479/
  123. endtry
  124. bwipe!
  125. endfunc
  126. " FIXME: this doesn't fail without the fix but hangs
  127. func Skip_Test_open_command_state()
  128. " Tricky script that failed because State was not set properly
  129. let lines =<< trim END
  130. !ls ƒ
  131. 0scìi
  132. so! Xsourced
  133. set t_û0=0
  134. v/-/o
  135. END
  136. call writefile(lines, 'XopenScript', '')
  137. let sourced = ["!f\u0083\x02\<Esc>z=0"]
  138. call writefile(sourced, 'Xsourced', 'b')
  139. CheckRunVimInTerminal
  140. let buf = RunVimInTerminal('-u NONE -i NONE -n -m -X -Z -e -s -S XopenScript -c qa!', #{rows: 6, wait_for_ruler: 0, no_clean: 1})
  141. sleep 3
  142. call StopVimInTerminal(buf)
  143. endfunc
  144. " Test for :g/pat/visual to run vi commands in Ex mode
  145. " This used to hang Vim before 8.2.0274.
  146. func Test_Ex_global()
  147. new
  148. call setline(1, ['', 'foo', 'bar', 'foo', 'bar', 'foo'])
  149. call feedkeys("Q\<bs>g/bar/visual\<CR>$rxQ$ryQvisual\<CR>j", "xt")
  150. call assert_equal('bax', getline(3))
  151. call assert_equal('bay', getline(5))
  152. bwipe!
  153. endfunc
  154. " Test for pressing Ctrl-C in :append inside a loop in Ex mode
  155. " This used to hang Vim
  156. func Test_Ex_append_in_loop()
  157. CheckRunVimInTerminal
  158. let buf = RunVimInTerminal('', {'rows': 6})
  159. call term_sendkeys(buf, "gQ")
  160. call term_sendkeys(buf, "for i in range(1)\<CR>")
  161. call term_sendkeys(buf, "append\<CR>")
  162. call WaitForAssert({-> assert_match(': append', term_getline(buf, 5))}, 1000)
  163. call term_sendkeys(buf, "\<C-C>")
  164. " Wait for input to be flushed
  165. call term_wait(buf)
  166. call term_sendkeys(buf, "foo\<CR>")
  167. call WaitForAssert({-> assert_match('foo', term_getline(buf, 5))}, 1000)
  168. call term_sendkeys(buf, ".\<CR>")
  169. call WaitForAssert({-> assert_match('.', term_getline(buf, 5))}, 1000)
  170. call term_sendkeys(buf, "endfor\<CR>")
  171. call term_sendkeys(buf, "vi\<CR>")
  172. call WaitForAssert({-> assert_match('foo', term_getline(buf, 1))}, 1000)
  173. call StopVimInTerminal(buf)
  174. endfunc
  175. " In Ex-mode, a backslash escapes a newline
  176. func Test_Ex_escape_enter()
  177. call feedkeys("gQlet l = \"a\\\<kEnter>b\"\<cr>vi\<cr>", 'xt')
  178. call assert_equal("a\rb", l)
  179. endfunc
  180. " Test for :append! command in Ex mode
  181. func Test_Ex_append()
  182. throw 'Skipped: Nvim only supports Vim Ex mode'
  183. new
  184. call setline(1, "\t abc")
  185. call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt')
  186. call assert_equal(["\t abc", "\t pqr", "\t xyz"], getline(1, '$'))
  187. close!
  188. endfunc
  189. " In Ex-mode, backslashes at the end of a command should be halved.
  190. func Test_Ex_echo_backslash()
  191. throw 'Skipped: Nvim only supports Vim Ex mode'
  192. " This test works only when the language is English
  193. CheckEnglish
  194. let bsl = '\\\\'
  195. let bsl2 = '\\\'
  196. call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
  197. \ 'E15: Invalid expression: "\\"')
  198. call assert_fails('call feedkeys("Qecho " .. bsl2 .. "\nm\nvisual\n", "xt")',
  199. \ "E15: Invalid expression: \"\\\nm\"")
  200. endfunc
  201. func Test_ex_mode_errors()
  202. " Not allowed to enter ex mode when text is locked
  203. au InsertCharPre <buffer> normal! gQ<CR>
  204. let caught_e565 = 0
  205. try
  206. call feedkeys("ix\<esc>", 'xt')
  207. catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
  208. let caught_e565 = 1
  209. endtry
  210. call assert_equal(1, caught_e565)
  211. au! InsertCharPre
  212. new
  213. au CmdLineEnter * call ExEnterFunc()
  214. func ExEnterFunc()
  215. endfunc
  216. call feedkeys("gQvi\r", 'xt')
  217. au! CmdLineEnter
  218. delfunc ExEnterFunc
  219. au CmdlineEnter * :
  220. call feedkeys("gQecho 1\r", 'xt')
  221. au! CmdlineEnter
  222. quit
  223. endfunc
  224. func Test_ex_mode_count_overflow()
  225. " The multiplication causes an integer overflow
  226. CheckNotAsan
  227. " this used to cause a crash
  228. let lines =<< trim END
  229. call feedkeys("\<Esc>gQ\<CR>")
  230. v9|9silent! vi|333333233333y32333333%O
  231. call writefile(['done'], 'Xdidexmode')
  232. qall!
  233. END
  234. call writefile(lines, 'Xexmodescript')
  235. call assert_equal(1, RunVim([], [], '-e -s -S Xexmodescript -c qa'))
  236. call assert_equal(['done'], readfile('Xdidexmode'))
  237. call delete('Xdidexmode')
  238. call delete('Xexmodescript')
  239. endfunc
  240. func Test_ex_mode_large_indent()
  241. new
  242. set ts=500 ai
  243. call setline(1, "\t")
  244. exe "normal gQi\<CR>."
  245. set ts=8 noai
  246. bwipe!
  247. endfunc
  248. " Testing implicit print command
  249. func Test_implicit_print()
  250. new
  251. call setline(1, ['one', 'two', 'three'])
  252. call feedkeys('Q:let a=execute(":1,2")', 'xt')
  253. call feedkeys('Q:let b=execute(":3")', 'xt')
  254. call assert_equal('one two', a->split('\n')->join(' '))
  255. call assert_equal('three', b->split('\n')->join(' '))
  256. bw!
  257. endfunc
  258. " Test inserting text after the trailing bar
  259. func Test_insert_after_trailing_bar()
  260. new
  261. call feedkeys("Qi|\nfoo\n.\na|bar\nbar\n.\nc|baz\n.", "xt")
  262. call assert_equal(['', 'foo', 'bar', 'baz'], getline(1, '$'))
  263. bwipe!
  264. endfunc
  265. " Test global insert of a newline without terminating period
  266. func Test_global_insert_newline()
  267. new
  268. call setline(1, ['foo'])
  269. call feedkeys("Qg/foo/i\\\n", "xt")
  270. call assert_equal(['', 'foo'], getline(1, '$'))
  271. bwipe!
  272. endfunc
  273. " An empty command followed by a newline shouldn't cause E749 in Ex mode.
  274. func Test_ex_empty_command_newline()
  275. let g:var = 0
  276. call feedkeys("gQexecute \"\\nlet g:var = 1\"\r", 'xt')
  277. call assert_equal(1, g:var)
  278. call feedkeys("gQexecute \" \\nlet g:var = 2\"\r", 'xt')
  279. call assert_equal(2, g:var)
  280. call feedkeys("gQexecute \"\\t \\nlet g:var = 3\"\r", 'xt')
  281. call assert_equal(3, g:var)
  282. call feedkeys("gQexecute \"\\\"?!\\nlet g:var = 4\"\r", 'xt')
  283. call assert_equal(4, g:var)
  284. call feedkeys("gQexecute \" \\\"?!\\nlet g:var = 5\"\r", 'xt')
  285. call assert_equal(5, g:var)
  286. unlet g:var
  287. endfunc
  288. " vim: shiftwidth=2 sts=2 expandtab