blob: b25cd60803c354b4ef38518595bdcd2773d2bf67 [file] [log] [blame]
Yegappan Lakshmanan5e877ba2022-03-25 21:19:26 +00001" Tests for the substitute (:s) command
Bram Moolenaarcd055da2016-09-02 19:50:48 +02002
Bram Moolenaar9f6277b2020-02-11 22:04:02 +01003source shared.vim
Bram Moolenaar7a2217b2021-06-06 12:33:49 +02004source check.vim
Bram Moolenaara04f4572022-09-13 13:45:26 +01005source screendump.vim
Bram Moolenaar9f6277b2020-02-11 22:04:02 +01006
Christian Brabandt26c11c52023-11-22 21:26:41 +01007" NOTE: This needs to be the first test to be
8" run in the file, since it depends on
9" that the previous substitution atom
10" was not yet set.
11"
12" recursive call of :s and sub-replace special
13" (did cause heap-use-after free in < v9.0.2121)
14func Test_aaaa_substitute_expr_recursive_special()
15 func R()
16 " FIXME: leaving out the 'n' flag leaks memory, why?
17 %s/./\='.'/gn
18 endfunc
19 new Xfoobar_UAF
20 put ='abcdef'
21 let bufnr = bufnr('%')
22 try
23 silent! :s/./~\=R()/0
24 "call assert_fails(':s/./~\=R()/0', 'E939:')
25 let @/='.'
26 ~g
27 catch /^Vim\%((\a\+)\)\=:E565:/
28 endtry
29 delfunc R
30 exe bufnr .. "bw!"
31endfunc
32
Bram Moolenaar1e115362019-01-09 23:01:02 +010033func Test_multiline_subst()
Bram Moolenaarcd055da2016-09-02 19:50:48 +020034 enew!
35 call append(0, ["1 aa",
36 \ "bb",
37 \ "cc",
38 \ "2 dd",
39 \ "ee",
40 \ "3 ef",
41 \ "gh",
42 \ "4 ij",
43 \ "5 a8",
44 \ "8b c9",
45 \ "9d",
46 \ "6 e7",
47 \ "77f",
48 \ "xxxxx"])
49
50 1
51 " test if replacing a line break works with a back reference
52 /^1/,/^2/s/\n\(.\)/ \1/
53 " test if inserting a line break works with a back reference
54 /^3/,/^4/s/\(.\)$/\r\1/
55 " test if replacing a line break with another line break works
56 /^5/,/^6/s/\(\_d\{3}\)/x\1x/
57 call assert_equal('1 aa bb cc 2 dd ee', getline(1))
58 call assert_equal('3 e', getline(2))
59 call assert_equal('f', getline(3))
60 call assert_equal('g', getline(4))
61 call assert_equal('h', getline(5))
62 call assert_equal('4 i', getline(6))
63 call assert_equal('j', getline(7))
64 call assert_equal('5 ax8', getline(8))
65 call assert_equal('8xb cx9', getline(9))
66 call assert_equal('9xd', getline(10))
67 call assert_equal('6 ex7', getline(11))
68 call assert_equal('7x7f', getline(12))
69 call assert_equal('xxxxx', getline(13))
70 enew!
Bram Moolenaar1e115362019-01-09 23:01:02 +010071endfunc
Bram Moolenaar8c50d502017-02-17 18:28:24 +010072
Bram Moolenaar1e115362019-01-09 23:01:02 +010073func Test_substitute_variants()
Bram Moolenaar8c50d502017-02-17 18:28:24 +010074 " Validate that all the 2-/3-letter variants which embed the flags into the
75 " command name actually work.
76 enew!
77 let ln = 'Testing string'
78 let variants = [
79 \ { 'cmd': ':s/Test/test/c', 'exp': 'testing string', 'prompt': 'y' },
80 \ { 'cmd': ':s/foo/bar/ce', 'exp': ln },
81 \ { 'cmd': ':s/t/r/cg', 'exp': 'Tesring srring', 'prompt': 'a' },
82 \ { 'cmd': ':s/t/r/ci', 'exp': 'resting string', 'prompt': 'y' },
83 \ { 'cmd': ':s/t/r/cI', 'exp': 'Tesring string', 'prompt': 'y' },
Bram Moolenaarea3db912020-02-02 15:32:13 +010084 \ { 'cmd': ':s/t/r/c', 'exp': 'Testing string', 'prompt': 'n' },
Bram Moolenaar8c50d502017-02-17 18:28:24 +010085 \ { 'cmd': ':s/t/r/cn', 'exp': ln },
86 \ { 'cmd': ':s/t/r/cp', 'exp': 'Tesring string', 'prompt': 'y' },
87 \ { 'cmd': ':s/t/r/cl', 'exp': 'Tesring string', 'prompt': 'y' },
88 \ { 'cmd': ':s/t/r/gc', 'exp': 'Tesring srring', 'prompt': 'a' },
Bram Moolenaarea3db912020-02-02 15:32:13 +010089 \ { 'cmd': ':s/i/I/gc', 'exp': 'TestIng string', 'prompt': 'l' },
Bram Moolenaar8c50d502017-02-17 18:28:24 +010090 \ { 'cmd': ':s/foo/bar/ge', 'exp': ln },
91 \ { 'cmd': ':s/t/r/g', 'exp': 'Tesring srring' },
92 \ { 'cmd': ':s/t/r/gi', 'exp': 'resring srring' },
93 \ { 'cmd': ':s/t/r/gI', 'exp': 'Tesring srring' },
94 \ { 'cmd': ':s/t/r/gn', 'exp': ln },
95 \ { 'cmd': ':s/t/r/gp', 'exp': 'Tesring srring' },
96 \ { 'cmd': ':s/t/r/gl', 'exp': 'Tesring srring' },
97 \ { 'cmd': ':s//r/gr', 'exp': 'Testr strr' },
98 \ { 'cmd': ':s/t/r/ic', 'exp': 'resting string', 'prompt': 'y' },
99 \ { 'cmd': ':s/foo/bar/ie', 'exp': ln },
100 \ { 'cmd': ':s/t/r/i', 'exp': 'resting string' },
101 \ { 'cmd': ':s/t/r/iI', 'exp': 'Tesring string' },
102 \ { 'cmd': ':s/t/r/in', 'exp': ln },
103 \ { 'cmd': ':s/t/r/ip', 'exp': 'resting string' },
104 \ { 'cmd': ':s//r/ir', 'exp': 'Testr string' },
105 \ { 'cmd': ':s/t/r/Ic', 'exp': 'Tesring string', 'prompt': 'y' },
106 \ { 'cmd': ':s/foo/bar/Ie', 'exp': ln },
107 \ { 'cmd': ':s/t/r/Ig', 'exp': 'Tesring srring' },
108 \ { 'cmd': ':s/t/r/Ii', 'exp': 'resting string' },
109 \ { 'cmd': ':s/t/r/I', 'exp': 'Tesring string' },
110 \ { 'cmd': ':s/t/r/Ip', 'exp': 'Tesring string' },
111 \ { 'cmd': ':s/t/r/Il', 'exp': 'Tesring string' },
112 \ { 'cmd': ':s//r/Ir', 'exp': 'Testr string' },
113 \ { 'cmd': ':s//r/rc', 'exp': 'Testr string', 'prompt': 'y' },
114 \ { 'cmd': ':s//r/rg', 'exp': 'Testr strr' },
115 \ { 'cmd': ':s//r/ri', 'exp': 'Testr string' },
116 \ { 'cmd': ':s//r/rI', 'exp': 'Testr string' },
117 \ { 'cmd': ':s//r/rn', 'exp': 'Testing string' },
118 \ { 'cmd': ':s//r/rp', 'exp': 'Testr string' },
119 \ { 'cmd': ':s//r/rl', 'exp': 'Testr string' },
120 \ { 'cmd': ':s//r/r', 'exp': 'Testr string' },
Bram Moolenaarea3db912020-02-02 15:32:13 +0100121 \ { 'cmd': ':s/i/I/gc', 'exp': 'Testing string', 'prompt': 'q' },
Bram Moolenaar8c50d502017-02-17 18:28:24 +0100122 \]
123
124 for var in variants
125 for run in [1, 2]
126 let cmd = var.cmd
127 if run == 2 && cmd =~ "/.*/.*/."
128 " Change :s/from/to/{flags} to :s{flags}
129 let cmd = substitute(cmd, '/.*/', '', '')
130 endif
131 call setline(1, [ln])
132 let msg = printf('using "%s"', cmd)
133 let @/='ing'
134 let v:errmsg = ''
135 call feedkeys(cmd . "\<CR>" . get(var, 'prompt', ''), 'ntx')
136 " No error should exist (matters for testing e flag)
137 call assert_equal('', v:errmsg, msg)
138 call assert_equal(var.exp, getline('.'), msg)
139 endfor
140 endfor
Bram Moolenaar1e115362019-01-09 23:01:02 +0100141endfunc
Bram Moolenaarba748c82017-02-26 14:00:07 +0100142
Bram Moolenaar94747162019-02-10 21:55:26 +0100143" Test the l, p, # flags.
144func Test_substitute_flags_lp()
145 new
146 call setline(1, "abc\tdef\<C-h>ghi")
147
148 let a = execute('s/a/a/p')
149 call assert_equal("\nabc def^Hghi", a)
150
151 let a = execute('s/a/a/l')
152 call assert_equal("\nabc^Idef^Hghi$", a)
153
154 let a = execute('s/a/a/#')
155 call assert_equal("\n 1 abc def^Hghi", a)
156
157 let a = execute('s/a/a/p#')
158 call assert_equal("\n 1 abc def^Hghi", a)
159
160 let a = execute('s/a/a/l#')
161 call assert_equal("\n 1 abc^Idef^Hghi$", a)
162
163 let a = execute('s/a/a/')
164 call assert_equal("", a)
165
166 bwipe!
167endfunc
168
Bram Moolenaarba748c82017-02-26 14:00:07 +0100169func Test_substitute_repeat()
170 " This caused an invalid memory access.
Bram Moolenaarb18b4962022-09-02 21:55:50 +0100171 split Xsubfile
Bram Moolenaarba748c82017-02-26 14:00:07 +0100172 s/^/x
173 call feedkeys("Qsc\<CR>y", 'tx')
174 bwipe!
175endfunc
zeertzjq789679c2024-05-23 17:41:26 +0200176
zeertzjq30741372024-05-24 07:37:36 +0200177" Test :s with ? as delimiter.
178func Test_substitute_question_delimiter()
zeertzjq789679c2024-05-23 17:41:26 +0200179 new
180 call setline(1, '??:??')
181 %s?\?\??!!?g
182 call assert_equal('!!:!!', getline(1))
183 bwipe!
184endfunc
185
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100186" Test %s/\n// which is implemented as a special case to use a
187" more efficient join rather than doing a regular substitution.
188func Test_substitute_join()
189 new
190
191 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
192 let a = execute('%s/\n//')
193 call assert_equal("", a)
194 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
195 call assert_equal('\n', histget("search", -1))
196
197 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
198 let a = execute('%s/\n//g')
199 call assert_equal("", a)
200 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
201 call assert_equal('\n', histget("search", -1))
202
203 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
204 let a = execute('%s/\n//p')
205 call assert_equal("\nfoo barbar^Hfoo", a)
206 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
207 call assert_equal('\n', histget("search", -1))
208
209 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
210 let a = execute('%s/\n//l')
211 call assert_equal("\nfoo^Ibarbar^Hfoo$", a)
212 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
213 call assert_equal('\n', histget("search", -1))
214
215 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
216 let a = execute('%s/\n//#')
217 call assert_equal("\n 1 foo barbar^Hfoo", a)
218 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
219 call assert_equal('\n', histget("search", -1))
220
Bram Moolenaarea3db912020-02-02 15:32:13 +0100221 call setline(1, ['foo', 'bar', 'baz', 'qux'])
222 call execute('1,2s/\n//')
223 call assert_equal(['foobarbaz', 'qux'], getline(1, '$'))
224
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100225 bwipe!
226endfunc
227
228func Test_substitute_count()
229 new
230 call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo'])
231 2
232
233 s/foo/bar/3
234 call assert_equal(['foo foo', 'bar foo', 'bar foo', 'bar foo', 'foo foo'],
235 \ getline(1, '$'))
236
237 call assert_fails('s/foo/bar/0', 'E939:')
238
Bram Moolenaarea3db912020-02-02 15:32:13 +0100239 call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo'])
240 2,4s/foo/bar/ 10
241 call assert_equal(['foo foo', 'foo foo', 'foo foo', 'bar foo', 'bar foo'],
242 \ getline(1, '$'))
243
Christian Brabandtac637872023-11-14 20:45:48 +0100244 call assert_fails('s/./b/2147483647', 'E1510:')
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100245 bwipe!
246endfunc
247
248" Test substitute 'n' flag (report number of matches, do not substitute).
249func Test_substitute_flag_n()
250 new
251 let lines = ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo']
252 call setline(1, lines)
253
254 call assert_equal("\n3 matches on 3 lines", execute('2,4s/foo/bar/n'))
255 call assert_equal("\n6 matches on 3 lines", execute('2,4s/foo/bar/gn'))
256
257 " c flag (confirm) should be ignored when using n flag.
258 call assert_equal("\n3 matches on 3 lines", execute('2,4s/foo/bar/nc'))
259
260 " No substitution should have been done.
261 call assert_equal(lines, getline(1, '$'))
262
Bram Moolenaarea3db912020-02-02 15:32:13 +0100263 %delete _
264 call setline(1, ['A', 'Bar', 'Baz'])
265 call assert_equal("\n1 match on 1 line", execute('s/\nB\@=//gn'))
266
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100267 bwipe!
268endfunc
269
270func Test_substitute_errors()
271 new
272 call setline(1, 'foobar')
273
274 call assert_fails('s/FOO/bar/', 'E486:')
275 call assert_fails('s/foo/bar/@', 'E488:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200276 call assert_fails('s/\(/bar/', 'E54:')
Bram Moolenaar5d98dc22020-01-29 21:57:34 +0100277 call assert_fails('s afooabara', 'E146:')
278 call assert_fails('s\\a', 'E10:')
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100279
280 setl nomodifiable
281 call assert_fails('s/foo/bar/', 'E21:')
282
Bram Moolenaar0e05de42020-03-25 22:23:46 +0100283 call assert_fails("let s=substitute([], 'a', 'A', 'g')", 'E730:')
284 call assert_fails("let s=substitute('abcda', [], 'A', 'g')", 'E730:')
285 call assert_fails("let s=substitute('abcda', 'a', [], 'g')", 'E730:')
286 call assert_fails("let s=substitute('abcda', 'a', 'A', [])", 'E730:')
Bram Moolenaar531be472020-09-23 22:38:05 +0200287 call assert_fails("let s=substitute('abc', '\\%(', 'A', 'g')", 'E53:')
Bram Moolenaar0e05de42020-03-25 22:23:46 +0100288
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100289 bwipe!
290endfunc
291
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200292" Test for *sub-replace-special* and *sub-replace-expression* on substitute().
293func Test_sub_replace_1()
294 " Run the tests with 'magic' on
295 set magic
296 set cpo&
297 call assert_equal('AA', substitute('A', 'A', '&&', ''))
298 call assert_equal('&', substitute('B', 'B', '\&', ''))
299 call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
300 call assert_equal('d', substitute('D', 'D', 'd', ''))
301 call assert_equal('~', substitute('E', 'E', '~', ''))
302 call assert_equal('~', substitute('F', 'F', '\~', ''))
303 call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
304 call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
305 call assert_equal('iI', substitute('I', 'I', '\lII', ''))
306 call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
307 call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
308 call assert_equal("l\<C-V>\<C-M>l",
309 \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
310 call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
311 call assert_equal("n\<C-V>\<C-M>n",
312 \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
313 call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
314 call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
315 call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
316 call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
317 call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
318 call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
319 call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
320 call assert_equal("w\\w", substitute('wWw', 'W', "\\", ''))
321 call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
322 call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
323 call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
Bram Moolenaar004a6782020-04-11 17:09:31 +0200324 " \v or \V after $
325 call assert_equal('abxx', substitute('abcd', 'xy$\v|cd$', 'xx', ''))
326 call assert_equal('abxx', substitute('abcd', 'xy$\V\|cd\$', 'xx', ''))
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200327endfunc
328
329func Test_sub_replace_2()
330 " Run the tests with 'magic' off
331 set nomagic
332 set cpo&
333 call assert_equal('AA', substitute('A', 'A', '&&', ''))
334 call assert_equal('&', substitute('B', 'B', '\&', ''))
335 call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
336 call assert_equal('d', substitute('D', 'D', 'd', ''))
337 call assert_equal('~', substitute('E', 'E', '~', ''))
338 call assert_equal('~', substitute('F', 'F', '\~', ''))
339 call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
340 call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
341 call assert_equal('iI', substitute('I', 'I', '\lII', ''))
342 call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
343 call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
344 call assert_equal("l\<C-V>\<C-M>l",
345 \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
346 call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
347 call assert_equal("n\<C-V>\<C-M>n",
348 \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
349 call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
350 call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
351 call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
352 call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
353 call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
354 call assert_equal("t\<C-M>t", substitute('tTt', 'T', "\r", ''))
355 call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
356 call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
357 call assert_equal('w\w', substitute('wWw', 'W', "\\", ''))
358 call assert_equal('XxxX', substitute('X', 'X', '\L\uxXx\l\EX', ''))
359 call assert_equal('yYYy', substitute('Y', 'Y', '\U\lYyY\u\Ey', ''))
360endfunc
361
362func Test_sub_replace_3()
363 set magic&
364 set cpo&
365 call assert_equal('a\a', substitute('aAa', 'A', '\="\\"', ''))
366 call assert_equal('b\\b', substitute('bBb', 'B', '\="\\\\"', ''))
367 call assert_equal("c\rc", substitute('cCc', 'C', "\\=\"\r\"", ''))
368 call assert_equal("d\\\rd", substitute('dDd', 'D', "\\=\"\\\\\r\"", ''))
369 call assert_equal("e\\\\\re", substitute('eEe', 'E', "\\=\"\\\\\\\\\r\"", ''))
370 call assert_equal('f\rf', substitute('fFf', 'F', '\="\\r"', ''))
371 call assert_equal('j\nj', substitute('jJj', 'J', '\="\\n"', ''))
372 call assert_equal("k\<C-M>k", substitute('kKk', 'K', '\="\r"', ''))
373 call assert_equal("l\nl", substitute('lLl', 'L', '\="\n"', ''))
374endfunc
375
376" Test for submatch() on substitute().
377func Test_sub_replace_4()
378 set magic&
379 set cpo&
380 call assert_equal('a\a', substitute('aAa', 'A',
381 \ '\=substitute(submatch(0), ".", "\\", "")', ''))
382 call assert_equal('b\b', substitute('bBb', 'B',
383 \ '\=substitute(submatch(0), ".", "\\\\", "")', ''))
384 call assert_equal("c\<C-V>\<C-M>c", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\<C-V>\<C-M>", "")', ''))
385 call assert_equal("d\<C-V>\<C-M>d", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\<C-V>\<C-M>", "")', ''))
386 call assert_equal("e\\\<C-V>\<C-M>e", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-M>", "")', ''))
387 call assert_equal("f\<C-M>f", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', ''))
388 call assert_equal("j\nj", substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', ''))
389 call assert_equal("k\rk", substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', ''))
390 call assert_equal("l\nl", substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', ''))
391endfunc
392
393func Test_sub_replace_5()
394 set magic&
395 set cpo&
396 call assert_equal('A123456789987654321', substitute('A123456789',
397 \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
398 \ '\=submatch(0) . submatch(9) . submatch(8) . ' .
399 \ 'submatch(7) . submatch(6) . submatch(5) . ' .
400 \ 'submatch(4) . submatch(3) . submatch(2) . submatch(1)',
401 \ ''))
402 call assert_equal("[['A123456789'], ['9'], ['8'], ['7'], ['6'], " .
403 \ "['5'], ['4'], ['3'], ['2'], ['1']]",
404 \ substitute('A123456789',
405 \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
406 \ '\=string([submatch(0, 1), submatch(9, 1), ' .
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200407 \ 'submatch(8, 1), 7->submatch(1), submatch(6, 1), ' .
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200408 \ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' .
409 \ 'submatch(2, 1), submatch(1, 1)])',
410 \ ''))
411endfunc
412
413func Test_sub_replace_6()
414 set magic&
415 set cpo+=/
416 call assert_equal('a', substitute('A', 'A', 'a', ''))
417 call assert_equal('%', substitute('B', 'B', '%', ''))
418 set cpo-=/
419 call assert_equal('c', substitute('C', 'C', 'c', ''))
420 call assert_equal('%', substitute('D', 'D', '%', ''))
421endfunc
422
423func Test_sub_replace_7()
424 set magic&
425 set cpo&
426 call assert_equal('AA', substitute('AA', 'A.', '\=submatch(0)', ''))
427 call assert_equal("B\nB", substitute("B\nB", 'B.', '\=submatch(0)', ''))
428 call assert_equal("['B\n']B", substitute("B\nB", 'B.', '\=string(submatch(0, 1))', ''))
429 call assert_equal('-abab', substitute('-bb', '\zeb', 'a', 'g'))
430 call assert_equal('c-cbcbc', substitute('-bb', '\ze', 'c', 'g'))
431endfunc
432
433" Test for *:s%* on :substitute.
434func Test_sub_replace_8()
435 new
436 set magic&
437 set cpo&
438 $put =',,X'
439 s/\(^\|,\)\ze\(,\|X\)/\1N/g
440 call assert_equal('N,,NX', getline("$"))
441 $put =',,Y'
442 let cmd = ':s/\(^\|,\)\ze\(,\|Y\)/\1N/gc'
443 call feedkeys(cmd . "\<CR>a", "xt")
444 call assert_equal('N,,NY', getline("$"))
445 :$put =',,Z'
446 let cmd = ':s/\(^\|,\)\ze\(,\|Z\)/\1N/gc'
447 call feedkeys(cmd . "\<CR>yy", "xt")
448 call assert_equal('N,,NZ', getline("$"))
449 enew! | close
450endfunc
451
452func Test_sub_replace_9()
453 new
454 set magic&
455 set cpo&
456 $put ='xxx'
457 call feedkeys(":s/x/X/gc\<CR>yyq", "xt")
458 call assert_equal('XXx', getline("$"))
459 enew! | close
460endfunc
461
462func Test_sub_replace_10()
463 set magic&
464 set cpo&
465 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
466 call assert_equal('aaa', substitute('123', '\zs.', 'a', 'g'))
467 call assert_equal('1a2a3a', substitute('123', '.\zs', 'a', 'g'))
468 call assert_equal('a1a2a3a', substitute('123', '\ze', 'a', 'g'))
469 call assert_equal('a1a2a3', substitute('123', '\ze.', 'a', 'g'))
470 call assert_equal('aaa', substitute('123', '.\ze', 'a', 'g'))
471 call assert_equal('aa2a3a', substitute('123', '1\|\ze', 'a', 'g'))
472 call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g'))
473endfunc
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200474
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100475func SubReplacer(text, submatches)
476 return a:text .. a:submatches[0] .. a:text
477endfunc
zeertzjq48db5da2022-09-16 12:10:03 +0100478func SubReplacerVar(text, ...)
479 return a:text .. a:1[0] .. a:text
480endfunc
zeertzjqabd58d82022-09-16 16:06:32 +0100481def SubReplacerVar9(text: string, ...args: list<list<string>>): string
482 return text .. args[0][0] .. text
483enddef
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100484func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches)
485 return a:t3 .. a:submatches[0] .. a:t11
486endfunc
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100487
488func Test_substitute_partial()
zeertzjq48db5da2022-09-16 12:10:03 +0100489 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g'))
490 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar', ['foo']), 'g'))
zeertzjqabd58d82022-09-16 16:06:32 +0100491 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar9', ['foo']), 'g'))
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100492
zeertzjq48db5da2022-09-16 12:10:03 +0100493 " 19 arguments plus one is just OK
494 let Replacer = function('SubReplacer20', repeat(['foo'], 19))
495 call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g'))
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100496
zeertzjq48db5da2022-09-16 12:10:03 +0100497 " 20 arguments plus one is too many
498 let Replacer = function('SubReplacer20', repeat(['foo'], 20))
499 call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118:')
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100500endfunc
501
Bram Moolenaar7a2217b2021-06-06 12:33:49 +0200502func Test_substitute_float()
Bram Moolenaar7a2217b2021-06-06 12:33:49 +0200503 call assert_equal('number 1.23', substitute('number ', '$', { -> 1.23 }, ''))
504 vim9 assert_equal('number 1.23', substitute('number ', '$', () => 1.23, ''))
505endfunc
506
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200507" Tests for *sub-replace-special* and *sub-replace-expression* on :substitute.
508
509" Execute a list of :substitute command tests
510func Run_SubCmd_Tests(tests)
511 enew!
512 for t in a:tests
513 let start = line('.') + 1
514 let end = start + len(t[2]) - 1
515 exe "normal o" . t[0]
516 call cursor(start, 1)
517 exe t[1]
518 call assert_equal(t[2], getline(start, end), t[1])
519 endfor
520 enew!
521endfunc
522
523func Test_sub_cmd_1()
524 set magic
525 set cpo&
526
527 " List entry format: [input, cmd, output]
528 let tests = [['A', 's/A/&&/', ['AA']],
529 \ ['B', 's/B/\&/', ['&']],
530 \ ['C123456789', 's/C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
531 \ ['D', 's/D/d/', ['d']],
532 \ ['E', 's/E/~/', ['d']],
533 \ ['F', 's/F/\~/', ['~']],
534 \ ['G', 's/G/\ugg/', ['Gg']],
535 \ ['H', 's/H/\Uh\Eh/', ['Hh']],
536 \ ['I', 's/I/\lII/', ['iI']],
537 \ ['J', 's/J/\LJ\EJ/', ['jJ']],
538 \ ['K', 's/K/\Uk\ek/', ['Kk']],
539 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
540 \ ['mMm', 's/M/\r/', ['m', 'm']],
541 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
542 \ ['oOo', 's/O/\n/', ["o\no"]],
543 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
544 \ ['qQq', 's/Q/\t/', ["q\tq"]],
545 \ ['rRr', 's/R/\\/', ['r\r']],
546 \ ['sSs', 's/S/\c/', ['scs']],
547 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
548 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
zeertzjq3269efd2022-06-12 11:13:05 +0100549 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
550 \ ['\', 's/\\/\\\\/', ['\\']]
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200551 \ ]
552 call Run_SubCmd_Tests(tests)
553endfunc
554
555func Test_sub_cmd_2()
556 set nomagic
557 set cpo&
558
559 " List entry format: [input, cmd, output]
560 let tests = [['A', 's/A/&&/', ['&&']],
561 \ ['B', 's/B/\&/', ['B']],
562 \ ['C123456789', 's/\mC\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
563 \ ['D', 's/D/d/', ['d']],
564 \ ['E', 's/E/~/', ['~']],
565 \ ['F', 's/F/\~/', ['~']],
566 \ ['G', 's/G/\ugg/', ['Gg']],
567 \ ['H', 's/H/\Uh\Eh/', ['Hh']],
568 \ ['I', 's/I/\lII/', ['iI']],
569 \ ['J', 's/J/\LJ\EJ/', ['jJ']],
570 \ ['K', 's/K/\Uk\ek/', ['Kk']],
571 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
572 \ ['mMm', 's/M/\r/', ['m', 'm']],
573 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
574 \ ['oOo', 's/O/\n/', ["o\no"]],
575 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
576 \ ['qQq', 's/Q/\t/', ["q\tq"]],
577 \ ['rRr', 's/R/\\/', ['r\r']],
578 \ ['sSs', 's/S/\c/', ['scs']],
579 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
580 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
zeertzjq3269efd2022-06-12 11:13:05 +0100581 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
582 \ ['\', 's/\\/\\\\/', ['\\']]
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200583 \ ]
584 call Run_SubCmd_Tests(tests)
585endfunc
586
587func Test_sub_cmd_3()
588 set nomagic
589 set cpo&
590
591 " List entry format: [input, cmd, output]
592 let tests = [['aAa', "s/A/\\='\\'/", ['a\a']],
593 \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']],
594 \ ['cCc', "s/C/\\='\<C-V>\<C-M>'/", ["c\<C-V>", 'c']],
595 \ ['dDd', "s/D/\\='\\\<C-V>\<C-M>'/", ["d\\\<C-V>", 'd']],
596 \ ['eEe', "s/E/\\='\\\\\<C-V>\<C-M>'/", ["e\\\\\<C-V>", 'e']],
597 \ ['fFf', "s/F/\\='\r'/", ['f', 'f']],
598 \ ['gGg', "s/G/\\='\<C-V>\<C-J>'/", ["g\<C-V>", 'g']],
599 \ ['hHh', "s/H/\\='\\\<C-V>\<C-J>'/", ["h\\\<C-V>", 'h']],
600 \ ['iIi', "s/I/\\='\\\\\<C-V>\<C-J>'/", ["i\\\\\<C-V>", 'i']],
601 \ ['jJj', "s/J/\\='\n'/", ['j', 'j']],
602 \ ['kKk', 's/K/\="\r"/', ['k', 'k']],
603 \ ['lLl', 's/L/\="\n"/', ['l', 'l']]
604 \ ]
605 call Run_SubCmd_Tests(tests)
606endfunc
607
Bram Moolenaarf1699962019-08-31 17:48:19 +0200608" Test for submatch() on :substitute.
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200609func Test_sub_cmd_4()
610 set magic&
611 set cpo&
612
613 " List entry format: [input, cmd, output]
614 let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/",
Bram Moolenaar1e115362019-01-09 23:01:02 +0100615 \ ['a\a']],
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200616 \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/",
Bram Moolenaar1e115362019-01-09 23:01:02 +0100617 \ ['b\b']],
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200618 \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/",
619 \ ["c\<C-V>", 'c']],
620 \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/",
621 \ ["d\<C-V>", 'd']],
622 \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\<C-V>\<C-M>', '')/",
623 \ ["e\\\<C-V>", 'e']],
624 \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/",
625 \ ['f', 'f']],
626 \ ['gGg', 's/G/\=substitute(submatch(0), ".", "\<C-V>\<C-J>", "")/',
627 \ ["g\<C-V>", 'g']],
628 \ ['hHh', 's/H/\=substitute(submatch(0), ".", "\\\<C-V>\<C-J>", "")/',
629 \ ["h\<C-V>", 'h']],
630 \ ['iIi', 's/I/\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-J>", "")/',
631 \ ["i\\\<C-V>", 'i']],
632 \ ['jJj', "s/J/\\=substitute(submatch(0), '.', '\\n', '')/",
633 \ ['j', 'j']],
634 \ ['kKk', "s/K/\\=substitute(submatch(0), '.', '\\r', '')/",
635 \ ['k', 'k']],
636 \ ['lLl', "s/L/\\=substitute(submatch(0), '.', '\\n', '')/",
637 \ ['l', 'l']],
638 \ ]
639 call Run_SubCmd_Tests(tests)
640endfunc
641
642func Test_sub_cmd_5()
643 set magic&
644 set cpo&
645
646 " List entry format: [input, cmd, output]
647 let tests = [ ['A123456789', 's/A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)/', ['A123456789987654321']],
648 \ ['B123456789', 's/B\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])/', ["[['B123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]"]],
649 \ ]
650 call Run_SubCmd_Tests(tests)
651endfunc
652
653" Test for *:s%* on :substitute.
654func Test_sub_cmd_6()
655 set magic&
656 set cpo+=/
657
658 " List entry format: [input, cmd, output]
659 let tests = [ ['A', 's/A/a/', ['a']],
660 \ ['B', 's/B/%/', ['a']],
661 \ ]
662 call Run_SubCmd_Tests(tests)
663
664 set cpo-=/
665 let tests = [ ['C', 's/C/c/', ['c']],
666 \ ['D', 's/D/%/', ['%']],
667 \ ]
668 call Run_SubCmd_Tests(tests)
669
670 set cpo&
671endfunc
672
673" Test for :s replacing \n with line break.
674func Test_sub_cmd_7()
675 set magic&
676 set cpo&
677
678 " List entry format: [input, cmd, output]
679 let tests = [ ["A\<C-V>\<C-M>A", 's/A./\=submatch(0)/', ['A', 'A']],
680 \ ["B\<C-V>\<C-J>B", 's/B./\=submatch(0)/', ['B', 'B']],
681 \ ["C\<C-V>\<C-J>C", 's/C./\=strtrans(string(submatch(0, 1)))/', [strtrans("['C\<C-J>']C")]],
682 \ ["D\<C-V>\<C-J>\nD", 's/D.\nD/\=strtrans(string(submatch(0, 1)))/', [strtrans("['D\<C-J>', 'D']")]],
683 \ ["E\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>E", 's/E\_.\{-}E/\=strtrans(string(submatch(0, 1)))/', [strtrans("['E\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>E']")]],
684 \ ]
685 call Run_SubCmd_Tests(tests)
686
687 exe "normal oQ\nQ\<Esc>k"
Bram Moolenaare2e40752020-09-04 21:18:46 +0200688 call assert_fails('s/Q[^\n]Q/\=submatch(0)."foobar"/', 'E486:')
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200689 enew!
690endfunc
691
692func TitleString()
693 let check = 'foo' =~ 'bar'
694 return ""
695endfunc
696
697func Test_sub_cmd_8()
698 set titlestring=%{TitleString()}
699
700 enew!
701 call append(0, ['', 'test_one', 'test_two'])
702 call cursor(1,1)
703 /^test_one/s/.*/\="foo\nbar"/
704 call assert_equal('foo', getline(2))
705 call assert_equal('bar', getline(3))
706 call feedkeys(':/^test_two/s/.*/\="foo\nbar"/c', "t")
707 call feedkeys("\<CR>y", "xt")
708 call assert_equal('foo', getline(4))
709 call assert_equal('bar', getline(5))
710
711 enew!
712 set titlestring&
713endfunc
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100714
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200715func Test_sub_cmd_9()
716 new
717 let input = ['1 aaa', '2 aaa', '3 aaa']
718 call setline(1, input)
719 func Foo()
720 return submatch(0)
721 endfunc
722 %s/aaa/\=Foo()/gn
723 call assert_equal(input, getline(1, '$'))
724 call assert_equal(1, &modifiable)
725
726 delfunc Foo
727 bw!
728endfunc
729
Bram Moolenaara04f4572022-09-13 13:45:26 +0100730func Test_sub_highlight_zero_match()
731 CheckRunVimInTerminal
732
733 let lines =<< trim END
734 call setline(1, ['one', 'two', 'three'])
735 END
736 call writefile(lines, 'XscriptSubHighlight', 'D')
737 let buf = RunVimInTerminal('-S XscriptSubHighlight', #{rows: 8, cols: 60})
738 call term_sendkeys(buf, ":%s/^/ /c\<CR>")
739 call VerifyScreenDump(buf, 'Test_sub_highlight_zer_match_1', {})
740
741 call term_sendkeys(buf, "\<Esc>")
742 call StopVimInTerminal(buf)
743endfunc
744
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100745func Test_nocatch_sub_failure_handling()
Bram Moolenaar94722c52023-01-28 19:19:03 +0000746 " normal error results in all replacements
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200747 func Foo()
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100748 foobar
749 endfunc
750 new
751 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
zeertzjq3269efd2022-06-12 11:13:05 +0100752 " need silent! to avoid a delay when entering Insert mode
753 silent! %s/aaa/\=Foo()/g
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100754 call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3))
755
zeertzjq3269efd2022-06-12 11:13:05 +0100756 " Throw without try-catch causes abort after the first line.
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100757 " We cannot test this, since it would stop executing the test script.
758
759 " try/catch does not result in any changes
760 func! Foo()
761 throw 'error'
762 endfunc
763 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
764 let error_caught = 0
765 try
766 %s/aaa/\=Foo()/g
767 catch
768 let error_caught = 1
769 endtry
770 call assert_equal(1, error_caught)
771 call assert_equal(['1 aaa', '2 aaa', '3 aaa'], getline(1, 3))
772
Bram Moolenaar6349e942019-05-18 13:41:22 +0200773 " Same, but using "n" flag so that "sandbox" gets set
774 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
775 let error_caught = 0
776 try
777 %s/aaa/\=Foo()/gn
778 catch
779 let error_caught = 1
780 endtry
781 call assert_equal(1, error_caught)
782 call assert_equal(['1 aaa', '2 aaa', '3 aaa'], getline(1, 3))
783
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200784 delfunc Foo
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100785 bwipe!
786endfunc
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200787
788" Test ":s/pat/sub/" with different ~s in sub.
789func Test_replace_with_tilde()
790 new
791 " Set the last replace string to empty
792 s/^$//
793 call append(0, ['- Bug in "vPPPP" on this text:'])
794 normal gg
795 s/u/~u~/
796 call assert_equal('- Bug in "vPPPP" on this text:', getline(1))
797 s/i/~u~/
798 call assert_equal('- Bug uuun "vPPPP" on this text:', getline(1))
799 s/o/~~~/
800 call assert_equal('- Bug uuun "vPPPP" uuuuuuuuun this text:', getline(1))
801 close!
802endfunc
803
804func Test_replace_keeppatterns()
805 new
806 a
807foobar
808
Gregory Anders3b59be42024-08-15 22:04:22 +0200809substitute foo asdf foo
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200810
811one two
812.
813
814 normal gg
815 /^substitute
816 s/foo/bar/
817 call assert_equal('foo', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200818 call assert_equal('substitute bar asdf foo', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200819
820 /^substitute
821 keeppatterns s/asdf/xyz/
822 call assert_equal('^substitute', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200823 call assert_equal('substitute bar xyz foo', getline('.'))
824
825 /^substitute
826 &
827 call assert_equal('^substitute', @/)
828 call assert_equal('substitute bar xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200829
830 exe "normal /bar /e\<CR>"
831 call assert_equal(15, col('.'))
832 normal -
833 keeppatterns /xyz
834 call assert_equal('bar ', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200835 call assert_equal('substitute bar xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200836 exe "normal 0dn"
Gregory Anders3b59be42024-08-15 22:04:22 +0200837 call assert_equal('xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200838
839 close!
840endfunc
Bram Moolenaarbb265962019-10-31 04:38:36 +0100841
842func Test_sub_beyond_end()
843 new
844 call setline(1, '#')
845 let @/ = '^#\n\zs'
846 s///e
847 call assert_equal('#', getline(1))
848 bwipe!
849endfunc
Bram Moolenaar5d98dc22020-01-29 21:57:34 +0100850
Bram Moolenaarea3db912020-02-02 15:32:13 +0100851" Test for repeating last substitution using :~ and :&r
852func Test_repeat_last_sub()
853 new
854 call setline(1, ['blue green yellow orange white'])
855 s/blue/red/
856 let @/ = 'yellow'
857 ~
858 let @/ = 'white'
859 :&r
860 let @/ = 'green'
861 s//gray
862 call assert_equal('red gray red orange red', getline(1))
863 close!
864endfunc
865
866" Test for Vi compatible substitution:
867" \/{string}/, \?{string}? and \&{string}&
868func Test_sub_vi_compatibility()
869 new
870 call setline(1, ['blue green yellow orange blue'])
871 let @/ = 'orange'
872 s\/white/
873 let @/ = 'blue'
874 s\?amber?
875 let @/ = 'white'
876 s\&green&
877 call assert_equal('amber green yellow white green', getline(1))
878 close!
Bram Moolenaar9fb7b422022-03-05 21:13:26 +0000879
880 call assert_fails('vim9cmd s\/white/', 'E1270:')
881 call assert_fails('vim9cmd s\?white?', 'E1270:')
882 call assert_fails('vim9cmd s\&white&', 'E1270:')
Bram Moolenaarea3db912020-02-02 15:32:13 +0100883endfunc
884
885" Test for substitute with the new text longer than the original text
886func Test_sub_expand_text()
887 new
888 call setline(1, 'abcabcabcabcabcabcabcabc')
889 s/b/\=repeat('B', 10)/g
890 call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1))
891 close!
892endfunc
893
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100894" Test for command failures when the last substitute pattern is not set.
895func Test_sub_with_no_last_pat()
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100896 let lines =<< trim [SCRIPT]
897 call assert_fails('~', 'E33:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200898 call assert_fails('s//abc/g', 'E35:')
899 call assert_fails('s\/bar', 'E35:')
900 call assert_fails('s\&bar&', 'E33:')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100901 call writefile(v:errors, 'Xresult')
902 qall!
903 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +0100904 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100905 if RunVim([], [], '--clean -S Xscript')
906 call assert_equal([], readfile('Xresult'))
907 endif
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100908
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100909 let lines =<< trim [SCRIPT]
910 set cpo+=/
911 call assert_fails('s/abc/%/', 'E33:')
912 call writefile(v:errors, 'Xresult')
913 qall!
914 [SCRIPT]
915 call writefile(lines, 'Xscript')
916 if RunVim([], [], '--clean -S Xscript')
917 call assert_equal([], readfile('Xresult'))
918 endif
919
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100920 call delete('Xresult')
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100921endfunc
922
Bram Moolenaarca68ae12020-03-30 19:32:53 +0200923func Test_substitute()
924 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
Bram Moolenaar004a6782020-04-11 17:09:31 +0200925 " Substitute with special keys
926 call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", ''))
927endfunc
928
929func Test_substitute_expr()
930 let g:val = 'XXX'
931 call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
932 call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
933 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
934 \ '\=nr2char("0x" . submatch(1))', 'g'))
935 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
936 \ {-> nr2char("0x" . submatch(1))}, 'g'))
937
938 call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
939 \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
940
941 func Recurse()
942 return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
943 endfunc
944 " recursive call works
945 call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
946
947 call assert_fails("let s=submatch([])", 'E745:')
948 call assert_fails("let s=submatch(2, [])", 'E745:')
949endfunc
950
951func Test_invalid_submatch()
952 " This was causing invalid memory access in Vim-7.4.2232 and older
953 call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
954 call assert_fails('eval submatch(-1)', 'E935:')
955 call assert_equal('', submatch(0))
956 call assert_equal('', submatch(1))
957 call assert_equal([], submatch(0, 1))
958 call assert_equal([], submatch(1, 1))
959endfunc
960
Bram Moolenaar8a0dcf42020-09-06 15:14:45 +0200961func Test_submatch_list_concatenate()
962 let pat = 'A\(.\)'
963 let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
964 call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
965endfunc
966
Bram Moolenaar004a6782020-04-11 17:09:31 +0200967func Test_substitute_expr_arg()
968 call assert_equal('123456789-123456789=', substitute('123456789',
969 \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
970 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
971
972 call assert_equal('123456-123456=789', substitute('123456789',
973 \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
974 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
975
976 call assert_equal('123456789-123456789x=', substitute('123456789',
977 \ '\(.\)\(.\)\(.*\)',
978 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
979
980 call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
981 call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
982 call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
983 call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
984endfunc
985
986" Test for using a function to supply the substitute string
987func Test_substitute_using_func()
988 func Xfunc()
989 return '1234'
990 endfunc
991 call assert_equal('a1234f', substitute('abcdef', 'b..e',
992 \ function("Xfunc"), ''))
993 delfunc Xfunc
994endfunc
995
996" Test for using submatch() with a multiline match
997func Test_substitute_multiline_submatch()
998 new
999 call setline(1, ['line1', 'line2', 'line3', 'line4'])
1000 %s/^line1\(\_.\+\)line4$/\=submatch(1)/
1001 call assert_equal(['', 'line2', 'line3', ''], getline(1, '$'))
1002 close!
Bram Moolenaarca68ae12020-03-30 19:32:53 +02001003endfunc
1004
Bram Moolenaardf365142021-05-03 20:01:45 +02001005func Test_substitute_skipped_range()
1006 new
1007 if 0
1008 /1/5/2/2/\n
1009 endif
1010 call assert_equal([0, 1, 1, 0, 1], getcurpos())
1011 bwipe!
1012endfunc
1013
Dominique Pellebfb2bb12021-08-14 21:11:51 +02001014" Test using the 'gdefault' option (when on, flag 'g' is default on).
1015func Test_substitute_gdefault()
1016 new
1017
1018 " First check without 'gdefault'
1019 call setline(1, 'foo bar foo')
1020 s/foo/FOO/
1021 call assert_equal('FOO bar foo', getline(1))
1022 call setline(1, 'foo bar foo')
1023 s/foo/FOO/g
1024 call assert_equal('FOO bar FOO', getline(1))
1025 call setline(1, 'foo bar foo')
1026 s/foo/FOO/gg
1027 call assert_equal('FOO bar foo', getline(1))
1028
1029 " Then check with 'gdefault'
1030 set gdefault
1031 call setline(1, 'foo bar foo')
1032 s/foo/FOO/
1033 call assert_equal('FOO bar FOO', getline(1))
1034 call setline(1, 'foo bar foo')
1035 s/foo/FOO/g
1036 call assert_equal('FOO bar foo', getline(1))
1037 call setline(1, 'foo bar foo')
1038 s/foo/FOO/gg
1039 call assert_equal('FOO bar FOO', getline(1))
1040
1041 " Setting 'compatible' should reset 'gdefault'
1042 call assert_equal(1, &gdefault)
1043 set compatible
1044 call assert_equal(0, &gdefault)
1045 set nocompatible
1046 call assert_equal(0, &gdefault)
1047
1048 bw!
1049endfunc
1050
Bram Moolenaar37f47952022-01-29 14:21:51 +00001051" This was using "old_sub" after it was freed.
1052func Test_using_old_sub()
1053 set compatible maxfuncdepth=10
1054 new
1055 call setline(1, 'some text.')
1056 func Repl()
1057 ~
1058 s/
1059 endfunc
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001060 silent! s/\%')/\=Repl()
Bram Moolenaar37f47952022-01-29 14:21:51 +00001061
1062 delfunc Repl
1063 bwipe!
1064 set nocompatible
1065endfunc
1066
Bram Moolenaare2bd8602022-05-18 13:11:57 +01001067" This was switching windows in between computing the length and using it.
1068func Test_sub_change_window()
1069 silent! lfile
1070 sil! norm o0000000000000000000000000000000000000000000000000000
1071 func Repl()
1072 lopen
1073 endfunc
1074 silent! s/\%')/\=Repl()
1075 bwipe!
1076 bwipe!
1077 delfunc Repl
1078endfunc
1079
Bram Moolenaar338f1fc2022-05-26 15:56:23 +01001080" This was undoign a change in between computing the length and using it.
1081func Do_Test_sub_undo_change()
1082 new
1083 norm o0000000000000000000000000000000000000000000000000000
1084 silent! s/\%')/\=Repl()
1085 bwipe!
1086endfunc
1087
1088func Test_sub_undo_change()
1089 func Repl()
1090 silent! norm g-
1091 endfunc
1092 call Do_Test_sub_undo_change()
1093
1094 func! Repl()
1095 silent earlier
1096 endfunc
1097 call Do_Test_sub_undo_change()
1098
1099 delfunc Repl
1100endfunc
1101
Bram Moolenaar71223e22022-05-30 15:23:09 +01001102" This was opening a command line window from the expression
1103func Test_sub_open_cmdline_win()
1104 " the error only happens in a very specific setup, run a new Vim instance to
1105 " get a clean starting point.
1106 let lines =<< trim [SCRIPT]
Bram Moolenaarbe990422022-05-30 16:01:42 +01001107 set vb t_vb=
Bram Moolenaar71223e22022-05-30 15:23:09 +01001108 norm o0000000000000000000000000000000000000000000000000000
1109 func Replace()
1110 norm q/
1111 endfunc
1112 s/\%')/\=Replace()
1113 redir >Xresult
1114 messages
1115 redir END
1116 qall!
1117 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +01001118 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar71223e22022-05-30 15:23:09 +01001119 if RunVim([], [], '-u NONE -S Xscript')
Bram Moolenaarbe990422022-05-30 16:01:42 +01001120 call assert_match('E565: Not allowed to change text or change window',
1121 \ readfile('Xresult')->join('XX'))
Bram Moolenaar71223e22022-05-30 15:23:09 +01001122 endif
1123
Bram Moolenaar71223e22022-05-30 15:23:09 +01001124 call delete('Xresult')
1125endfunc
1126
Bram Moolenaard6211a52022-06-18 19:48:14 +01001127" This was editing a script file from the expression
1128func Test_sub_edit_scriptfile()
1129 new
1130 norm o0000000000000000000000000000000000000000000000000000
1131 func EditScript()
Bram Moolenaarb18b4962022-09-02 21:55:50 +01001132 silent! scr! Xsedfile
Bram Moolenaard6211a52022-06-18 19:48:14 +01001133 endfunc
1134 s/\%')/\=EditScript()
1135
1136 delfunc EditScript
1137 bwipe!
1138endfunc
1139
Bram Moolenaarcc762a42022-11-25 13:03:31 +00001140" This was editing another file from the expression.
1141func Test_sub_expr_goto_other_file()
1142 call writefile([''], 'Xfileone', 'D')
1143 enew!
1144 call setline(1, ['a', 'b', 'c', 'd',
1145 \ 'Xfileone zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'])
1146
1147 func g:SplitGotoFile()
1148 exe "sil! norm 0\<C-W>gf"
1149 return ''
1150 endfunc
1151
1152 $
1153 s/\%')/\=g:SplitGotoFile()
1154
1155 delfunc g:SplitGotoFile
1156 bwipe!
1157endfunc
1158
Bram Moolenaar3ac1d972023-01-04 17:17:54 +00001159func Test_recursive_expr_substitute()
1160 " this was reading invalid memory
1161 let lines =<< trim END
1162 func Repl(g, n)
1163 s
1164 r%:s000
1165 endfunc
1166 next 0
1167 let caught = 0
1168 s/\%')/\=Repl(0, 0)
1169 qall!
1170 END
1171 call writefile(lines, 'XexprSubst', 'D')
1172 call RunVim([], [], '--clean -S XexprSubst')
1173endfunc
1174
Yegappan Lakshmanan5e877ba2022-03-25 21:19:26 +00001175" Test for the 2-letter and 3-letter :substitute commands
1176func Test_substitute_short_cmd()
1177 new
1178 call setline(1, ['one', 'one one one'])
1179 s/one/two
1180 call cursor(2, 1)
1181
1182 " :sc
1183 call feedkeys(":sc\<CR>y", 'xt')
1184 call assert_equal('two one one', getline(2))
1185
1186 " :scg
1187 call setline(2, 'one one one')
1188 call feedkeys(":scg\<CR>nyq", 'xt')
1189 call assert_equal('one two one', getline(2))
1190
1191 " :sci
1192 call setline(2, 'ONE One onE')
1193 call feedkeys(":sci\<CR>y", 'xt')
1194 call assert_equal('two One onE', getline(2))
1195
1196 " :scI
1197 set ignorecase
1198 call setline(2, 'ONE One one')
1199 call feedkeys(":scI\<CR>y", 'xt')
1200 call assert_equal('ONE One two', getline(2))
1201 set ignorecase&
1202
1203 " :scn
1204 call setline(2, 'one one one')
1205 let t = execute('scn')->split("\n")
1206 call assert_equal(['1 match on 1 line'], t)
1207 call assert_equal('one one one', getline(2))
1208
1209 " :scp
1210 call setline(2, "\tone one one")
1211 redir => output
1212 call feedkeys(":scp\<CR>y", 'xt')
1213 redir END
1214 call assert_equal(' two one one', output->split("\n")[-1])
1215 call assert_equal("\ttwo one one", getline(2))
1216
1217 " :scl
1218 call setline(2, "\tone one one")
1219 redir => output
1220 call feedkeys(":scl\<CR>y", 'xt')
1221 redir END
1222 call assert_equal("^Itwo one one$", output->split("\n")[-1])
1223 call assert_equal("\ttwo one one", getline(2))
1224
1225 " :sgc
1226 call setline(2, 'one one one one one')
1227 call feedkeys(":sgc\<CR>nyyq", 'xt')
1228 call assert_equal('one two two one one', getline(2))
1229
1230 " :sg
1231 call setline(2, 'one one one')
1232 sg
1233 call assert_equal('two two two', getline(2))
1234
1235 " :sgi
1236 call setline(2, 'ONE One onE')
1237 sgi
1238 call assert_equal('two two two', getline(2))
1239
1240 " :sgI
1241 set ignorecase
1242 call setline(2, 'ONE One one')
1243 sgI
1244 call assert_equal('ONE One two', getline(2))
1245 set ignorecase&
1246
1247 " :sgn
1248 call setline(2, 'one one one')
1249 let t = execute('sgn')->split("\n")
1250 call assert_equal(['3 matches on 1 line'], t)
1251 call assert_equal('one one one', getline(2))
1252
1253 " :sgp
1254 call setline(2, "\tone one one")
1255 redir => output
1256 sgp
1257 redir END
1258 call assert_equal(' two two two', output->split("\n")[-1])
1259 call assert_equal("\ttwo two two", getline(2))
1260
1261 " :sgl
1262 call setline(2, "\tone one one")
1263 redir => output
1264 sgl
1265 redir END
1266 call assert_equal("^Itwo two two$", output->split("\n")[-1])
1267 call assert_equal("\ttwo two two", getline(2))
1268
1269 " :sgr
1270 call setline(2, "one one one")
1271 call cursor(2, 1)
1272 s/abc/xyz/e
1273 let @/ = 'one'
1274 sgr
1275 call assert_equal('xyz xyz xyz', getline(2))
1276
1277 " :sic
1278 call cursor(1, 1)
1279 s/one/two/e
1280 call setline(2, "ONE One one")
1281 call cursor(2, 1)
1282 call feedkeys(":sic\<CR>y", 'xt')
1283 call assert_equal('two One one', getline(2))
1284
1285 " :si
1286 call setline(2, "ONE One one")
1287 si
1288 call assert_equal('two One one', getline(2))
1289
1290 " :siI
1291 call setline(2, "ONE One one")
1292 siI
1293 call assert_equal('ONE One two', getline(2))
1294
1295 " :sin
1296 call setline(2, 'ONE One onE')
1297 let t = execute('sin')->split("\n")
1298 call assert_equal(['1 match on 1 line'], t)
1299 call assert_equal('ONE One onE', getline(2))
1300
1301 " :sip
1302 call setline(2, "\tONE One onE")
1303 redir => output
1304 sip
1305 redir END
1306 call assert_equal(' two One onE', output->split("\n")[-1])
1307 call assert_equal("\ttwo One onE", getline(2))
1308
1309 " :sir
1310 call setline(2, "ONE One onE")
1311 call cursor(2, 1)
1312 s/abc/xyz/e
1313 let @/ = 'one'
1314 sir
1315 call assert_equal('xyz One onE', getline(2))
1316
1317 " :sIc
1318 call cursor(1, 1)
1319 s/one/two/e
1320 call setline(2, "ONE One one")
1321 call cursor(2, 1)
1322 call feedkeys(":sIc\<CR>y", 'xt')
1323 call assert_equal('ONE One two', getline(2))
1324
1325 " :sIg
1326 call setline(2, "ONE one onE one")
1327 sIg
1328 call assert_equal('ONE two onE two', getline(2))
1329
1330 " :sIi
1331 call setline(2, "ONE One one")
1332 sIi
1333 call assert_equal('two One one', getline(2))
1334
1335 " :sI
1336 call setline(2, "ONE One one")
1337 sI
1338 call assert_equal('ONE One two', getline(2))
1339
1340 " :sIn
1341 call setline(2, 'ONE One one')
1342 let t = execute('sIn')->split("\n")
1343 call assert_equal(['1 match on 1 line'], t)
1344 call assert_equal('ONE One one', getline(2))
1345
1346 " :sIp
1347 call setline(2, "\tONE One one")
1348 redir => output
1349 sIp
1350 redir END
1351 call assert_equal(' ONE One two', output->split("\n")[-1])
1352 call assert_equal("\tONE One two", getline(2))
1353
1354 " :sIl
1355 call setline(2, "\tONE onE one")
1356 redir => output
1357 sIl
1358 redir END
1359 call assert_equal("^IONE onE two$", output->split("\n")[-1])
1360 call assert_equal("\tONE onE two", getline(2))
1361
1362 " :sIr
1363 call setline(2, "ONE one onE")
1364 call cursor(2, 1)
1365 s/abc/xyz/e
1366 let @/ = 'one'
1367 sIr
1368 call assert_equal('ONE xyz onE', getline(2))
1369
1370 " :src
1371 call setline(2, "ONE one one")
1372 call cursor(2, 1)
1373 s/abc/xyz/e
1374 let @/ = 'one'
1375 call feedkeys(":src\<CR>y", 'xt')
1376 call assert_equal('ONE xyz one', getline(2))
1377
1378 " :srg
1379 call setline(2, "one one one")
1380 call cursor(2, 1)
1381 s/abc/xyz/e
1382 let @/ = 'one'
1383 srg
1384 call assert_equal('xyz xyz xyz', getline(2))
1385
1386 " :sri
1387 call setline(2, "ONE one onE")
1388 call cursor(2, 1)
1389 s/abc/xyz/e
1390 let @/ = 'one'
1391 sri
1392 call assert_equal('xyz one onE', getline(2))
1393
1394 " :srI
1395 call setline(2, "ONE one onE")
1396 call cursor(2, 1)
1397 s/abc/xyz/e
1398 let @/ = 'one'
1399 srI
1400 call assert_equal('ONE xyz onE', getline(2))
1401
1402 " :srn
1403 call setline(2, "ONE one onE")
1404 call cursor(2, 1)
1405 s/abc/xyz/e
1406 let @/ = 'one'
1407 let t = execute('srn')->split("\n")
1408 call assert_equal(['1 match on 1 line'], t)
1409 call assert_equal('ONE one onE', getline(2))
1410
1411 " :srp
1412 call setline(2, "\tONE one onE")
1413 call cursor(2, 1)
1414 s/abc/xyz/e
1415 let @/ = 'one'
1416 redir => output
1417 srp
1418 redir END
1419 call assert_equal(' ONE xyz onE', output->split("\n")[-1])
1420 call assert_equal("\tONE xyz onE", getline(2))
1421
1422 " :srl
1423 call setline(2, "\tONE one onE")
1424 call cursor(2, 1)
1425 s/abc/xyz/e
1426 let @/ = 'one'
1427 redir => output
1428 srl
1429 redir END
1430 call assert_equal("^IONE xyz onE$", output->split("\n")[-1])
1431 call assert_equal("\tONE xyz onE", getline(2))
1432
1433 " :sr
1434 call setline(2, "ONE one onE")
1435 call cursor(2, 1)
1436 s/abc/xyz/e
1437 let @/ = 'one'
1438 sr
1439 call assert_equal('ONE xyz onE', getline(2))
1440
1441 " :sce
1442 s/abc/xyz/e
1443 call assert_fails("sc", 'E486:')
1444 sce
1445 " :sge
1446 call assert_fails("sg", 'E486:')
1447 sge
1448 " :sie
1449 call assert_fails("si", 'E486:')
1450 sie
1451 " :sIe
1452 call assert_fails("sI", 'E486:')
1453 sIe
1454
1455 bw!
1456endfunc
Bram Moolenaar37f47952022-01-29 14:21:51 +00001457
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001458" Check handling expanding "~" resulting in extremely long text.
Bram Moolenaar916d6dd2023-05-09 21:45:47 +01001459" FIXME: disabled, it takes too long to run on CI
Bram Moolenaara4467c42023-05-09 22:07:11 +01001460"func Test_substitute_tilde_too_long()
1461" enew!
1462"
1463" s/.*/ixxx
1464" s//~~~~~~~~~AAAAAAA@(
1465"
1466" " Either fails with "out of memory" or "text too long".
1467" " This can take a long time.
1468" call assert_fails('sil! norm &&&&&&&&&', ['E1240:\|E342:'])
1469"
1470" bwipe!
1471"endfunc
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001472
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001473" This should be done last to reveal a memory leak when vim_regsub_both() is
1474" called to evaluate an expression but it is not used in a second call.
1475func Test_z_substitute_expr_leak()
1476 func SubExpr()
1477 ~n
1478 endfunc
1479 silent! s/\%')/\=SubExpr()
1480 delfunc SubExpr
1481endfunc
1482
Christian Brabandt18d27092023-09-06 19:53:36 +02001483func Test_substitute_expr_switch_win()
1484 func R()
1485 wincmd x
1486 return 'XXXX'
1487 endfunc
1488 new Xfoobar
1489 let bufnr = bufnr('%')
Christian Brabandt26c11c52023-11-22 21:26:41 +01001490 put ='abcdef'
Christian Brabandt18d27092023-09-06 19:53:36 +02001491 silent! s/\%')/\=R()
Christian Brabandtee17b6f2023-09-09 11:23:50 +02001492 call assert_fails(':%s/./\=R()/g', 'E565:')
Christian Brabandt18d27092023-09-06 19:53:36 +02001493 delfunc R
1494 exe bufnr .. "bw!"
1495endfunc
1496
Christian Brabandt26c11c52023-11-22 21:26:41 +01001497" recursive call of :s using test-replace special
1498func Test_substitute_expr_recursive()
1499 func Q()
1500 %s/./\='foobar'/gn
1501 return "foobar"
1502 endfunc
1503 func R()
1504 %s/./\=Q()/g
1505 endfunc
1506 new Xfoobar_UAF
1507 let bufnr = bufnr('%')
1508 put ='abcdef'
1509 silent! s/./\=R()/g
1510 call assert_fails(':%s/./\=R()/g', 'E565:')
1511 delfunc R
1512 delfunc Q
1513 exe bufnr .. "bw!"
1514endfunc
1515
Yegappan Lakshmanan4776e642024-05-19 09:06:50 +02001516" Test for changing 'cpo' in a substitute expression
1517func Test_substitute_expr_cpo()
1518 func XSubExpr()
1519 set cpo=
1520 return 'x'
1521 endfunc
1522
1523 let save_cpo = &cpo
1524 call assert_equal('xxx', substitute('abc', '.', '\=XSubExpr()', 'g'))
1525 call assert_equal(save_cpo, &cpo)
1526
1527 delfunc XSubExpr
1528endfunc
1529
Bram Moolenaar5d98dc22020-01-29 21:57:34 +01001530" vim: shiftwidth=2 sts=2 expandtab