blob: cf2c73fb954aff0156a4fa0a4a5dc7dc8943ba5e [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
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100176" Test %s/\n// which is implemented as a special case to use a
177" more efficient join rather than doing a regular substitution.
178func Test_substitute_join()
179 new
180
181 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
182 let a = execute('%s/\n//')
183 call assert_equal("", a)
184 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
185 call assert_equal('\n', histget("search", -1))
186
187 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
188 let a = execute('%s/\n//g')
189 call assert_equal("", a)
190 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
191 call assert_equal('\n', histget("search", -1))
192
193 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
194 let a = execute('%s/\n//p')
195 call assert_equal("\nfoo barbar^Hfoo", a)
196 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
197 call assert_equal('\n', histget("search", -1))
198
199 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
200 let a = execute('%s/\n//l')
201 call assert_equal("\nfoo^Ibarbar^Hfoo$", a)
202 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
203 call assert_equal('\n', histget("search", -1))
204
205 call setline(1, ["foo\tbar", "bar\<C-H>foo"])
206 let a = execute('%s/\n//#')
207 call assert_equal("\n 1 foo barbar^Hfoo", a)
208 call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
209 call assert_equal('\n', histget("search", -1))
210
Bram Moolenaarea3db912020-02-02 15:32:13 +0100211 call setline(1, ['foo', 'bar', 'baz', 'qux'])
212 call execute('1,2s/\n//')
213 call assert_equal(['foobarbaz', 'qux'], getline(1, '$'))
214
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100215 bwipe!
216endfunc
217
218func Test_substitute_count()
219 new
220 call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo'])
221 2
222
223 s/foo/bar/3
224 call assert_equal(['foo foo', 'bar foo', 'bar foo', 'bar foo', 'foo foo'],
225 \ getline(1, '$'))
226
227 call assert_fails('s/foo/bar/0', 'E939:')
228
Bram Moolenaarea3db912020-02-02 15:32:13 +0100229 call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo'])
230 2,4s/foo/bar/ 10
231 call assert_equal(['foo foo', 'foo foo', 'foo foo', 'bar foo', 'bar foo'],
232 \ getline(1, '$'))
233
Christian Brabandtac637872023-11-14 20:45:48 +0100234 call assert_fails('s/./b/2147483647', 'E1510:')
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100235 bwipe!
236endfunc
237
238" Test substitute 'n' flag (report number of matches, do not substitute).
239func Test_substitute_flag_n()
240 new
241 let lines = ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo']
242 call setline(1, lines)
243
244 call assert_equal("\n3 matches on 3 lines", execute('2,4s/foo/bar/n'))
245 call assert_equal("\n6 matches on 3 lines", execute('2,4s/foo/bar/gn'))
246
247 " c flag (confirm) should be ignored when using n flag.
248 call assert_equal("\n3 matches on 3 lines", execute('2,4s/foo/bar/nc'))
249
250 " No substitution should have been done.
251 call assert_equal(lines, getline(1, '$'))
252
Bram Moolenaarea3db912020-02-02 15:32:13 +0100253 %delete _
254 call setline(1, ['A', 'Bar', 'Baz'])
255 call assert_equal("\n1 match on 1 line", execute('s/\nB\@=//gn'))
256
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100257 bwipe!
258endfunc
259
260func Test_substitute_errors()
261 new
262 call setline(1, 'foobar')
263
264 call assert_fails('s/FOO/bar/', 'E486:')
265 call assert_fails('s/foo/bar/@', 'E488:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200266 call assert_fails('s/\(/bar/', 'E54:')
Bram Moolenaar5d98dc22020-01-29 21:57:34 +0100267 call assert_fails('s afooabara', 'E146:')
268 call assert_fails('s\\a', 'E10:')
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100269
270 setl nomodifiable
271 call assert_fails('s/foo/bar/', 'E21:')
272
Bram Moolenaar0e05de42020-03-25 22:23:46 +0100273 call assert_fails("let s=substitute([], 'a', 'A', 'g')", 'E730:')
274 call assert_fails("let s=substitute('abcda', [], 'A', 'g')", 'E730:')
275 call assert_fails("let s=substitute('abcda', 'a', [], 'g')", 'E730:')
276 call assert_fails("let s=substitute('abcda', 'a', 'A', [])", 'E730:')
Bram Moolenaar531be472020-09-23 22:38:05 +0200277 call assert_fails("let s=substitute('abc', '\\%(', 'A', 'g')", 'E53:')
Bram Moolenaar0e05de42020-03-25 22:23:46 +0100278
Bram Moolenaard77aa4d2019-02-10 22:50:14 +0100279 bwipe!
280endfunc
281
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200282" Test for *sub-replace-special* and *sub-replace-expression* on substitute().
283func Test_sub_replace_1()
284 " Run the tests with 'magic' on
285 set magic
286 set cpo&
287 call assert_equal('AA', substitute('A', 'A', '&&', ''))
288 call assert_equal('&', substitute('B', 'B', '\&', ''))
289 call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
290 call assert_equal('d', substitute('D', 'D', 'd', ''))
291 call assert_equal('~', substitute('E', 'E', '~', ''))
292 call assert_equal('~', substitute('F', 'F', '\~', ''))
293 call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
294 call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
295 call assert_equal('iI', substitute('I', 'I', '\lII', ''))
296 call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
297 call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
298 call assert_equal("l\<C-V>\<C-M>l",
299 \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
300 call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
301 call assert_equal("n\<C-V>\<C-M>n",
302 \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
303 call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
304 call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
305 call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
306 call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
307 call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
308 call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
309 call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
310 call assert_equal("w\\w", substitute('wWw', 'W', "\\", ''))
311 call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
312 call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
313 call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
Bram Moolenaar004a6782020-04-11 17:09:31 +0200314 " \v or \V after $
315 call assert_equal('abxx', substitute('abcd', 'xy$\v|cd$', 'xx', ''))
316 call assert_equal('abxx', substitute('abcd', 'xy$\V\|cd\$', 'xx', ''))
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200317endfunc
318
319func Test_sub_replace_2()
320 " Run the tests with 'magic' off
321 set nomagic
322 set cpo&
323 call assert_equal('AA', substitute('A', 'A', '&&', ''))
324 call assert_equal('&', substitute('B', 'B', '\&', ''))
325 call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
326 call assert_equal('d', substitute('D', 'D', 'd', ''))
327 call assert_equal('~', substitute('E', 'E', '~', ''))
328 call assert_equal('~', substitute('F', 'F', '\~', ''))
329 call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
330 call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
331 call assert_equal('iI', substitute('I', 'I', '\lII', ''))
332 call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
333 call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
334 call assert_equal("l\<C-V>\<C-M>l",
335 \ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
336 call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
337 call assert_equal("n\<C-V>\<C-M>n",
338 \ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
339 call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
340 call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
341 call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
342 call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
343 call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
344 call assert_equal("t\<C-M>t", substitute('tTt', 'T', "\r", ''))
345 call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
346 call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
347 call assert_equal('w\w', substitute('wWw', 'W', "\\", ''))
348 call assert_equal('XxxX', substitute('X', 'X', '\L\uxXx\l\EX', ''))
349 call assert_equal('yYYy', substitute('Y', 'Y', '\U\lYyY\u\Ey', ''))
350endfunc
351
352func Test_sub_replace_3()
353 set magic&
354 set cpo&
355 call assert_equal('a\a', substitute('aAa', 'A', '\="\\"', ''))
356 call assert_equal('b\\b', substitute('bBb', 'B', '\="\\\\"', ''))
357 call assert_equal("c\rc", substitute('cCc', 'C', "\\=\"\r\"", ''))
358 call assert_equal("d\\\rd", substitute('dDd', 'D', "\\=\"\\\\\r\"", ''))
359 call assert_equal("e\\\\\re", substitute('eEe', 'E', "\\=\"\\\\\\\\\r\"", ''))
360 call assert_equal('f\rf', substitute('fFf', 'F', '\="\\r"', ''))
361 call assert_equal('j\nj', substitute('jJj', 'J', '\="\\n"', ''))
362 call assert_equal("k\<C-M>k", substitute('kKk', 'K', '\="\r"', ''))
363 call assert_equal("l\nl", substitute('lLl', 'L', '\="\n"', ''))
364endfunc
365
366" Test for submatch() on substitute().
367func Test_sub_replace_4()
368 set magic&
369 set cpo&
370 call assert_equal('a\a', substitute('aAa', 'A',
371 \ '\=substitute(submatch(0), ".", "\\", "")', ''))
372 call assert_equal('b\b', substitute('bBb', 'B',
373 \ '\=substitute(submatch(0), ".", "\\\\", "")', ''))
374 call assert_equal("c\<C-V>\<C-M>c", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\<C-V>\<C-M>", "")', ''))
375 call assert_equal("d\<C-V>\<C-M>d", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\<C-V>\<C-M>", "")', ''))
376 call assert_equal("e\\\<C-V>\<C-M>e", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-M>", "")', ''))
377 call assert_equal("f\<C-M>f", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', ''))
378 call assert_equal("j\nj", substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', ''))
379 call assert_equal("k\rk", substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', ''))
380 call assert_equal("l\nl", substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', ''))
381endfunc
382
383func Test_sub_replace_5()
384 set magic&
385 set cpo&
386 call assert_equal('A123456789987654321', substitute('A123456789',
387 \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
388 \ '\=submatch(0) . submatch(9) . submatch(8) . ' .
389 \ 'submatch(7) . submatch(6) . submatch(5) . ' .
390 \ 'submatch(4) . submatch(3) . submatch(2) . submatch(1)',
391 \ ''))
392 call assert_equal("[['A123456789'], ['9'], ['8'], ['7'], ['6'], " .
393 \ "['5'], ['4'], ['3'], ['2'], ['1']]",
394 \ substitute('A123456789',
395 \ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
396 \ '\=string([submatch(0, 1), submatch(9, 1), ' .
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200397 \ 'submatch(8, 1), 7->submatch(1), submatch(6, 1), ' .
Bram Moolenaar1a333bc2017-08-30 20:21:58 +0200398 \ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' .
399 \ 'submatch(2, 1), submatch(1, 1)])',
400 \ ''))
401endfunc
402
403func Test_sub_replace_6()
404 set magic&
405 set cpo+=/
406 call assert_equal('a', substitute('A', 'A', 'a', ''))
407 call assert_equal('%', substitute('B', 'B', '%', ''))
408 set cpo-=/
409 call assert_equal('c', substitute('C', 'C', 'c', ''))
410 call assert_equal('%', substitute('D', 'D', '%', ''))
411endfunc
412
413func Test_sub_replace_7()
414 set magic&
415 set cpo&
416 call assert_equal('AA', substitute('AA', 'A.', '\=submatch(0)', ''))
417 call assert_equal("B\nB", substitute("B\nB", 'B.', '\=submatch(0)', ''))
418 call assert_equal("['B\n']B", substitute("B\nB", 'B.', '\=string(submatch(0, 1))', ''))
419 call assert_equal('-abab', substitute('-bb', '\zeb', 'a', 'g'))
420 call assert_equal('c-cbcbc', substitute('-bb', '\ze', 'c', 'g'))
421endfunc
422
423" Test for *:s%* on :substitute.
424func Test_sub_replace_8()
425 new
426 set magic&
427 set cpo&
428 $put =',,X'
429 s/\(^\|,\)\ze\(,\|X\)/\1N/g
430 call assert_equal('N,,NX', getline("$"))
431 $put =',,Y'
432 let cmd = ':s/\(^\|,\)\ze\(,\|Y\)/\1N/gc'
433 call feedkeys(cmd . "\<CR>a", "xt")
434 call assert_equal('N,,NY', getline("$"))
435 :$put =',,Z'
436 let cmd = ':s/\(^\|,\)\ze\(,\|Z\)/\1N/gc'
437 call feedkeys(cmd . "\<CR>yy", "xt")
438 call assert_equal('N,,NZ', getline("$"))
439 enew! | close
440endfunc
441
442func Test_sub_replace_9()
443 new
444 set magic&
445 set cpo&
446 $put ='xxx'
447 call feedkeys(":s/x/X/gc\<CR>yyq", "xt")
448 call assert_equal('XXx', getline("$"))
449 enew! | close
450endfunc
451
452func Test_sub_replace_10()
453 set magic&
454 set cpo&
455 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
456 call assert_equal('aaa', substitute('123', '\zs.', 'a', 'g'))
457 call assert_equal('1a2a3a', substitute('123', '.\zs', 'a', 'g'))
458 call assert_equal('a1a2a3a', substitute('123', '\ze', 'a', 'g'))
459 call assert_equal('a1a2a3', substitute('123', '\ze.', 'a', 'g'))
460 call assert_equal('aaa', substitute('123', '.\ze', 'a', 'g'))
461 call assert_equal('aa2a3a', substitute('123', '1\|\ze', 'a', 'g'))
462 call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g'))
463endfunc
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200464
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100465func SubReplacer(text, submatches)
466 return a:text .. a:submatches[0] .. a:text
467endfunc
zeertzjq48db5da2022-09-16 12:10:03 +0100468func SubReplacerVar(text, ...)
469 return a:text .. a:1[0] .. a:text
470endfunc
zeertzjqabd58d82022-09-16 16:06:32 +0100471def SubReplacerVar9(text: string, ...args: list<list<string>>): string
472 return text .. args[0][0] .. text
473enddef
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100474func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches)
475 return a:t3 .. a:submatches[0] .. a:t11
476endfunc
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100477
478func Test_substitute_partial()
zeertzjq48db5da2022-09-16 12:10:03 +0100479 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g'))
480 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar', ['foo']), 'g'))
zeertzjqabd58d82022-09-16 16:06:32 +0100481 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar9', ['foo']), 'g'))
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100482
zeertzjq48db5da2022-09-16 12:10:03 +0100483 " 19 arguments plus one is just OK
484 let Replacer = function('SubReplacer20', repeat(['foo'], 19))
485 call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g'))
Bram Moolenaar4c054e92019-11-10 00:13:50 +0100486
zeertzjq48db5da2022-09-16 12:10:03 +0100487 " 20 arguments plus one is too many
488 let Replacer = function('SubReplacer20', repeat(['foo'], 20))
489 call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118:')
Bram Moolenaarb0745b22019-11-09 22:28:11 +0100490endfunc
491
Bram Moolenaar7a2217b2021-06-06 12:33:49 +0200492func Test_substitute_float()
Bram Moolenaar7a2217b2021-06-06 12:33:49 +0200493 call assert_equal('number 1.23', substitute('number ', '$', { -> 1.23 }, ''))
494 vim9 assert_equal('number 1.23', substitute('number ', '$', () => 1.23, ''))
495endfunc
496
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200497" Tests for *sub-replace-special* and *sub-replace-expression* on :substitute.
498
499" Execute a list of :substitute command tests
500func Run_SubCmd_Tests(tests)
501 enew!
502 for t in a:tests
503 let start = line('.') + 1
504 let end = start + len(t[2]) - 1
505 exe "normal o" . t[0]
506 call cursor(start, 1)
507 exe t[1]
508 call assert_equal(t[2], getline(start, end), t[1])
509 endfor
510 enew!
511endfunc
512
513func Test_sub_cmd_1()
514 set magic
515 set cpo&
516
517 " List entry format: [input, cmd, output]
518 let tests = [['A', 's/A/&&/', ['AA']],
519 \ ['B', 's/B/\&/', ['&']],
520 \ ['C123456789', 's/C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
521 \ ['D', 's/D/d/', ['d']],
522 \ ['E', 's/E/~/', ['d']],
523 \ ['F', 's/F/\~/', ['~']],
524 \ ['G', 's/G/\ugg/', ['Gg']],
525 \ ['H', 's/H/\Uh\Eh/', ['Hh']],
526 \ ['I', 's/I/\lII/', ['iI']],
527 \ ['J', 's/J/\LJ\EJ/', ['jJ']],
528 \ ['K', 's/K/\Uk\ek/', ['Kk']],
529 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
530 \ ['mMm', 's/M/\r/', ['m', 'm']],
531 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
532 \ ['oOo', 's/O/\n/', ["o\no"]],
533 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
534 \ ['qQq', 's/Q/\t/', ["q\tq"]],
535 \ ['rRr', 's/R/\\/', ['r\r']],
536 \ ['sSs', 's/S/\c/', ['scs']],
537 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
538 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
zeertzjq3269efd2022-06-12 11:13:05 +0100539 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
540 \ ['\', 's/\\/\\\\/', ['\\']]
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200541 \ ]
542 call Run_SubCmd_Tests(tests)
543endfunc
544
545func Test_sub_cmd_2()
546 set nomagic
547 set cpo&
548
549 " List entry format: [input, cmd, output]
550 let tests = [['A', 's/A/&&/', ['&&']],
551 \ ['B', 's/B/\&/', ['B']],
552 \ ['C123456789', 's/\mC\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
553 \ ['D', 's/D/d/', ['d']],
554 \ ['E', 's/E/~/', ['~']],
555 \ ['F', 's/F/\~/', ['~']],
556 \ ['G', 's/G/\ugg/', ['Gg']],
557 \ ['H', 's/H/\Uh\Eh/', ['Hh']],
558 \ ['I', 's/I/\lII/', ['iI']],
559 \ ['J', 's/J/\LJ\EJ/', ['jJ']],
560 \ ['K', 's/K/\Uk\ek/', ['Kk']],
561 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
562 \ ['mMm', 's/M/\r/', ['m', 'm']],
563 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
564 \ ['oOo', 's/O/\n/', ["o\no"]],
565 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
566 \ ['qQq', 's/Q/\t/', ["q\tq"]],
567 \ ['rRr', 's/R/\\/', ['r\r']],
568 \ ['sSs', 's/S/\c/', ['scs']],
569 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
570 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
zeertzjq3269efd2022-06-12 11:13:05 +0100571 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
572 \ ['\', 's/\\/\\\\/', ['\\']]
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200573 \ ]
574 call Run_SubCmd_Tests(tests)
575endfunc
576
577func Test_sub_cmd_3()
578 set nomagic
579 set cpo&
580
581 " List entry format: [input, cmd, output]
582 let tests = [['aAa', "s/A/\\='\\'/", ['a\a']],
583 \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']],
584 \ ['cCc', "s/C/\\='\<C-V>\<C-M>'/", ["c\<C-V>", 'c']],
585 \ ['dDd', "s/D/\\='\\\<C-V>\<C-M>'/", ["d\\\<C-V>", 'd']],
586 \ ['eEe', "s/E/\\='\\\\\<C-V>\<C-M>'/", ["e\\\\\<C-V>", 'e']],
587 \ ['fFf', "s/F/\\='\r'/", ['f', 'f']],
588 \ ['gGg', "s/G/\\='\<C-V>\<C-J>'/", ["g\<C-V>", 'g']],
589 \ ['hHh', "s/H/\\='\\\<C-V>\<C-J>'/", ["h\\\<C-V>", 'h']],
590 \ ['iIi', "s/I/\\='\\\\\<C-V>\<C-J>'/", ["i\\\\\<C-V>", 'i']],
591 \ ['jJj', "s/J/\\='\n'/", ['j', 'j']],
592 \ ['kKk', 's/K/\="\r"/', ['k', 'k']],
593 \ ['lLl', 's/L/\="\n"/', ['l', 'l']]
594 \ ]
595 call Run_SubCmd_Tests(tests)
596endfunc
597
Bram Moolenaarf1699962019-08-31 17:48:19 +0200598" Test for submatch() on :substitute.
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200599func Test_sub_cmd_4()
600 set magic&
601 set cpo&
602
603 " List entry format: [input, cmd, output]
604 let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/",
Bram Moolenaar1e115362019-01-09 23:01:02 +0100605 \ ['a\a']],
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200606 \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/",
Bram Moolenaar1e115362019-01-09 23:01:02 +0100607 \ ['b\b']],
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200608 \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/",
609 \ ["c\<C-V>", 'c']],
610 \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/",
611 \ ["d\<C-V>", 'd']],
612 \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\<C-V>\<C-M>', '')/",
613 \ ["e\\\<C-V>", 'e']],
614 \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/",
615 \ ['f', 'f']],
616 \ ['gGg', 's/G/\=substitute(submatch(0), ".", "\<C-V>\<C-J>", "")/',
617 \ ["g\<C-V>", 'g']],
618 \ ['hHh', 's/H/\=substitute(submatch(0), ".", "\\\<C-V>\<C-J>", "")/',
619 \ ["h\<C-V>", 'h']],
620 \ ['iIi', 's/I/\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-J>", "")/',
621 \ ["i\\\<C-V>", 'i']],
622 \ ['jJj', "s/J/\\=substitute(submatch(0), '.', '\\n', '')/",
623 \ ['j', 'j']],
624 \ ['kKk', "s/K/\\=substitute(submatch(0), '.', '\\r', '')/",
625 \ ['k', 'k']],
626 \ ['lLl', "s/L/\\=substitute(submatch(0), '.', '\\n', '')/",
627 \ ['l', 'l']],
628 \ ]
629 call Run_SubCmd_Tests(tests)
630endfunc
631
632func Test_sub_cmd_5()
633 set magic&
634 set cpo&
635
636 " List entry format: [input, cmd, output]
637 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']],
638 \ ['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']]"]],
639 \ ]
640 call Run_SubCmd_Tests(tests)
641endfunc
642
643" Test for *:s%* on :substitute.
644func Test_sub_cmd_6()
645 set magic&
646 set cpo+=/
647
648 " List entry format: [input, cmd, output]
649 let tests = [ ['A', 's/A/a/', ['a']],
650 \ ['B', 's/B/%/', ['a']],
651 \ ]
652 call Run_SubCmd_Tests(tests)
653
654 set cpo-=/
655 let tests = [ ['C', 's/C/c/', ['c']],
656 \ ['D', 's/D/%/', ['%']],
657 \ ]
658 call Run_SubCmd_Tests(tests)
659
660 set cpo&
661endfunc
662
663" Test for :s replacing \n with line break.
664func Test_sub_cmd_7()
665 set magic&
666 set cpo&
667
668 " List entry format: [input, cmd, output]
669 let tests = [ ["A\<C-V>\<C-M>A", 's/A./\=submatch(0)/', ['A', 'A']],
670 \ ["B\<C-V>\<C-J>B", 's/B./\=submatch(0)/', ['B', 'B']],
671 \ ["C\<C-V>\<C-J>C", 's/C./\=strtrans(string(submatch(0, 1)))/', [strtrans("['C\<C-J>']C")]],
672 \ ["D\<C-V>\<C-J>\nD", 's/D.\nD/\=strtrans(string(submatch(0, 1)))/', [strtrans("['D\<C-J>', 'D']")]],
673 \ ["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']")]],
674 \ ]
675 call Run_SubCmd_Tests(tests)
676
677 exe "normal oQ\nQ\<Esc>k"
Bram Moolenaare2e40752020-09-04 21:18:46 +0200678 call assert_fails('s/Q[^\n]Q/\=submatch(0)."foobar"/', 'E486:')
Bram Moolenaar15993ce2017-10-26 20:21:44 +0200679 enew!
680endfunc
681
682func TitleString()
683 let check = 'foo' =~ 'bar'
684 return ""
685endfunc
686
687func Test_sub_cmd_8()
688 set titlestring=%{TitleString()}
689
690 enew!
691 call append(0, ['', 'test_one', 'test_two'])
692 call cursor(1,1)
693 /^test_one/s/.*/\="foo\nbar"/
694 call assert_equal('foo', getline(2))
695 call assert_equal('bar', getline(3))
696 call feedkeys(':/^test_two/s/.*/\="foo\nbar"/c', "t")
697 call feedkeys("\<CR>y", "xt")
698 call assert_equal('foo', getline(4))
699 call assert_equal('bar', getline(5))
700
701 enew!
702 set titlestring&
703endfunc
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100704
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200705func Test_sub_cmd_9()
706 new
707 let input = ['1 aaa', '2 aaa', '3 aaa']
708 call setline(1, input)
709 func Foo()
710 return submatch(0)
711 endfunc
712 %s/aaa/\=Foo()/gn
713 call assert_equal(input, getline(1, '$'))
714 call assert_equal(1, &modifiable)
715
716 delfunc Foo
717 bw!
718endfunc
719
Bram Moolenaara04f4572022-09-13 13:45:26 +0100720func Test_sub_highlight_zero_match()
721 CheckRunVimInTerminal
722
723 let lines =<< trim END
724 call setline(1, ['one', 'two', 'three'])
725 END
726 call writefile(lines, 'XscriptSubHighlight', 'D')
727 let buf = RunVimInTerminal('-S XscriptSubHighlight', #{rows: 8, cols: 60})
728 call term_sendkeys(buf, ":%s/^/ /c\<CR>")
729 call VerifyScreenDump(buf, 'Test_sub_highlight_zer_match_1', {})
730
731 call term_sendkeys(buf, "\<Esc>")
732 call StopVimInTerminal(buf)
733endfunc
734
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100735func Test_nocatch_sub_failure_handling()
Bram Moolenaar94722c52023-01-28 19:19:03 +0000736 " normal error results in all replacements
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200737 func Foo()
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100738 foobar
739 endfunc
740 new
741 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
zeertzjq3269efd2022-06-12 11:13:05 +0100742 " need silent! to avoid a delay when entering Insert mode
743 silent! %s/aaa/\=Foo()/g
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100744 call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3))
745
zeertzjq3269efd2022-06-12 11:13:05 +0100746 " Throw without try-catch causes abort after the first line.
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100747 " We cannot test this, since it would stop executing the test script.
748
749 " try/catch does not result in any changes
750 func! Foo()
751 throw 'error'
752 endfunc
753 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
754 let error_caught = 0
755 try
756 %s/aaa/\=Foo()/g
757 catch
758 let error_caught = 1
759 endtry
760 call assert_equal(1, error_caught)
761 call assert_equal(['1 aaa', '2 aaa', '3 aaa'], getline(1, 3))
762
Bram Moolenaar6349e942019-05-18 13:41:22 +0200763 " Same, but using "n" flag so that "sandbox" gets set
764 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
765 let error_caught = 0
766 try
767 %s/aaa/\=Foo()/gn
768 catch
769 let error_caught = 1
770 endtry
771 call assert_equal(1, error_caught)
772 call assert_equal(['1 aaa', '2 aaa', '3 aaa'], getline(1, 3))
773
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200774 delfunc Foo
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100775 bwipe!
776endfunc
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200777
778" Test ":s/pat/sub/" with different ~s in sub.
779func Test_replace_with_tilde()
780 new
781 " Set the last replace string to empty
782 s/^$//
783 call append(0, ['- Bug in "vPPPP" on this text:'])
784 normal gg
785 s/u/~u~/
786 call assert_equal('- Bug in "vPPPP" on this text:', getline(1))
787 s/i/~u~/
788 call assert_equal('- Bug uuun "vPPPP" on this text:', getline(1))
789 s/o/~~~/
790 call assert_equal('- Bug uuun "vPPPP" uuuuuuuuun this text:', getline(1))
791 close!
792endfunc
793
794func Test_replace_keeppatterns()
795 new
796 a
797foobar
798
799substitute foo asdf
800
801one two
802.
803
804 normal gg
805 /^substitute
806 s/foo/bar/
807 call assert_equal('foo', @/)
808 call assert_equal('substitute bar asdf', getline('.'))
809
810 /^substitute
811 keeppatterns s/asdf/xyz/
812 call assert_equal('^substitute', @/)
813 call assert_equal('substitute bar xyz', getline('.'))
814
815 exe "normal /bar /e\<CR>"
816 call assert_equal(15, col('.'))
817 normal -
818 keeppatterns /xyz
819 call assert_equal('bar ', @/)
820 call assert_equal('substitute bar xyz', getline('.'))
821 exe "normal 0dn"
822 call assert_equal('xyz', getline('.'))
823
824 close!
825endfunc
Bram Moolenaarbb265962019-10-31 04:38:36 +0100826
827func Test_sub_beyond_end()
828 new
829 call setline(1, '#')
830 let @/ = '^#\n\zs'
831 s///e
832 call assert_equal('#', getline(1))
833 bwipe!
834endfunc
Bram Moolenaar5d98dc22020-01-29 21:57:34 +0100835
Bram Moolenaarea3db912020-02-02 15:32:13 +0100836" Test for repeating last substitution using :~ and :&r
837func Test_repeat_last_sub()
838 new
839 call setline(1, ['blue green yellow orange white'])
840 s/blue/red/
841 let @/ = 'yellow'
842 ~
843 let @/ = 'white'
844 :&r
845 let @/ = 'green'
846 s//gray
847 call assert_equal('red gray red orange red', getline(1))
848 close!
849endfunc
850
851" Test for Vi compatible substitution:
852" \/{string}/, \?{string}? and \&{string}&
853func Test_sub_vi_compatibility()
854 new
855 call setline(1, ['blue green yellow orange blue'])
856 let @/ = 'orange'
857 s\/white/
858 let @/ = 'blue'
859 s\?amber?
860 let @/ = 'white'
861 s\&green&
862 call assert_equal('amber green yellow white green', getline(1))
863 close!
Bram Moolenaar9fb7b422022-03-05 21:13:26 +0000864
865 call assert_fails('vim9cmd s\/white/', 'E1270:')
866 call assert_fails('vim9cmd s\?white?', 'E1270:')
867 call assert_fails('vim9cmd s\&white&', 'E1270:')
Bram Moolenaarea3db912020-02-02 15:32:13 +0100868endfunc
869
870" Test for substitute with the new text longer than the original text
871func Test_sub_expand_text()
872 new
873 call setline(1, 'abcabcabcabcabcabcabcabc')
874 s/b/\=repeat('B', 10)/g
875 call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1))
876 close!
877endfunc
878
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100879" Test for command failures when the last substitute pattern is not set.
880func Test_sub_with_no_last_pat()
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100881 let lines =<< trim [SCRIPT]
882 call assert_fails('~', 'E33:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200883 call assert_fails('s//abc/g', 'E35:')
884 call assert_fails('s\/bar', 'E35:')
885 call assert_fails('s\&bar&', 'E33:')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100886 call writefile(v:errors, 'Xresult')
887 qall!
888 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +0100889 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100890 if RunVim([], [], '--clean -S Xscript')
891 call assert_equal([], readfile('Xresult'))
892 endif
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100893
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100894 let lines =<< trim [SCRIPT]
895 set cpo+=/
896 call assert_fails('s/abc/%/', 'E33:')
897 call writefile(v:errors, 'Xresult')
898 qall!
899 [SCRIPT]
900 call writefile(lines, 'Xscript')
901 if RunVim([], [], '--clean -S Xscript')
902 call assert_equal([], readfile('Xresult'))
903 endif
904
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100905 call delete('Xresult')
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100906endfunc
907
Bram Moolenaarca68ae12020-03-30 19:32:53 +0200908func Test_substitute()
909 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
Bram Moolenaar004a6782020-04-11 17:09:31 +0200910 " Substitute with special keys
911 call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", ''))
912endfunc
913
914func Test_substitute_expr()
915 let g:val = 'XXX'
916 call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
917 call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
918 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
919 \ '\=nr2char("0x" . submatch(1))', 'g'))
920 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
921 \ {-> nr2char("0x" . submatch(1))}, 'g'))
922
923 call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
924 \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
925
926 func Recurse()
927 return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
928 endfunc
929 " recursive call works
930 call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
931
932 call assert_fails("let s=submatch([])", 'E745:')
933 call assert_fails("let s=submatch(2, [])", 'E745:')
934endfunc
935
936func Test_invalid_submatch()
937 " This was causing invalid memory access in Vim-7.4.2232 and older
938 call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
939 call assert_fails('eval submatch(-1)', 'E935:')
940 call assert_equal('', submatch(0))
941 call assert_equal('', submatch(1))
942 call assert_equal([], submatch(0, 1))
943 call assert_equal([], submatch(1, 1))
944endfunc
945
Bram Moolenaar8a0dcf42020-09-06 15:14:45 +0200946func Test_submatch_list_concatenate()
947 let pat = 'A\(.\)'
948 let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
949 call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
950endfunc
951
Bram Moolenaar004a6782020-04-11 17:09:31 +0200952func Test_substitute_expr_arg()
953 call assert_equal('123456789-123456789=', substitute('123456789',
954 \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
955 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
956
957 call assert_equal('123456-123456=789', substitute('123456789',
958 \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
959 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
960
961 call assert_equal('123456789-123456789x=', substitute('123456789',
962 \ '\(.\)\(.\)\(.*\)',
963 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
964
965 call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
966 call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
967 call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
968 call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
969endfunc
970
971" Test for using a function to supply the substitute string
972func Test_substitute_using_func()
973 func Xfunc()
974 return '1234'
975 endfunc
976 call assert_equal('a1234f', substitute('abcdef', 'b..e',
977 \ function("Xfunc"), ''))
978 delfunc Xfunc
979endfunc
980
981" Test for using submatch() with a multiline match
982func Test_substitute_multiline_submatch()
983 new
984 call setline(1, ['line1', 'line2', 'line3', 'line4'])
985 %s/^line1\(\_.\+\)line4$/\=submatch(1)/
986 call assert_equal(['', 'line2', 'line3', ''], getline(1, '$'))
987 close!
Bram Moolenaarca68ae12020-03-30 19:32:53 +0200988endfunc
989
Bram Moolenaardf365142021-05-03 20:01:45 +0200990func Test_substitute_skipped_range()
991 new
992 if 0
993 /1/5/2/2/\n
994 endif
995 call assert_equal([0, 1, 1, 0, 1], getcurpos())
996 bwipe!
997endfunc
998
Dominique Pellebfb2bb12021-08-14 21:11:51 +0200999" Test using the 'gdefault' option (when on, flag 'g' is default on).
1000func Test_substitute_gdefault()
1001 new
1002
1003 " First check without 'gdefault'
1004 call setline(1, 'foo bar foo')
1005 s/foo/FOO/
1006 call assert_equal('FOO bar foo', getline(1))
1007 call setline(1, 'foo bar foo')
1008 s/foo/FOO/g
1009 call assert_equal('FOO bar FOO', getline(1))
1010 call setline(1, 'foo bar foo')
1011 s/foo/FOO/gg
1012 call assert_equal('FOO bar foo', getline(1))
1013
1014 " Then check with 'gdefault'
1015 set gdefault
1016 call setline(1, 'foo bar foo')
1017 s/foo/FOO/
1018 call assert_equal('FOO bar FOO', getline(1))
1019 call setline(1, 'foo bar foo')
1020 s/foo/FOO/g
1021 call assert_equal('FOO bar foo', getline(1))
1022 call setline(1, 'foo bar foo')
1023 s/foo/FOO/gg
1024 call assert_equal('FOO bar FOO', getline(1))
1025
1026 " Setting 'compatible' should reset 'gdefault'
1027 call assert_equal(1, &gdefault)
1028 set compatible
1029 call assert_equal(0, &gdefault)
1030 set nocompatible
1031 call assert_equal(0, &gdefault)
1032
1033 bw!
1034endfunc
1035
Bram Moolenaar37f47952022-01-29 14:21:51 +00001036" This was using "old_sub" after it was freed.
1037func Test_using_old_sub()
1038 set compatible maxfuncdepth=10
1039 new
1040 call setline(1, 'some text.')
1041 func Repl()
1042 ~
1043 s/
1044 endfunc
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001045 silent! s/\%')/\=Repl()
Bram Moolenaar37f47952022-01-29 14:21:51 +00001046
1047 delfunc Repl
1048 bwipe!
1049 set nocompatible
1050endfunc
1051
Bram Moolenaare2bd8602022-05-18 13:11:57 +01001052" This was switching windows in between computing the length and using it.
1053func Test_sub_change_window()
1054 silent! lfile
1055 sil! norm o0000000000000000000000000000000000000000000000000000
1056 func Repl()
1057 lopen
1058 endfunc
1059 silent! s/\%')/\=Repl()
1060 bwipe!
1061 bwipe!
1062 delfunc Repl
1063endfunc
1064
Bram Moolenaar338f1fc2022-05-26 15:56:23 +01001065" This was undoign a change in between computing the length and using it.
1066func Do_Test_sub_undo_change()
1067 new
1068 norm o0000000000000000000000000000000000000000000000000000
1069 silent! s/\%')/\=Repl()
1070 bwipe!
1071endfunc
1072
1073func Test_sub_undo_change()
1074 func Repl()
1075 silent! norm g-
1076 endfunc
1077 call Do_Test_sub_undo_change()
1078
1079 func! Repl()
1080 silent earlier
1081 endfunc
1082 call Do_Test_sub_undo_change()
1083
1084 delfunc Repl
1085endfunc
1086
Bram Moolenaar71223e22022-05-30 15:23:09 +01001087" This was opening a command line window from the expression
1088func Test_sub_open_cmdline_win()
1089 " the error only happens in a very specific setup, run a new Vim instance to
1090 " get a clean starting point.
1091 let lines =<< trim [SCRIPT]
Bram Moolenaarbe990422022-05-30 16:01:42 +01001092 set vb t_vb=
Bram Moolenaar71223e22022-05-30 15:23:09 +01001093 norm o0000000000000000000000000000000000000000000000000000
1094 func Replace()
1095 norm q/
1096 endfunc
1097 s/\%')/\=Replace()
1098 redir >Xresult
1099 messages
1100 redir END
1101 qall!
1102 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +01001103 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar71223e22022-05-30 15:23:09 +01001104 if RunVim([], [], '-u NONE -S Xscript')
Bram Moolenaarbe990422022-05-30 16:01:42 +01001105 call assert_match('E565: Not allowed to change text or change window',
1106 \ readfile('Xresult')->join('XX'))
Bram Moolenaar71223e22022-05-30 15:23:09 +01001107 endif
1108
Bram Moolenaar71223e22022-05-30 15:23:09 +01001109 call delete('Xresult')
1110endfunc
1111
Bram Moolenaard6211a52022-06-18 19:48:14 +01001112" This was editing a script file from the expression
1113func Test_sub_edit_scriptfile()
1114 new
1115 norm o0000000000000000000000000000000000000000000000000000
1116 func EditScript()
Bram Moolenaarb18b4962022-09-02 21:55:50 +01001117 silent! scr! Xsedfile
Bram Moolenaard6211a52022-06-18 19:48:14 +01001118 endfunc
1119 s/\%')/\=EditScript()
1120
1121 delfunc EditScript
1122 bwipe!
1123endfunc
1124
Bram Moolenaarcc762a42022-11-25 13:03:31 +00001125" This was editing another file from the expression.
1126func Test_sub_expr_goto_other_file()
1127 call writefile([''], 'Xfileone', 'D')
1128 enew!
1129 call setline(1, ['a', 'b', 'c', 'd',
1130 \ 'Xfileone zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'])
1131
1132 func g:SplitGotoFile()
1133 exe "sil! norm 0\<C-W>gf"
1134 return ''
1135 endfunc
1136
1137 $
1138 s/\%')/\=g:SplitGotoFile()
1139
1140 delfunc g:SplitGotoFile
1141 bwipe!
1142endfunc
1143
Bram Moolenaar3ac1d972023-01-04 17:17:54 +00001144func Test_recursive_expr_substitute()
1145 " this was reading invalid memory
1146 let lines =<< trim END
1147 func Repl(g, n)
1148 s
1149 r%:s000
1150 endfunc
1151 next 0
1152 let caught = 0
1153 s/\%')/\=Repl(0, 0)
1154 qall!
1155 END
1156 call writefile(lines, 'XexprSubst', 'D')
1157 call RunVim([], [], '--clean -S XexprSubst')
1158endfunc
1159
Yegappan Lakshmanan5e877ba2022-03-25 21:19:26 +00001160" Test for the 2-letter and 3-letter :substitute commands
1161func Test_substitute_short_cmd()
1162 new
1163 call setline(1, ['one', 'one one one'])
1164 s/one/two
1165 call cursor(2, 1)
1166
1167 " :sc
1168 call feedkeys(":sc\<CR>y", 'xt')
1169 call assert_equal('two one one', getline(2))
1170
1171 " :scg
1172 call setline(2, 'one one one')
1173 call feedkeys(":scg\<CR>nyq", 'xt')
1174 call assert_equal('one two one', getline(2))
1175
1176 " :sci
1177 call setline(2, 'ONE One onE')
1178 call feedkeys(":sci\<CR>y", 'xt')
1179 call assert_equal('two One onE', getline(2))
1180
1181 " :scI
1182 set ignorecase
1183 call setline(2, 'ONE One one')
1184 call feedkeys(":scI\<CR>y", 'xt')
1185 call assert_equal('ONE One two', getline(2))
1186 set ignorecase&
1187
1188 " :scn
1189 call setline(2, 'one one one')
1190 let t = execute('scn')->split("\n")
1191 call assert_equal(['1 match on 1 line'], t)
1192 call assert_equal('one one one', getline(2))
1193
1194 " :scp
1195 call setline(2, "\tone one one")
1196 redir => output
1197 call feedkeys(":scp\<CR>y", 'xt')
1198 redir END
1199 call assert_equal(' two one one', output->split("\n")[-1])
1200 call assert_equal("\ttwo one one", getline(2))
1201
1202 " :scl
1203 call setline(2, "\tone one one")
1204 redir => output
1205 call feedkeys(":scl\<CR>y", 'xt')
1206 redir END
1207 call assert_equal("^Itwo one one$", output->split("\n")[-1])
1208 call assert_equal("\ttwo one one", getline(2))
1209
1210 " :sgc
1211 call setline(2, 'one one one one one')
1212 call feedkeys(":sgc\<CR>nyyq", 'xt')
1213 call assert_equal('one two two one one', getline(2))
1214
1215 " :sg
1216 call setline(2, 'one one one')
1217 sg
1218 call assert_equal('two two two', getline(2))
1219
1220 " :sgi
1221 call setline(2, 'ONE One onE')
1222 sgi
1223 call assert_equal('two two two', getline(2))
1224
1225 " :sgI
1226 set ignorecase
1227 call setline(2, 'ONE One one')
1228 sgI
1229 call assert_equal('ONE One two', getline(2))
1230 set ignorecase&
1231
1232 " :sgn
1233 call setline(2, 'one one one')
1234 let t = execute('sgn')->split("\n")
1235 call assert_equal(['3 matches on 1 line'], t)
1236 call assert_equal('one one one', getline(2))
1237
1238 " :sgp
1239 call setline(2, "\tone one one")
1240 redir => output
1241 sgp
1242 redir END
1243 call assert_equal(' two two two', output->split("\n")[-1])
1244 call assert_equal("\ttwo two two", getline(2))
1245
1246 " :sgl
1247 call setline(2, "\tone one one")
1248 redir => output
1249 sgl
1250 redir END
1251 call assert_equal("^Itwo two two$", output->split("\n")[-1])
1252 call assert_equal("\ttwo two two", getline(2))
1253
1254 " :sgr
1255 call setline(2, "one one one")
1256 call cursor(2, 1)
1257 s/abc/xyz/e
1258 let @/ = 'one'
1259 sgr
1260 call assert_equal('xyz xyz xyz', getline(2))
1261
1262 " :sic
1263 call cursor(1, 1)
1264 s/one/two/e
1265 call setline(2, "ONE One one")
1266 call cursor(2, 1)
1267 call feedkeys(":sic\<CR>y", 'xt')
1268 call assert_equal('two One one', getline(2))
1269
1270 " :si
1271 call setline(2, "ONE One one")
1272 si
1273 call assert_equal('two One one', getline(2))
1274
1275 " :siI
1276 call setline(2, "ONE One one")
1277 siI
1278 call assert_equal('ONE One two', getline(2))
1279
1280 " :sin
1281 call setline(2, 'ONE One onE')
1282 let t = execute('sin')->split("\n")
1283 call assert_equal(['1 match on 1 line'], t)
1284 call assert_equal('ONE One onE', getline(2))
1285
1286 " :sip
1287 call setline(2, "\tONE One onE")
1288 redir => output
1289 sip
1290 redir END
1291 call assert_equal(' two One onE', output->split("\n")[-1])
1292 call assert_equal("\ttwo One onE", getline(2))
1293
1294 " :sir
1295 call setline(2, "ONE One onE")
1296 call cursor(2, 1)
1297 s/abc/xyz/e
1298 let @/ = 'one'
1299 sir
1300 call assert_equal('xyz One onE', getline(2))
1301
1302 " :sIc
1303 call cursor(1, 1)
1304 s/one/two/e
1305 call setline(2, "ONE One one")
1306 call cursor(2, 1)
1307 call feedkeys(":sIc\<CR>y", 'xt')
1308 call assert_equal('ONE One two', getline(2))
1309
1310 " :sIg
1311 call setline(2, "ONE one onE one")
1312 sIg
1313 call assert_equal('ONE two onE two', getline(2))
1314
1315 " :sIi
1316 call setline(2, "ONE One one")
1317 sIi
1318 call assert_equal('two One one', getline(2))
1319
1320 " :sI
1321 call setline(2, "ONE One one")
1322 sI
1323 call assert_equal('ONE One two', getline(2))
1324
1325 " :sIn
1326 call setline(2, 'ONE One one')
1327 let t = execute('sIn')->split("\n")
1328 call assert_equal(['1 match on 1 line'], t)
1329 call assert_equal('ONE One one', getline(2))
1330
1331 " :sIp
1332 call setline(2, "\tONE One one")
1333 redir => output
1334 sIp
1335 redir END
1336 call assert_equal(' ONE One two', output->split("\n")[-1])
1337 call assert_equal("\tONE One two", getline(2))
1338
1339 " :sIl
1340 call setline(2, "\tONE onE one")
1341 redir => output
1342 sIl
1343 redir END
1344 call assert_equal("^IONE onE two$", output->split("\n")[-1])
1345 call assert_equal("\tONE onE two", getline(2))
1346
1347 " :sIr
1348 call setline(2, "ONE one onE")
1349 call cursor(2, 1)
1350 s/abc/xyz/e
1351 let @/ = 'one'
1352 sIr
1353 call assert_equal('ONE xyz onE', getline(2))
1354
1355 " :src
1356 call setline(2, "ONE one one")
1357 call cursor(2, 1)
1358 s/abc/xyz/e
1359 let @/ = 'one'
1360 call feedkeys(":src\<CR>y", 'xt')
1361 call assert_equal('ONE xyz one', getline(2))
1362
1363 " :srg
1364 call setline(2, "one one one")
1365 call cursor(2, 1)
1366 s/abc/xyz/e
1367 let @/ = 'one'
1368 srg
1369 call assert_equal('xyz xyz xyz', getline(2))
1370
1371 " :sri
1372 call setline(2, "ONE one onE")
1373 call cursor(2, 1)
1374 s/abc/xyz/e
1375 let @/ = 'one'
1376 sri
1377 call assert_equal('xyz one onE', getline(2))
1378
1379 " :srI
1380 call setline(2, "ONE one onE")
1381 call cursor(2, 1)
1382 s/abc/xyz/e
1383 let @/ = 'one'
1384 srI
1385 call assert_equal('ONE xyz onE', getline(2))
1386
1387 " :srn
1388 call setline(2, "ONE one onE")
1389 call cursor(2, 1)
1390 s/abc/xyz/e
1391 let @/ = 'one'
1392 let t = execute('srn')->split("\n")
1393 call assert_equal(['1 match on 1 line'], t)
1394 call assert_equal('ONE one onE', getline(2))
1395
1396 " :srp
1397 call setline(2, "\tONE one onE")
1398 call cursor(2, 1)
1399 s/abc/xyz/e
1400 let @/ = 'one'
1401 redir => output
1402 srp
1403 redir END
1404 call assert_equal(' ONE xyz onE', output->split("\n")[-1])
1405 call assert_equal("\tONE xyz onE", getline(2))
1406
1407 " :srl
1408 call setline(2, "\tONE one onE")
1409 call cursor(2, 1)
1410 s/abc/xyz/e
1411 let @/ = 'one'
1412 redir => output
1413 srl
1414 redir END
1415 call assert_equal("^IONE xyz onE$", output->split("\n")[-1])
1416 call assert_equal("\tONE xyz onE", getline(2))
1417
1418 " :sr
1419 call setline(2, "ONE one onE")
1420 call cursor(2, 1)
1421 s/abc/xyz/e
1422 let @/ = 'one'
1423 sr
1424 call assert_equal('ONE xyz onE', getline(2))
1425
1426 " :sce
1427 s/abc/xyz/e
1428 call assert_fails("sc", 'E486:')
1429 sce
1430 " :sge
1431 call assert_fails("sg", 'E486:')
1432 sge
1433 " :sie
1434 call assert_fails("si", 'E486:')
1435 sie
1436 " :sIe
1437 call assert_fails("sI", 'E486:')
1438 sIe
1439
1440 bw!
1441endfunc
Bram Moolenaar37f47952022-01-29 14:21:51 +00001442
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001443" Check handling expanding "~" resulting in extremely long text.
Bram Moolenaar916d6dd2023-05-09 21:45:47 +01001444" FIXME: disabled, it takes too long to run on CI
Bram Moolenaara4467c42023-05-09 22:07:11 +01001445"func Test_substitute_tilde_too_long()
1446" enew!
1447"
1448" s/.*/ixxx
1449" s//~~~~~~~~~AAAAAAA@(
1450"
1451" " Either fails with "out of memory" or "text too long".
1452" " This can take a long time.
1453" call assert_fails('sil! norm &&&&&&&&&', ['E1240:\|E342:'])
1454"
1455" bwipe!
1456"endfunc
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001457
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001458" This should be done last to reveal a memory leak when vim_regsub_both() is
1459" called to evaluate an expression but it is not used in a second call.
1460func Test_z_substitute_expr_leak()
1461 func SubExpr()
1462 ~n
1463 endfunc
1464 silent! s/\%')/\=SubExpr()
1465 delfunc SubExpr
1466endfunc
1467
Christian Brabandt18d27092023-09-06 19:53:36 +02001468func Test_substitute_expr_switch_win()
1469 func R()
1470 wincmd x
1471 return 'XXXX'
1472 endfunc
1473 new Xfoobar
1474 let bufnr = bufnr('%')
Christian Brabandt26c11c52023-11-22 21:26:41 +01001475 put ='abcdef'
Christian Brabandt18d27092023-09-06 19:53:36 +02001476 silent! s/\%')/\=R()
Christian Brabandtee17b6f2023-09-09 11:23:50 +02001477 call assert_fails(':%s/./\=R()/g', 'E565:')
Christian Brabandt18d27092023-09-06 19:53:36 +02001478 delfunc R
1479 exe bufnr .. "bw!"
1480endfunc
1481
Christian Brabandt26c11c52023-11-22 21:26:41 +01001482" recursive call of :s using test-replace special
1483func Test_substitute_expr_recursive()
1484 func Q()
1485 %s/./\='foobar'/gn
1486 return "foobar"
1487 endfunc
1488 func R()
1489 %s/./\=Q()/g
1490 endfunc
1491 new Xfoobar_UAF
1492 let bufnr = bufnr('%')
1493 put ='abcdef'
1494 silent! s/./\=R()/g
1495 call assert_fails(':%s/./\=R()/g', 'E565:')
1496 delfunc R
1497 delfunc Q
1498 exe bufnr .. "bw!"
1499endfunc
1500
Yegappan Lakshmanan4776e642024-05-19 09:06:50 +02001501" Test for changing 'cpo' in a substitute expression
1502func Test_substitute_expr_cpo()
1503 func XSubExpr()
1504 set cpo=
1505 return 'x'
1506 endfunc
1507
1508 let save_cpo = &cpo
1509 call assert_equal('xxx', substitute('abc', '.', '\=XSubExpr()', 'g'))
1510 call assert_equal(save_cpo, &cpo)
1511
1512 delfunc XSubExpr
1513endfunc
1514
Bram Moolenaar5d98dc22020-01-29 21:57:34 +01001515" vim: shiftwidth=2 sts=2 expandtab