blob: febf67855c1606226c2d7dd713c0d284a0a5767f [file] [log] [blame]
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +01001" Tests for various Visual modes.
Bram Moolenaarc3c766e2017-03-08 22:55:19 +01002
Bram Moolenaard1ad99b2020-10-04 16:16:54 +02003source shared.vim
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02004source check.vim
Bram Moolenaar9cee4a12021-07-03 15:08:37 +02005source screendump.vim
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01006import './vim9.vim' as v9
Bram Moolenaard1ad99b2020-10-04 16:16:54 +02007
Bram Moolenaar019b9c62016-03-05 17:26:00 +01008func Test_block_shift_multibyte()
Bram Moolenaarf8eb9c52017-01-02 17:31:24 +01009 " Uses double-wide character.
Bram Moolenaar019b9c62016-03-05 17:26:00 +010010 split
11 call setline(1, ['xヹxxx', 'ヹxxx'])
12 exe "normal 1G0l\<C-V>jl>"
13 call assert_equal('x ヹxxx', getline(1))
14 call assert_equal(' ヹxxx', getline(2))
15 q!
16endfunc
Bram Moolenaarf8eb9c52017-01-02 17:31:24 +010017
Bram Moolenaarbae5a172017-08-06 15:42:06 +020018func Test_block_shift_overflow()
19 " This used to cause a multiplication overflow followed by a crash.
20 new
21 normal ii
22 exe "normal \<C-V>876543210>"
23 q!
24endfunc
25
Bram Moolenaarf8eb9c52017-01-02 17:31:24 +010026func Test_dotregister_paste()
27 new
28 exe "norm! ihello world\<esc>"
29 norm! 0ve".p
30 call assert_equal('hello world world', getline(1))
31 q!
32endfunc
Bram Moolenaar23fa81d2017-02-01 21:50:21 +010033
34func Test_Visual_ctrl_o()
35 new
36 call setline(1, ['one', 'two', 'three'])
37 call cursor(1,2)
38 set noshowmode
39 set tw=0
40 call feedkeys("\<c-v>jjlIa\<c-\>\<c-o>:set tw=88\<cr>\<esc>", 'tx')
41 call assert_equal(['oane', 'tawo', 'tahree'], getline(1, 3))
42 call assert_equal(88, &tw)
43 set tw&
44 bw!
45endfu
Bram Moolenaar84b2a382017-02-17 11:40:00 +010046
47func Test_Visual_vapo()
48 new
49 normal oxx
50 normal vapo
51 bwipe!
52endfunc
Bram Moolenaar46522af2017-02-18 23:12:01 +010053
54func Test_Visual_inner_quote()
55 new
56 normal oxX
57 normal vki'
58 bwipe!
59endfunc
Bram Moolenaar75373f32017-08-07 22:02:30 +020060
61" Test for Visual mode not being reset causing E315 error.
62func TriggerTheProblem()
63 " At this point there is no visual selection because :call reset it.
64 " Let's restore the selection:
65 normal gv
66 '<,'>del _
67 try
68 exe "normal \<Esc>"
69 catch /^Vim\%((\a\+)\)\=:E315/
70 echom 'Snap! E315 error!'
Bram Moolenaar63e82db2018-03-06 12:10:48 +010071 let g:msg = 'Snap! E315 error!'
Bram Moolenaar75373f32017-08-07 22:02:30 +020072 endtry
73endfunc
74
75func Test_visual_mode_reset()
Bram Moolenaar75373f32017-08-07 22:02:30 +020076 enew
Bram Moolenaar63e82db2018-03-06 12:10:48 +010077 let g:msg = "Everything's fine."
Bram Moolenaar75373f32017-08-07 22:02:30 +020078 enew
79 setl buftype=nofile
80 call append(line('$'), 'Delete this line.')
81
82 " NOTE: this has to be done by a call to a function because executing :del
83 " the ex-way will require the colon operator which resets the visual mode
84 " thus preventing the problem:
85 exe "normal! GV:call TriggerTheProblem()\<CR>"
86 call assert_equal("Everything's fine.", g:msg)
Bram Moolenaar75373f32017-08-07 22:02:30 +020087endfunc
Bram Moolenaar67418d92017-10-15 22:07:39 +020088
Bram Moolenaar15993ce2017-10-26 20:21:44 +020089" Test for visual block shift and tab characters.
90func Test_block_shift_tab()
Bram Moolenaar3e72dca2021-05-29 16:30:12 +020091 new
Bram Moolenaar15993ce2017-10-26 20:21:44 +020092 call append(0, repeat(['one two three'], 5))
93 call cursor(1,1)
94 exe "normal i\<C-G>u"
95 exe "normal fe\<C-V>4jR\<Esc>ugvr1"
96 call assert_equal('on1 two three', getline(1))
97 call assert_equal('on1 two three', getline(2))
98 call assert_equal('on1 two three', getline(5))
99
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200100 %d _
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200101 call append(0, repeat(['abcdefghijklmnopqrstuvwxyz'], 5))
102 call cursor(1,1)
103 exe "normal \<C-V>4jI \<Esc>j<<11|D"
104 exe "normal j7|a\<Tab>\<Tab>"
105 exe "normal j7|a\<Tab>\<Tab> "
106 exe "normal j7|a\<Tab> \<Tab>\<Esc>4k13|\<C-V>4j<"
107 call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
108 call assert_equal('abcdefghij', getline(2))
109 call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
110 call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(4))
111 call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
112
113 %s/\s\+//g
114 call cursor(1,1)
115 exe "normal \<C-V>4jI \<Esc>j<<"
116 exe "normal j7|a\<Tab>\<Tab>"
117 exe "normal j7|a\<Tab>\<Tab>\<Tab>\<Tab>\<Tab>"
118 exe "normal j7|a\<Tab> \<Tab>\<Tab>\<Esc>4k13|\<C-V>4j3<"
119 call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
120 call assert_equal('abcdefghij', getline(2))
121 call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
122 call assert_equal(" abc\<Tab>\<Tab>defghijklmnopqrstuvwxyz", getline(4))
123 call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
124
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200125 " Test for block shift with space characters at the beginning and with
126 " 'noexpandtab' and 'expandtab'
127 %d _
128 call setline(1, [" 1", " 2", " 3"])
129 setlocal shiftwidth=2 noexpandtab
130 exe "normal gg\<C-V>3j>"
131 call assert_equal(["\t1", "\t2", "\t3"], getline(1, '$'))
132 %d _
133 call setline(1, [" 1", " 2", " 3"])
134 setlocal shiftwidth=2 expandtab
135 exe "normal gg\<C-V>3j>"
136 call assert_equal([" 1", " 2", " 3"], getline(1, '$'))
137 setlocal shiftwidth&
138
139 bw!
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200140endfunc
141
142" Tests Blockwise Visual when there are TABs before the text.
143func Test_blockwise_visual()
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200144 new
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200145 call append(0, ['123456',
146 \ '234567',
147 \ '345678',
148 \ '',
149 \ 'test text test tex start here',
150 \ "\t\tsome text",
151 \ "\t\ttest text",
152 \ 'test text'])
153 call cursor(1,1)
154 exe "normal /start here$\<CR>"
155 exe 'normal "by$' . "\<C-V>jjlld"
156 exe "normal /456$\<CR>"
157 exe "normal \<C-V>jj" . '"bP'
158 call assert_equal(['123start here56',
159 \ '234start here67',
160 \ '345start here78',
161 \ '',
162 \ 'test text test tex rt here',
163 \ "\t\tsomext",
164 \ "\t\ttesext"], getline(1, 7))
165
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200166 bw!
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200167endfunc
168
Bram Moolenaar2e949762018-05-20 14:06:38 +0200169" Test swapping corners in blockwise visual mode with o and O
170func Test_blockwise_visual_o_O()
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200171 new
Bram Moolenaar2e949762018-05-20 14:06:38 +0200172
173 exe "norm! 10i.\<Esc>Y4P3lj\<C-V>4l2jr "
174 exe "norm! gvO\<Esc>ra"
175 exe "norm! gvO\<Esc>rb"
176 exe "norm! gvo\<C-c>rc"
177 exe "norm! gvO\<C-c>rd"
Bram Moolenaar1671f442020-03-10 07:48:13 +0100178 set selection=exclusive
179 exe "norm! gvOo\<C-c>re"
180 call assert_equal('...a be.', getline(4))
181 exe "norm! gvOO\<C-c>rf"
182 set selection&
Bram Moolenaar2e949762018-05-20 14:06:38 +0200183
184 call assert_equal(['..........',
185 \ '...c d..',
186 \ '... ..',
Bram Moolenaar1671f442020-03-10 07:48:13 +0100187 \ '...a bf.',
Bram Moolenaar2e949762018-05-20 14:06:38 +0200188 \ '..........'], getline(1, '$'))
189
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200190 bw!
Bram Moolenaar2e949762018-05-20 14:06:38 +0200191endfun
192
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200193" Test Virtual replace mode.
194func Test_virtual_replace()
Bram Moolenaardf0d24b2018-03-06 14:22:58 +0100195 if exists('&t_kD')
196 let save_t_kD = &t_kD
197 endif
198 if exists('&t_kb')
199 let save_t_kb = &t_kb
200 endif
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200201 exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08"
202 enew!
203 exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz"
204 call cursor(1,1)
205 set ai bs=2
206 exe "normal gR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR"
207 call assert_equal([' 1',
208 \ ' A',
209 \ ' BCDEFGHIJ',
210 \ ' KL',
211 \ ' MNO',
212 \ ' PQR',
213 \ ], getline(1, 6))
214 normal G
215 mark a
216 exe "normal o0\<C-D>\nabcdefghi\njk\tlmn\n opq\trst\n\<C-D>uvwxyz\n"
217 exe "normal 'ajgR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" . repeat("\<BS>", 29)
218 call assert_equal([' 1',
219 \ 'abcdefghi',
220 \ 'jk lmn',
221 \ ' opq rst',
222 \ 'uvwxyz'], getline(7, 11))
223 normal G
224 exe "normal iab\tcdefghi\tjkl"
225 exe "normal 0gRAB......CDEFGHI.J\<Esc>o"
226 exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
227 call assert_equal(['AB......CDEFGHI.Jkl',
228 \ 'AB IJKLMNO QRst'], getline(12, 13))
Bram Moolenaar845e0ee2020-06-20 16:05:32 +0200229
230 " Test inserting Tab with 'noexpandtab' and 'softabstop' set to 4
231 %d
232 call setline(1, 'aaaaaaaaaaaaa')
233 set softtabstop=4
234 exe "normal gggR\<Tab>\<Tab>x"
235 call assert_equal("\txaaaa", getline(1))
236 set softtabstop&
237
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200238 enew!
Bram Moolenaare7808482018-03-06 13:17:23 +0100239 set noai bs&vim
Bram Moolenaardf0d24b2018-03-06 14:22:58 +0100240 if exists('save_t_kD')
241 let &t_kD = save_t_kD
242 endif
243 if exists('save_t_kb')
244 let &t_kb = save_t_kb
245 endif
Bram Moolenaar63e82db2018-03-06 12:10:48 +0100246endfunc
247
248" Test Virtual replace mode.
249func Test_virtual_replace2()
250 enew!
251 set bs=2
252 exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz"
253 call cursor(1,1)
254 " Test 1: Test that del deletes the newline
255 exe "normal gR0\<del> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR"
256 call assert_equal(['0 1',
257 \ 'A',
258 \ 'BCDEFGHIJ',
259 \ ' KL',
260 \ 'MNO',
261 \ 'PQR',
262 \ ], getline(1, 6))
263 " Test 2:
264 " a newline is not deleted, if no newline has been added in virtual replace mode
265 %d_
266 call setline(1, ['abcd', 'efgh', 'ijkl'])
267 call cursor(2,1)
268 exe "norm! gR1234\<cr>5\<bs>\<bs>\<bs>"
269 call assert_equal(['abcd',
270 \ '123h',
271 \ 'ijkl'], getline(1, '$'))
272 " Test 3:
273 " a newline is deleted, if a newline has been inserted before in virtual replace mode
274 %d_
275 call setline(1, ['abcd', 'efgh', 'ijkl'])
276 call cursor(2,1)
277 exe "norm! gR1234\<cr>\<cr>56\<bs>\<bs>\<bs>"
278 call assert_equal(['abcd',
279 \ '1234',
280 \ 'ijkl'], getline(1, '$'))
281 " Test 4:
282 " delete add a newline, delete it, add it again and check undo
283 %d_
284 call setline(1, ['abcd', 'efgh', 'ijkl'])
285 call cursor(2,1)
286 " break undo sequence explicitly
287 let &ul = &ul
288 exe "norm! gR1234\<cr>\<bs>\<del>56\<cr>"
289 let &ul = &ul
290 call assert_equal(['abcd',
291 \ '123456',
292 \ ''], getline(1, '$'))
293 norm! u
294 call assert_equal(['abcd',
295 \ 'efgh',
296 \ 'ijkl'], getline(1, '$'))
Bram Moolenaarca68ae12020-03-30 19:32:53 +0200297
298 " Test for truncating spaces in a newly added line using 'autoindent' if
299 " characters are not added to that line.
300 %d_
301 call setline(1, [' app', ' bee', ' cat'])
302 setlocal autoindent
303 exe "normal gg$gRt\n\nr"
304 call assert_equal([' apt', '', ' rat'], getline(1, '$'))
305
Bram Moolenaar63e82db2018-03-06 12:10:48 +0100306 " clean up
307 %d_
308 set bs&vim
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200309endfunc
Bram Moolenaar6d3a1942019-01-03 23:10:32 +0100310
Bram Moolenaar81b1ba42019-01-13 16:12:40 +0100311func Test_Visual_word_textobject()
312 new
313 call setline(1, ['First sentence. Second sentence.'])
314
315 " When start and end of visual area are identical, 'aw' or 'iw' select
316 " the whole word.
317 norm! 1go2fcvawy
318 call assert_equal('Second ', @")
319 norm! 1go2fcviwy
320 call assert_equal('Second', @")
321
322 " When start and end of visual area are not identical, 'aw' or 'iw'
323 " extend the word in direction of the end of the visual area.
324 norm! 1go2fcvlawy
325 call assert_equal('cond ', @")
326 norm! gv2awy
327 call assert_equal('cond sentence.', @")
328
329 norm! 1go2fcvliwy
330 call assert_equal('cond', @")
331 norm! gv2iwy
332 call assert_equal('cond sentence', @")
333
334 " Extend visual area in opposite direction.
335 norm! 1go2fcvhawy
336 call assert_equal(' Sec', @")
337 norm! gv2awy
338 call assert_equal(' sentence. Sec', @")
339
340 norm! 1go2fcvhiwy
341 call assert_equal('Sec', @")
342 norm! gv2iwy
343 call assert_equal('. Sec', @")
344
345 bwipe!
346endfunc
347
Bram Moolenaar6d3a1942019-01-03 23:10:32 +0100348func Test_Visual_sentence_textobject()
349 new
Bram Moolenaar81b1ba42019-01-13 16:12:40 +0100350 call setline(1, ['First sentence. Second sentence. Third', 'sentence. Fourth sentence'])
Bram Moolenaar6d3a1942019-01-03 23:10:32 +0100351
352 " When start and end of visual area are identical, 'as' or 'is' select
353 " the whole sentence.
354 norm! 1gofdvasy
355 call assert_equal('Second sentence. ', @")
356 norm! 1gofdvisy
357 call assert_equal('Second sentence.', @")
358
359 " When start and end of visual area are not identical, 'as' or 'is'
360 " extend the sentence in direction of the end of the visual area.
361 norm! 1gofdvlasy
362 call assert_equal('d sentence. ', @")
363 norm! gvasy
364 call assert_equal("d sentence. Third\nsentence. ", @")
365
366 norm! 1gofdvlisy
367 call assert_equal('d sentence.', @")
368 norm! gvisy
369 call assert_equal('d sentence. ', @")
370 norm! gvisy
371 call assert_equal("d sentence. Third\nsentence.", @")
372
373 " Extend visual area in opposite direction.
374 norm! 1gofdvhasy
375 call assert_equal(' Second', @")
376 norm! gvasy
377 call assert_equal("First sentence. Second", @")
378
379 norm! 1gofdvhisy
380 call assert_equal('Second', @")
381 norm! gvisy
382 call assert_equal(' Second', @")
383 norm! gvisy
384 call assert_equal('First sentence. Second', @")
385
386 bwipe!
387endfunc
Bram Moolenaar81b1ba42019-01-13 16:12:40 +0100388
389func Test_Visual_paragraph_textobject()
390 new
Bram Moolenaar8a9bc952020-10-02 18:48:07 +0200391 let lines =<< trim [END]
392 First line.
393
394 Second line.
395 Third line.
396 Fourth line.
397 Fifth line.
398
399 Sixth line.
400 [END]
401 call setline(1, lines)
Bram Moolenaar81b1ba42019-01-13 16:12:40 +0100402
403 " When start and end of visual area are identical, 'ap' or 'ip' select
404 " the whole paragraph.
405 norm! 4ggvapy
406 call assert_equal("Second line.\nThird line.\nFourth line.\nFifth line.\n\n", @")
407 norm! 4ggvipy
408 call assert_equal("Second line.\nThird line.\nFourth line.\nFifth line.\n", @")
409
410 " When start and end of visual area are not identical, 'ap' or 'ip'
411 " extend the sentence in direction of the end of the visual area.
412 " FIXME: actually, it is not sufficient to have different start and
413 " end of visual selection, the start line and end line have to differ,
414 " which is not consistent with the documentation.
415 norm! 4ggVjapy
416 call assert_equal("Third line.\nFourth line.\nFifth line.\n\n", @")
417 norm! gvapy
418 call assert_equal("Third line.\nFourth line.\nFifth line.\n\nSixth line.\n", @")
419 norm! 4ggVjipy
420 call assert_equal("Third line.\nFourth line.\nFifth line.\n", @")
421 norm! gvipy
422 call assert_equal("Third line.\nFourth line.\nFifth line.\n\n", @")
423 norm! gvipy
424 call assert_equal("Third line.\nFourth line.\nFifth line.\n\nSixth line.\n", @")
425
426 " Extend visual area in opposite direction.
427 norm! 5ggVkapy
428 call assert_equal("\nSecond line.\nThird line.\nFourth line.\n", @")
429 norm! gvapy
430 call assert_equal("First line.\n\nSecond line.\nThird line.\nFourth line.\n", @")
431 norm! 5ggVkipy
432 call assert_equal("Second line.\nThird line.\nFourth line.\n", @")
433 norma gvipy
434 call assert_equal("\nSecond line.\nThird line.\nFourth line.\n", @")
435 norm! gvipy
436 call assert_equal("First line.\n\nSecond line.\nThird line.\nFourth line.\n", @")
437
438 bwipe!
439endfunc
Bram Moolenaar19a66852019-03-07 11:25:32 +0100440
441func Test_curswant_not_changed()
442 new
443 call setline(1, ['one', 'two'])
444 au InsertLeave * call getcurpos()
445 call feedkeys("gg0\<C-V>jI123 \<Esc>j", 'xt')
446 call assert_equal([0, 2, 1, 0, 1], getcurpos())
447
448 bwipe!
449 au! InsertLeave
450endfunc
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200451
452" Tests for "vaBiB", end could be wrong.
453func Test_Visual_Block()
454 new
455 a
456- Bug in "vPPPP" on this text:
457 {
458 cmd;
459 {
460 cmd;\t/* <-- Start cursor here */
461 {
462 }
463 }
464 }
465.
466 normal gg
467 call search('Start cursor here')
468 normal vaBiBD
469 call assert_equal(['- Bug in "vPPPP" on this text:',
470 \ "\t{",
471 \ "\t}"], getline(1, '$'))
472
473 close!
474endfunc
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +0100475
476" Test for 'p'ut in visual block mode
477func Test_visual_block_put()
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200478 new
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +0100479 call append(0, ['One', 'Two', 'Three'])
480 normal gg
481 yank
482 call feedkeys("jl\<C-V>ljp", 'xt')
483 call assert_equal(['One', 'T', 'Tee', 'One', ''], getline(1, '$'))
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200484 bw!
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +0100485endfunc
486
Bram Moolenaar36343ae2022-10-15 19:04:05 +0100487func Test_visual_block_put_invalid()
488 enew!
489 behave mswin
490 norm yy
491 norm v)Ps/^/
492 " this was causing the column to become negative
493 silent norm ggv)P
494
495 bwipe!
496 behave xterm
497endfunc
498
Bram Moolenaar309976e2019-12-05 18:16:33 +0100499" Visual modes (v V CTRL-V) followed by an operator; count; repeating
500func Test_visual_mode_op()
501 new
502 call append(0, '')
503
504 call setline(1, 'apple banana cherry')
505 call cursor(1, 1)
506 normal lvld.l3vd.
507 call assert_equal('a y', getline(1))
508
509 call setline(1, ['line 1 line 1', 'line 2 line 2', 'line 3 line 3',
510 \ 'line 4 line 4', 'line 5 line 5', 'line 6 line 6'])
511 call cursor(1, 1)
512 exe "normal Vcnewline\<Esc>j.j2Vd."
513 call assert_equal(['newline', 'newline'], getline(1, '$'))
514
515 call deletebufline('', 1, '$')
516 call setline(1, ['xxxxxxxxxxxxx', 'xxxxxxxxxxxxx', 'xxxxxxxxxxxxx',
517 \ 'xxxxxxxxxxxxx'])
518 exe "normal \<C-V>jlc \<Esc>l.l2\<C-V>c----\<Esc>l."
519 call assert_equal([' --------x',
520 \ ' --------x',
521 \ 'xxxx--------x',
522 \ 'xxxx--------x'], getline(1, '$'))
523
524 bwipe!
525endfunc
526
527" Visual mode maps (movement and text object)
528" Visual mode maps; count; repeating
529" - Simple
530" - With an Ex command (custom text object)
531func Test_visual_mode_maps()
532 new
533 call append(0, '')
534
535 func SelectInCaps()
536 let [line1, col1] = searchpos('\u', 'bcnW')
537 let [line2, col2] = searchpos('.\u', 'nW')
538 call setpos("'<", [0, line1, col1, 0])
539 call setpos("'>", [0, line2, col2, 0])
540 normal! gv
541 endfunction
542
543 vnoremap W /\u/s-1<CR>
544 vnoremap iW :<C-U>call SelectInCaps()<CR>
545
546 call setline(1, 'KiwiRaspberryDateWatermelonPeach')
547 call cursor(1, 1)
548 exe "normal vWcNo\<Esc>l.fD2vd."
549 call assert_equal('NoNoberryach', getline(1))
550
551 call setline(1, 'JambuRambutanBananaTangerineMango')
552 call cursor(1, 1)
553 exe "normal llviWc-\<Esc>l.l2vdl."
554 call assert_equal('--ago', getline(1))
555
556 vunmap W
557 vunmap iW
558 bwipe!
559 delfunc SelectInCaps
560endfunc
561
562" Operator-pending mode maps (movement and text object)
563" - Simple
564" - With Ex command moving the cursor
565" - With Ex command and Visual selection (custom text object)
566func Test_visual_oper_pending_mode_maps()
567 new
568 call append(0, '')
569
570 func MoveToCap()
571 call search('\u', 'W')
572 endfunction
573
574 func SelectInCaps()
575 let [line1, col1] = searchpos('\u', 'bcnW')
576 let [line2, col2] = searchpos('.\u', 'nW')
577 call setpos("'<", [0, line1, col1, 0])
578 call setpos("'>", [0, line2, col2, 0])
579 normal! gv
580 endfunction
581
582 onoremap W /\u/<CR>
583 onoremap <Leader>W :<C-U>call MoveToCap()<CR>
584 onoremap iW :<C-U>call SelectInCaps()<CR>
585
586 call setline(1, 'PineappleQuinceLoganberryOrangeGrapefruitKiwiZ')
587 call cursor(1, 1)
588 exe "normal cW-\<Esc>l.l2.l."
589 call assert_equal('----Z', getline(1))
590
591 call setline(1, 'JuniperDurianZ')
592 call cursor(1, 1)
593 exe "normal g?\WfD."
594 call assert_equal('WhavcreQhevnaZ', getline(1))
595
596 call setline(1, 'LemonNectarineZ')
597 call cursor(1, 1)
598 exe "normal yiWPlciWNew\<Esc>fr."
599 call assert_equal('LemonNewNewZ', getline(1))
600
601 ounmap W
602 ounmap <Leader>W
603 ounmap iW
604 bwipe!
605 delfunc MoveToCap
606 delfunc SelectInCaps
607endfunc
608
609" Patch 7.3.879: Properly abort Operator-pending mode for "dv:<Esc>" etc.
610func Test_op_pend_mode_abort()
611 new
612 call append(0, '')
613
614 call setline(1, ['zzzz', 'zzzz'])
615 call cursor(1, 1)
616
617 exe "normal dV:\<CR>dv:\<CR>"
618 call assert_equal(['zzz'], getline(1, 2))
619 set nomodifiable
620 call assert_fails('exe "normal d:\<CR>"', 'E21:')
621 set modifiable
622 call feedkeys("dv:\<Esc>dV:\<Esc>", 'xt')
623 call assert_equal(['zzz'], getline(1, 2))
624 set nomodifiable
625 let v:errmsg = ''
626 call feedkeys("d:\<Esc>", 'xt')
627 call assert_true(v:errmsg !~# '^E21:')
628 set modifiable
629
630 bwipe!
631endfunc
632
633func Test_characterwise_visual_mode()
634 new
635
636 " characterwise visual mode: replace last line
637 $put ='a'
638 let @" = 'x'
639 normal v$p
640 call assert_equal('x', getline('$'))
641
642 " characterwise visual mode: delete middle line
643 call deletebufline('', 1, '$')
644 call append('$', ['a', 'b', 'c'])
645 normal G
646 normal kkv$d
647 call assert_equal(['', 'b', 'c'], getline(1, '$'))
648
649 " characterwise visual mode: delete middle two lines
650 call deletebufline('', 1, '$')
651 call append('$', ['a', 'b', 'c'])
652 normal Gkkvj$d
653 call assert_equal(['', 'c'], getline(1, '$'))
654
655 " characterwise visual mode: delete last line
656 call deletebufline('', 1, '$')
657 call append('$', ['a', 'b', 'c'])
658 normal Gv$d
659 call assert_equal(['', 'a', 'b', ''], getline(1, '$'))
660
661 " characterwise visual mode: delete last two lines
662 call deletebufline('', 1, '$')
663 call append('$', ['a', 'b', 'c'])
664 normal Gkvj$d
665 call assert_equal(['', 'a', ''], getline(1, '$'))
666
Bram Moolenaar8a9bc952020-10-02 18:48:07 +0200667 " characterwise visual mode: use a count with the visual mode from the last
668 " line in the buffer
669 %d _
670 call setline(1, ['one', 'two', 'three', 'four'])
671 norm! vj$y
672 norm! G1vy
673 call assert_equal('four', @")
674
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200675 " characterwise visual mode: replace a single character line and the eol
676 %d _
677 call setline(1, "a")
678 normal v$rx
679 call assert_equal(['x'], getline(1, '$'))
680
Bram Moolenaar6ecf58b2021-12-16 10:05:41 +0000681 " replace a character with composing characters
682 call setline(1, "xã̳x")
683 normal gg0lvrb
684 call assert_equal("xbx", getline(1))
685
Bram Moolenaar309976e2019-12-05 18:16:33 +0100686 bwipe!
687endfunc
688
Bram Moolenaar309976e2019-12-05 18:16:33 +0100689func Test_visual_mode_put()
690 new
691
692 " v_p: replace last character with line register at middle line
693 call append('$', ['aaa', 'bbb', 'ccc'])
694 normal G
695 -2yank
696 normal k$vp
697 call assert_equal(['', 'aaa', 'bb', 'aaa', '', 'ccc'], getline(1, '$'))
698
699 " v_p: replace last character with line register at middle line selecting
700 " newline
701 call deletebufline('', 1, '$')
702 call append('$', ['aaa', 'bbb', 'ccc'])
703 normal G
704 -2yank
705 normal k$v$p
706 call assert_equal(['', 'aaa', 'bb', 'aaa', 'ccc'], getline(1, '$'))
707
708 " v_p: replace last character with line register at last line
709 call deletebufline('', 1, '$')
710 call append('$', ['aaa', 'bbb', 'ccc'])
711 normal G
712 -2yank
713 normal $vp
714 call assert_equal(['', 'aaa', 'bbb', 'cc', 'aaa', ''], getline(1, '$'))
715
716 " v_p: replace last character with line register at last line selecting
717 " newline
718 call deletebufline('', 1, '$')
719 call append('$', ['aaa', 'bbb', 'ccc'])
720 normal G
721 -2yank
722 normal $v$p
723 call assert_equal(['', 'aaa', 'bbb', 'cc', 'aaa', ''], getline(1, '$'))
724
725 bwipe!
726endfunc
727
Bram Moolenaar515545e2020-03-22 14:08:59 +0100728func Test_gv_with_exclusive_selection()
Bram Moolenaar309976e2019-12-05 18:16:33 +0100729 new
730
Bram Moolenaar515545e2020-03-22 14:08:59 +0100731 " gv with exclusive selection after an operation
Bram Moolenaar309976e2019-12-05 18:16:33 +0100732 call append('$', ['zzz ', 'äà '])
733 set selection=exclusive
734 normal Gkv3lyjv3lpgvcxxx
735 call assert_equal(['', 'zzz ', 'xxx '], getline(1, '$'))
736
Bram Moolenaar515545e2020-03-22 14:08:59 +0100737 " gv with exclusive selection without an operation
Bram Moolenaar309976e2019-12-05 18:16:33 +0100738 call deletebufline('', 1, '$')
739 call append('$', 'zzz ')
740 set selection=exclusive
741 exe "normal G0v3l\<Esc>gvcxxx"
742 call assert_equal(['', 'xxx '], getline(1, '$'))
743
744 set selection&vim
745 bwipe!
746endfunc
747
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +0100748" Tests for the visual block mode commands
749func Test_visual_block_mode()
750 new
751 call append(0, '')
Bram Moolenaar1671f442020-03-10 07:48:13 +0100752 call setline(1, repeat(['abcdefghijklm'], 5))
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +0100753 call cursor(1, 1)
754
755 " Test shift-right of a block
756 exe "normal jllll\<C-V>jj>wll\<C-V>jlll>"
757 " Test shift-left of a block
758 exe "normal G$hhhh\<C-V>kk<"
759 " Test block-insert
760 exe "normal Gkl\<C-V>kkkIxyz"
761 " Test block-replace
762 exe "normal Gllll\<C-V>kkklllrq"
763 " Test block-change
764 exe "normal G$khhh\<C-V>hhkkcmno"
765 call assert_equal(['axyzbcdefghijklm',
766 \ 'axyzqqqq mno ghijklm',
767 \ 'axyzqqqqef mno ghijklm',
768 \ 'axyzqqqqefgmnoklm',
769 \ 'abcdqqqqijklm'], getline(1, 5))
770
Bram Moolenaar1671f442020-03-10 07:48:13 +0100771 " Test 'C' to change till the end of the line
772 call cursor(3, 4)
773 exe "normal! \<C-V>j3lCooo"
774 call assert_equal(['axyooo', 'axyooo'], getline(3, 4))
775
776 " Test 'D' to delete till the end of the line
777 call cursor(3, 3)
778 exe "normal! \<C-V>j2lD"
779 call assert_equal(['ax', 'ax'], getline(3, 4))
780
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200781 " Test block insert with a short line that ends before the block
782 %d _
783 call setline(1, [" one", "a", " two"])
784 exe "normal gg\<C-V>2jIx"
785 call assert_equal([" xone", "a", " xtwo"], getline(1, '$'))
786
787 " Test block append at EOL with '$' and without '$'
788 %d _
789 call setline(1, ["one", "a", "two"])
790 exe "normal gg$\<C-V>2jAx"
791 call assert_equal(["onex", "ax", "twox"], getline(1, '$'))
792 %d _
793 call setline(1, ["one", "a", "two"])
794 exe "normal gg3l\<C-V>2jAx"
795 call assert_equal(["onex", "a x", "twox"], getline(1, '$'))
796
797 " Test block replace with an empty line in the middle and use $ to jump to
798 " the end of the line.
799 %d _
800 call setline(1, ['one', '', 'two'])
801 exe "normal gg$\<C-V>2jrx"
802 call assert_equal(["onx", "", "twx"], getline(1, '$'))
803
804 " Test block replace with an empty line in the middle and move cursor to the
805 " end of the line
806 %d _
807 call setline(1, ['one', '', 'two'])
808 exe "normal gg2l\<C-V>2jrx"
809 call assert_equal(["onx", "", "twx"], getline(1, '$'))
810
811 " Replace odd number of characters with a multibyte character
812 %d _
813 call setline(1, ['abcd', 'efgh'])
814 exe "normal ggl\<C-V>2ljr\u1100"
815 call assert_equal(["a\u1100 ", "e\u1100 "], getline(1, '$'))
816
817 " During visual block append, if the cursor moved outside of the selected
818 " range, then the edit should not be applied to the block.
819 %d _
820 call setline(1, ['aaa', 'bbb', 'ccc'])
821 exe "normal 2G\<C-V>jAx\<Up>"
822 call assert_equal(['aaa', 'bxbb', 'ccc'], getline(1, '$'))
823
824 " During visual block append, if the cursor is moved before the start of the
825 " block, then the new text should be appended there.
826 %d _
827 call setline(1, ['aaa', 'bbb', 'ccc'])
828 exe "normal $\<C-V>2jA\<Left>x"
Bram Moolenaar4067bd32021-06-29 18:54:35 +0200829 call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$'))
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200830 " Repeat the previous test but use 'l' to move the cursor instead of '$'
831 call setline(1, ['aaa', 'bbb', 'ccc'])
832 exe "normal! gg2l\<C-V>2jA\<Left>x"
833 call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$'))
Bram Moolenaar3e72dca2021-05-29 16:30:12 +0200834
835 " Change a characterwise motion to a blockwise motion using CTRL-V
836 %d _
837 call setline(1, ['123', '456', '789'])
838 exe "normal ld\<C-V>j"
839 call assert_equal(['13', '46', '789'], getline(1, '$'))
840
Yegappan Lakshmanan2ac71842021-05-31 19:23:01 +0200841 " Test from ':help v_b_I_example'
842 %d _
843 setlocal tabstop=8 shiftwidth=4
844 let lines =<< trim END
845 abcdefghijklmnopqrstuvwxyz
846 abc defghijklmnopqrstuvwxyz
847 abcdef ghi jklmnopqrstuvwxyz
848 abcdefghijklmnopqrstuvwxyz
849 END
850 call setline(1, lines)
851 exe "normal ggfo\<C-V>3jISTRING"
852 let expected =<< trim END
853 abcdefghijklmnSTRINGopqrstuvwxyz
854 abc STRING defghijklmnopqrstuvwxyz
855 abcdef ghi STRING jklmnopqrstuvwxyz
856 abcdefghijklmnSTRINGopqrstuvwxyz
857 END
858 call assert_equal(expected, getline(1, '$'))
859
860 " Test from ':help v_b_A_example'
861 %d _
862 let lines =<< trim END
863 abcdefghijklmnopqrstuvwxyz
864 abc defghijklmnopqrstuvwxyz
865 abcdef ghi jklmnopqrstuvwxyz
866 abcdefghijklmnopqrstuvwxyz
867 END
868 call setline(1, lines)
869 exe "normal ggfo\<C-V>3j$ASTRING"
870 let expected =<< trim END
871 abcdefghijklmnopqrstuvwxyzSTRING
872 abc defghijklmnopqrstuvwxyzSTRING
873 abcdef ghi jklmnopqrstuvwxyzSTRING
874 abcdefghijklmnopqrstuvwxyzSTRING
875 END
876 call assert_equal(expected, getline(1, '$'))
877
878 " Test from ':help v_b_<_example'
879 %d _
880 let lines =<< trim END
881 abcdefghijklmnopqrstuvwxyz
882 abc defghijklmnopqrstuvwxyz
883 abcdef ghi jklmnopqrstuvwxyz
884 abcdefghijklmnopqrstuvwxyz
885 END
886 call setline(1, lines)
887 exe "normal ggfo\<C-V>3j3l<.."
888 let expected =<< trim END
889 abcdefghijklmnopqrstuvwxyz
890 abc defghijklmnopqrstuvwxyz
891 abcdef ghi jklmnopqrstuvwxyz
892 abcdefghijklmnopqrstuvwxyz
893 END
894 call assert_equal(expected, getline(1, '$'))
895
896 " Test from ':help v_b_>_example'
897 %d _
898 let lines =<< trim END
899 abcdefghijklmnopqrstuvwxyz
900 abc defghijklmnopqrstuvwxyz
901 abcdef ghi jklmnopqrstuvwxyz
902 abcdefghijklmnopqrstuvwxyz
903 END
904 call setline(1, lines)
905 exe "normal ggfo\<C-V>3j>.."
906 let expected =<< trim END
907 abcdefghijklmn opqrstuvwxyz
908 abc defghijklmnopqrstuvwxyz
909 abcdef ghi jklmnopqrstuvwxyz
910 abcdefghijklmn opqrstuvwxyz
911 END
912 call assert_equal(expected, getline(1, '$'))
913
914 " Test from ':help v_b_r_example'
915 %d _
916 let lines =<< trim END
917 abcdefghijklmnopqrstuvwxyz
918 abc defghijklmnopqrstuvwxyz
919 abcdef ghi jklmnopqrstuvwxyz
920 abcdefghijklmnopqrstuvwxyz
921 END
922 call setline(1, lines)
923 exe "normal ggfo\<C-V>5l3jrX"
924 let expected =<< trim END
925 abcdefghijklmnXXXXXXuvwxyz
926 abc XXXXXXhijklmnopqrstuvwxyz
927 abcdef ghi XXXXXX jklmnopqrstuvwxyz
928 abcdefghijklmnXXXXXXuvwxyz
929 END
930 call assert_equal(expected, getline(1, '$'))
931
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +0100932 bwipe!
Yegappan Lakshmanan2ac71842021-05-31 19:23:01 +0200933 set tabstop& shiftwidth&
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +0100934endfunc
935
Bram Moolenaar21492742021-06-04 21:57:57 +0200936func Test_visual_force_motion_feedkeys()
937 onoremap <expr> i- execute('let g:mode = mode(1)')->slice(0, 0)
938 call feedkeys('dvi-', 'x')
939 call assert_equal('nov', g:mode)
940 call feedkeys('di-', 'x')
941 call assert_equal('no', g:mode)
942 ounmap i-
943endfunc
944
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +0100945" Test block-insert using cursor keys for movement
946func Test_visual_block_insert_cursor_keys()
947 new
948 call append(0, ['aaaaaa', 'bbbbbb', 'cccccc', 'dddddd'])
949 call cursor(1, 1)
950
951 exe "norm! l\<C-V>jjjlllI\<Right>\<Right> \<Esc>"
952 call assert_equal(['aaa aaa', 'bbb bbb', 'ccc ccc', 'ddd ddd'],
953 \ getline(1, 4))
954
955 call deletebufline('', 1, '$')
956 call setline(1, ['xaaa', 'bbbb', 'cccc', 'dddd'])
957 call cursor(1, 1)
958 exe "norm! \<C-V>jjjI<>\<Left>p\<Esc>"
959 call assert_equal(['<p>xaaa', '<p>bbbb', '<p>cccc', '<p>dddd'],
960 \ getline(1, 4))
961 bwipe!
962endfunc
963
964func Test_visual_block_create()
965 new
966 call append(0, '')
967 " Test for Visual block was created with the last <C-v>$
968 call setline(1, ['A23', '4567'])
969 call cursor(1, 1)
970 exe "norm! l\<C-V>j$Aab\<Esc>"
971 call assert_equal(['A23ab', '4567ab'], getline(1, 2))
972
973 " Test for Visual block was created with the middle <C-v>$ (1)
974 call deletebufline('', 1, '$')
975 call setline(1, ['B23', '4567'])
976 call cursor(1, 1)
977 exe "norm! l\<C-V>j$hAab\<Esc>"
978 call assert_equal(['B23 ab', '4567ab'], getline(1, 2))
979
980 " Test for Visual block was created with the middle <C-v>$ (2)
981 call deletebufline('', 1, '$')
982 call setline(1, ['C23', '4567'])
983 call cursor(1, 1)
984 exe "norm! l\<C-V>j$hhAab\<Esc>"
985 call assert_equal(['C23ab', '456ab7'], getline(1, 2))
986 bwipe!
987endfunc
988
989" Test for Visual block insert when virtualedit=all
990func Test_virtualedit_visual_block()
991 set ve=all
992 new
993 call append(0, ["\t\tline1", "\t\tline2", "\t\tline3"])
994 call cursor(1, 1)
995 exe "norm! 07l\<C-V>jjIx\<Esc>"
996 call assert_equal([" x \tline1",
997 \ " x \tline2",
998 \ " x \tline3"], getline(1, 3))
999
1000 " Test for Visual block append when virtualedit=all
1001 exe "norm! 012l\<C-v>jjAx\<Esc>"
1002 call assert_equal([' x x line1',
1003 \ ' x x line2',
1004 \ ' x x line3'], getline(1, 3))
1005 set ve=
1006 bwipe!
1007endfunc
1008
1009" Test for changing case
1010func Test_visual_change_case()
1011 new
zeertzjqe7102202024-02-13 20:32:04 +01001012 " gUe must uppercase a whole word, also when ß changes to
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +01001013 exe "normal Gothe youtußeuu end\<Esc>Ypk0wgUe\r"
1014 " gUfx must uppercase until x, inclusive.
1015 exe "normal O- youßtußexu -\<Esc>0fogUfx\r"
1016 " VU must uppercase a whole line
1017 exe "normal YpkVU\r"
1018 " same, when it's the last line in the buffer
1019 exe "normal YPGi111\<Esc>VUddP\r"
1020 " Uppercase two lines
1021 exe "normal Oblah di\rdoh dut\<Esc>VkUj\r"
1022 " Uppercase part of two lines
1023 exe "normal ddppi333\<Esc>k0i222\<Esc>fyllvjfuUk"
glepnirbd1232a2024-02-12 22:14:53 +01001024 call assert_equal(['the YOUTUẞEUU end', '- yOUẞTUẞEXu -',
1025 \ 'THE YOUTUẞEUU END', '111THE YOUTUẞEUU END', 'BLAH DI', 'DOH DUT',
1026 \ '222the yoUTUẞEUU END', '333THE YOUTUßeuu end'], getline(2, '$'))
Bram Moolenaar1f3e7d32019-12-06 20:43:36 +01001027 bwipe!
1028endfunc
1029
1030" Test for Visual replace using Enter or NL
1031func Test_visual_replace_crnl()
1032 new
1033 exe "normal G3o123456789\e2k05l\<C-V>2jr\r"
1034 exe "normal G3o98765\e2k02l\<C-V>2jr\<C-V>\r\n"
1035 exe "normal G3o123456789\e2k05l\<C-V>2jr\n"
1036 exe "normal G3o98765\e2k02l\<C-V>2jr\<C-V>\n"
1037 call assert_equal(['12345', '789', '12345', '789', '12345', '789', "98\r65",
1038 \ "98\r65", "98\r65", '12345', '789', '12345', '789', '12345', '789',
1039 \ "98\n65", "98\n65", "98\n65"], getline(2, '$'))
1040 bwipe!
1041endfunc
1042
1043func Test_ve_block_curpos()
1044 new
1045 " Test cursor position. When ve=block and Visual block mode and $gj
1046 call append(0, ['12345', '789'])
1047 call cursor(1, 3)
1048 set virtualedit=block
1049 exe "norm! \<C-V>$gj\<Esc>"
1050 call assert_equal([0, 2, 4, 0], getpos("'>"))
1051 set virtualedit=
1052 bwipe!
1053endfunc
1054
1055" Test for block_insert when replacing spaces in front of the a with tabs
1056func Test_block_insert_replace_tabs()
1057 new
1058 set ts=8 sts=4 sw=4
1059 call append(0, ["#define BO_ALL\t 0x0001",
1060 \ "#define BO_BS\t 0x0002",
1061 \ "#define BO_CRSR\t 0x0004"])
1062 call cursor(1, 1)
1063 exe "norm! f0\<C-V>2jI\<tab>\<esc>"
1064 call assert_equal([
1065 \ "#define BO_ALL\t\t0x0001",
1066 \ "#define BO_BS\t \t0x0002",
1067 \ "#define BO_CRSR\t \t0x0004", ''], getline(1, '$'))
1068 set ts& sts& sw&
1069 bwipe!
1070endfunc
1071
Bram Moolenaarbc2b71d2020-02-17 21:33:30 +01001072" Test for * register in :
1073func Test_star_register()
1074 call assert_fails('*bfirst', 'E16:')
1075 new
1076 call setline(1, ['foo', 'bar', 'baz', 'qux'])
1077 exe "normal jVj\<ESC>"
1078 *yank r
1079 call assert_equal("bar\nbaz\n", @r)
1080
1081 delmarks < >
1082 call assert_fails('*yank', 'E20:')
1083 close!
1084endfunc
1085
Bram Moolenaarf5f1e102020-03-08 05:13:15 +01001086" Test for changing text in visual mode with 'exclusive' selection
1087func Test_exclusive_selection()
1088 new
1089 call setline(1, ['one', 'two'])
1090 set selection=exclusive
1091 call feedkeys("vwcabc", 'xt')
1092 call assert_equal('abctwo', getline(1))
1093 call setline(1, ["\tone"])
1094 set virtualedit=all
1095 call feedkeys('0v2lcl', 'xt')
1096 call assert_equal('l one', getline(1))
1097 set virtualedit&
1098 set selection&
1099 close!
1100endfunc
1101
Bram Moolenaard1ad99b2020-10-04 16:16:54 +02001102" Test for starting linewise visual with a count.
1103" This test needs to be run without any previous visual mode. Otherwise the
1104" count will use the count from the previous visual mode.
1105func Test_linewise_visual_with_count()
1106 let after =<< trim [CODE]
1107 call setline(1, ['one', 'two', 'three', 'four'])
1108 norm! 3Vy
1109 call assert_equal("one\ntwo\nthree\n", @")
1110 call writefile(v:errors, 'Xtestout')
1111 qall!
1112 [CODE]
1113 if RunVim([], after, '')
1114 call assert_equal([], readfile('Xtestout'))
1115 call delete('Xtestout')
1116 endif
1117endfunc
1118
1119" Test for starting characterwise visual with a count.
1120" This test needs to be run without any previous visual mode. Otherwise the
1121" count will use the count from the previous visual mode.
1122func Test_characterwise_visual_with_count()
1123 let after =<< trim [CODE]
1124 call setline(1, ['one two', 'three'])
1125 norm! l5vy
1126 call assert_equal("ne tw", @")
1127 call writefile(v:errors, 'Xtestout')
1128 qall!
1129 [CODE]
1130 if RunVim([], after, '')
1131 call assert_equal([], readfile('Xtestout'))
1132 call delete('Xtestout')
1133 endif
Bram Moolenaarf5f1e102020-03-08 05:13:15 +01001134endfunc
1135
Bram Moolenaar224a5f12020-04-28 20:29:07 +02001136" Test for visually selecting an inner block (iB)
1137func Test_visual_inner_block()
1138 new
1139 call setline(1, ['one', '{', 'two', '{', 'three', '}', 'four', '}', 'five'])
1140 call cursor(5, 1)
1141 " visually select all the lines in the block and then execute iB
1142 call feedkeys("ViB\<C-C>", 'xt')
1143 call assert_equal([0, 5, 1, 0], getpos("'<"))
1144 call assert_equal([0, 5, 6, 0], getpos("'>"))
1145 " visually select two inner blocks
1146 call feedkeys("ViBiB\<C-C>", 'xt')
1147 call assert_equal([0, 3, 1, 0], getpos("'<"))
1148 call assert_equal([0, 7, 5, 0], getpos("'>"))
1149 " try to select non-existing inner block
1150 call cursor(5, 1)
1151 call assert_beeps('normal ViBiBiB')
zeertzjqc029c132024-03-28 11:37:26 +01001152 " try to select an unclosed inner block
Bram Moolenaar224a5f12020-04-28 20:29:07 +02001153 8,9d
1154 call cursor(5, 1)
1155 call assert_beeps('normal ViBiB')
1156 close!
1157endfunc
1158
Bram Moolenaarcd942772020-08-22 21:08:44 +02001159func Test_visual_put_in_block()
1160 new
1161 call setline(1, ['xxxx', 'yyy', 'zzzz'])
1162 normal 1G2yl
1163 exe "normal 1G2l\<C-V>jjlp"
1164 call assert_equal(['xxxx', 'yxx', 'zzxx'], getline(1, 3))
1165 bwipe!
1166endfunc
1167
Christian Brabandt2fa93842021-05-30 22:17:25 +02001168func Test_visual_put_in_block_using_zp()
1169 new
1170 " paste using zP
Bram Moolenaar94722c52023-01-28 19:19:03 +00001171 call setline(1, ['/path;text', '/path;text', '/path;text', '',
1172 \ '/subdir',
Christian Brabandt2fa93842021-05-30 22:17:25 +02001173 \ '/longsubdir',
1174 \ '/longlongsubdir'])
1175 exe "normal! 5G\<c-v>2j$y"
1176 norm! 1Gf;zP
1177 call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
1178 %d
1179 " paste using zP
Bram Moolenaar94722c52023-01-28 19:19:03 +00001180 call setline(1, ['/path;text', '/path;text', '/path;text', '',
1181 \ '/subdir',
Christian Brabandt2fa93842021-05-30 22:17:25 +02001182 \ '/longsubdir',
1183 \ '/longlongsubdir'])
1184 exe "normal! 5G\<c-v>2j$y"
1185 norm! 1Gf;hzp
1186 call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
1187 bwipe!
1188endfunc
1189
Christian Brabandt544a38e2021-06-10 19:39:11 +02001190func Test_visual_put_in_block_using_zy_and_zp()
1191 new
1192
1193 " Test 1) Paste using zp - after the cursor without trailing spaces
Bram Moolenaar94722c52023-01-28 19:19:03 +00001194 call setline(1, ['/path;text', '/path;text', '/path;text', '',
Christian Brabandt544a38e2021-06-10 19:39:11 +02001195 \ 'texttext /subdir columntext',
1196 \ 'texttext /longsubdir columntext',
1197 \ 'texttext /longlongsubdir columntext'])
1198 exe "normal! 5G0f/\<c-v>2jezy"
1199 norm! 1G0f;hzp
1200 call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
1201
1202 " Test 2) Paste using zP - in front of the cursor without trailing spaces
1203 %d
Bram Moolenaar94722c52023-01-28 19:19:03 +00001204 call setline(1, ['/path;text', '/path;text', '/path;text', '',
Christian Brabandt544a38e2021-06-10 19:39:11 +02001205 \ 'texttext /subdir columntext',
1206 \ 'texttext /longsubdir columntext',
1207 \ 'texttext /longlongsubdir columntext'])
1208 exe "normal! 5G0f/\<c-v>2jezy"
1209 norm! 1G0f;zP
1210 call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3))
1211
1212 " Test 3) Paste using p - with trailing spaces
1213 %d
Bram Moolenaar94722c52023-01-28 19:19:03 +00001214 call setline(1, ['/path;text', '/path;text', '/path;text', '',
Christian Brabandt544a38e2021-06-10 19:39:11 +02001215 \ 'texttext /subdir columntext',
1216 \ 'texttext /longsubdir columntext',
1217 \ 'texttext /longlongsubdir columntext'])
1218 exe "normal! 5G0f/\<c-v>2jezy"
1219 norm! 1G0f;hp
1220 call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3))
1221
1222 " Test 4) Paste using P - with trailing spaces
1223 %d
Bram Moolenaar94722c52023-01-28 19:19:03 +00001224 call setline(1, ['/path;text', '/path;text', '/path;text', '',
Christian Brabandt544a38e2021-06-10 19:39:11 +02001225 \ 'texttext /subdir columntext',
1226 \ 'texttext /longsubdir columntext',
1227 \ 'texttext /longlongsubdir columntext'])
1228 exe "normal! 5G0f/\<c-v>2jezy"
1229 norm! 1G0f;P
1230 call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3))
1231
1232 " Test 5) Yank with spaces inside the block
1233 %d
Bram Moolenaar94722c52023-01-28 19:19:03 +00001234 call setline(1, ['/path;text', '/path;text', '/path;text', '',
Christian Brabandt544a38e2021-06-10 19:39:11 +02001235 \ 'texttext /sub dir/ columntext',
1236 \ 'texttext /lon gsubdir/ columntext',
1237 \ 'texttext /lon glongsubdir/ columntext'])
1238 exe "normal! 5G0f/\<c-v>2jf/zy"
1239 norm! 1G0f;zP
1240 call assert_equal(['/path/sub dir/;text', '/path/lon gsubdir/;text', '/path/lon glongsubdir/;text'], getline(1, 3))
1241 bwipe!
1242endfunc
1243
Bram Moolenaar7d7bcc62021-06-28 21:54:27 +02001244func Test_visual_put_blockedit_zy_and_zp()
1245 new
1246
1247 call setline(1, ['aa', 'bbbbb', 'ccc', '', 'XX', 'GGHHJ', 'RTZU'])
1248 exe "normal! gg0\<c-v>2j$zy"
1249 norm! 5gg0zP
1250 call assert_equal(['aa', 'bbbbb', 'ccc', '', 'aaXX', 'bbbbbGGHHJ', 'cccRTZU'], getline(1, 7))
1251 "
1252 " now with blockmode editing
1253 sil %d
1254 :set ve=block
1255 call setline(1, ['aa', 'bbbbb', 'ccc', '', 'XX', 'GGHHJ', 'RTZU'])
1256 exe "normal! gg0\<c-v>2j$zy"
1257 norm! 5gg0zP
1258 call assert_equal(['aa', 'bbbbb', 'ccc', '', 'aaXX', 'bbbbbGGHHJ', 'cccRTZU'], getline(1, 7))
1259 set ve&vim
1260 bw!
1261endfunc
1262
Bram Moolenaar44db8212022-01-25 21:26:17 +00001263func Test_visual_block_yank_zy()
1264 new
1265 " this was reading before the start of the line
1266 exe "norm o\<C-T>\<Esc>\<C-V>zy"
1267 bwipe!
1268endfunc
1269
Bram Moolenaar9cee4a12021-07-03 15:08:37 +02001270func Test_visual_block_with_virtualedit()
1271 CheckScreendump
1272
1273 let lines =<< trim END
1274 call setline(1, ['aaaaaa', 'bbbb', 'cc'])
1275 set virtualedit=block
1276 normal G
1277 END
Bram Moolenaar5b148ef2022-10-15 21:35:56 +01001278 call writefile(lines, 'XTest_block', 'D')
Bram Moolenaar9cee4a12021-07-03 15:08:37 +02001279
1280 let buf = RunVimInTerminal('-S XTest_block', {'rows': 8, 'cols': 50})
1281 call term_sendkeys(buf, "\<C-V>gg$")
1282 call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit', {})
1283
Bram Moolenaarb17ab862021-07-03 22:15:17 +02001284 call term_sendkeys(buf, "\<Esc>gg\<C-V>G$")
1285 call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit2', {})
1286
Bram Moolenaar9cee4a12021-07-03 15:08:37 +02001287 " clean up
1288 call term_sendkeys(buf, "\<Esc>")
1289 call StopVimInTerminal(buf)
Bram Moolenaar9cee4a12021-07-03 15:08:37 +02001290endfunc
1291
Bram Moolenaar615ddd52021-11-17 18:00:31 +00001292func Test_visual_block_ctrl_w_f()
dundargocc57b5bc2022-11-02 13:30:51 +00001293 " Empty block selected in new buffer should not result in an error.
Bram Moolenaar615ddd52021-11-17 18:00:31 +00001294 au! BufNew foo sil norm f
1295 edit foo
1296
1297 au! BufNew
1298endfunc
1299
Bram Moolenaar9f8c3042022-01-17 17:30:21 +00001300func Test_visual_block_append_invalid_char()
1301 " this was going over the end of the line
Bram Moolenaar262898a2022-01-17 17:52:22 +00001302 set isprint=@,161-255
Bram Moolenaar9f8c3042022-01-17 17:30:21 +00001303 new
1304 call setline(1, [' let xxx', 'xxxxxˆ', 'xxxxxxxxxxx'])
1305 exe "normal 0\<C-V>jjA-\<Esc>"
1306 call assert_equal([' - let xxx', 'xxxxx ', 'xxxxxxxx-xxx'], getline(1, 3))
1307 bwipe!
Bram Moolenaar262898a2022-01-17 17:52:22 +00001308 set isprint&
Bram Moolenaar9f8c3042022-01-17 17:30:21 +00001309endfunc
1310
Bram Moolenaar7ce5b2b2022-05-16 19:40:59 +01001311func Test_visual_block_with_substitute()
1312 " this was reading beyond the end of the line
1313 new
1314 norm a0)
1315 sil! norm  O
1316 s/)
1317 sil! norm 
1318 bwipe!
1319endfunc
1320
Bram Moolenaarb07626d2021-10-11 15:40:43 +01001321func Test_visual_reselect_with_count()
Bram Moolenaar8f531662023-02-01 17:33:18 +00001322 enew
1323 call setline(1, ['aaaaaa', ' bbbb', ' bbbb'])
1324 exe "normal! 2Gw\<C-V>jed"
1325 exe "normal! gg0lP"
1326 call assert_equal(['abbbbaaaaa', 'bbbb ', ' '], getline(1, '$'))
1327
1328 exe "normal! 1vr."
1329 call assert_equal(['a....aaaaa', '✗.... ', ' '], getline(1, '$'))
1330
1331 bwipe!
1332
Bram Moolenaarb07626d2021-10-11 15:40:43 +01001333 " this was causing an illegal memory access
1334 let lines =<< trim END
1335
1336
1337
1338 :
1339 r<sfile>
1340 exe "%norm e3\<c-v>kr\t"
1341 :
1342
1343 :
1344 END
Bram Moolenaar5b148ef2022-10-15 21:35:56 +01001345 call writefile(lines, 'XvisualReselect', 'D')
Bram Moolenaarb07626d2021-10-11 15:40:43 +01001346 source XvisualReselect
1347
1348 bwipe!
Bram Moolenaarb07626d2021-10-11 15:40:43 +01001349endfunc
1350
Bram Moolenaar79c11e32023-01-10 17:29:29 +00001351func Test_visual_reselect_exclusive()
1352 new
1353 call setline(1, ['abcde', 'abcde'])
1354 set selection=exclusive
1355 normal 1G0viwd
1356 normal 2G01vd
1357 call assert_equal(['', ''], getline(1, 2))
1358
1359 set selection&
1360 bwipe!
1361endfunc
1362
Bram Moolenaar57df9e82022-01-20 12:10:48 +00001363func Test_visual_block_insert_round_off()
1364 new
1365 " The number of characters are tuned to fill a 4096 byte allocated block,
1366 " so that valgrind reports going over the end.
1367 call setline(1, ['xxxxx', repeat('0', 1350), "\t", repeat('x', 60)])
1368 exe "normal gg0\<C-V>GI" .. repeat('0', 1320) .. "\<Esc>"
1369 bwipe!
1370endfunc
1371
Bram Moolenaar05b27612022-01-20 13:32:50 +00001372" this was causing an ml_get error
1373func Test_visual_exchange_windows()
1374 enew!
1375 new
1376 call setline(1, ['foo', 'bar'])
1377 exe "normal G\<C-V>gg\<C-W>\<C-X>OO\<Esc>"
1378 bwipe!
1379 bwipe!
1380endfunc
1381
Bram Moolenaardc5490e2022-01-25 13:52:53 +00001382" this was leaving the end of the Visual area beyond the end of a line
1383func Test_visual_ex_copy_line()
1384 new
1385 call setline(1, ["aaa", "bbbbbbbbbxbb"])
1386 /x
1387 exe "normal ggvjfxO"
1388 t0
1389 normal gNU
1390 bwipe!
1391endfunc
1392
Bram Moolenaar8d02ce12022-01-25 18:24:00 +00001393" This was leaving the end of the Visual area beyond the end of a line.
1394" Set 'undolevels' to start a new undo block.
1395func Test_visual_undo_deletes_last_line()
1396 new
1397 call setline(1, ["aaa", "ccc", "dyd"])
1398 set undolevels=100
1399 exe "normal obbbbbbbbbxbb\<Esc>"
1400 set undolevels=100
1401 /y
1402 exe "normal ggvjfxO"
1403 undo
1404 normal gNU
Shougo Matsushitafb552072022-01-28 16:01:13 +00001405
Bram Moolenaar8d02ce12022-01-25 18:24:00 +00001406 bwipe!
1407endfunc
1408
Shougo Matsushitafb552072022-01-28 16:01:13 +00001409func Test_visual_paste()
1410 new
1411
1412 " v_p overwrites unnamed register.
1413 call setline(1, ['xxxx'])
1414 call setreg('"', 'foo')
1415 call setreg('-', 'bar')
zeertzjq6bf821e2022-02-07 10:33:20 +00001416 normal gg0vp
1417 call assert_equal('x', @")
1418 call assert_equal('x', @-)
1419 call assert_equal('fooxxx', getline(1))
1420 normal $vp
1421 call assert_equal('x', @")
1422 call assert_equal('x', @-)
1423 call assert_equal('fooxxx', getline(1))
1424 " Test with a different register as unnamed register.
1425 call setline(2, ['baz'])
1426 normal 2gg0"rD
1427 call assert_equal('baz', @")
1428 normal gg0vp
1429 call assert_equal('f', @")
1430 call assert_equal('f', @-)
1431 call assert_equal('bazooxxx', getline(1))
1432 normal $vp
1433 call assert_equal('x', @")
1434 call assert_equal('x', @-)
1435 call assert_equal('bazooxxf', getline(1))
Shougo Matsushitafb552072022-01-28 16:01:13 +00001436
Shougo Matsushita509142a2022-05-06 11:45:09 +01001437 bwipe!
1438endfunc
1439
1440func Test_visual_paste_clipboard()
1441 CheckFeature clipboard_working
1442
1443 if has('gui')
1444 " auto select feature breaks tests
1445 set guioptions-=a
1446 endif
1447
1448 " v_P does not overwrite unnamed register.
1449 call setline(1, ['xxxx'])
1450 call setreg('"', 'foo')
1451 call setreg('-', 'bar')
1452 normal gg0vP
1453 call assert_equal('foo', @")
1454 call assert_equal('bar', @-)
1455 call assert_equal('fooxxx', getline(1))
1456 normal $vP
1457 call assert_equal('foo', @")
1458 call assert_equal('bar', @-)
1459 call assert_equal('fooxxfoo', getline(1))
1460 " Test with a different register as unnamed register.
1461 call setline(2, ['baz'])
1462 normal 2gg0"rD
1463 call assert_equal('baz', @")
1464 normal gg0vP
1465 call assert_equal('baz', @")
1466 call assert_equal('bar', @-)
1467 call assert_equal('bazooxxfoo', getline(1))
1468 normal $vP
1469 call assert_equal('baz', @")
1470 call assert_equal('bar', @-)
1471 call assert_equal('bazooxxfobaz', getline(1))
1472
1473 " Test for unnamed clipboard
1474 set clipboard=unnamed
1475 call setline(1, ['xxxx'])
1476 call setreg('"', 'foo')
1477 call setreg('-', 'bar')
1478 call setreg('*', 'baz')
1479 normal gg0vP
1480 call assert_equal('foo', @")
1481 call assert_equal('bar', @-)
1482 call assert_equal('baz', @*)
1483 call assert_equal('bazxxx', getline(1))
1484
1485 " Test for unnamedplus clipboard
1486 if has('unnamedplus')
1487 set clipboard=unnamedplus
Shougo Matsushitafb552072022-01-28 16:01:13 +00001488 call setline(1, ['xxxx'])
1489 call setreg('"', 'foo')
1490 call setreg('-', 'bar')
Shougo Matsushita509142a2022-05-06 11:45:09 +01001491 call setreg('+', 'baz')
zeertzjq6bf821e2022-02-07 10:33:20 +00001492 normal gg0vP
1493 call assert_equal('foo', @")
Shougo Matsushita509142a2022-05-06 11:45:09 +01001494 call assert_equal('bar', @-)
1495 call assert_equal('baz', @+)
1496 call assert_equal('bazxxx', getline(1))
Shougo Matsushitafb552072022-01-28 16:01:13 +00001497 endif
1498
Shougo Matsushita509142a2022-05-06 11:45:09 +01001499 set clipboard&
1500 if has('gui')
1501 set guioptions&
1502 endif
Shougo Matsushitafb552072022-01-28 16:01:13 +00001503 bwipe!
1504endfunc
Christian Brabandt544a38e2021-06-10 19:39:11 +02001505
Bram Moolenaar3d51ce12022-07-01 15:26:15 +01001506func Test_visual_area_adjusted_when_hiding()
1507 " The Visual area ended after the end of the line after :hide
1508 call setline(1, 'xxx')
Bram Moolenaarb18b4962022-09-02 21:55:50 +01001509 vsplit Xvaafile
Bram Moolenaar3d51ce12022-07-01 15:26:15 +01001510 call setline(1, 'xxxxxxxx')
1511 norm! $o
1512 hid
1513 norm! zW
1514 bwipe!
1515 bwipe!
1516endfunc
1517
Bram Moolenaarcfeb8a52022-08-13 14:09:44 +01001518func Test_switch_buffer_ends_visual_mode()
1519 enew
1520 call setline(1, 'foo')
1521 set hidden
1522 set virtualedit=all
1523 let buf1 = bufnr()
1524 enew
1525 let buf2 = bufnr()
1526 call setline(1, ['', '', '', ''])
1527 call cursor(4, 5)
1528 call feedkeys("\<C-V>3k4h", 'xt')
1529 exe 'buffer' buf1
1530 call assert_equal('n', mode())
1531
1532 set nohidden
1533 set virtualedit=
1534 bwipe!
1535 exe 'bwipe!' buf2
1536endfunc
1537
Pavel Mayorove1121b12023-02-20 14:35:20 +00001538" Check fix for the heap-based buffer overflow bug found in the function
1539" utfc_ptr2len and reported at
1540" https://huntr.dev/bounties/ae933869-a1ec-402a-bbea-d51764c6618e
1541func Test_heap_buffer_overflow()
1542 enew
1543 set updatecount=0
1544
1545 norm R0
1546 split other
1547 norm R000
1548 exe "norm \<C-V>l"
1549 ball
1550 call assert_equal(getpos("."), getpos("v"))
1551 call assert_equal('n', mode())
1552 norm zW
1553
1554 %bwipe!
1555 set updatecount&
1556endfunc
1557
zeertzjq8fc6a1d2023-08-20 18:12:54 +02001558" Test Visual highlight with cursor at end of screen line and 'showbreak'
1559func Test_visual_hl_with_showbreak()
1560 CheckScreendump
1561
1562 let lines =<< trim END
1563 setlocal showbreak=+
1564 call setline(1, repeat('a', &columns + 10))
1565 normal g$v4lo
1566 END
1567 call writefile(lines, 'XTest_visual_sbr', 'D')
1568
1569 let buf = RunVimInTerminal('-S XTest_visual_sbr', {'rows': 6, 'cols': 50})
1570 call VerifyScreenDump(buf, 'Test_visual_hl_with_showbreak', {})
1571
1572 " clean up
1573 call term_sendkeys(buf, "\<Esc>")
1574 call StopVimInTerminal(buf)
1575endfunc
Pavel Mayorove1121b12023-02-20 14:35:20 +00001576
Christian Brabandt476733f2023-09-19 20:41:51 +02001577func Test_Visual_r_CTRL_C()
1578 new
1579 " visual r_cmd
1580 call setline(1, [' '])
1581 call feedkeys("\<c-v>$r\<c-c>", 'tx')
1582 call assert_equal([''], getline(1, 1))
1583
1584 " visual gr_cmd
1585 call setline(1, [' '])
1586 call feedkeys("\<c-v>$gr\<c-c>", 'tx')
1587 call assert_equal([''], getline(1, 1))
1588 bw!
zeertzjqec149242023-12-19 20:28:31 +01001589endfunc
1590
1591func Test_visual_drag_out_of_window()
1592 rightbelow vnew
1593 call setline(1, '123456789')
1594 set mouse=a
1595 func ClickExpr(off)
1596 call test_setmouse(1, getwininfo(win_getid())[0].wincol + a:off)
1597 return "\<LeftMouse>"
1598 endfunc
1599 func DragExpr(off)
1600 call test_setmouse(1, getwininfo(win_getid())[0].wincol + a:off)
1601 return "\<LeftDrag>"
1602 endfunc
1603
1604 nnoremap <expr> <F2> ClickExpr(5)
1605 nnoremap <expr> <F3> DragExpr(-1)
1606 redraw
1607 call feedkeys("\<F2>\<F3>\<LeftRelease>", 'tx')
1608 call assert_equal([1, 6], [col('.'), col('v')])
1609 call feedkeys("\<Esc>", 'tx')
1610
1611 nnoremap <expr> <F2> ClickExpr(6)
1612 nnoremap <expr> <F3> DragExpr(-2)
1613 redraw
1614 call feedkeys("\<F2>\<F3>\<LeftRelease>", 'tx')
1615 call assert_equal([1, 7], [col('.'), col('v')])
1616 call feedkeys("\<Esc>", 'tx')
1617
1618 nunmap <F2>
1619 nunmap <F3>
1620 delfunc ClickExpr
1621 delfunc DragExpr
1622 set mouse&
1623 bwipe!
1624endfunc
Christian Brabandt476733f2023-09-19 20:41:51 +02001625
Christian Brabandt7c71db32024-01-22 20:12:34 +01001626func Test_visual_substitute_visual()
1627 new
1628 call setline(1, ['one', 'two', 'three'])
1629 call feedkeys("Gk\<C-V>j$:s/\\%V\\_.*\\%V/foobar\<CR>", 'tx')
1630 call assert_equal(['one', 'foobar'], getline(1, '$'))
1631 bwipe!
1632endfunc
1633
zeertzjq701ad502024-05-23 07:47:55 +02001634func Test_virtualedit_exclusive_selection()
1635 new
1636 set virtualedit=all selection=exclusive
1637
1638 call setline(1, "a\tb")
1639 normal! 0v8ly
1640 call assert_equal("a\t", getreg('"'))
1641 normal! 0v6ly
1642 call assert_equal('a ', getreg('"'))
1643 normal! 06lv2ly
1644 call assert_equal(' ', getreg('"'))
1645
1646 set virtualedit& selection&
1647 bwipe!
1648endfunc
1649
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001650func Test_visual_getregion()
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001651 let lines =<< trim END
1652 new
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001653
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001654 call setline(1, ['one', 'two', 'three'])
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001655
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001656 #" Visual mode
1657 call cursor(1, 1)
1658 call feedkeys("\<ESC>vjl", 'tx')
zeertzjqc95e64f2024-05-20 14:00:31 +02001659
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001660 call assert_equal(['one', 'tw'],
1661 \ 'v'->getpos()->getregion(getpos('.')))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001662 call assert_equal([
1663 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
1664 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
1665 \ ],
1666 \ 'v'->getpos()->getregionpos(getpos('.')))
zeertzjqc95e64f2024-05-20 14:00:31 +02001667
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001668 call assert_equal(['one', 'tw'],
1669 \ '.'->getpos()->getregion(getpos('v')))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001670 call assert_equal([
1671 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
1672 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
1673 \ ],
1674 \ '.'->getpos()->getregionpos(getpos('v')))
zeertzjqc95e64f2024-05-20 14:00:31 +02001675
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001676 call assert_equal(['o'],
1677 \ 'v'->getpos()->getregion(getpos('v')))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001678 call assert_equal([
1679 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 1, 0]],
1680 \ ],
1681 \ 'v'->getpos()->getregionpos(getpos('v')))
zeertzjqc95e64f2024-05-20 14:00:31 +02001682
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001683 call assert_equal(['w'],
1684 \ '.'->getpos()->getregion(getpos('.'), {'type': 'v' }))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001685 call assert_equal([
1686 \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 0]],
1687 \ ],
1688 \ '.'->getpos()->getregionpos(getpos('.'), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001689
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001690 call assert_equal(['one', 'two'],
1691 \ getpos('.')->getregion(getpos('v'), {'type': 'V' }))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001692 call assert_equal([
1693 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
1694 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
1695 \ ],
1696 \ getpos('.')->getregionpos(getpos('v'), {'type': 'V' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001697
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001698 call assert_equal(['on', 'tw'],
1699 \ getpos('.')->getregion(getpos('v'), {'type': "\<C-v>" }))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001700 call assert_equal([
1701 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
1702 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]],
1703 \ ],
1704 \ getpos('.')->getregionpos(getpos('v'), {'type': "\<C-v>" }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001705
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001706 #" Line visual mode
1707 call cursor(1, 1)
1708 call feedkeys("\<ESC>Vl", 'tx')
1709 call assert_equal(['one'],
1710 \ getregion(getpos('v'), getpos('.'), {'type': 'V' }))
1711 call assert_equal(['one'],
1712 \ getregion(getpos('.'), getpos('v'), {'type': 'V' }))
1713 call assert_equal(['one'],
1714 \ getregion(getpos('v'), getpos('v'), {'type': 'V' }))
1715 call assert_equal(['one'],
1716 \ getregion(getpos('.'), getpos('.'), {'type': 'V' }))
1717 call assert_equal(['on'],
1718 \ getpos('.')->getregion(getpos('v'), {'type': 'v' }))
1719 call assert_equal(['on'],
1720 \ getpos('.')->getregion(getpos('v'), {'type': "\<C-v>" }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001721
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001722 #" Block visual mode
1723 call cursor(1, 1)
1724 call feedkeys("\<ESC>\<C-v>ll", 'tx')
1725 call assert_equal(['one'],
1726 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
1727 call assert_equal(['one'],
1728 \ getregion(getpos('.'), getpos('v'), {'type': "\<C-v>" }))
1729 call assert_equal(['o'],
1730 \ getregion(getpos('v'), getpos('v'), {'type': "\<C-v>" }))
1731 call assert_equal(['e'],
1732 \ getregion(getpos('.'), getpos('.'), {'type': "\<C-v>" }))
1733 call assert_equal(['one'],
1734 \ '.'->getpos()->getregion(getpos('v'), {'type': 'V' }))
1735 call assert_equal(['one'],
1736 \ '.'->getpos()->getregion(getpos('v'), {'type': 'v' }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001737
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001738 #" Using Marks
1739 call setpos("'a", [0, 2, 3, 0])
1740 call cursor(1, 1)
1741 call assert_equal(['one', 'two'],
1742 \ "'a"->getpos()->getregion(getpos('.'), {'type': 'v' }))
1743 call assert_equal(['one', 'two'],
1744 \ "."->getpos()->getregion(getpos("'a"), {'type': 'v' }))
1745 call assert_equal(['one', 'two'],
1746 \ "."->getpos()->getregion(getpos("'a"), {'type': 'V' }))
1747 call assert_equal(['two'],
1748 \ "'a"->getpos()->getregion(getpos("'a"), {'type': 'V' }))
1749 call assert_equal(['one', 'two'],
1750 \ "."->getpos()->getregion(getpos("'a"), {'type': "\<c-v>" }))
zeertzjq2ffdae72024-05-02 13:06:24 +02001751 call feedkeys("\<ESC>jVj\<ESC>", 'tx')
1752 call assert_equal(['two', 'three'], getregion(getpos("'<"), getpos("'>")))
1753 call assert_equal(['two', 'three'], getregion(getpos("'>"), getpos("'<")))
Shougo Matsushita19b71882024-02-28 22:48:12 +01001754
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001755 #" Using List
1756 call cursor(1, 1)
1757 call assert_equal(['one', 'two'],
1758 \ [0, 2, 3, 0]->getregion(getpos('.'), {'type': 'v' }))
1759 call assert_equal(['one', 'two'],
1760 \ '.'->getpos()->getregion([0, 2, 3, 0], {'type': 'v' }))
1761 call assert_equal(['one', 'two'],
1762 \ '.'->getpos()->getregion([0, 2, 3, 0], {'type': 'V' }))
1763 call assert_equal(['two'],
1764 \ [0, 2, 3, 0]->getregion([0, 2, 3, 0], {'type': 'V' }))
1765 call assert_equal(['one', 'two'],
1766 \ '.'->getpos()->getregion([0, 2, 3, 0], {'type': "\<c-v>" }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001767
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001768 #" Multiline with line visual mode
1769 call cursor(1, 1)
1770 call feedkeys("\<ESC>Vjj", 'tx')
1771 call assert_equal(['one', 'two', 'three'],
1772 \ getregion(getpos('v'), getpos('.'), {'type': 'V' }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001773
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001774 #" Multiline with block visual mode
1775 call cursor(1, 1)
1776 call feedkeys("\<ESC>\<C-v>jj", 'tx')
1777 call assert_equal(['o', 't', 't'],
1778 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001779
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001780 call cursor(1, 1)
1781 call feedkeys("\<ESC>\<C-v>jj$", 'tx')
1782 call assert_equal(['one', 'two', 'three'],
1783 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001784
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001785 #" 'virtualedit'
1786 set virtualedit=all
1787 call cursor(1, 1)
1788 call feedkeys("\<ESC>\<C-v>10ljj$", 'tx')
1789 call assert_equal(['one ', 'two ', 'three '],
1790 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
1791 set virtualedit&
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001792
zeertzjq26dd09a2024-03-10 15:46:58 +01001793 #" using wrong types for positions
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001794 call cursor(1, 1)
1795 call feedkeys("\<ESC>vjj$", 'tx')
1796 call assert_fails("call getregion(1, 2)", 'E1211:')
1797 call assert_fails("call getregion(getpos('.'), {})", 'E1211:')
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001798 call assert_fails(':echo "."->getpos()->getregion("$", [])', 'E1211:')
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001799 call assert_fails("call getregionpos(1, 2)", 'E1211:')
1800 call assert_fails("call getregionpos(getpos('.'), {})", 'E1211:')
1801 call assert_fails(':echo "."->getpos()->getregionpos("$", [])', 'E1211:')
Shougo Matsushita19b71882024-02-28 22:48:12 +01001802
zeertzjq26dd09a2024-03-10 15:46:58 +01001803 #" using invalid value for "type"
1804 call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' })", 'E475:')
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001805 call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' })", 'E475:')
zeertzjq26dd09a2024-03-10 15:46:58 +01001806
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01001807 #" using a mark from another buffer to current buffer
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001808 new
zeertzjq26dd09a2024-03-10 15:46:58 +01001809 LET g:buf = bufnr()
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001810 call setline(1, range(10))
1811 normal! GmA
1812 wincmd p
zeertzjq26dd09a2024-03-10 15:46:58 +01001813 call assert_equal([g:buf, 10, 1, 0], getpos("'A"))
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001814 call assert_equal([], getregion(getpos('.'), getpos("'A"), {'type': 'v' }))
1815 call assert_equal([], getregion(getpos("'A"), getpos('.'), {'type': 'v' }))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001816 call assert_equal([], getregionpos(getpos('.'), getpos("'A"), {'type': 'v' }))
1817 call assert_equal([], getregionpos(getpos("'A"), getpos('.'), {'type': 'v' }))
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01001818
zeertzjq26dd09a2024-03-10 15:46:58 +01001819 #" using two marks from another buffer
1820 wincmd p
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01001821 normal! GmB
1822 wincmd p
zeertzjq26dd09a2024-03-10 15:46:58 +01001823 call assert_equal([g:buf, 10, 1, 0], getpos("'B"))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001824 call assert_equal(['9'],
1825 \ getregion(getpos("'B"), getpos("'A"), {'type': 'v' }))
1826 call assert_equal([
1827 \ [[g:buf, 10, 1, 0], [g:buf, 10, 1, 0]],
1828 \ ],
1829 \ getregionpos(getpos("'B"), getpos("'A"), {'type': 'v' }))
zeertzjq26dd09a2024-03-10 15:46:58 +01001830
1831 #" using two positions from another buffer
1832 for type in ['v', 'V', "\<C-V>"]
1833 for exclusive in [v:false, v:true]
1834 call assert_equal(range(10)->mapnew('string(v:val)'),
zeertzjq5406eb82024-03-11 21:36:42 +01001835 \ getregion([g:buf, 1, 1, 0], [g:buf, 10, 2, 0],
1836 \ {'type': type, 'exclusive': exclusive }))
zeertzjq26dd09a2024-03-10 15:46:58 +01001837 call assert_equal(range(10)->mapnew('string(v:val)'),
zeertzjq5406eb82024-03-11 21:36:42 +01001838 \ getregion([g:buf, 10, 2, 0], [g:buf, 1, 1, 0],
1839 \ {'type': type, 'exclusive': exclusive }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001840 call assert_equal(range(1, 10)->mapnew('repeat([[g:buf, v:val, 1, 0]], 2)'),
1841 \ getregionpos([g:buf, 1, 1, 0], [g:buf, 10, 2, 0],
1842 \ {'type': type, 'exclusive': exclusive }))
1843 call assert_equal(range(1, 10)->mapnew('repeat([[g:buf, v:val, 1, 0]], 2)'),
1844 \ getregionpos([g:buf, 10, 2, 0], [g:buf, 1, 1, 0],
1845 \ {'type': type, 'exclusive': exclusive }))
zeertzjq26dd09a2024-03-10 15:46:58 +01001846 endfor
1847 endfor
1848
1849 #" using invalid positions in buffer
1850 call assert_fails('call getregion([g:buf, 0, 1, 0], [g:buf, 10, 2, 0])', 'E966:')
1851 call assert_fails('call getregion([g:buf, 10, 2, 0], [g:buf, 0, 1, 0])', 'E966:')
1852 call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 11, 2, 0])', 'E966:')
1853 call assert_fails('call getregion([g:buf, 11, 2, 0], [g:buf, 1, 1, 0])', 'E966:')
1854 call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 10, 0, 0])', 'E964:')
1855 call assert_fails('call getregion([g:buf, 10, 0, 0], [g:buf, 1, 1, 0])', 'E964:')
1856 call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 10, 3, 0])', 'E964:')
1857 call assert_fails('call getregion([g:buf, 10, 3, 0], [g:buf, 1, 1, 0])', 'E964:')
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001858 call assert_fails('call getregion([g:buf, 1, 0, 0], [g:buf, 1, 1, 0])', 'E964:')
1859 call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 1, 0, 0])', 'E964:')
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01001860
1861 #" using invalid buffer
zeertzjq26dd09a2024-03-10 15:46:58 +01001862 call assert_fails('call getregion([10000, 10, 1, 0], [10000, 10, 1, 0])', 'E681:')
1863
1864 exe $':{g:buf}bwipe!'
1865 unlet g:buf
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001866 END
1867 call v9.CheckLegacyAndVim9Success(lines)
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001868
1869 bwipe!
1870
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001871 let lines =<< trim END
1872 #" Selection in starts or ends in the middle of a multibyte character
1873 new
1874 call setline(1, [
1875 \ "abcdefghijk\u00ab",
1876 \ "\U0001f1e6\u00ab\U0001f1e7\u00ab\U0001f1e8\u00ab\U0001f1e9",
1877 \ "1234567890"
1878 \ ])
zeertzjqc95e64f2024-05-20 14:00:31 +02001879
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001880 call cursor(1, 3)
1881 call feedkeys("\<Esc>\<C-v>ljj", 'xt')
1882 call assert_equal(['cd', "\u00ab ", '34'],
1883 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001884 call assert_equal([
1885 \ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 4, 0]],
1886 \ [[bufnr('%'), 2, 5, 0], [bufnr('%'), 2, 7, 1]],
1887 \ [[bufnr('%'), 3, 3, 0], [bufnr('%'), 3, 4, 0]],
1888 \ ],
1889 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
1890
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001891 call cursor(1, 4)
1892 call feedkeys("\<Esc>\<C-v>ljj", 'xt')
1893 call assert_equal(['de', "\U0001f1e7", '45'],
1894 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001895 call assert_equal([
1896 \ [[bufnr('%'), 1, 4, 0], [bufnr('%'), 1, 5, 0]],
1897 \ [[bufnr('%'), 2, 7, 0], [bufnr('%'), 2, 10, 0]],
1898 \ [[bufnr('%'), 3, 4, 0], [bufnr('%'), 3, 5, 0]],
1899 \ ],
1900 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
1901
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001902 call cursor(1, 5)
1903 call feedkeys("\<Esc>\<C-v>jj", 'xt')
1904 call assert_equal(['e', ' ', '5'],
1905 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001906 call assert_equal([
zeertzjqc95e64f2024-05-20 14:00:31 +02001907 \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 5, 0]],
zeertzjq52a6f342024-05-22 16:42:44 +02001908 \ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 2]],
zeertzjqc95e64f2024-05-20 14:00:31 +02001909 \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 5, 0]],
1910 \ ],
1911 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
1912 call assert_equal([
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001913 \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 13, 0]],
1914 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 22, 0]],
1915 \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 5, 0]],
1916 \ ],
1917 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001918
zeertzjq52a6f342024-05-22 16:42:44 +02001919 #" characterwise selection with multibyte chars
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001920 call cursor(1, 1)
1921 call feedkeys("\<Esc>vj", 'xt')
1922 call assert_equal(['abcdefghijk«', "\U0001f1e6"],
1923 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001924 call assert_equal([
1925 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 13, 0]],
1926 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 4, 0]],
1927 \ ],
1928 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
Shougo Matsushita19b71882024-02-28 22:48:12 +01001929
zeertzjq52a6f342024-05-22 16:42:44 +02001930 set selection=exclusive
1931 call feedkeys('l', 'xt')
1932 call assert_equal(['abcdefghijk«', "\U0001f1e6"],
1933 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
1934 call assert_equal([
1935 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 13, 0]],
1936 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 4, 0]],
1937 \ ],
1938 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
1939
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001940 #" marks on multibyte chars
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001941 call setpos("'a", [0, 1, 11, 0])
1942 call setpos("'b", [0, 2, 16, 0])
1943 call setpos("'c", [0, 2, 0, 0])
1944 call cursor(1, 1)
zeertzjqc95e64f2024-05-20 14:00:31 +02001945
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001946 call assert_equal(['ghijk', '🇨«🇩'],
Shougo Matsushitab4757e62024-05-07 20:49:24 +02001947 \ getregion(getpos("'a"), getpos("'b"), {'type': "\<C-v>" }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001948 call assert_equal([
1949 \ [[bufnr('%'), 1, 7, 0], [bufnr('%'), 1, 11, 0]],
1950 \ [[bufnr('%'), 2, 13, 0], [bufnr('%'), 2, 22, 0]],
1951 \ ],
1952 \ getregionpos(getpos("'a"), getpos("'b"), {'type': "\<C-v>" }))
1953
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001954 call assert_equal(['k«', '🇦«🇧«🇨'],
1955 \ getregion(getpos("'a"), getpos("'b"), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001956 call assert_equal([
1957 \ [[bufnr('%'), 1, 11, 0], [bufnr('%'), 1, 13, 0]],
1958 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 16, 0]],
1959 \ ],
1960 \ getregionpos(getpos("'a"), getpos("'b"), {'type': 'v' }))
1961
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001962 call assert_equal(['k«'],
1963 \ getregion(getpos("'a"), getpos("'c"), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02001964 call assert_equal([
1965 \ [[bufnr('%'), 1, 11, 0], [bufnr('%'), 1, 13, 0]],
1966 \ ],
1967 \ getregionpos(getpos("'a"), getpos("'c"), {'type': 'v' }))
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001968
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001969 #" use inclusive selection, although 'selection' is exclusive
1970 call setpos("'a", [0, 1, 11, 0])
1971 call setpos("'b", [0, 1, 1, 0])
1972 call assert_equal(['abcdefghijk'],
1973 \ getregion(getpos("'a"), getpos("'b"),
1974 \ {'type': "\<c-v>", 'exclusive': v:false }))
1975 call assert_equal(['abcdefghij'],
1976 \ getregion(getpos("'a"), getpos("'b"),
1977 \ {'type': "\<c-v>", 'exclusive': v:true }))
1978 call assert_equal(['abcdefghijk'],
1979 \ getregion(getpos("'a"), getpos("'b"),
1980 \ {'type': 'v', 'exclusive': 0 }))
1981 call assert_equal(['abcdefghij'],
1982 \ getregion(getpos("'a"), getpos("'b"),
1983 \ {'type': 'v', 'exclusive': 1 }))
1984 call assert_equal(['abcdefghijk«'],
1985 \ getregion(getpos("'a"), getpos("'b"),
1986 \ {'type': 'V', 'exclusive': 0 }))
1987 call assert_equal(['abcdefghijk«'],
1988 \ getregion(getpos("'a"), getpos("'b"),
1989 \ {'type': 'V', 'exclusive': 1 }))
1990 :set selection&
1991 END
1992 call v9.CheckLegacyAndVim9Success(lines)
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01001993
1994 bwipe!
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01001995
1996 let lines =<< trim END
1997 #" Exclusive selection
1998 new
1999 set selection=exclusive
2000 call setline(1, ["a\tc", "x\tz", '', ''])
2001 call cursor(1, 1)
2002 call feedkeys("\<Esc>v2l", 'xt')
2003 call assert_equal(["a\t"],
2004 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2005 call cursor(1, 1)
2006 call feedkeys("\<Esc>v$G", 'xt')
2007 call assert_equal(["a\tc", "x\tz", ''],
2008 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2009 call cursor(1, 1)
2010 call feedkeys("\<Esc>v$j", 'xt')
2011 call assert_equal(["a\tc", "x\tz"],
2012 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2013 call cursor(1, 1)
2014 call feedkeys("\<Esc>\<C-v>$j", 'xt')
2015 call assert_equal(["a\tc", "x\tz"],
2016 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2017 call cursor(1, 1)
2018 call feedkeys("\<Esc>\<C-v>$G", 'xt')
2019 call assert_equal(["a", "x", '', ''],
2020 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2021 call cursor(1, 1)
2022 call feedkeys("\<Esc>wv2j", 'xt')
2023 call assert_equal(["c", "x\tz"],
2024 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2025 set selection&
zeertzjq52a6f342024-05-22 16:42:44 +02002026 bwipe!
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002027
2028 #" Exclusive selection 2
2029 new
2030 call setline(1, ["a\tc", "x\tz", '', ''])
zeertzjq701ad502024-05-23 07:47:55 +02002031
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002032 call cursor(1, 1)
2033 call feedkeys("\<Esc>v2l", 'xt')
2034 call assert_equal(["a\t"],
2035 \ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
zeertzjq701ad502024-05-23 07:47:55 +02002036 call assert_equal([
2037 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
2038 \ ],
2039 \ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
2040
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002041 call cursor(1, 1)
2042 call feedkeys("\<Esc>v$G", 'xt')
2043 call assert_equal(["a\tc", "x\tz", ''],
2044 \ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
zeertzjq701ad502024-05-23 07:47:55 +02002045 call assert_equal([
2046 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2047 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
2048 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 0]],
2049 \ ],
2050 \ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
2051
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002052 call cursor(1, 1)
2053 call feedkeys("\<Esc>v$j", 'xt')
2054 call assert_equal(["a\tc", "x\tz"],
2055 \ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
zeertzjq701ad502024-05-23 07:47:55 +02002056 call assert_equal([
2057 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2058 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
2059 \ ],
2060 \ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
2061
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002062 call cursor(1, 1)
2063 call feedkeys("\<Esc>\<C-v>$j", 'xt')
2064 call assert_equal(["a\tc", "x\tz"],
2065 \ getregion(getpos('v'), getpos('.'),
2066 \ {'exclusive': v:true, 'type': "\<C-v>" }))
zeertzjq701ad502024-05-23 07:47:55 +02002067 call assert_equal([
2068 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2069 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
2070 \ ],
2071 \ getregionpos(getpos('v'), getpos('.'),
2072 \ {'exclusive': v:true, 'type': "\<C-v>" }))
2073
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002074 call cursor(1, 1)
2075 call feedkeys("\<Esc>\<C-v>$G", 'xt')
2076 call assert_equal(["a", "x", '', ''],
2077 \ getregion(getpos('v'), getpos('.'),
2078 \ {'exclusive': v:true, 'type': "\<C-v>" }))
zeertzjq701ad502024-05-23 07:47:55 +02002079 call assert_equal([
2080 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 1, 0]],
2081 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 1, 0]],
2082 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 0]],
2083 \ [[bufnr('%'), 4, 0, 0], [bufnr('%'), 4, 0, 0]],
2084 \ ],
2085 \ getregionpos(getpos('v'), getpos('.'),
2086 \ {'exclusive': v:true, 'type': "\<C-v>" }))
2087
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002088 call cursor(1, 1)
2089 call feedkeys("\<Esc>wv2j", 'xt')
2090 call assert_equal(["c", "x\tz"],
2091 \ getregion(getpos('v'), getpos('.'), {'exclusive': v:true }))
zeertzjq701ad502024-05-23 07:47:55 +02002092 call assert_equal([
2093 \ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 3, 0]],
2094 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
2095 \ ],
2096 \ getregionpos(getpos('v'), getpos('.'), {'exclusive': v:true }))
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002097
zeertzjq701ad502024-05-23 07:47:55 +02002098 #" 'virtualedit' with exclusive selection
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002099 set selection=exclusive
2100 set virtualedit=all
zeertzjqc95e64f2024-05-20 14:00:31 +02002101
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002102 call cursor(1, 1)
zeertzjq701ad502024-05-23 07:47:55 +02002103 call feedkeys("\<Esc>vj", 'xt')
2104 call assert_equal(["a\tc"],
2105 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2106 call assert_equal([
2107 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2108 \ ],
2109 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2110
2111 call cursor(1, 1)
2112 call feedkeys("\<Esc>v8l", 'xt')
2113 call assert_equal(["a\t"],
2114 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2115 call assert_equal([
2116 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
2117 \ ],
2118 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2119
2120 call cursor(1, 1)
2121 call feedkeys("\<Esc>v6l", 'xt')
2122 call assert_equal(['a '],
2123 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2124 call assert_equal([
2125 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 5]],
2126 \ ],
2127 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2128
2129 call cursor(1, 1)
2130 call feedkeys("\<Esc>6lv2l", 'xt')
2131 call assert_equal([' '],
2132 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2133 call assert_equal([
2134 \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 0]],
2135 \ ],
2136 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2137
2138 call cursor(1, 1)
zeertzjq52a6f342024-05-22 16:42:44 +02002139 call feedkeys("\<Esc>lv2l", 'xt')
2140 call assert_equal([' '],
2141 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2142 call assert_equal([
2143 \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 2]],
2144 \ ],
2145 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2146
2147 call cursor(1, 1)
2148 call feedkeys("\<Esc>2lv2l", 'xt')
2149 call assert_equal([' '],
2150 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2151 call assert_equal([
2152 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 3]],
2153 \ ],
2154 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2155
2156 call feedkeys('j', 'xt')
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002157 call assert_equal([' c', 'x '],
2158 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
zeertzjqc95e64f2024-05-20 14:00:31 +02002159 call assert_equal([
2160 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 3, 0]],
2161 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 3]],
2162 \ ],
2163 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2164
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002165 call cursor(1, 1)
zeertzjq52a6f342024-05-22 16:42:44 +02002166 call feedkeys("\<Esc>6l\<C-v>2lj", 'xt')
2167 call assert_equal([' ', ' '],
2168 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2169 call assert_equal([
2170 \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 7]],
2171 \ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 2, 7]],
2172 \ ],
2173 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2174
2175 call cursor(1, 1)
2176 call feedkeys("\<Esc>l\<C-v>2l2j", 'xt')
2177 call assert_equal([' ', ' ', ' '],
2178 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2179 call assert_equal([
2180 \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 2]],
2181 \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 2]],
2182 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 2]],
2183 \ ],
2184 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2185
2186 call cursor(1, 1)
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002187 call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt')
2188 call assert_equal([' ', ' ', ' '],
2189 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
zeertzjqc95e64f2024-05-20 14:00:31 +02002190 call assert_equal([
zeertzjq52a6f342024-05-22 16:42:44 +02002191 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 3]],
2192 \ [[bufnr('%'), 2, 2, 1], [bufnr('%'), 2, 2, 3]],
zeertzjqc95e64f2024-05-20 14:00:31 +02002193 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 2]],
2194 \ ],
2195 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2196
zeertzjq701ad502024-05-23 07:47:55 +02002197 #" 'virtualedit' with inclusive selection
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002198 set selection&
2199
zeertzjq701ad502024-05-23 07:47:55 +02002200 call cursor(1, 1)
2201 call feedkeys("\<Esc>vj", 'xt')
2202 call assert_equal(["a\tc", 'x'],
2203 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2204 call assert_equal([
2205 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2206 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 1, 0]],
2207 \ ],
2208 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2209
2210 call cursor(1, 1)
2211 call feedkeys("\<Esc>v8l", 'xt')
2212 call assert_equal(["a\tc"],
2213 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2214 call assert_equal([
2215 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
2216 \ ],
2217 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2218
2219 call cursor(1, 1)
2220 call feedkeys("\<Esc>v6l", 'xt')
2221 call assert_equal(['a '],
2222 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2223 call assert_equal([
2224 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 6]],
2225 \ ],
2226 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2227
2228 call cursor(1, 1)
2229 call feedkeys("\<Esc>6lv2l", 'xt')
2230 call assert_equal([' c'],
2231 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2232 call assert_equal([
2233 \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 3, 0]],
2234 \ ],
2235 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2236
2237 call cursor(1, 1)
2238 call feedkeys("\<Esc>lv2l", 'xt')
2239 call assert_equal([' '],
2240 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2241 call assert_equal([
2242 \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 3]],
2243 \ ],
2244 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2245
2246 call cursor(1, 1)
2247 call feedkeys("\<Esc>2lv2l", 'xt')
2248 call assert_equal([' '],
2249 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2250 call assert_equal([
2251 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 4]],
2252 \ ],
2253 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2254
2255 call feedkeys('j', 'xt')
2256 call assert_equal([' c', 'x '],
2257 \ getregion(getpos('v'), getpos('.'), {'type': 'v' }))
2258 call assert_equal([
2259 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 3, 0]],
2260 \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 4]],
2261 \ ],
2262 \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
2263
2264 call cursor(1, 1)
2265 call feedkeys("\<Esc>6l\<C-v>2lj", 'xt')
2266 call assert_equal([' c', ' z'],
2267 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2268 call assert_equal([
2269 \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 3, 0]],
2270 \ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 3, 0]],
2271 \ ],
2272 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2273
2274 call cursor(1, 1)
2275 call feedkeys("\<Esc>l\<C-v>2l2j", 'xt')
2276 call assert_equal([' ', ' ', ' '],
2277 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2278 call assert_equal([
2279 \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 3]],
2280 \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 3]],
2281 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 3]],
2282 \ ],
2283 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2284
2285 call cursor(1, 1)
2286 call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt')
2287 call assert_equal([' ', ' ', ' '],
2288 \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2289 call assert_equal([
2290 \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 4]],
2291 \ [[bufnr('%'), 2, 2, 1], [bufnr('%'), 2, 2, 4]],
2292 \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 3]],
2293 \ ],
2294 \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
2295
2296 set virtualedit&
Yegappan Lakshmanan4d55c542024-02-29 17:30:43 +01002297 bwipe!
2298 END
2299 call v9.CheckLegacyAndVim9Success(lines)
Shougo Matsushita3f905ab2024-02-21 00:02:45 +01002300endfunc
2301
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01002302func Test_getregion_invalid_buf()
2303 new
2304 help
2305 call cursor(5, 7)
2306 norm! mA
2307 call cursor(5, 18)
2308 norm! mB
2309 call assert_equal(['Move around:'], getregion(getpos("'A"), getpos("'B")))
2310 " close the help window
2311 q
zeertzjq26dd09a2024-03-10 15:46:58 +01002312 call assert_fails("call getregion(getpos(\"'A\"), getpos(\"'B\"))", 'E681:')
Shougo Matsushita84bf6e62024-03-06 21:10:18 +01002313 bwipe!
2314endfunc
2315
Shougo Matsushitab4757e62024-05-07 20:49:24 +02002316func Test_getregion_maxcol()
2317 new
2318 autocmd TextYankPost *
2319 \ : if v:event.operator ==? 'y'
2320 \ | call assert_equal([
2321 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
2322 \ ],
2323 \ getregionpos(getpos("'["), getpos("']"),
2324 \ #{ mode: visualmode() }))
2325 \ | call assert_equal(['abcd'],
2326 \ getregion(getpos("'["), getpos("']"),
2327 \ #{ mode: visualmode() }))
2328 \ | call assert_equal([
2329 \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
2330 \ ],
2331 \ getregionpos(getpos("']"), getpos("'["),
2332 \ #{ mode: visualmode() }))
2333 \ | call assert_equal(['abcd'],
2334 \ getregion(getpos("']"), getpos("'["),
2335 \ #{ mode: visualmode() }))
2336 \ | endif
2337 call setline(1, ['abcd', 'efghij'])
2338 normal yy
2339 bwipe!
2340endfunc
2341
Christian Brabandtd5c8c092024-05-08 22:17:19 +02002342func Test_visual_block_cursor_delete()
2343 new
2344 call setline(1, 'ab')
2345 exe ":norm! $\<c-v>hI\<Del>\<ESC>"
2346 call assert_equal(['b'], getline(1, 1))
2347 bwipe!
2348endfunc
2349
Bram Moolenaar6f1f0ca2019-12-01 18:16:18 +01002350" vim: shiftwidth=2 sts=2 expandtab