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