blob: 21527db5f5994a8adf2c62f915761afe2ab6a7a1 [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()
Drew Vogelea67ba72025-05-07 22:05:17 +0200731 CheckScreendump
Bram Moolenaara04f4572022-09-13 13:45:26 +0100732 CheckRunVimInTerminal
733
734 let lines =<< trim END
735 call setline(1, ['one', 'two', 'three'])
736 END
737 call writefile(lines, 'XscriptSubHighlight', 'D')
738 let buf = RunVimInTerminal('-S XscriptSubHighlight', #{rows: 8, cols: 60})
739 call term_sendkeys(buf, ":%s/^/ /c\<CR>")
740 call VerifyScreenDump(buf, 'Test_sub_highlight_zer_match_1', {})
741
742 call term_sendkeys(buf, "\<Esc>")
743 call StopVimInTerminal(buf)
744endfunc
745
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100746func Test_nocatch_sub_failure_handling()
Bram Moolenaar94722c52023-01-28 19:19:03 +0000747 " normal error results in all replacements
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200748 func Foo()
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100749 foobar
750 endfunc
751 new
752 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
zeertzjq3269efd2022-06-12 11:13:05 +0100753 " need silent! to avoid a delay when entering Insert mode
754 silent! %s/aaa/\=Foo()/g
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100755 call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3))
756
zeertzjq3269efd2022-06-12 11:13:05 +0100757 " Throw without try-catch causes abort after the first line.
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100758 " We cannot test this, since it would stop executing the test script.
759
760 " try/catch does not result in any changes
761 func! Foo()
762 throw 'error'
763 endfunc
764 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
765 let error_caught = 0
766 try
767 %s/aaa/\=Foo()/g
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 Moolenaar6349e942019-05-18 13:41:22 +0200774 " Same, but using "n" flag so that "sandbox" gets set
775 call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
776 let error_caught = 0
777 try
778 %s/aaa/\=Foo()/gn
779 catch
780 let error_caught = 1
781 endtry
782 call assert_equal(1, error_caught)
783 call assert_equal(['1 aaa', '2 aaa', '3 aaa'], getline(1, 3))
784
Bram Moolenaar80341bc2019-05-20 20:34:51 +0200785 delfunc Foo
Bram Moolenaar0e97b942019-03-27 22:53:53 +0100786 bwipe!
787endfunc
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200788
789" Test ":s/pat/sub/" with different ~s in sub.
790func Test_replace_with_tilde()
791 new
792 " Set the last replace string to empty
793 s/^$//
794 call append(0, ['- Bug in "vPPPP" on this text:'])
795 normal gg
796 s/u/~u~/
797 call assert_equal('- Bug in "vPPPP" on this text:', getline(1))
798 s/i/~u~/
799 call assert_equal('- Bug uuun "vPPPP" on this text:', getline(1))
800 s/o/~~~/
801 call assert_equal('- Bug uuun "vPPPP" uuuuuuuuun this text:', getline(1))
802 close!
803endfunc
804
805func Test_replace_keeppatterns()
806 new
807 a
808foobar
809
Gregory Anders3b59be42024-08-15 22:04:22 +0200810substitute foo asdf foo
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200811
812one two
813.
814
815 normal gg
816 /^substitute
817 s/foo/bar/
818 call assert_equal('foo', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200819 call assert_equal('substitute bar asdf foo', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200820
821 /^substitute
822 keeppatterns s/asdf/xyz/
823 call assert_equal('^substitute', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200824 call assert_equal('substitute bar xyz foo', getline('.'))
825
826 /^substitute
827 &
828 call assert_equal('^substitute', @/)
829 call assert_equal('substitute bar xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200830
831 exe "normal /bar /e\<CR>"
832 call assert_equal(15, col('.'))
833 normal -
834 keeppatterns /xyz
835 call assert_equal('bar ', @/)
Gregory Anders3b59be42024-08-15 22:04:22 +0200836 call assert_equal('substitute bar xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200837 exe "normal 0dn"
Gregory Anders3b59be42024-08-15 22:04:22 +0200838 call assert_equal('xyz bar', getline('.'))
Bram Moolenaarc6b37db2019-04-27 18:00:34 +0200839
840 close!
841endfunc
Bram Moolenaarbb265962019-10-31 04:38:36 +0100842
843func Test_sub_beyond_end()
844 new
845 call setline(1, '#')
846 let @/ = '^#\n\zs'
847 s///e
848 call assert_equal('#', getline(1))
849 bwipe!
850endfunc
Bram Moolenaar5d98dc22020-01-29 21:57:34 +0100851
Bram Moolenaarea3db912020-02-02 15:32:13 +0100852" Test for repeating last substitution using :~ and :&r
853func Test_repeat_last_sub()
854 new
855 call setline(1, ['blue green yellow orange white'])
856 s/blue/red/
857 let @/ = 'yellow'
858 ~
859 let @/ = 'white'
860 :&r
861 let @/ = 'green'
862 s//gray
863 call assert_equal('red gray red orange red', getline(1))
864 close!
865endfunc
866
867" Test for Vi compatible substitution:
868" \/{string}/, \?{string}? and \&{string}&
869func Test_sub_vi_compatibility()
870 new
871 call setline(1, ['blue green yellow orange blue'])
872 let @/ = 'orange'
873 s\/white/
874 let @/ = 'blue'
875 s\?amber?
876 let @/ = 'white'
877 s\&green&
878 call assert_equal('amber green yellow white green', getline(1))
879 close!
Bram Moolenaar9fb7b422022-03-05 21:13:26 +0000880
881 call assert_fails('vim9cmd s\/white/', 'E1270:')
882 call assert_fails('vim9cmd s\?white?', 'E1270:')
883 call assert_fails('vim9cmd s\&white&', 'E1270:')
Bram Moolenaarea3db912020-02-02 15:32:13 +0100884endfunc
885
886" Test for substitute with the new text longer than the original text
887func Test_sub_expand_text()
888 new
889 call setline(1, 'abcabcabcabcabcabcabcabc')
890 s/b/\=repeat('B', 10)/g
891 call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1))
892 close!
893endfunc
894
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100895" Test for command failures when the last substitute pattern is not set.
896func Test_sub_with_no_last_pat()
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100897 let lines =<< trim [SCRIPT]
898 call assert_fails('~', 'E33:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +0200899 call assert_fails('s//abc/g', 'E35:')
900 call assert_fails('s\/bar', 'E35:')
901 call assert_fails('s\&bar&', 'E33:')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100902 call writefile(v:errors, 'Xresult')
903 qall!
904 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +0100905 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100906 if RunVim([], [], '--clean -S Xscript')
907 call assert_equal([], readfile('Xresult'))
908 endif
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100909
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100910 let lines =<< trim [SCRIPT]
911 set cpo+=/
912 call assert_fails('s/abc/%/', 'E33:')
913 call writefile(v:errors, 'Xresult')
914 qall!
915 [SCRIPT]
916 call writefile(lines, 'Xscript')
917 if RunVim([], [], '--clean -S Xscript')
918 call assert_equal([], readfile('Xresult'))
919 endif
920
Bram Moolenaar9f6277b2020-02-11 22:04:02 +0100921 call delete('Xresult')
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100922endfunc
923
Bram Moolenaarca68ae12020-03-30 19:32:53 +0200924func Test_substitute()
925 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
Bram Moolenaar004a6782020-04-11 17:09:31 +0200926 " Substitute with special keys
927 call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", ''))
928endfunc
929
930func Test_substitute_expr()
931 let g:val = 'XXX'
932 call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
933 call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
934 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
935 \ '\=nr2char("0x" . submatch(1))', 'g'))
936 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
937 \ {-> nr2char("0x" . submatch(1))}, 'g'))
938
939 call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
940 \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
941
942 func Recurse()
943 return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
944 endfunc
945 " recursive call works
946 call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
947
948 call assert_fails("let s=submatch([])", 'E745:')
949 call assert_fails("let s=submatch(2, [])", 'E745:')
950endfunc
951
952func Test_invalid_submatch()
953 " This was causing invalid memory access in Vim-7.4.2232 and older
954 call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
955 call assert_fails('eval submatch(-1)', 'E935:')
956 call assert_equal('', submatch(0))
957 call assert_equal('', submatch(1))
958 call assert_equal([], submatch(0, 1))
959 call assert_equal([], submatch(1, 1))
960endfunc
961
Bram Moolenaar8a0dcf42020-09-06 15:14:45 +0200962func Test_submatch_list_concatenate()
963 let pat = 'A\(.\)'
964 let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
965 call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
966endfunc
967
Bram Moolenaar004a6782020-04-11 17:09:31 +0200968func Test_substitute_expr_arg()
969 call assert_equal('123456789-123456789=', substitute('123456789',
970 \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
971 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
972
973 call assert_equal('123456-123456=789', substitute('123456789',
974 \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
975 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
976
977 call assert_equal('123456789-123456789x=', substitute('123456789',
978 \ '\(.\)\(.\)\(.*\)',
979 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
980
981 call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
982 call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
983 call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
984 call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
985endfunc
986
987" Test for using a function to supply the substitute string
988func Test_substitute_using_func()
989 func Xfunc()
990 return '1234'
991 endfunc
992 call assert_equal('a1234f', substitute('abcdef', 'b..e',
993 \ function("Xfunc"), ''))
994 delfunc Xfunc
995endfunc
996
997" Test for using submatch() with a multiline match
998func Test_substitute_multiline_submatch()
999 new
1000 call setline(1, ['line1', 'line2', 'line3', 'line4'])
1001 %s/^line1\(\_.\+\)line4$/\=submatch(1)/
1002 call assert_equal(['', 'line2', 'line3', ''], getline(1, '$'))
1003 close!
Bram Moolenaarca68ae12020-03-30 19:32:53 +02001004endfunc
1005
Bram Moolenaardf365142021-05-03 20:01:45 +02001006func Test_substitute_skipped_range()
1007 new
1008 if 0
1009 /1/5/2/2/\n
1010 endif
1011 call assert_equal([0, 1, 1, 0, 1], getcurpos())
1012 bwipe!
1013endfunc
1014
Dominique Pellebfb2bb12021-08-14 21:11:51 +02001015" Test using the 'gdefault' option (when on, flag 'g' is default on).
1016func Test_substitute_gdefault()
1017 new
1018
1019 " First check without 'gdefault'
1020 call setline(1, 'foo bar foo')
1021 s/foo/FOO/
1022 call assert_equal('FOO bar foo', getline(1))
1023 call setline(1, 'foo bar foo')
1024 s/foo/FOO/g
1025 call assert_equal('FOO bar FOO', getline(1))
1026 call setline(1, 'foo bar foo')
1027 s/foo/FOO/gg
1028 call assert_equal('FOO bar foo', getline(1))
1029
1030 " Then check with 'gdefault'
1031 set gdefault
1032 call setline(1, 'foo bar foo')
1033 s/foo/FOO/
1034 call assert_equal('FOO bar FOO', getline(1))
1035 call setline(1, 'foo bar foo')
1036 s/foo/FOO/g
1037 call assert_equal('FOO bar foo', getline(1))
1038 call setline(1, 'foo bar foo')
1039 s/foo/FOO/gg
1040 call assert_equal('FOO bar FOO', getline(1))
1041
1042 " Setting 'compatible' should reset 'gdefault'
1043 call assert_equal(1, &gdefault)
1044 set compatible
1045 call assert_equal(0, &gdefault)
1046 set nocompatible
1047 call assert_equal(0, &gdefault)
1048
1049 bw!
1050endfunc
1051
Bram Moolenaar37f47952022-01-29 14:21:51 +00001052" This was using "old_sub" after it was freed.
1053func Test_using_old_sub()
1054 set compatible maxfuncdepth=10
1055 new
1056 call setline(1, 'some text.')
1057 func Repl()
1058 ~
1059 s/
1060 endfunc
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001061 silent! s/\%')/\=Repl()
Bram Moolenaar37f47952022-01-29 14:21:51 +00001062
1063 delfunc Repl
1064 bwipe!
1065 set nocompatible
1066endfunc
1067
Bram Moolenaare2bd8602022-05-18 13:11:57 +01001068" This was switching windows in between computing the length and using it.
1069func Test_sub_change_window()
1070 silent! lfile
1071 sil! norm o0000000000000000000000000000000000000000000000000000
1072 func Repl()
1073 lopen
1074 endfunc
1075 silent! s/\%')/\=Repl()
1076 bwipe!
1077 bwipe!
1078 delfunc Repl
1079endfunc
1080
Bram Moolenaar338f1fc2022-05-26 15:56:23 +01001081" This was undoign a change in between computing the length and using it.
1082func Do_Test_sub_undo_change()
1083 new
1084 norm o0000000000000000000000000000000000000000000000000000
1085 silent! s/\%')/\=Repl()
1086 bwipe!
1087endfunc
1088
1089func Test_sub_undo_change()
1090 func Repl()
1091 silent! norm g-
1092 endfunc
1093 call Do_Test_sub_undo_change()
1094
1095 func! Repl()
1096 silent earlier
1097 endfunc
1098 call Do_Test_sub_undo_change()
1099
1100 delfunc Repl
1101endfunc
1102
Bram Moolenaar71223e22022-05-30 15:23:09 +01001103" This was opening a command line window from the expression
1104func Test_sub_open_cmdline_win()
1105 " the error only happens in a very specific setup, run a new Vim instance to
1106 " get a clean starting point.
1107 let lines =<< trim [SCRIPT]
Bram Moolenaarbe990422022-05-30 16:01:42 +01001108 set vb t_vb=
Bram Moolenaar71223e22022-05-30 15:23:09 +01001109 norm o0000000000000000000000000000000000000000000000000000
1110 func Replace()
1111 norm q/
1112 endfunc
1113 s/\%')/\=Replace()
1114 redir >Xresult
1115 messages
1116 redir END
1117 qall!
1118 [SCRIPT]
Bram Moolenaar56564962022-10-10 22:39:42 +01001119 call writefile(lines, 'Xscript', 'D')
Bram Moolenaar71223e22022-05-30 15:23:09 +01001120 if RunVim([], [], '-u NONE -S Xscript')
Bram Moolenaarbe990422022-05-30 16:01:42 +01001121 call assert_match('E565: Not allowed to change text or change window',
1122 \ readfile('Xresult')->join('XX'))
Bram Moolenaar71223e22022-05-30 15:23:09 +01001123 endif
1124
Bram Moolenaar71223e22022-05-30 15:23:09 +01001125 call delete('Xresult')
1126endfunc
1127
Bram Moolenaard6211a52022-06-18 19:48:14 +01001128" This was editing a script file from the expression
1129func Test_sub_edit_scriptfile()
1130 new
1131 norm o0000000000000000000000000000000000000000000000000000
1132 func EditScript()
Bram Moolenaarb18b4962022-09-02 21:55:50 +01001133 silent! scr! Xsedfile
Bram Moolenaard6211a52022-06-18 19:48:14 +01001134 endfunc
1135 s/\%')/\=EditScript()
1136
1137 delfunc EditScript
1138 bwipe!
1139endfunc
1140
Bram Moolenaarcc762a42022-11-25 13:03:31 +00001141" This was editing another file from the expression.
1142func Test_sub_expr_goto_other_file()
1143 call writefile([''], 'Xfileone', 'D')
1144 enew!
1145 call setline(1, ['a', 'b', 'c', 'd',
1146 \ 'Xfileone zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'])
1147
1148 func g:SplitGotoFile()
1149 exe "sil! norm 0\<C-W>gf"
1150 return ''
1151 endfunc
1152
1153 $
1154 s/\%')/\=g:SplitGotoFile()
1155
1156 delfunc g:SplitGotoFile
1157 bwipe!
1158endfunc
1159
Bram Moolenaar3ac1d972023-01-04 17:17:54 +00001160func Test_recursive_expr_substitute()
1161 " this was reading invalid memory
1162 let lines =<< trim END
1163 func Repl(g, n)
1164 s
1165 r%:s000
1166 endfunc
1167 next 0
1168 let caught = 0
1169 s/\%')/\=Repl(0, 0)
1170 qall!
1171 END
1172 call writefile(lines, 'XexprSubst', 'D')
1173 call RunVim([], [], '--clean -S XexprSubst')
1174endfunc
1175
Yegappan Lakshmanan5e877ba2022-03-25 21:19:26 +00001176" Test for the 2-letter and 3-letter :substitute commands
1177func Test_substitute_short_cmd()
1178 new
1179 call setline(1, ['one', 'one one one'])
1180 s/one/two
1181 call cursor(2, 1)
1182
1183 " :sc
1184 call feedkeys(":sc\<CR>y", 'xt')
1185 call assert_equal('two one one', getline(2))
1186
1187 " :scg
1188 call setline(2, 'one one one')
1189 call feedkeys(":scg\<CR>nyq", 'xt')
1190 call assert_equal('one two one', getline(2))
1191
1192 " :sci
1193 call setline(2, 'ONE One onE')
1194 call feedkeys(":sci\<CR>y", 'xt')
1195 call assert_equal('two One onE', getline(2))
1196
1197 " :scI
1198 set ignorecase
1199 call setline(2, 'ONE One one')
1200 call feedkeys(":scI\<CR>y", 'xt')
1201 call assert_equal('ONE One two', getline(2))
1202 set ignorecase&
1203
1204 " :scn
1205 call setline(2, 'one one one')
1206 let t = execute('scn')->split("\n")
1207 call assert_equal(['1 match on 1 line'], t)
1208 call assert_equal('one one one', getline(2))
1209
1210 " :scp
1211 call setline(2, "\tone one one")
1212 redir => output
1213 call feedkeys(":scp\<CR>y", 'xt')
1214 redir END
1215 call assert_equal(' two one one', output->split("\n")[-1])
1216 call assert_equal("\ttwo one one", getline(2))
1217
1218 " :scl
1219 call setline(2, "\tone one one")
1220 redir => output
1221 call feedkeys(":scl\<CR>y", 'xt')
1222 redir END
1223 call assert_equal("^Itwo one one$", output->split("\n")[-1])
1224 call assert_equal("\ttwo one one", getline(2))
1225
1226 " :sgc
1227 call setline(2, 'one one one one one')
1228 call feedkeys(":sgc\<CR>nyyq", 'xt')
1229 call assert_equal('one two two one one', getline(2))
1230
1231 " :sg
1232 call setline(2, 'one one one')
1233 sg
1234 call assert_equal('two two two', getline(2))
1235
1236 " :sgi
1237 call setline(2, 'ONE One onE')
1238 sgi
1239 call assert_equal('two two two', getline(2))
1240
1241 " :sgI
1242 set ignorecase
1243 call setline(2, 'ONE One one')
1244 sgI
1245 call assert_equal('ONE One two', getline(2))
1246 set ignorecase&
1247
1248 " :sgn
1249 call setline(2, 'one one one')
1250 let t = execute('sgn')->split("\n")
1251 call assert_equal(['3 matches on 1 line'], t)
1252 call assert_equal('one one one', getline(2))
1253
1254 " :sgp
1255 call setline(2, "\tone one one")
1256 redir => output
1257 sgp
1258 redir END
1259 call assert_equal(' two two two', output->split("\n")[-1])
1260 call assert_equal("\ttwo two two", getline(2))
1261
1262 " :sgl
1263 call setline(2, "\tone one one")
1264 redir => output
1265 sgl
1266 redir END
1267 call assert_equal("^Itwo two two$", output->split("\n")[-1])
1268 call assert_equal("\ttwo two two", getline(2))
1269
1270 " :sgr
1271 call setline(2, "one one one")
1272 call cursor(2, 1)
1273 s/abc/xyz/e
1274 let @/ = 'one'
1275 sgr
1276 call assert_equal('xyz xyz xyz', getline(2))
1277
1278 " :sic
1279 call cursor(1, 1)
1280 s/one/two/e
1281 call setline(2, "ONE One one")
1282 call cursor(2, 1)
1283 call feedkeys(":sic\<CR>y", 'xt')
1284 call assert_equal('two One one', getline(2))
1285
1286 " :si
1287 call setline(2, "ONE One one")
1288 si
1289 call assert_equal('two One one', getline(2))
1290
1291 " :siI
1292 call setline(2, "ONE One one")
1293 siI
1294 call assert_equal('ONE One two', getline(2))
1295
1296 " :sin
1297 call setline(2, 'ONE One onE')
1298 let t = execute('sin')->split("\n")
1299 call assert_equal(['1 match on 1 line'], t)
1300 call assert_equal('ONE One onE', getline(2))
1301
1302 " :sip
1303 call setline(2, "\tONE One onE")
1304 redir => output
1305 sip
1306 redir END
1307 call assert_equal(' two One onE', output->split("\n")[-1])
1308 call assert_equal("\ttwo One onE", getline(2))
1309
1310 " :sir
1311 call setline(2, "ONE One onE")
1312 call cursor(2, 1)
1313 s/abc/xyz/e
1314 let @/ = 'one'
1315 sir
1316 call assert_equal('xyz One onE', getline(2))
1317
1318 " :sIc
1319 call cursor(1, 1)
1320 s/one/two/e
1321 call setline(2, "ONE One one")
1322 call cursor(2, 1)
1323 call feedkeys(":sIc\<CR>y", 'xt')
1324 call assert_equal('ONE One two', getline(2))
1325
1326 " :sIg
1327 call setline(2, "ONE one onE one")
1328 sIg
1329 call assert_equal('ONE two onE two', getline(2))
1330
1331 " :sIi
1332 call setline(2, "ONE One one")
1333 sIi
1334 call assert_equal('two One one', getline(2))
1335
1336 " :sI
1337 call setline(2, "ONE One one")
1338 sI
1339 call assert_equal('ONE One two', getline(2))
1340
1341 " :sIn
1342 call setline(2, 'ONE One one')
1343 let t = execute('sIn')->split("\n")
1344 call assert_equal(['1 match on 1 line'], t)
1345 call assert_equal('ONE One one', getline(2))
1346
1347 " :sIp
1348 call setline(2, "\tONE One one")
1349 redir => output
1350 sIp
1351 redir END
1352 call assert_equal(' ONE One two', output->split("\n")[-1])
1353 call assert_equal("\tONE One two", getline(2))
1354
1355 " :sIl
1356 call setline(2, "\tONE onE one")
1357 redir => output
1358 sIl
1359 redir END
1360 call assert_equal("^IONE onE two$", output->split("\n")[-1])
1361 call assert_equal("\tONE onE two", getline(2))
1362
1363 " :sIr
1364 call setline(2, "ONE one onE")
1365 call cursor(2, 1)
1366 s/abc/xyz/e
1367 let @/ = 'one'
1368 sIr
1369 call assert_equal('ONE xyz onE', getline(2))
1370
1371 " :src
1372 call setline(2, "ONE one one")
1373 call cursor(2, 1)
1374 s/abc/xyz/e
1375 let @/ = 'one'
1376 call feedkeys(":src\<CR>y", 'xt')
1377 call assert_equal('ONE xyz one', getline(2))
1378
1379 " :srg
1380 call setline(2, "one one one")
1381 call cursor(2, 1)
1382 s/abc/xyz/e
1383 let @/ = 'one'
1384 srg
1385 call assert_equal('xyz xyz xyz', getline(2))
1386
1387 " :sri
1388 call setline(2, "ONE one onE")
1389 call cursor(2, 1)
1390 s/abc/xyz/e
1391 let @/ = 'one'
1392 sri
1393 call assert_equal('xyz one onE', getline(2))
1394
1395 " :srI
1396 call setline(2, "ONE one onE")
1397 call cursor(2, 1)
1398 s/abc/xyz/e
1399 let @/ = 'one'
1400 srI
1401 call assert_equal('ONE xyz onE', getline(2))
1402
1403 " :srn
1404 call setline(2, "ONE one onE")
1405 call cursor(2, 1)
1406 s/abc/xyz/e
1407 let @/ = 'one'
1408 let t = execute('srn')->split("\n")
1409 call assert_equal(['1 match on 1 line'], t)
1410 call assert_equal('ONE one onE', getline(2))
1411
1412 " :srp
1413 call setline(2, "\tONE one onE")
1414 call cursor(2, 1)
1415 s/abc/xyz/e
1416 let @/ = 'one'
1417 redir => output
1418 srp
1419 redir END
1420 call assert_equal(' ONE xyz onE', output->split("\n")[-1])
1421 call assert_equal("\tONE xyz onE", getline(2))
1422
1423 " :srl
1424 call setline(2, "\tONE one onE")
1425 call cursor(2, 1)
1426 s/abc/xyz/e
1427 let @/ = 'one'
1428 redir => output
1429 srl
1430 redir END
1431 call assert_equal("^IONE xyz onE$", output->split("\n")[-1])
1432 call assert_equal("\tONE xyz onE", getline(2))
1433
1434 " :sr
1435 call setline(2, "ONE one onE")
1436 call cursor(2, 1)
1437 s/abc/xyz/e
1438 let @/ = 'one'
1439 sr
1440 call assert_equal('ONE xyz onE', getline(2))
1441
1442 " :sce
1443 s/abc/xyz/e
1444 call assert_fails("sc", 'E486:')
1445 sce
1446 " :sge
1447 call assert_fails("sg", 'E486:')
1448 sge
1449 " :sie
1450 call assert_fails("si", 'E486:')
1451 sie
1452 " :sIe
1453 call assert_fails("sI", 'E486:')
1454 sIe
1455
1456 bw!
1457endfunc
Bram Moolenaar37f47952022-01-29 14:21:51 +00001458
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001459" Check handling expanding "~" resulting in extremely long text.
Bram Moolenaar916d6dd2023-05-09 21:45:47 +01001460" FIXME: disabled, it takes too long to run on CI
Bram Moolenaara4467c42023-05-09 22:07:11 +01001461"func Test_substitute_tilde_too_long()
1462" enew!
1463"
1464" s/.*/ixxx
1465" s//~~~~~~~~~AAAAAAA@(
1466"
1467" " Either fails with "out of memory" or "text too long".
1468" " This can take a long time.
1469" call assert_fails('sil! norm &&&&&&&&&', ['E1240:\|E342:'])
1470"
1471" bwipe!
1472"endfunc
Bram Moolenaarab9a2d82023-05-09 21:15:30 +01001473
Bram Moolenaar44ddf192022-06-21 22:15:25 +01001474" This should be done last to reveal a memory leak when vim_regsub_both() is
1475" called to evaluate an expression but it is not used in a second call.
1476func Test_z_substitute_expr_leak()
1477 func SubExpr()
1478 ~n
1479 endfunc
1480 silent! s/\%')/\=SubExpr()
1481 delfunc SubExpr
1482endfunc
1483
Christian Brabandt18d27092023-09-06 19:53:36 +02001484func Test_substitute_expr_switch_win()
1485 func R()
1486 wincmd x
1487 return 'XXXX'
1488 endfunc
1489 new Xfoobar
1490 let bufnr = bufnr('%')
Christian Brabandt26c11c52023-11-22 21:26:41 +01001491 put ='abcdef'
Christian Brabandt18d27092023-09-06 19:53:36 +02001492 silent! s/\%')/\=R()
Christian Brabandtee17b6f2023-09-09 11:23:50 +02001493 call assert_fails(':%s/./\=R()/g', 'E565:')
Christian Brabandt18d27092023-09-06 19:53:36 +02001494 delfunc R
1495 exe bufnr .. "bw!"
1496endfunc
1497
Christian Brabandt26c11c52023-11-22 21:26:41 +01001498" recursive call of :s using test-replace special
1499func Test_substitute_expr_recursive()
1500 func Q()
1501 %s/./\='foobar'/gn
1502 return "foobar"
1503 endfunc
1504 func R()
1505 %s/./\=Q()/g
1506 endfunc
1507 new Xfoobar_UAF
1508 let bufnr = bufnr('%')
1509 put ='abcdef'
1510 silent! s/./\=R()/g
1511 call assert_fails(':%s/./\=R()/g', 'E565:')
1512 delfunc R
1513 delfunc Q
1514 exe bufnr .. "bw!"
1515endfunc
1516
Yegappan Lakshmanan4776e642024-05-19 09:06:50 +02001517" Test for changing 'cpo' in a substitute expression
1518func Test_substitute_expr_cpo()
1519 func XSubExpr()
1520 set cpo=
1521 return 'x'
1522 endfunc
1523
1524 let save_cpo = &cpo
1525 call assert_equal('xxx', substitute('abc', '.', '\=XSubExpr()', 'g'))
1526 call assert_equal(save_cpo, &cpo)
1527
1528 delfunc XSubExpr
1529endfunc
1530
Bram Moolenaar5d98dc22020-01-29 21:57:34 +01001531" vim: shiftwidth=2 sts=2 expandtab