1" Tests for defining text property types and adding text properties to the 2" buffer. 3 4source check.vim 5CheckFeature textprop 6 7source screendump.vim 8 9func Test_proptype_global() 10 call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) 11 let proptypes = prop_type_list() 12 call assert_equal(1, len(proptypes)) 13 call assert_equal('comment', proptypes[0]) 14 15 let proptype = prop_type_get('comment') 16 call assert_equal('Directory', proptype['highlight']) 17 call assert_equal(123, proptype['priority']) 18 call assert_equal(1, proptype['start_incl']) 19 call assert_equal(1, proptype['end_incl']) 20 21 call prop_type_delete('comment') 22 call assert_equal(0, len(prop_type_list())) 23 24 call prop_type_add('one', {}) 25 call assert_equal(1, len(prop_type_list())) 26 let proptype = 'one'->prop_type_get() 27 call assert_false(has_key(proptype, 'highlight')) 28 call assert_equal(0, proptype['priority']) 29 call assert_equal(0, proptype['start_incl']) 30 call assert_equal(0, proptype['end_incl']) 31 32 call prop_type_add('two', {}) 33 call assert_equal(2, len(prop_type_list())) 34 call prop_type_delete('one') 35 call assert_equal(1, len(prop_type_list())) 36 call prop_type_delete('two') 37 call assert_equal(0, len(prop_type_list())) 38endfunc 39 40func Test_proptype_buf() 41 let bufnr = bufnr('') 42 call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) 43 let proptypes = prop_type_list({'bufnr': bufnr}) 44 call assert_equal(1, len(proptypes)) 45 call assert_equal('comment', proptypes[0]) 46 47 let proptype = prop_type_get('comment', {'bufnr': bufnr}) 48 call assert_equal('Directory', proptype['highlight']) 49 call assert_equal(123, proptype['priority']) 50 call assert_equal(1, proptype['start_incl']) 51 call assert_equal(1, proptype['end_incl']) 52 53 call prop_type_delete('comment', {'bufnr': bufnr}) 54 call assert_equal(0, len({'bufnr': bufnr}->prop_type_list())) 55 56 call prop_type_add('one', {'bufnr': bufnr}) 57 let proptype = prop_type_get('one', {'bufnr': bufnr}) 58 call assert_false(has_key(proptype, 'highlight')) 59 call assert_equal(0, proptype['priority']) 60 call assert_equal(0, proptype['start_incl']) 61 call assert_equal(0, proptype['end_incl']) 62 63 call prop_type_add('two', {'bufnr': bufnr}) 64 call assert_equal(2, len(prop_type_list({'bufnr': bufnr}))) 65 call prop_type_delete('one', {'bufnr': bufnr}) 66 call assert_equal(1, len(prop_type_list({'bufnr': bufnr}))) 67 call prop_type_delete('two', {'bufnr': bufnr}) 68 call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) 69 70 call assert_fails("call prop_type_add('one', {'bufnr': 98764})", "E158:") 71endfunc 72 73func AddPropTypes() 74 call prop_type_add('one', {}) 75 call prop_type_add('two', {}) 76 call prop_type_add('three', {}) 77 call prop_type_add('whole', {}) 78endfunc 79 80func DeletePropTypes() 81 call prop_type_delete('one') 82 call prop_type_delete('two') 83 call prop_type_delete('three') 84 call prop_type_delete('whole') 85endfunc 86 87func SetupPropsInFirstLine() 88 call setline(1, 'one two three') 89 call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'}) 90 eval 1->prop_add(5, {'length': 3, 'id': 12, 'type': 'two'}) 91 call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'}) 92 call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'}) 93endfunc 94 95func Get_expected_props() 96 return [ 97 \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1}, 98 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 99 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 100 \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, 101 \ ] 102endfunc 103 104func Test_prop_find() 105 new 106 call setline(1, ['one one one', 'twotwo', 'three', 'fourfour', 'five', 'sixsix']) 107 108 " Add two text props on lines 1 and 5, and one spanning lines 2 to 4. 109 call prop_type_add('prop_name', {'highlight': 'Directory'}) 110 call prop_add(1, 5, {'type': 'prop_name', 'id': 10, 'length': 3}) 111 call prop_add(2, 4, {'type': 'prop_name', 'id': 11, 'end_lnum': 4, 'end_col': 9}) 112 call prop_add(5, 4, {'type': 'prop_name', 'id': 12, 'length': 1}) 113 114 let expected = [ 115 \ {'lnum': 1, 'col': 5, 'length': 3, 'id': 10, 'type': 'prop_name', 'start': 1, 'end': 1}, 116 \ {'lnum': 2, 'col': 4, 'id': 11, 'type': 'prop_name', 'start': 1, 'end': 0}, 117 \ {'lnum': 5, 'col': 4, 'length': 1, 'id': 12, 'type': 'prop_name', 'start': 1, 'end': 1} 118 \ ] 119 120 " Starting at line 5 col 1 this should find the prop at line 5 col 4. 121 call cursor(5,1) 122 let result = prop_find({'type': 'prop_name'}, 'f') 123 call assert_equal(expected[2], result) 124 125 " With skipstart left at false (default), this should find the prop at line 126 " 5 col 4. 127 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4}, 'b') 128 call assert_equal(expected[2], result) 129 130 " With skipstart set to true, this should skip the prop at line 5 col 4. 131 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4, 'skipstart': 1}, 'b') 132 unlet result.length 133 call assert_equal(expected[1], result) 134 135 " Search backwards from line 1 col 10 to find the prop on the same line. 136 let result = prop_find({'type': 'prop_name', 'lnum': 1, 'col': 10}, 'b') 137 call assert_equal(expected[0], result) 138 139 " with skipstart set to false, if the start position is anywhere between the 140 " start and end lines of a text prop (searching forward or backward), the 141 " result should be the prop on the first line (the line with 'start' set to 1). 142 call cursor(3,1) 143 let result = prop_find({'type': 'prop_name'}, 'f') 144 unlet result.length 145 call assert_equal(expected[1], result) 146 let result = prop_find({'type': 'prop_name'}, 'b') 147 unlet result.length 148 call assert_equal(expected[1], result) 149 150 " with skipstart set to true, if the start position is anywhere between the 151 " start and end lines of a text prop (searching forward or backward), all lines 152 " of the prop will be skipped. 153 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'b') 154 call assert_equal(expected[0], result) 155 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'f') 156 call assert_equal(expected[2], result) 157 158 " Use skipstart to search through all props with type name 'prop_name'. 159 " First forward... 160 let lnum = 1 161 let col = 1 162 let i = 0 163 for exp in expected 164 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'f') 165 if !has_key(exp, "length") 166 unlet result.length 167 endif 168 call assert_equal(exp, result) 169 let lnum = result.lnum 170 let col = result.col 171 let i = i + 1 172 endfor 173 174 " ...then backwards. 175 let lnum = 6 176 let col = 4 177 let i = 2 178 while i >= 0 179 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'b') 180 if !has_key(expected[i], "length") 181 unlet result.length 182 endif 183 call assert_equal(expected[i], result) 184 let lnum = result.lnum 185 let col = result.col 186 let i = i - 1 187 endwhile 188 189 " Starting from line 6 col 1 search backwards for prop with id 10. 190 call cursor(6,1) 191 let result = prop_find({'id': 10, 'skipstart': 1}, 'b') 192 call assert_equal(expected[0], result) 193 194 " Starting from line 1 col 1 search forwards for prop with id 12. 195 call cursor(1,1) 196 let result = prop_find({'id': 12}, 'f') 197 call assert_equal(expected[2], result) 198 199 " Search for a prop with an unknown id. 200 let result = prop_find({'id': 999}, 'f') 201 call assert_equal({}, result) 202 203 " Search backwards from the proceeding position of the prop with id 11 204 " (at line num 2 col 4). This should return an empty dict. 205 let result = prop_find({'id': 11, 'lnum': 2, 'col': 3}, 'b') 206 call assert_equal({}, result) 207 208 " When lnum is given and col is omitted, use column 1. 209 let result = prop_find({'type': 'prop_name', 'lnum': 1}, 'f') 210 call assert_equal(expected[0], result) 211 212 call prop_clear(1,6) 213 call prop_type_delete('prop_name') 214 215 bwipe! 216endfunc 217 218def Test_prop_find2() 219 # Multiple props per line, start on the first, should find the second. 220 new 221 ['the quikc bronw fox jumsp over the layz dog']->repeat(2)->setline(1) 222 prop_type_add('misspell', {highlight: 'ErrorMsg'}) 223 for lnum in [1, 2] 224 for col in [8, 14, 24, 38] 225 prop_add(lnum, col, {type: 'misspell', length: 2}) 226 endfor 227 endfor 228 cursor(1, 8) 229 var expected = {lnum: 1, id: 0, col: 14, end: 1, type: 'misspell', length: 2, start: 1} 230 var result = prop_find({type: 'misspell', skipstart: true}, 'f') 231 assert_equal(expected, result) 232 233 prop_type_delete('misspell') 234 bwipe! 235enddef 236 237func Test_prop_find_smaller_len_than_match_col() 238 new 239 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 240 call setline(1, ['xxxx', 'x']) 241 call prop_add(1, 4, {'type': 'test'}) 242 call assert_equal({'id': 0, 'lnum': 1, 'col': 4, 'type': 'test', 'length': 0, 'start': 1, 'end': 1}, 243 \ prop_find({'type': 'test', 'lnum': 2, 'col': 1}, 'b')) 244 bwipe! 245 call prop_type_delete('test') 246endfunc 247 248func Test_prop_add() 249 new 250 call AddPropTypes() 251 call SetupPropsInFirstLine() 252 let expected_props = Get_expected_props() 253 call assert_equal(expected_props, prop_list(1)) 254 call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:') 255 call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:') 256 257 " Insert a line above, text props must still be there. 258 call append(0, 'empty') 259 call assert_equal(expected_props, prop_list(2)) 260 " Delete a line above, text props must still be there. 261 1del 262 call assert_equal(expected_props, prop_list(1)) 263 264 " Prop without length or end column is zero length 265 call prop_clear(1) 266 call prop_type_add('included', {'start_incl': 1, 'end_incl': 1}) 267 call prop_add(1, 5, #{type: 'included'}) 268 let expected = [#{col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}] 269 call assert_equal(expected, prop_list(1)) 270 271 " Inserting text makes the prop bigger. 272 exe "normal 5|ixx\<Esc>" 273 let expected = [#{col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}] 274 call assert_equal(expected, prop_list(1)) 275 276 call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:') 277 278 call DeletePropTypes() 279 call prop_type_delete('included') 280 bwipe! 281endfunc 282 283func Test_prop_remove() 284 new 285 call AddPropTypes() 286 call SetupPropsInFirstLine() 287 let props = Get_expected_props() 288 call assert_equal(props, prop_list(1)) 289 290 " remove by id 291 call assert_equal(1, {'id': 12}->prop_remove(1)) 292 unlet props[2] 293 call assert_equal(props, prop_list(1)) 294 295 " remove by type 296 call assert_equal(1, prop_remove({'type': 'one'}, 1)) 297 unlet props[1] 298 call assert_equal(props, prop_list(1)) 299 300 " remove from unknown buffer 301 call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:') 302 303 call DeletePropTypes() 304 bwipe! 305 306 new 307 call AddPropTypes() 308 call SetupPropsInFirstLine() 309 call prop_add(1, 6, {'length': 2, 'id': 11, 'type': 'three'}) 310 let props = Get_expected_props() 311 call insert(props, {'col': 6, 'length': 2, 'id': 11, 'type': 'three', 'start': 1, 'end': 1}, 3) 312 call assert_equal(props, prop_list(1)) 313 call assert_equal(1, prop_remove({'type': 'three', 'id': 11, 'both': 1, 'all': 1}, 1)) 314 unlet props[3] 315 call assert_equal(props, prop_list(1)) 316 317 call assert_fails("call prop_remove({'id': 11, 'both': 1})", 'E860:') 318 call assert_fails("call prop_remove({'type': 'three', 'both': 1})", 'E860:') 319 320 call DeletePropTypes() 321 bwipe! 322endfunc 323 324def Test_prop_add_vim9() 325 prop_type_add('comment', { 326 highlight: 'Directory', 327 priority: 123, 328 start_incl: true, 329 end_incl: true, 330 combine: false, 331 }) 332 prop_type_delete('comment') 333enddef 334 335def Test_prop_remove_vim9() 336 new 337 AddPropTypes() 338 SetupPropsInFirstLine() 339 assert_equal(1, prop_remove({type: 'three', id: 13, both: true, all: true})) 340 DeletePropTypes() 341 bwipe! 342enddef 343 344func SetupOneLine() 345 call setline(1, 'xonex xtwoxx') 346 normal gg0 347 call AddPropTypes() 348 call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) 349 call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) 350 let expected = [ 351 \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 352 \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 353 \] 354 call assert_equal(expected, prop_list(1)) 355 return expected 356endfunc 357 358func Test_prop_add_remove_buf() 359 new 360 let bufnr = bufnr('') 361 call AddPropTypes() 362 for lnum in range(1, 4) 363 call setline(lnum, 'one two three') 364 endfor 365 wincmd w 366 for lnum in range(1, 4) 367 call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr}) 368 call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr}) 369 call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr}) 370 endfor 371 372 let props = [ 373 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 374 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 375 \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, 376 \] 377 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 378 379 " remove by id 380 let before_props = deepcopy(props) 381 unlet props[1] 382 383 call prop_remove({'id': 12, 'bufnr': bufnr}, 1) 384 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 385 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 386 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 387 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 388 389 call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4) 390 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 391 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 392 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 393 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 394 395 call prop_remove({'id': 12, 'bufnr': bufnr}) 396 for lnum in range(1, 4) 397 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 398 endfor 399 400 " remove by type 401 let before_props = deepcopy(props) 402 unlet props[0] 403 404 call prop_remove({'type': 'one', 'bufnr': bufnr}, 1) 405 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 406 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 407 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 408 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 409 410 call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4) 411 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 412 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 413 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 414 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 415 416 call prop_remove({'type': 'one', 'bufnr': bufnr}) 417 for lnum in range(1, 4) 418 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 419 endfor 420 421 call DeletePropTypes() 422 wincmd w 423 bwipe! 424endfunc 425 426func Test_prop_backspace() 427 new 428 set bs=2 429 let expected = SetupOneLine() " 'xonex xtwoxx' 430 431 exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>" 432 call assert_equal('one xtwoxx', getline(1)) 433 let expected[0].col = 1 434 let expected[1].col = 6 435 call assert_equal(expected, prop_list(1)) 436 437 call DeletePropTypes() 438 bwipe! 439 set bs& 440endfunc 441 442func Test_prop_replace() 443 new 444 set bs=2 445 let expected = SetupOneLine() " 'xonex xtwoxx' 446 447 exe "normal 0Ryyy\<Esc>" 448 call assert_equal('yyyex xtwoxx', getline(1)) 449 call assert_equal(expected, prop_list(1)) 450 451 exe "normal ftRyy\<BS>" 452 call assert_equal('yyyex xywoxx', getline(1)) 453 call assert_equal(expected, prop_list(1)) 454 455 exe "normal 0fwRyy\<BS>" 456 call assert_equal('yyyex xyyoxx', getline(1)) 457 call assert_equal(expected, prop_list(1)) 458 459 exe "normal 0foRyy\<BS>\<BS>" 460 call assert_equal('yyyex xyyoxx', getline(1)) 461 call assert_equal(expected, prop_list(1)) 462 463 call DeletePropTypes() 464 bwipe! 465 set bs& 466endfunc 467 468func Test_prop_open_line() 469 new 470 471 " open new line, props stay in top line 472 let expected = SetupOneLine() " 'xonex xtwoxx' 473 exe "normal o\<Esc>" 474 call assert_equal('xonex xtwoxx', getline(1)) 475 call assert_equal('', getline(2)) 476 call assert_equal(expected, prop_list(1)) 477 call DeletePropTypes() 478 479 " move all props to next line 480 let expected = SetupOneLine() " 'xonex xtwoxx' 481 exe "normal 0i\<CR>\<Esc>" 482 call assert_equal('', getline(1)) 483 call assert_equal('xonex xtwoxx', getline(2)) 484 call assert_equal(expected, prop_list(2)) 485 call DeletePropTypes() 486 487 " split just before prop, move all props to next line 488 let expected = SetupOneLine() " 'xonex xtwoxx' 489 exe "normal 0li\<CR>\<Esc>" 490 call assert_equal('x', getline(1)) 491 call assert_equal('onex xtwoxx', getline(2)) 492 let expected[0].col -= 1 493 let expected[1].col -= 1 494 call assert_equal(expected, prop_list(2)) 495 call DeletePropTypes() 496 497 " split inside prop, split first prop 498 let expected = SetupOneLine() " 'xonex xtwoxx' 499 exe "normal 0lli\<CR>\<Esc>" 500 call assert_equal('xo', getline(1)) 501 call assert_equal('nex xtwoxx', getline(2)) 502 let exp_first = [deepcopy(expected[0])] 503 let exp_first[0].length = 1 504 let exp_first[0].end = 0 505 call assert_equal(exp_first, prop_list(1)) 506 let expected[0].col = 1 507 let expected[0].length = 2 508 let expected[0].start = 0 509 let expected[1].col -= 2 510 call assert_equal(expected, prop_list(2)) 511 call DeletePropTypes() 512 513 " split just after first prop, second prop move to next line 514 let expected = SetupOneLine() " 'xonex xtwoxx' 515 exe "normal 0fea\<CR>\<Esc>" 516 call assert_equal('xone', getline(1)) 517 call assert_equal('x xtwoxx', getline(2)) 518 let exp_first = expected[0:0] 519 call assert_equal(exp_first, prop_list(1)) 520 let expected = expected[1:1] 521 let expected[0].col -= 4 522 call assert_equal(expected, prop_list(2)) 523 call DeletePropTypes() 524 525 bwipe! 526 set bs& 527endfunc 528 529func Test_prop_clear() 530 new 531 call AddPropTypes() 532 call SetupPropsInFirstLine() 533 call assert_equal(Get_expected_props(), prop_list(1)) 534 535 eval 1->prop_clear() 536 call assert_equal([], 1->prop_list()) 537 538 call DeletePropTypes() 539 bwipe! 540endfunc 541 542func Test_prop_clear_buf() 543 new 544 call AddPropTypes() 545 call SetupPropsInFirstLine() 546 let bufnr = bufnr('') 547 wincmd w 548 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 549 550 call prop_clear(1, 1, {'bufnr': bufnr}) 551 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 552 553 wincmd w 554 call DeletePropTypes() 555 bwipe! 556endfunc 557 558func Test_prop_setline() 559 new 560 call AddPropTypes() 561 call SetupPropsInFirstLine() 562 call assert_equal(Get_expected_props(), prop_list(1)) 563 564 call setline(1, 'foobar') 565 call assert_equal([], prop_list(1)) 566 567 call DeletePropTypes() 568 bwipe! 569endfunc 570 571func Test_prop_setbufline() 572 new 573 call AddPropTypes() 574 call SetupPropsInFirstLine() 575 let bufnr = bufnr('') 576 wincmd w 577 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 578 579 call setbufline(bufnr, 1, 'foobar') 580 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 581 582 wincmd w 583 call DeletePropTypes() 584 bwipe! 585endfunc 586 587func Test_prop_substitute() 588 new 589 " Set first line to 'one two three' 590 call AddPropTypes() 591 call SetupPropsInFirstLine() 592 let expected_props = Get_expected_props() 593 call assert_equal(expected_props, prop_list(1)) 594 595 " Change "n" in "one" to XX: 'oXXe two three' 596 s/n/XX/ 597 let expected_props[0].length += 1 598 let expected_props[1].length += 1 599 let expected_props[2].col += 1 600 let expected_props[3].col += 1 601 call assert_equal(expected_props, prop_list(1)) 602 603 " Delete "t" in "two" and "three" to XX: 'oXXe wo hree' 604 s/t//g 605 let expected_props[0].length -= 2 606 let expected_props[2].length -= 1 607 let expected_props[3].length -= 1 608 let expected_props[3].col -= 1 609 call assert_equal(expected_props, prop_list(1)) 610 611 " Split the line by changing w to line break: 'oXXe ', 'o hree' 612 " The long prop is split and spans both lines. 613 " The props on "two" and "three" move to the next line. 614 s/w/\r/ 615 let new_props = [ 616 \ copy(expected_props[0]), 617 \ copy(expected_props[2]), 618 \ copy(expected_props[3]), 619 \ ] 620 let expected_props[0].length = 5 621 let expected_props[0].end = 0 622 unlet expected_props[3] 623 unlet expected_props[2] 624 call assert_equal(expected_props, prop_list(1)) 625 626 let new_props[0].length = 6 627 let new_props[0].start = 0 628 let new_props[1].col = 1 629 let new_props[1].length = 1 630 let new_props[2].col = 3 631 call assert_equal(new_props, prop_list(2)) 632 633 call DeletePropTypes() 634 bwipe! 635endfunc 636 637func Test_prop_change_indent() 638 call prop_type_add('comment', {'highlight': 'Directory'}) 639 new 640 call setline(1, [' xxx', 'yyyyy']) 641 call prop_add(2, 2, {'length': 2, 'type': 'comment'}) 642 let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0} 643 call assert_equal([expect], prop_list(2)) 644 645 set shiftwidth=3 646 normal 2G>> 647 call assert_equal(' yyyyy', getline(2)) 648 let expect.col += 3 649 call assert_equal([expect], prop_list(2)) 650 651 normal 2G== 652 call assert_equal(' yyyyy', getline(2)) 653 let expect.col = 6 654 call assert_equal([expect], prop_list(2)) 655 656 call prop_clear(2) 657 call prop_add(2, 2, {'length': 5, 'type': 'comment'}) 658 let expect.col = 2 659 let expect.length = 5 660 call assert_equal([expect], prop_list(2)) 661 662 normal 2G<< 663 call assert_equal(' yyyyy', getline(2)) 664 let expect.length = 2 665 call assert_equal([expect], prop_list(2)) 666 667 set shiftwidth& 668 call prop_type_delete('comment') 669endfunc 670 671" Setup a three line prop in lines 2 - 4. 672" Add short props in line 1 and 5. 673func Setup_three_line_prop() 674 new 675 call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five']) 676 call prop_add(1, 2, {'length': 1, 'type': 'comment'}) 677 call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'}) 678 call prop_add(5, 2, {'length': 1, 'type': 'comment'}) 679endfunc 680 681func Test_prop_multiline() 682 eval 'comment'->prop_type_add({'highlight': 'Directory'}) 683 new 684 call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz']) 685 686 " start halfway line 1, end halfway line 3 687 call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'}) 688 let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 689 call assert_equal([expect1], prop_list(1)) 690 let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 691 call assert_equal([expect2], prop_list(2)) 692 let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0} 693 call assert_equal([expect3], prop_list(3)) 694 call prop_clear(1, 3) 695 696 " include all three lines 697 call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'}) 698 let expect1.col = 1 699 let expect1.length = 8 700 call assert_equal([expect1], prop_list(1)) 701 call assert_equal([expect2], prop_list(2)) 702 let expect3.length = 9 703 call assert_equal([expect3], prop_list(3)) 704 call prop_clear(1, 3) 705 706 bwipe! 707 708 " Test deleting the first line of a multi-line prop. 709 call Setup_three_line_prop() 710 let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0} 711 call assert_equal([expect_short], prop_list(1)) 712 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 713 call assert_equal([expect2], prop_list(2)) 714 2del 715 call assert_equal([expect_short], prop_list(1)) 716 let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 717 call assert_equal([expect2], prop_list(2)) 718 bwipe! 719 720 " Test deleting the last line of a multi-line prop. 721 call Setup_three_line_prop() 722 let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 723 call assert_equal([expect3], prop_list(3)) 724 let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0} 725 call assert_equal([expect4], prop_list(4)) 726 4del 727 let expect3.end = 1 728 call assert_equal([expect3], prop_list(3)) 729 call assert_equal([expect_short], prop_list(4)) 730 bwipe! 731 732 " Test appending a line below the multi-line text prop start. 733 call Setup_three_line_prop() 734 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 735 call assert_equal([expect2], prop_list(2)) 736 call append(2, "new line") 737 call assert_equal([expect2], prop_list(2)) 738 let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 739 call assert_equal([expect3], prop_list(3)) 740 bwipe! 741 742 call prop_type_delete('comment') 743endfunc 744 745func Test_prop_line2byte() 746 call prop_type_add('comment', {'highlight': 'Directory'}) 747 new 748 call setline(1, ['line1', 'second line', '']) 749 set ff=unix 750 call assert_equal(19, line2byte(3)) 751 call prop_add(1, 1, {'end_col': 3, 'type': 'comment'}) 752 call assert_equal(19, line2byte(3)) 753 754 bwipe! 755 call prop_type_delete('comment') 756endfunc 757 758func Test_prop_byte2line() 759 new 760 set ff=unix 761 call setline(1, ['one one', 'two two', 'three three', 'four four', 'five']) 762 call assert_equal(4, byte2line(line2byte(4))) 763 call assert_equal(5, byte2line(line2byte(5))) 764 765 call prop_type_add('prop', {'highlight': 'Directory'}) 766 call prop_add(3, 1, {'length': 5, 'type': 'prop'}) 767 call assert_equal(4, byte2line(line2byte(4))) 768 call assert_equal(5, byte2line(line2byte(5))) 769 770 bwipe! 771 call prop_type_delete('prop') 772endfunc 773 774func Test_prop_goto_byte() 775 new 776 call setline(1, '') 777 call setline(2, 'two three') 778 call setline(3, '') 779 call setline(4, 'four five') 780 781 call prop_type_add('testprop', {'highlight': 'Directory'}) 782 call search('^two') 783 call prop_add(line('.'), col('.'), { 784 \ 'length': len('two'), 785 \ 'type': 'testprop' 786 \ }) 787 788 call search('two \zsthree') 789 let expected_pos = line2byte(line('.')) + col('.') - 1 790 exe expected_pos .. 'goto' 791 let actual_pos = line2byte(line('.')) + col('.') - 1 792 eval actual_pos->assert_equal(expected_pos) 793 794 call search('four \zsfive') 795 let expected_pos = line2byte(line('.')) + col('.') - 1 796 exe expected_pos .. 'goto' 797 let actual_pos = line2byte(line('.')) + col('.') - 1 798 eval actual_pos->assert_equal(expected_pos) 799 800 call prop_type_delete('testprop') 801 bwipe! 802endfunc 803 804func Test_prop_undo() 805 new 806 call prop_type_add('comment', {'highlight': 'Directory'}) 807 call setline(1, ['oneone', 'twotwo', 'three']) 808 " Set 'undolevels' to break changes into undo-able pieces. 809 set ul& 810 811 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'}) 812 let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 813 call assert_equal(expected, prop_list(1)) 814 815 " Insert a character, then undo. 816 exe "normal 0lllix\<Esc>" 817 set ul& 818 let expected[0].length = 3 819 call assert_equal(expected, prop_list(1)) 820 undo 821 let expected[0].length = 2 822 call assert_equal(expected, prop_list(1)) 823 824 " Delete a character, then undo 825 exe "normal 0lllx" 826 set ul& 827 let expected[0].length = 1 828 call assert_equal(expected, prop_list(1)) 829 undo 830 let expected[0].length = 2 831 call assert_equal(expected, prop_list(1)) 832 833 " Delete the line, then undo 834 1d 835 set ul& 836 call assert_equal([], prop_list(1)) 837 undo 838 call assert_equal(expected, prop_list(1)) 839 840 " Insert a character, delete two characters, then undo with "U" 841 exe "normal 0lllix\<Esc>" 842 set ul& 843 let expected[0].length = 3 844 call assert_equal(expected, prop_list(1)) 845 exe "normal 0lllxx" 846 set ul& 847 let expected[0].length = 1 848 call assert_equal(expected, prop_list(1)) 849 normal U 850 let expected[0].length = 2 851 call assert_equal(expected, prop_list(1)) 852 853 " substitute a word, then undo 854 call setline(1, 'the number 123 is highlighted.') 855 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 856 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 857 call assert_equal(expected, prop_list(1)) 858 set ul& 859 1s/number/foo 860 let expected[0].col = 9 861 call assert_equal(expected, prop_list(1)) 862 undo 863 let expected[0].col = 12 864 call assert_equal(expected, prop_list(1)) 865 call prop_clear(1) 866 867 " substitute with backslash 868 call setline(1, 'the number 123 is highlighted.') 869 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 870 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 871 call assert_equal(expected, prop_list(1)) 872 1s/the/\The 873 call assert_equal(expected, prop_list(1)) 874 1s/^/\\ 875 let expected[0].col += 1 876 call assert_equal(expected, prop_list(1)) 877 1s/^/\~ 878 let expected[0].col += 1 879 call assert_equal(expected, prop_list(1)) 880 1s/123/12\\3 881 let expected[0].length += 1 882 call assert_equal(expected, prop_list(1)) 883 call prop_clear(1) 884 885 bwipe! 886 call prop_type_delete('comment') 887endfunc 888 889func Test_prop_delete_text() 890 new 891 call prop_type_add('comment', {'highlight': 'Directory'}) 892 call setline(1, ['oneone', 'twotwo', 'three']) 893 894 " zero length property 895 call prop_add(1, 3, {'type': 'comment'}) 896 let expected = [{'col': 3, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 897 call assert_equal(expected, prop_list(1)) 898 899 " delete one char moves the property 900 normal! x 901 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 902 call assert_equal(expected, prop_list(1)) 903 904 " delete char of the property has no effect 905 normal! lx 906 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 907 call assert_equal(expected, prop_list(1)) 908 909 " delete more chars moves property to first column, is not deleted 910 normal! 0xxxx 911 let expected = [{'col': 1, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 912 call assert_equal(expected, prop_list(1)) 913 914 bwipe! 915 call prop_type_delete('comment') 916endfunc 917 918" screenshot test with textprop highlighting 919func Test_textprop_screenshot_various() 920 CheckScreendump 921 " The Vim running in the terminal needs to use utf-8. 922 if g:orig_encoding != 'utf-8' 923 throw 'Skipped: not using utf-8' 924 endif 925 call writefile([ 926 \ "call setline(1, [" 927 \ .. "'One two'," 928 \ .. "'Numbér 123 änd thœn 4¾7.'," 929 \ .. "'--aa--bb--cc--dd--'," 930 \ .. "'// comment with error in it'," 931 \ .. "'first line'," 932 \ .. "' second line '," 933 \ .. "'third line'," 934 \ .. "' fourth line'," 935 \ .. "])", 936 \ "hi NumberProp ctermfg=blue", 937 \ "hi LongProp ctermbg=yellow", 938 \ "hi BackgroundProp ctermbg=lightgrey", 939 \ "hi UnderlineProp cterm=underline", 940 \ "call prop_type_add('number', {'highlight': 'NumberProp'})", 941 \ "call prop_type_add('long', {'highlight': 'NumberProp'})", 942 \ "call prop_type_change('long', {'highlight': 'LongProp'})", 943 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})", 944 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})", 945 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})", 946 \ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})", 947 \ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})", 948 \ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})", 949 \ "call prop_type_add('error', {'highlight': 'UnderlineProp'})", 950 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})", 951 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})", 952 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})", 953 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})", 954 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})", 955 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})", 956 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})", 957 \ "call prop_add(4, 6, {'length': 3, 'type': 'background'})", 958 \ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})", 959 \ "call prop_add(4, 17, {'length': 5, 'type': 'error'})", 960 \ "call prop_add(5, 7, {'length': 4, 'type': 'long'})", 961 \ "call prop_add(6, 1, {'length': 8, 'type': 'long'})", 962 \ "call prop_add(8, 1, {'length': 1, 'type': 'long'})", 963 \ "call prop_add(8, 11, {'length': 4, 'type': 'long'})", 964 \ "set number cursorline", 965 \ "hi clear SpellBad", 966 \ "set spell", 967 \ "syn match Comment '//.*'", 968 \ "hi Comment ctermfg=green", 969 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>", 970 \ "normal 3G0lli\<BS>\<Esc>", 971 \ "normal 6G0i\<BS>\<Esc>", 972 \ "normal 3J", 973 \ "normal 3G", 974 \], 'XtestProp') 975 let buf = RunVimInTerminal('-S XtestProp', {'rows': 8}) 976 call VerifyScreenDump(buf, 'Test_textprop_01', {}) 977 978 " clean up 979 call StopVimInTerminal(buf) 980 call delete('XtestProp') 981endfunc 982 983func RunTestVisualBlock(width, dump) 984 call writefile([ 985 \ "call setline(1, [" 986 \ .. "'xxxxxxxxx 123 x'," 987 \ .. "'xxxxxxxx 123 x'," 988 \ .. "'xxxxxxx 123 x'," 989 \ .. "'xxxxxx 123 x'," 990 \ .. "'xxxxx 123 x'," 991 \ .. "'xxxx 123 xx'," 992 \ .. "'xxx 123 xxx'," 993 \ .. "'xx 123 xxxx'," 994 \ .. "'x 123 xxxxx'," 995 \ .. "' 123 xxxxxx'," 996 \ .. "])", 997 \ "hi SearchProp ctermbg=yellow", 998 \ "call prop_type_add('search', {'highlight': 'SearchProp'})", 999 \ "call prop_add(1, 11, {'length': 3, 'type': 'search'})", 1000 \ "call prop_add(2, 10, {'length': 3, 'type': 'search'})", 1001 \ "call prop_add(3, 9, {'length': 3, 'type': 'search'})", 1002 \ "call prop_add(4, 8, {'length': 3, 'type': 'search'})", 1003 \ "call prop_add(5, 7, {'length': 3, 'type': 'search'})", 1004 \ "call prop_add(6, 6, {'length': 3, 'type': 'search'})", 1005 \ "call prop_add(7, 5, {'length': 3, 'type': 'search'})", 1006 \ "call prop_add(8, 4, {'length': 3, 'type': 'search'})", 1007 \ "call prop_add(9, 3, {'length': 3, 'type': 'search'})", 1008 \ "call prop_add(10, 2, {'length': 3, 'type': 'search'})", 1009 \ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx", 1010 \], 'XtestPropVis') 1011 let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12}) 1012 call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {}) 1013 1014 " clean up 1015 call StopVimInTerminal(buf) 1016 call delete('XtestPropVis') 1017endfunc 1018 1019" screenshot test with Visual block mode operations 1020func Test_textprop_screenshot_visual() 1021 CheckScreendump 1022 1023 " Delete two columns while text props are three chars wide. 1024 call RunTestVisualBlock(2, '01') 1025 1026 " Same, but delete four columns 1027 call RunTestVisualBlock(4, '02') 1028endfunc 1029 1030func Test_textprop_after_tab() 1031 CheckScreendump 1032 1033 let lines =<< trim END 1034 call setline(1, [ 1035 \ "\txxx", 1036 \ "x\txxx", 1037 \ ]) 1038 hi SearchProp ctermbg=yellow 1039 call prop_type_add('search', {'highlight': 'SearchProp'}) 1040 call prop_add(1, 2, {'length': 3, 'type': 'search'}) 1041 call prop_add(2, 3, {'length': 3, 'type': 'search'}) 1042 END 1043 call writefile(lines, 'XtestPropTab') 1044 let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6}) 1045 call VerifyScreenDump(buf, 'Test_textprop_tab', {}) 1046 1047 " clean up 1048 call StopVimInTerminal(buf) 1049 call delete('XtestPropTab') 1050endfunc 1051 1052func Test_textprop_nowrap_scrolled() 1053 CheckScreendump 1054 1055 let lines =<< trim END 1056 vim9script 1057 set nowrap 1058 setline(1, 'The number 123 is smaller than 4567.' .. repeat('X', &columns)) 1059 prop_type_add('number', {'highlight': 'ErrorMsg'}) 1060 prop_add(1, 12, {'length': 3, 'type': 'number'}) 1061 prop_add(1, 32, {'length': 4, 'type': 'number'}) 1062 feedkeys('gg20zl', 'nxt') 1063 END 1064 call writefile(lines, 'XtestNowrap') 1065 let buf = RunVimInTerminal('-S XtestNowrap', {'rows': 6}) 1066 call VerifyScreenDump(buf, 'Test_textprop_nowrap_01', {}) 1067 1068 call term_sendkeys(buf, "$") 1069 call VerifyScreenDump(buf, 'Test_textprop_nowrap_02', {}) 1070 1071 " clean up 1072 call StopVimInTerminal(buf) 1073 call delete('XtestNowrap') 1074endfunc 1075 1076func Test_textprop_with_syntax() 1077 CheckScreendump 1078 1079 let lines =<< trim END 1080 call setline(1, [ 1081 \ "(abc)", 1082 \ ]) 1083 syn match csParens "[()]" display 1084 hi! link csParens MatchParen 1085 1086 call prop_type_add('TPTitle', #{ highlight: 'Title' }) 1087 call prop_add(1, 2, #{type: 'TPTitle', end_col: 5}) 1088 END 1089 call writefile(lines, 'XtestPropSyn') 1090 let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6}) 1091 call VerifyScreenDump(buf, 'Test_textprop_syn_1', {}) 1092 1093 " clean up 1094 call StopVimInTerminal(buf) 1095 call delete('XtestPropSyn') 1096endfunc 1097 1098" Adding a text property to a new buffer should not fail 1099func Test_textprop_empty_buffer() 1100 call prop_type_add('comment', {'highlight': 'Search'}) 1101 new 1102 call prop_add(1, 1, {'type': 'comment'}) 1103 close 1104 call prop_type_delete('comment') 1105endfunc 1106 1107" Adding a text property with invalid highlight should be ignored. 1108func Test_textprop_invalid_highlight() 1109 call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:') 1110 new 1111 call setline(1, ['asdf','asdf']) 1112 call prop_add(1, 1, {'length': 4, 'type': 'dni'}) 1113 redraw 1114 bwipe! 1115 call prop_type_delete('dni') 1116endfunc 1117 1118" Adding a text property to an empty buffer and then editing another 1119func Test_textprop_empty_buffer_next() 1120 call prop_type_add("xxx", {}) 1121 call prop_add(1, 1, {"type": "xxx"}) 1122 next X 1123 call prop_type_delete('xxx') 1124endfunc 1125 1126func Test_textprop_remove_from_buf() 1127 new 1128 let buf = bufnr('') 1129 call prop_type_add('one', {'bufnr': buf}) 1130 call prop_add(1, 1, {'type': 'one', 'id': 234}) 1131 file x 1132 edit y 1133 call prop_remove({'id': 234, 'bufnr': buf}, 1) 1134 call prop_type_delete('one', {'bufnr': buf}) 1135 bwipe! x 1136 close 1137endfunc 1138 1139func Test_textprop_in_unloaded_buf() 1140 edit Xaaa 1141 call setline(1, 'aaa') 1142 write 1143 edit Xbbb 1144 call setline(1, 'bbb') 1145 write 1146 let bnr = bufnr('') 1147 edit Xaaa 1148 1149 call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'}) 1150 call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:') 1151 exe 'buf ' .. bnr 1152 call assert_equal('bbb', getline(1)) 1153 call assert_equal(0, prop_list(1)->len()) 1154 1155 bwipe! Xaaa 1156 bwipe! Xbbb 1157 cal delete('Xaaa') 1158 cal delete('Xbbb') 1159endfunc 1160 1161func Test_proptype_substitute2() 1162 new 1163 " text_prop.vim 1164 call setline(1, [ 1165 \ 'The num 123 is smaller than 4567.', 1166 \ '123 The number 123 is smaller than 4567.', 1167 \ '123 The number 123 is smaller than 4567.']) 1168 1169 call prop_type_add('number', {'highlight': 'ErrorMsg'}) 1170 1171 call prop_add(1, 12, {'length': 3, 'type': 'number'}) 1172 call prop_add(2, 1, {'length': 3, 'type': 'number'}) 1173 call prop_add(3, 36, {'length': 4, 'type': 'number'}) 1174 set ul& 1175 let expected = [{'id': 0, 'col': 13, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}, 1176 \ {'id': 0, 'col': 1, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}, 1177 \ {'id': 0, 'col': 50, 'end': 1, 'type': 'number', 'length': 4, 'start': 1}] 1178 " Add some text in between 1179 %s/\s\+/ /g 1180 call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3)) 1181 1182 " remove some text 1183 :1s/[a-z]\{3\}//g 1184 let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}] 1185 call assert_equal(expected, prop_list(1)) 1186 bwipe! 1187endfunc 1188 1189" This was causing property corruption. 1190func Test_proptype_substitute3() 1191 new 1192 call setline(1, ['abcxxx', 'def']) 1193 call prop_type_add("test", {"highlight": "Search"}) 1194 call prop_add(1, 2, {"end_lnum": 2, "end_col": 2, "type": "test"}) 1195 %s/x\+$// 1196 redraw 1197 1198 call prop_type_delete('test') 1199 bwipe! 1200endfunc 1201 1202func SaveOptions() 1203 let d = #{tabstop: &tabstop, 1204 \ softtabstop: &softtabstop, 1205 \ shiftwidth: &shiftwidth, 1206 \ expandtab: &expandtab, 1207 \ foldmethod: '"' .. &foldmethod .. '"', 1208 \ } 1209 return d 1210endfunc 1211 1212func RestoreOptions(dict) 1213 for name in keys(a:dict) 1214 exe 'let &' .. name .. ' = ' .. a:dict[name] 1215 endfor 1216endfunc 1217 1218func Test_textprop_noexpandtab() 1219 new 1220 let save_dict = SaveOptions() 1221 1222 set tabstop=8 1223 set softtabstop=4 1224 set shiftwidth=4 1225 set noexpandtab 1226 set foldmethod=marker 1227 1228 call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx") 1229 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1230 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1231 call feedkeys("0i\<tab>", "tx") 1232 call prop_remove({'type': 'test'}) 1233 call prop_add(1, 2, {'end_col': 3, 'type': 'test'}) 1234 call feedkeys("A\<left>\<tab>", "tx") 1235 call prop_remove({'type': 'test'}) 1236 try 1237 " It is correct that this does not pass 1238 call prop_add(1, 6, {'end_col': 7, 'type': 'test'}) 1239 " Has already collapsed here, start_col:6 does not result in an error 1240 call feedkeys("A\<left>\<tab>", "tx") 1241 catch /^Vim\%((\a\+)\)\=:E964/ 1242 endtry 1243 call prop_remove({'type': 'test'}) 1244 call prop_type_delete('test') 1245 1246 call RestoreOptions(save_dict) 1247 bwipe! 1248endfunc 1249 1250func Test_textprop_noexpandtab_redraw() 1251 new 1252 let save_dict = SaveOptions() 1253 1254 set tabstop=8 1255 set softtabstop=4 1256 set shiftwidth=4 1257 set noexpandtab 1258 set foldmethod=marker 1259 1260 call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx") 1261 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1262 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1263 call feedkeys("0i\<tab>", "tx") 1264 " Internally broken at the next line 1265 call feedkeys("A\<left>\<tab>", "tx") 1266 redraw 1267 " Index calculation failed internally on next line 1268 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1269 call prop_remove({'type': 'test', 'all': v:true}) 1270 call prop_type_delete('test') 1271 call prop_type_delete('test') 1272 1273 call RestoreOptions(save_dict) 1274 bwipe! 1275endfunc 1276 1277func Test_textprop_ins_str() 1278 new 1279 call setline(1, 'just some text') 1280 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1281 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1282 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1)) 1283 1284 call feedkeys("foi\<F8>\<Esc>", "tx") 1285 call assert_equal('just s<F8>ome text', getline(1)) 1286 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1)) 1287 1288 bwipe! 1289 call prop_remove({'type': 'test'}) 1290 call prop_type_delete('test') 1291endfunc 1292 1293func Test_find_prop_later_in_line() 1294 new 1295 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1296 call setline(1, 'just some text') 1297 call prop_add(1, 1, {'length': 4, 'type': 'test'}) 1298 call prop_add(1, 10, {'length': 3, 'type': 'test'}) 1299 1300 call assert_equal({'id': 0, 'lnum': 1, 'col': 10, 'end': 1, 'type': 'test', 'length': 3, 'start': 1}, 1301 \ prop_find(#{type: 'test', lnum: 1, col: 6})) 1302 1303 bwipe! 1304 call prop_type_delete('test') 1305endfunc 1306 1307func Test_find_zerowidth_prop_sol() 1308 new 1309 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1310 call setline(1, 'just some text') 1311 call prop_add(1, 1, {'length': 0, 'type': 'test'}) 1312 1313 call assert_equal({'id': 0, 'lnum': 1, 'col': 1, 'end': 1, 'type': 'test', 'length': 0, 'start': 1}, 1314 \ prop_find(#{type: 'test', lnum: 1})) 1315 1316 bwipe! 1317 call prop_type_delete('test') 1318endfunc 1319 1320" Test for passing invalid arguments to prop_xxx() functions 1321func Test_prop_func_invalid_args() 1322 call assert_fails('call prop_clear(1, 2, [])', 'E715:') 1323 call assert_fails('call prop_clear(-1, 2)', 'E16:') 1324 call assert_fails('call prop_find(test_null_dict())', 'E474:') 1325 call assert_fails('call prop_find({"bufnr" : []})', 'E730:') 1326 call assert_fails('call prop_find({})', 'E968:') 1327 call assert_fails('call prop_find({}, "x")', 'E474:') 1328 call assert_fails('call prop_find({"lnum" : -2})', 'E16:') 1329 call assert_fails('call prop_list(1, [])', 'E715:') 1330 call assert_fails('call prop_list(-1, {})', 'E16:') 1331 call assert_fails('call prop_remove([])', 'E474:') 1332 call assert_fails('call prop_remove({}, -2)', 'E16:') 1333 call assert_fails('call prop_remove({})', 'E968:') 1334 call assert_fails('call prop_type_add([], {})', 'E730:') 1335 call assert_fails("call prop_type_change('long', {'xyz' : 10})", 'E971:') 1336 call assert_fails("call prop_type_delete([])", 'E730:') 1337 call assert_fails("call prop_type_delete('xyz', [])", 'E715:') 1338 call assert_fails("call prop_type_get([])", 'E730:') 1339 call assert_fails("call prop_type_get('', [])", 'E474:') 1340 call assert_fails("call prop_type_list([])", 'E715:') 1341endfunc 1342 1343func Test_prop_split_join() 1344 new 1345 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1346 call setline(1, 'just some text') 1347 call prop_add(1, 6, {'length': 4, 'type': 'test'}) 1348 1349 " Split in middle of "some" 1350 execute "normal! 8|i\<CR>" 1351 call assert_equal([{'id': 0, 'col': 6, 'end': 0, 'type': 'test', 'length': 2, 'start': 1}], 1352 \ prop_list(1)) 1353 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 2, 'start': 0}], 1354 \ prop_list(2)) 1355 1356 " Join the two lines back together 1357 normal! 1GJ 1358 call assert_equal([{'id': 0, 'col': 6, 'end': 1, 'type': 'test', 'length': 5, 'start': 1}], prop_list(1)) 1359 1360 bwipe! 1361 call prop_type_delete('test') 1362endfunc 1363 1364func Test_prop_increment_decrement() 1365 new 1366 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1367 call setline(1, 'its 998 times') 1368 call prop_add(1, 5, {'length': 3, 'type': 'test'}) 1369 1370 exe "normal! 0f9\<C-A>" 1371 eval getline(1)->assert_equal('its 999 times') 1372 eval prop_list(1)->assert_equal([ 1373 \ #{id: 0, col: 5, end: 1, type: 'test', length: 3, start: 1}]) 1374 1375 exe "normal! 0f9\<C-A>" 1376 eval getline(1)->assert_equal('its 1000 times') 1377 eval prop_list(1)->assert_equal([ 1378 \ #{id: 0, col: 5, end: 1, type: 'test', length: 4, start: 1}]) 1379 1380 bwipe! 1381 call prop_type_delete('test') 1382endfunc 1383 1384func Test_prop_block_insert() 1385 new 1386 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1387 call setline(1, ['one ', 'two ']) 1388 call prop_add(1, 1, {'length': 3, 'type': 'test'}) 1389 call prop_add(2, 1, {'length': 3, 'type': 'test'}) 1390 1391 " insert "xx" in the first column of both lines 1392 exe "normal! gg0\<C-V>jIxx\<Esc>" 1393 eval getline(1, 2)->assert_equal(['xxone ', 'xxtwo ']) 1394 let expected = [#{id: 0, col: 3, end: 1, type: 'test', length: 3, start: 1}] 1395 eval prop_list(1)->assert_equal(expected) 1396 eval prop_list(2)->assert_equal(expected) 1397 1398 " insert "yy" inside the text props to make them longer 1399 exe "normal! gg03l\<C-V>jIyy\<Esc>" 1400 eval getline(1, 2)->assert_equal(['xxoyyne ', 'xxtyywo ']) 1401 let expected[0].length = 5 1402 eval prop_list(1)->assert_equal(expected) 1403 eval prop_list(2)->assert_equal(expected) 1404 1405 " insert "zz" after the text props, text props don't change 1406 exe "normal! gg07l\<C-V>jIzz\<Esc>" 1407 eval getline(1, 2)->assert_equal(['xxoyynezz ', 'xxtyywozz ']) 1408 eval prop_list(1)->assert_equal(expected) 1409 eval prop_list(2)->assert_equal(expected) 1410 1411 bwipe! 1412 call prop_type_delete('test') 1413endfunc 1414 1415" this was causing an ml_get error because w_botline was wrong 1416func Test_prop_one_line_window() 1417 enew 1418 call range(2)->setline(1) 1419 call prop_type_add('testprop', {}) 1420 call prop_add(1, 1, {'type': 'testprop'}) 1421 call popup_create('popup', {'textprop': 'testprop'}) 1422 $ 1423 new 1424 wincmd _ 1425 call feedkeys("\r", 'xt') 1426 redraw 1427 1428 call popup_clear() 1429 call prop_type_delete('testprop') 1430 close 1431 bwipe! 1432endfunc 1433 1434 1435" vim: shiftwidth=2 sts=2 expandtab 1436