test_substitute.vim (46232B)
1 " Tests for the substitute (:s) command 2 3 source shared.vim 4 source check.vim 5 source screendump.vim 6 7 " 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) 14 func 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!" 31 endfunc 32 33 func Test_multiline_subst() 34 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! 71 endfunc 72 73 func Test_substitute_variants() 74 " 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' }, 84 \ { 'cmd': ':s/t/r/c', 'exp': 'Testing string', 'prompt': 'n' }, 85 \ { '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' }, 89 \ { 'cmd': ':s/i/I/gc', 'exp': 'TestIng string', 'prompt': 'l' }, 90 \ { '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' }, 121 \ { 'cmd': ':s/i/I/gc', 'exp': 'Testing string', 'prompt': 'q' }, 122 \] 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 141 endfunc 142 143 " Test the l, p, # flags. 144 func 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! 167 endfunc 168 169 func Test_substitute_repeat() 170 " This caused an invalid memory access. 171 split Xfile 172 s/^/x 173 call feedkeys("Qsc\<CR>y", 'tx') 174 bwipe! 175 endfunc 176 177 " Test :s with ? as delimiter. 178 func Test_substitute_question_delimiter() 179 new 180 call setline(1, '??:??') 181 %s?\?\??!!?g 182 call assert_equal('!!:!!', getline(1)) 183 bwipe! 184 endfunc 185 186 " Test %s/\n// which is implemented as a special case to use a 187 " more efficient join rather than doing a regular substitution. 188 func 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 221 call setline(1, ['foo', 'bar', 'baz', 'qux']) 222 call execute('1,2s/\n//') 223 call assert_equal(['foobarbaz', 'qux'], getline(1, '$')) 224 225 bwipe! 226 endfunc 227 228 func 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 239 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 244 call assert_fails('s/./b/2147483647', 'E1510:') 245 bwipe! 246 endfunc 247 248 " Test substitute 'n' flag (report number of matches, do not substitute). 249 func 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 263 %delete _ 264 call setline(1, ['A', 'Bar', 'Baz']) 265 call assert_equal("\n1 match on 1 line", execute('s/\nB\@=//gn')) 266 267 bwipe! 268 endfunc 269 270 func 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:') 276 call assert_fails('s/\(/bar/', 'E54:') 277 call assert_fails('s afooabara', 'E146:') 278 call assert_fails('s\\a', 'E10:') 279 280 setl nomodifiable 281 call assert_fails('s/foo/bar/', 'E21:') 282 283 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:') 287 call assert_fails("let s=substitute('abc', '\\%(', 'A', 'g')", 'E53:') 288 289 bwipe! 290 endfunc 291 292 " Test for *sub-replace-special* and *sub-replace-expression* on substitute(). 293 func 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', '')) 324 " \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', '')) 327 endfunc 328 329 func 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', '')) 360 endfunc 361 362 func 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"', '')) 374 endfunc 375 376 " Test for submatch() on substitute(). 377 func 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", "")', '')) 391 endfunc 392 393 func 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), ' . 407 \ 'submatch(8, 1), 7->submatch(1), submatch(6, 1), ' . 408 \ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' . 409 \ 'submatch(2, 1), submatch(1, 1)])', 410 \ '')) 411 endfunc 412 413 func Test_sub_replace_6() 414 set magic& 415 " Nvim: no "/" flag in 'cpoptions'. 416 " set cpo+=/ 417 call assert_equal('a', substitute('A', 'A', 'a', '')) 418 call assert_equal('%', substitute('B', 'B', '%', '')) 419 set cpo-=/ 420 call assert_equal('c', substitute('C', 'C', 'c', '')) 421 call assert_equal('%', substitute('D', 'D', '%', '')) 422 endfunc 423 424 func Test_sub_replace_7() 425 set magic& 426 set cpo& 427 call assert_equal('AA', substitute('AA', 'A.', '\=submatch(0)', '')) 428 call assert_equal("B\nB", substitute("B\nB", 'B.', '\=submatch(0)', '')) 429 call assert_equal("['B\n']B", substitute("B\nB", 'B.', '\=string(submatch(0, 1))', '')) 430 call assert_equal('-abab', substitute('-bb', '\zeb', 'a', 'g')) 431 call assert_equal('c-cbcbc', substitute('-bb', '\ze', 'c', 'g')) 432 endfunc 433 434 " Test for *:s%* on :substitute. 435 func Test_sub_replace_8() 436 new 437 set magic& 438 set cpo& 439 $put =',,X' 440 s/\(^\|,\)\ze\(,\|X\)/\1N/g 441 call assert_equal('N,,NX', getline("$")) 442 $put =',,Y' 443 let cmd = ':s/\(^\|,\)\ze\(,\|Y\)/\1N/gc' 444 call feedkeys(cmd . "\<CR>a", "xt") 445 call assert_equal('N,,NY', getline("$")) 446 :$put =',,Z' 447 let cmd = ':s/\(^\|,\)\ze\(,\|Z\)/\1N/gc' 448 call feedkeys(cmd . "\<CR>yy", "xt") 449 call assert_equal('N,,NZ', getline("$")) 450 enew! | close 451 endfunc 452 453 func Test_sub_replace_9() 454 new 455 set magic& 456 set cpo& 457 $put ='xxx' 458 call feedkeys(":s/x/X/gc\<CR>yyq", "xt") 459 call assert_equal('XXx', getline("$")) 460 enew! | close 461 endfunc 462 463 func Test_sub_replace_10() 464 set magic& 465 set cpo& 466 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g')) 467 call assert_equal('aaa', substitute('123', '\zs.', 'a', 'g')) 468 call assert_equal('1a2a3a', substitute('123', '.\zs', 'a', 'g')) 469 call assert_equal('a1a2a3a', substitute('123', '\ze', 'a', 'g')) 470 call assert_equal('a1a2a3', substitute('123', '\ze.', 'a', 'g')) 471 call assert_equal('aaa', substitute('123', '.\ze', 'a', 'g')) 472 call assert_equal('aa2a3a', substitute('123', '1\|\ze', 'a', 'g')) 473 call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g')) 474 endfunc 475 476 func SubReplacer(text, submatches) 477 return a:text .. a:submatches[0] .. a:text 478 endfunc 479 func SubReplacerVar(text, ...) 480 return a:text .. a:1[0] .. a:text 481 endfunc 482 func 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 484 endfunc 485 486 func Test_substitute_partial() 487 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g')) 488 call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar', ['foo']), 'g')) 489 490 " 19 arguments plus one is just OK 491 let Replacer = function('SubReplacer20', repeat(['foo'], 19)) 492 call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g')) 493 494 " 20 arguments plus one is too many 495 let Replacer = function('SubReplacer20', repeat(['foo'], 20)) 496 call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118:') 497 endfunc 498 499 func Test_substitute_float() 500 CheckFeature float 501 502 call assert_equal('number 1.23', substitute('number ', '$', { -> 1.23 }, '')) 503 " vim9 assert_equal('number 1.23', substitute('number ', '$', () => 1.23, '')) 504 endfunc 505 506 " Tests for *sub-replace-special* and *sub-replace-expression* on :substitute. 507 508 " Execute a list of :substitute command tests 509 func Run_SubCmd_Tests(tests) 510 enew! 511 for t in a:tests 512 let start = line('.') + 1 513 let end = start + len(t[2]) - 1 514 exe "normal o" . t[0] 515 call cursor(start, 1) 516 exe t[1] 517 call assert_equal(t[2], getline(start, end), t[1]) 518 endfor 519 enew! 520 endfunc 521 522 func Test_sub_cmd_1() 523 set magic 524 set cpo& 525 526 " List entry format: [input, cmd, output] 527 let tests = [['A', 's/A/&&/', ['AA']], 528 \ ['B', 's/B/\&/', ['&']], 529 \ ['C123456789', 's/C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']], 530 \ ['D', 's/D/d/', ['d']], 531 \ ['E', 's/E/~/', ['d']], 532 \ ['F', 's/F/\~/', ['~']], 533 \ ['G', 's/G/\ugg/', ['Gg']], 534 \ ['H', 's/H/\Uh\Eh/', ['Hh']], 535 \ ['I', 's/I/\lII/', ['iI']], 536 \ ['J', 's/J/\LJ\EJ/', ['jJ']], 537 \ ['K', 's/K/\Uk\ek/', ['Kk']], 538 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']], 539 \ ['mMm', 's/M/\r/', ['m', 'm']], 540 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']], 541 \ ['oOo', 's/O/\n/', ["o\no"]], 542 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]], 543 \ ['qQq', 's/Q/\t/', ["q\tq"]], 544 \ ['rRr', 's/R/\\/', ['r\r']], 545 \ ['sSs', 's/S/\c/', ['scs']], 546 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]], 547 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']], 548 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']], 549 \ ['\', 's/\\/\\\\/', ['\\']] 550 \ ] 551 call Run_SubCmd_Tests(tests) 552 endfunc 553 554 func Test_sub_cmd_2() 555 set nomagic 556 set cpo& 557 558 " List entry format: [input, cmd, output] 559 let tests = [['A', 's/A/&&/', ['&&']], 560 \ ['B', 's/B/\&/', ['B']], 561 \ ['C123456789', 's/\mC\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']], 562 \ ['D', 's/D/d/', ['d']], 563 \ ['E', 's/E/~/', ['~']], 564 \ ['F', 's/F/\~/', ['~']], 565 \ ['G', 's/G/\ugg/', ['Gg']], 566 \ ['H', 's/H/\Uh\Eh/', ['Hh']], 567 \ ['I', 's/I/\lII/', ['iI']], 568 \ ['J', 's/J/\LJ\EJ/', ['jJ']], 569 \ ['K', 's/K/\Uk\ek/', ['Kk']], 570 \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']], 571 \ ['mMm', 's/M/\r/', ['m', 'm']], 572 \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']], 573 \ ['oOo', 's/O/\n/', ["o\no"]], 574 \ ['pPp', 's/P/\b/', ["p\<C-H>p"]], 575 \ ['qQq', 's/Q/\t/', ["q\tq"]], 576 \ ['rRr', 's/R/\\/', ['r\r']], 577 \ ['sSs', 's/S/\c/', ['scs']], 578 \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]], 579 \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']], 580 \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']], 581 \ ['\', 's/\\/\\\\/', ['\\']] 582 \ ] 583 call Run_SubCmd_Tests(tests) 584 endfunc 585 586 func Test_sub_cmd_3() 587 set nomagic 588 set cpo& 589 590 " List entry format: [input, cmd, output] 591 let tests = [['aAa', "s/A/\\='\\'/", ['a\a']], 592 \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']], 593 \ ['cCc', "s/C/\\='\<C-V>\<C-M>'/", ["c\<C-V>", 'c']], 594 \ ['dDd', "s/D/\\='\\\<C-V>\<C-M>'/", ["d\\\<C-V>", 'd']], 595 \ ['eEe', "s/E/\\='\\\\\<C-V>\<C-M>'/", ["e\\\\\<C-V>", 'e']], 596 \ ['fFf', "s/F/\\='\r'/", ['f', 'f']], 597 \ ['gGg', "s/G/\\='\<C-V>\<C-J>'/", ["g\<C-V>", 'g']], 598 \ ['hHh', "s/H/\\='\\\<C-V>\<C-J>'/", ["h\\\<C-V>", 'h']], 599 \ ['iIi', "s/I/\\='\\\\\<C-V>\<C-J>'/", ["i\\\\\<C-V>", 'i']], 600 \ ['jJj', "s/J/\\='\n'/", ['j', 'j']], 601 \ ['kKk', 's/K/\="\r"/', ['k', 'k']], 602 \ ['lLl', 's/L/\="\n"/', ['l', 'l']] 603 \ ] 604 call Run_SubCmd_Tests(tests) 605 endfunc 606 607 " Test for submatch() on :substitute. 608 func Test_sub_cmd_4() 609 set magic& 610 set cpo& 611 612 " List entry format: [input, cmd, output] 613 let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/", 614 \ ['a\a']], 615 \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/", 616 \ ['b\b']], 617 \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/", 618 \ ["c\<C-V>", 'c']], 619 \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/", 620 \ ["d\<C-V>", 'd']], 621 \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\<C-V>\<C-M>', '')/", 622 \ ["e\\\<C-V>", 'e']], 623 \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/", 624 \ ['f', 'f']], 625 \ ['gGg', 's/G/\=substitute(submatch(0), ".", "\<C-V>\<C-J>", "")/', 626 \ ["g\<C-V>", 'g']], 627 \ ['hHh', 's/H/\=substitute(submatch(0), ".", "\\\<C-V>\<C-J>", "")/', 628 \ ["h\<C-V>", 'h']], 629 \ ['iIi', 's/I/\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-J>", "")/', 630 \ ["i\\\<C-V>", 'i']], 631 \ ['jJj', "s/J/\\=substitute(submatch(0), '.', '\\n', '')/", 632 \ ['j', 'j']], 633 \ ['kKk', "s/K/\\=substitute(submatch(0), '.', '\\r', '')/", 634 \ ['k', 'k']], 635 \ ['lLl', "s/L/\\=substitute(submatch(0), '.', '\\n', '')/", 636 \ ['l', 'l']], 637 \ ] 638 call Run_SubCmd_Tests(tests) 639 endfunc 640 641 func Test_sub_cmd_5() 642 set magic& 643 set cpo& 644 645 " List entry format: [input, cmd, output] 646 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']], 647 \ ['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']]"]], 648 \ ] 649 call Run_SubCmd_Tests(tests) 650 endfunc 651 652 " Test for *:s%* on :substitute. 653 func Test_sub_cmd_6() 654 set magic& 655 " Nvim: no "/" flag in 'cpoptions'. 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& 671 endfunc 672 673 " Test for :s replacing \n with line break. 674 func 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" 688 call assert_fails('s/Q[^\n]Q/\=submatch(0)."foobar"/', 'E486') 689 enew! 690 endfunc 691 692 func TitleString() 693 let check = 'foo' =~ 'bar' 694 return "" 695 endfunc 696 697 func 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& 713 endfunc 714 715 func 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! 728 endfunc 729 730 func Test_sub_highlight_zero_match() 731 CheckScreendump 732 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) 744 endfunc 745 746 func Test_nocatch_sub_failure_handling() 747 " normal error results in all replacements 748 func Foo() 749 foobar 750 endfunc 751 new 752 call setline(1, ['1 aaa', '2 aaa', '3 aaa']) 753 " need silent! to avoid a delay when entering Insert mode 754 silent! %s/aaa/\=Foo()/g 755 call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3)) 756 757 " Throw without try-catch causes abort after the first line. 758 " 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 774 " 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 785 delfunc Foo 786 bwipe! 787 endfunc 788 789 " Test ":s/pat/sub/" with different ~s in sub. 790 func 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! 803 endfunc 804 805 func Test_replace_keeppatterns() 806 new 807 a 808 foobar 809 810 substitute foo asdf foo 811 812 one two 813 . 814 815 normal gg 816 /^substitute 817 s/foo/bar/ 818 call assert_equal('foo', @/) 819 call assert_equal('substitute bar asdf foo', getline('.')) 820 821 /^substitute 822 keeppatterns s/asdf/xyz/ 823 call assert_equal('^substitute', @/) 824 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('.')) 830 831 exe "normal /bar /e\<CR>" 832 call assert_equal(15, col('.')) 833 normal - 834 keeppatterns /xyz 835 call assert_equal('bar ', @/) 836 call assert_equal('substitute bar xyz bar', getline('.')) 837 exe "normal 0dn" 838 call assert_equal('xyz bar', getline('.')) 839 840 close! 841 endfunc 842 843 func 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! 850 endfunc 851 852 " Test for repeating last substitution using :~ and :&r 853 func 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! 865 endfunc 866 867 " Test for Vi compatible substitution: 868 " \/{string}/, \?{string}? and \&{string}& 869 func 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! 880 endfunc 881 882 " Test for substitute with the new text longer than the original text 883 func Test_sub_expand_text() 884 new 885 call setline(1, 'abcabcabcabcabcabcabcabc') 886 s/b/\=repeat('B', 10)/g 887 call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1)) 888 close! 889 endfunc 890 891 " Test for command failures when the last substitute pattern is not set. 892 func Test_sub_with_no_last_pat() 893 let lines =<< trim [SCRIPT] 894 call assert_fails('~', 'E33:') 895 call assert_fails('s//abc/g', 'E35:') 896 call assert_fails('s\/bar', 'E35:') 897 call assert_fails('s\&bar&', 'E33:') 898 call writefile(v:errors, 'Xresult') 899 qall! 900 [SCRIPT] 901 call writefile(lines, 'Xscript', 'D') 902 if RunVim([], [], '--clean -S Xscript') 903 call assert_equal([], readfile('Xresult')) 904 endif 905 906 let lines =<< trim [SCRIPT] 907 set cpo+=/ 908 call assert_fails('s/abc/%/', 'E33:') 909 call writefile(v:errors, 'Xresult') 910 qall! 911 [SCRIPT] 912 " Nvim: no "/" flag in 'cpoptions'. 913 " call writefile(lines, 'Xscript') 914 " if RunVim([], [], '--clean -S Xscript') 915 " call assert_equal([], readfile('Xresult')) 916 " endif 917 918 call delete('Xresult') 919 endfunc 920 921 func Test_substitute() 922 call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g')) 923 " Substitute with special keys 924 call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", '')) 925 endfunc 926 927 func Test_substitute_expr() 928 let g:val = 'XXX' 929 call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', '')) 930 call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, '')) 931 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)', 932 \ '\=nr2char("0x" . submatch(1))', 'g')) 933 call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)', 934 \ {-> nr2char("0x" . submatch(1))}, 'g')) 935 936 call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)', 937 \ {-> submatch(2) . submatch(3) . submatch(1)}, '')) 938 939 func Recurse() 940 return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '') 941 endfunc 942 " recursive call works 943 call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, '')) 944 945 call assert_fails("let s=submatch([])", 'E745:') 946 call assert_fails("let s=submatch(2, [])", 'E745:') 947 endfunc 948 949 func Test_invalid_submatch() 950 " This was causing invalid memory access in Vim-7.4.2232 and older 951 call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:') 952 call assert_fails('eval submatch(-1)', 'E935:') 953 call assert_equal('', submatch(0)) 954 call assert_equal('', submatch(1)) 955 call assert_equal([], submatch(0, 1)) 956 call assert_equal([], submatch(1, 1)) 957 endfunc 958 959 func Test_submatch_list_concatenate() 960 let pat = 'A\(.\)' 961 let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])} 962 call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]") 963 endfunc 964 965 func Test_substitute_expr_arg() 966 call assert_equal('123456789-123456789=', substitute('123456789', 967 \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', 968 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, '')) 969 970 call assert_equal('123456-123456=789', substitute('123456789', 971 \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)', 972 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, '')) 973 974 call assert_equal('123456789-123456789x=', substitute('123456789', 975 \ '\(.\)\(.\)\(.*\)', 976 \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, '')) 977 978 call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:') 979 call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:') 980 call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:') 981 call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:') 982 endfunc 983 984 " Test for using a function to supply the substitute string 985 func Test_substitute_using_func() 986 func Xfunc() 987 return '1234' 988 endfunc 989 call assert_equal('a1234f', substitute('abcdef', 'b..e', 990 \ function("Xfunc"), '')) 991 delfunc Xfunc 992 endfunc 993 994 " Test for using submatch() with a multiline match 995 func Test_substitute_multiline_submatch() 996 new 997 call setline(1, ['line1', 'line2', 'line3', 'line4']) 998 %s/^line1\(\_.\+\)line4$/\=submatch(1)/ 999 call assert_equal(['', 'line2', 'line3', ''], getline(1, '$')) 1000 close! 1001 endfunc 1002 1003 func Test_substitute_skipped_range() 1004 new 1005 if 0 1006 /1/5/2/2/\n 1007 endif 1008 call assert_equal([0, 1, 1, 0, 1], getcurpos()) 1009 bwipe! 1010 endfunc 1011 1012 " Test using the 'gdefault' option (when on, flag 'g' is default on). 1013 func Test_substitute_gdefault() 1014 new 1015 1016 " First check without 'gdefault' 1017 call setline(1, 'foo bar foo') 1018 s/foo/FOO/ 1019 call assert_equal('FOO bar foo', getline(1)) 1020 call setline(1, 'foo bar foo') 1021 s/foo/FOO/g 1022 call assert_equal('FOO bar FOO', getline(1)) 1023 call setline(1, 'foo bar foo') 1024 s/foo/FOO/gg 1025 call assert_equal('FOO bar foo', getline(1)) 1026 1027 " Then check with 'gdefault' 1028 set gdefault 1029 call setline(1, 'foo bar foo') 1030 s/foo/FOO/ 1031 call assert_equal('FOO bar FOO', getline(1)) 1032 call setline(1, 'foo bar foo') 1033 s/foo/FOO/g 1034 call assert_equal('FOO bar foo', getline(1)) 1035 call setline(1, 'foo bar foo') 1036 s/foo/FOO/gg 1037 call assert_equal('FOO bar FOO', getline(1)) 1038 1039 " Setting 'compatible' should reset 'gdefault' 1040 call assert_equal(1, &gdefault) 1041 " set compatible 1042 set nogdefault 1043 call assert_equal(0, &gdefault) 1044 set nocompatible 1045 call assert_equal(0, &gdefault) 1046 1047 bw! 1048 endfunc 1049 1050 " This was using "old_sub" after it was freed. 1051 func Test_using_old_sub() 1052 " set compatible maxfuncdepth=10 1053 set maxfuncdepth=10 1054 new 1055 call setline(1, 'some text.') 1056 func Repl() 1057 ~ 1058 s/ 1059 endfunc 1060 silent! s/\%')/\=Repl() 1061 1062 delfunc Repl 1063 bwipe! 1064 set nocompatible 1065 endfunc 1066 1067 " This was switching windows in between computing the length and using it. 1068 func Test_sub_change_window() 1069 silent! lfile 1070 sil! norm o0000000000000000000000000000000000000000000000000000 1071 func Repl() 1072 lopen 1073 endfunc 1074 silent! s/\%')/\=Repl() 1075 bwipe! 1076 bwipe! 1077 delfunc Repl 1078 endfunc 1079 1080 " This was undoign a change in between computing the length and using it. 1081 func Do_Test_sub_undo_change() 1082 new 1083 norm o0000000000000000000000000000000000000000000000000000 1084 silent! s/\%')/\=Repl() 1085 bwipe! 1086 endfunc 1087 1088 func Test_sub_undo_change() 1089 func Repl() 1090 silent! norm g- 1091 endfunc 1092 call Do_Test_sub_undo_change() 1093 1094 func! Repl() 1095 silent earlier 1096 endfunc 1097 call Do_Test_sub_undo_change() 1098 1099 delfunc Repl 1100 endfunc 1101 1102 " This was opening a command line window from the expression 1103 func Test_sub_open_cmdline_win() 1104 " the error only happens in a very specific setup, run a new Vim instance to 1105 " get a clean starting point. 1106 let lines =<< trim [SCRIPT] 1107 set vb t_vb= 1108 norm o0000000000000000000000000000000000000000000000000000 1109 func Replace() 1110 norm q/ 1111 endfunc 1112 s/\%')/\=Replace() 1113 redir >Xresult 1114 messages 1115 redir END 1116 qall! 1117 [SCRIPT] 1118 call writefile(lines, 'Xscript', 'D') 1119 if RunVim([], [], '-u NONE -S Xscript') 1120 call assert_match('E565: Not allowed to change text or change window', 1121 \ readfile('Xresult')->join('XX')) 1122 endif 1123 1124 call delete('Xresult') 1125 endfunc 1126 1127 " This was editing a script file from the expression 1128 func Test_sub_edit_scriptfile() 1129 new 1130 norm o0000000000000000000000000000000000000000000000000000 1131 func EditScript() 1132 silent! scr! Xfile 1133 endfunc 1134 s/\%')/\=EditScript() 1135 1136 delfunc EditScript 1137 bwipe! 1138 endfunc 1139 1140 " This was editing another file from the expression. 1141 func Test_sub_expr_goto_other_file() 1142 call writefile([''], 'Xfileone', 'D') 1143 enew! 1144 call setline(1, ['a', 'b', 'c', 'd', 1145 \ 'Xfileone zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz']) 1146 1147 func g:SplitGotoFile() 1148 exe "sil! norm 0\<C-W>gf" 1149 return '' 1150 endfunc 1151 1152 $ 1153 s/\%')/\=g:SplitGotoFile() 1154 1155 delfunc g:SplitGotoFile 1156 bwipe! 1157 endfunc 1158 1159 func Test_recursive_expr_substitute() 1160 " this was reading invalid memory 1161 let lines =<< trim END 1162 func Repl(g, n) 1163 s 1164 r%:s000 1165 endfunc 1166 next 0 1167 let caught = 0 1168 s/\%')/\=Repl(0, 0) 1169 qall! 1170 END 1171 call writefile(lines, 'XexprSubst', 'D') 1172 call RunVim([], [], '--clean -S XexprSubst') 1173 endfunc 1174 1175 " Test for the 2-letter and 3-letter :substitute commands 1176 func Test_substitute_short_cmd() 1177 new 1178 call setline(1, ['one', 'one one one']) 1179 s/one/two 1180 call cursor(2, 1) 1181 1182 " :sc 1183 call feedkeys(":sc\<CR>y", 'xt') 1184 call assert_equal('two one one', getline(2)) 1185 1186 " :scg 1187 call setline(2, 'one one one') 1188 call feedkeys(":scg\<CR>nyq", 'xt') 1189 call assert_equal('one two one', getline(2)) 1190 1191 " :sci 1192 call setline(2, 'ONE One onE') 1193 call feedkeys(":sci\<CR>y", 'xt') 1194 call assert_equal('two One onE', getline(2)) 1195 1196 " :scI 1197 set ignorecase 1198 call setline(2, 'ONE One one') 1199 call feedkeys(":scI\<CR>y", 'xt') 1200 call assert_equal('ONE One two', getline(2)) 1201 set ignorecase& 1202 1203 " :scn 1204 call setline(2, 'one one one') 1205 let t = execute('scn')->split("\n") 1206 call assert_equal(['1 match on 1 line'], t) 1207 call assert_equal('one one one', getline(2)) 1208 1209 " :scp 1210 call setline(2, "\tone one one") 1211 redir => output 1212 call feedkeys(":scp\<CR>y", 'xt') 1213 redir END 1214 call assert_equal(' two one one', output->split("\n")[-1]) 1215 call assert_equal("\ttwo one one", getline(2)) 1216 1217 " :scl 1218 call setline(2, "\tone one one") 1219 redir => output 1220 call feedkeys(":scl\<CR>y", 'xt') 1221 redir END 1222 call assert_equal("^Itwo one one$", output->split("\n")[-1]) 1223 call assert_equal("\ttwo one one", getline(2)) 1224 1225 " :sgc 1226 call setline(2, 'one one one one one') 1227 call feedkeys(":sgc\<CR>nyyq", 'xt') 1228 call assert_equal('one two two one one', getline(2)) 1229 1230 " :sg 1231 call setline(2, 'one one one') 1232 sg 1233 call assert_equal('two two two', getline(2)) 1234 1235 " :sgi 1236 call setline(2, 'ONE One onE') 1237 sgi 1238 call assert_equal('two two two', getline(2)) 1239 1240 " :sgI 1241 set ignorecase 1242 call setline(2, 'ONE One one') 1243 sgI 1244 call assert_equal('ONE One two', getline(2)) 1245 set ignorecase& 1246 1247 " :sgn 1248 call setline(2, 'one one one') 1249 let t = execute('sgn')->split("\n") 1250 call assert_equal(['3 matches on 1 line'], t) 1251 call assert_equal('one one one', getline(2)) 1252 1253 " :sgp 1254 call setline(2, "\tone one one") 1255 redir => output 1256 sgp 1257 redir END 1258 call assert_equal(' two two two', output->split("\n")[-1]) 1259 call assert_equal("\ttwo two two", getline(2)) 1260 1261 " :sgl 1262 call setline(2, "\tone one one") 1263 redir => output 1264 sgl 1265 redir END 1266 call assert_equal("^Itwo two two$", output->split("\n")[-1]) 1267 call assert_equal("\ttwo two two", getline(2)) 1268 1269 " :sgr 1270 call setline(2, "one one one") 1271 call cursor(2, 1) 1272 s/abc/xyz/e 1273 let @/ = 'one' 1274 sgr 1275 call assert_equal('xyz xyz xyz', getline(2)) 1276 1277 " :sic 1278 call cursor(1, 1) 1279 s/one/two/e 1280 call setline(2, "ONE One one") 1281 call cursor(2, 1) 1282 call feedkeys(":sic\<CR>y", 'xt') 1283 call assert_equal('two One one', getline(2)) 1284 1285 " :si 1286 call setline(2, "ONE One one") 1287 si 1288 call assert_equal('two One one', getline(2)) 1289 1290 " :siI 1291 call setline(2, "ONE One one") 1292 siI 1293 call assert_equal('ONE One two', getline(2)) 1294 1295 " :sin 1296 call setline(2, 'ONE One onE') 1297 let t = execute('sin')->split("\n") 1298 call assert_equal(['1 match on 1 line'], t) 1299 call assert_equal('ONE One onE', getline(2)) 1300 1301 " :sip 1302 call setline(2, "\tONE One onE") 1303 redir => output 1304 sip 1305 redir END 1306 call assert_equal(' two One onE', output->split("\n")[-1]) 1307 call assert_equal("\ttwo One onE", getline(2)) 1308 1309 " :sir 1310 call setline(2, "ONE One onE") 1311 call cursor(2, 1) 1312 s/abc/xyz/e 1313 let @/ = 'one' 1314 sir 1315 call assert_equal('xyz One onE', getline(2)) 1316 1317 " :sIc 1318 call cursor(1, 1) 1319 s/one/two/e 1320 call setline(2, "ONE One one") 1321 call cursor(2, 1) 1322 call feedkeys(":sIc\<CR>y", 'xt') 1323 call assert_equal('ONE One two', getline(2)) 1324 1325 " :sIg 1326 call setline(2, "ONE one onE one") 1327 sIg 1328 call assert_equal('ONE two onE two', getline(2)) 1329 1330 " :sIi 1331 call setline(2, "ONE One one") 1332 sIi 1333 call assert_equal('two One one', getline(2)) 1334 1335 " :sI 1336 call setline(2, "ONE One one") 1337 sI 1338 call assert_equal('ONE One two', getline(2)) 1339 1340 " :sIn 1341 call setline(2, 'ONE One one') 1342 let t = execute('sIn')->split("\n") 1343 call assert_equal(['1 match on 1 line'], t) 1344 call assert_equal('ONE One one', getline(2)) 1345 1346 " :sIp 1347 call setline(2, "\tONE One one") 1348 redir => output 1349 sIp 1350 redir END 1351 call assert_equal(' ONE One two', output->split("\n")[-1]) 1352 call assert_equal("\tONE One two", getline(2)) 1353 1354 " :sIl 1355 call setline(2, "\tONE onE one") 1356 redir => output 1357 sIl 1358 redir END 1359 call assert_equal("^IONE onE two$", output->split("\n")[-1]) 1360 call assert_equal("\tONE onE two", getline(2)) 1361 1362 " :sIr 1363 call setline(2, "ONE one onE") 1364 call cursor(2, 1) 1365 s/abc/xyz/e 1366 let @/ = 'one' 1367 sIr 1368 call assert_equal('ONE xyz onE', getline(2)) 1369 1370 " :src 1371 call setline(2, "ONE one one") 1372 call cursor(2, 1) 1373 s/abc/xyz/e 1374 let @/ = 'one' 1375 call feedkeys(":src\<CR>y", 'xt') 1376 call assert_equal('ONE xyz one', getline(2)) 1377 1378 " :srg 1379 call setline(2, "one one one") 1380 call cursor(2, 1) 1381 s/abc/xyz/e 1382 let @/ = 'one' 1383 srg 1384 call assert_equal('xyz xyz xyz', getline(2)) 1385 1386 " :sri 1387 call setline(2, "ONE one onE") 1388 call cursor(2, 1) 1389 s/abc/xyz/e 1390 let @/ = 'one' 1391 sri 1392 call assert_equal('xyz one onE', getline(2)) 1393 1394 " :srI 1395 call setline(2, "ONE one onE") 1396 call cursor(2, 1) 1397 s/abc/xyz/e 1398 let @/ = 'one' 1399 srI 1400 call assert_equal('ONE xyz onE', getline(2)) 1401 1402 " :srn 1403 call setline(2, "ONE one onE") 1404 call cursor(2, 1) 1405 s/abc/xyz/e 1406 let @/ = 'one' 1407 let t = execute('srn')->split("\n") 1408 call assert_equal(['1 match on 1 line'], t) 1409 call assert_equal('ONE one onE', getline(2)) 1410 1411 " :srp 1412 call setline(2, "\tONE one onE") 1413 call cursor(2, 1) 1414 s/abc/xyz/e 1415 let @/ = 'one' 1416 redir => output 1417 srp 1418 redir END 1419 call assert_equal(' ONE xyz onE', output->split("\n")[-1]) 1420 call assert_equal("\tONE xyz onE", getline(2)) 1421 1422 " :srl 1423 call setline(2, "\tONE one onE") 1424 call cursor(2, 1) 1425 s/abc/xyz/e 1426 let @/ = 'one' 1427 redir => output 1428 srl 1429 redir END 1430 call assert_equal("^IONE xyz onE$", output->split("\n")[-1]) 1431 call assert_equal("\tONE xyz onE", getline(2)) 1432 1433 " :sr 1434 call setline(2, "ONE one onE") 1435 call cursor(2, 1) 1436 s/abc/xyz/e 1437 let @/ = 'one' 1438 sr 1439 call assert_equal('ONE xyz onE', getline(2)) 1440 1441 " :sce 1442 s/abc/xyz/e 1443 call assert_fails("sc", 'E486:') 1444 sce 1445 " :sge 1446 call assert_fails("sg", 'E486:') 1447 sge 1448 " :sie 1449 call assert_fails("si", 'E486:') 1450 sie 1451 " :sIe 1452 call assert_fails("sI", 'E486:') 1453 sIe 1454 1455 bw! 1456 endfunc 1457 1458 " Check handling expanding "~" resulting in extremely long text. 1459 " FIXME: disabled, it takes too long to run on CI 1460 "func Test_substitute_tilde_too_long() 1461 " enew! 1462 " 1463 " s/.*/ixxx 1464 " s//~~~~~~~~~AAAAAAA@( 1465 " 1466 " " Either fails with "out of memory" or "text too long". 1467 " " This can take a long time. 1468 " call assert_fails('sil! norm &&&&&&&&&', ['E1240:\|E342:']) 1469 " 1470 " bwipe! 1471 "endfunc 1472 1473 " This should be done last to reveal a memory leak when vim_regsub_both() is 1474 " called to evaluate an expression but it is not used in a second call. 1475 func Test_z_substitute_expr_leak() 1476 func SubExpr() 1477 ~n 1478 endfunc 1479 silent! s/\%')/\=SubExpr() 1480 delfunc SubExpr 1481 endfunc 1482 1483 func Test_substitute_expr_switch_win() 1484 func R() 1485 wincmd x 1486 return 'XXXX' 1487 endfunc 1488 new Xfoobar 1489 let bufnr = bufnr('%') 1490 put ='abcdef' 1491 silent! s/\%')/\=R() 1492 call assert_fails(':%s/./\=R()/g', 'E565:') 1493 delfunc R 1494 exe bufnr .. "bw!" 1495 endfunc 1496 1497 " recursive call of :s using test-replace special 1498 func Test_substitute_expr_recursive() 1499 func Q() 1500 %s/./\='foobar'/gn 1501 return "foobar" 1502 endfunc 1503 func R() 1504 %s/./\=Q()/g 1505 endfunc 1506 new Xfoobar_UAF 1507 let bufnr = bufnr('%') 1508 put ='abcdef' 1509 silent! s/./\=R()/g 1510 call assert_fails(':%s/./\=R()/g', 'E565:') 1511 delfunc R 1512 delfunc Q 1513 exe bufnr .. "bw!" 1514 endfunc 1515 1516 " Test for changing 'cpo' in a substitute expression 1517 func Test_substitute_expr_cpo() 1518 func XSubExpr() 1519 set cpo= 1520 return 'x' 1521 endfunc 1522 1523 let save_cpo = &cpo 1524 call assert_equal('xxx', substitute('abc', '.', '\=XSubExpr()', 'g')) 1525 call assert_equal(save_cpo, &cpo) 1526 1527 delfunc XSubExpr 1528 endfunc 1529 1530 " vim: shiftwidth=2 sts=2 expandtab