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_undo() 775 new 776 call prop_type_add('comment', {'highlight': 'Directory'}) 777 call setline(1, ['oneone', 'twotwo', 'three']) 778 " Set 'undolevels' to break changes into undo-able pieces. 779 set ul& 780 781 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'}) 782 let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 783 call assert_equal(expected, prop_list(1)) 784 785 " Insert a character, then undo. 786 exe "normal 0lllix\<Esc>" 787 set ul& 788 let expected[0].length = 3 789 call assert_equal(expected, prop_list(1)) 790 undo 791 let expected[0].length = 2 792 call assert_equal(expected, prop_list(1)) 793 794 " Delete a character, then undo 795 exe "normal 0lllx" 796 set ul& 797 let expected[0].length = 1 798 call assert_equal(expected, prop_list(1)) 799 undo 800 let expected[0].length = 2 801 call assert_equal(expected, prop_list(1)) 802 803 " Delete the line, then undo 804 1d 805 set ul& 806 call assert_equal([], prop_list(1)) 807 undo 808 call assert_equal(expected, prop_list(1)) 809 810 " Insert a character, delete two characters, then undo with "U" 811 exe "normal 0lllix\<Esc>" 812 set ul& 813 let expected[0].length = 3 814 call assert_equal(expected, prop_list(1)) 815 exe "normal 0lllxx" 816 set ul& 817 let expected[0].length = 1 818 call assert_equal(expected, prop_list(1)) 819 normal U 820 let expected[0].length = 2 821 call assert_equal(expected, prop_list(1)) 822 823 " substitute a word, then undo 824 call setline(1, 'the number 123 is highlighted.') 825 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 826 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 827 call assert_equal(expected, prop_list(1)) 828 set ul& 829 1s/number/foo 830 let expected[0].col = 9 831 call assert_equal(expected, prop_list(1)) 832 undo 833 let expected[0].col = 12 834 call assert_equal(expected, prop_list(1)) 835 call prop_clear(1) 836 837 " substitute with backslash 838 call setline(1, 'the number 123 is highlighted.') 839 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 840 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 841 call assert_equal(expected, prop_list(1)) 842 1s/the/\The 843 call assert_equal(expected, prop_list(1)) 844 1s/^/\\ 845 let expected[0].col += 1 846 call assert_equal(expected, prop_list(1)) 847 1s/^/\~ 848 let expected[0].col += 1 849 call assert_equal(expected, prop_list(1)) 850 1s/123/12\\3 851 let expected[0].length += 1 852 call assert_equal(expected, prop_list(1)) 853 call prop_clear(1) 854 855 bwipe! 856 call prop_type_delete('comment') 857endfunc 858 859func Test_prop_delete_text() 860 new 861 call prop_type_add('comment', {'highlight': 'Directory'}) 862 call setline(1, ['oneone', 'twotwo', 'three']) 863 864 " zero length property 865 call prop_add(1, 3, {'type': 'comment'}) 866 let expected = [{'col': 3, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 867 call assert_equal(expected, prop_list(1)) 868 869 " delete one char moves the property 870 normal! x 871 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 872 call assert_equal(expected, prop_list(1)) 873 874 " delete char of the property has no effect 875 normal! lx 876 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 877 call assert_equal(expected, prop_list(1)) 878 879 " delete more chars moves property to first column, is not deleted 880 normal! 0xxxx 881 let expected = [{'col': 1, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 882 call assert_equal(expected, prop_list(1)) 883 884 bwipe! 885 call prop_type_delete('comment') 886endfunc 887 888" screenshot test with textprop highlighting 889func Test_textprop_screenshot_various() 890 CheckScreendump 891 " The Vim running in the terminal needs to use utf-8. 892 if g:orig_encoding != 'utf-8' 893 throw 'Skipped: not using utf-8' 894 endif 895 call writefile([ 896 \ "call setline(1, [" 897 \ .. "'One two'," 898 \ .. "'Numbér 123 änd thœn 4¾7.'," 899 \ .. "'--aa--bb--cc--dd--'," 900 \ .. "'// comment with error in it'," 901 \ .. "'first line'," 902 \ .. "' second line '," 903 \ .. "'third line'," 904 \ .. "' fourth line'," 905 \ .. "])", 906 \ "hi NumberProp ctermfg=blue", 907 \ "hi LongProp ctermbg=yellow", 908 \ "hi BackgroundProp ctermbg=lightgrey", 909 \ "hi UnderlineProp cterm=underline", 910 \ "call prop_type_add('number', {'highlight': 'NumberProp'})", 911 \ "call prop_type_add('long', {'highlight': 'NumberProp'})", 912 \ "call prop_type_change('long', {'highlight': 'LongProp'})", 913 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})", 914 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})", 915 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})", 916 \ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})", 917 \ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})", 918 \ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})", 919 \ "call prop_type_add('error', {'highlight': 'UnderlineProp'})", 920 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})", 921 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})", 922 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})", 923 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})", 924 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})", 925 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})", 926 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})", 927 \ "call prop_add(4, 6, {'length': 3, 'type': 'background'})", 928 \ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})", 929 \ "call prop_add(4, 17, {'length': 5, 'type': 'error'})", 930 \ "call prop_add(5, 7, {'length': 4, 'type': 'long'})", 931 \ "call prop_add(6, 1, {'length': 8, 'type': 'long'})", 932 \ "call prop_add(8, 1, {'length': 1, 'type': 'long'})", 933 \ "call prop_add(8, 11, {'length': 4, 'type': 'long'})", 934 \ "set number cursorline", 935 \ "hi clear SpellBad", 936 \ "set spell", 937 \ "syn match Comment '//.*'", 938 \ "hi Comment ctermfg=green", 939 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>", 940 \ "normal 3G0lli\<BS>\<Esc>", 941 \ "normal 6G0i\<BS>\<Esc>", 942 \ "normal 3J", 943 \ "normal 3G", 944 \], 'XtestProp') 945 let buf = RunVimInTerminal('-S XtestProp', {'rows': 8}) 946 call VerifyScreenDump(buf, 'Test_textprop_01', {}) 947 948 " clean up 949 call StopVimInTerminal(buf) 950 call delete('XtestProp') 951endfunc 952 953func RunTestVisualBlock(width, dump) 954 call writefile([ 955 \ "call setline(1, [" 956 \ .. "'xxxxxxxxx 123 x'," 957 \ .. "'xxxxxxxx 123 x'," 958 \ .. "'xxxxxxx 123 x'," 959 \ .. "'xxxxxx 123 x'," 960 \ .. "'xxxxx 123 x'," 961 \ .. "'xxxx 123 xx'," 962 \ .. "'xxx 123 xxx'," 963 \ .. "'xx 123 xxxx'," 964 \ .. "'x 123 xxxxx'," 965 \ .. "' 123 xxxxxx'," 966 \ .. "])", 967 \ "hi SearchProp ctermbg=yellow", 968 \ "call prop_type_add('search', {'highlight': 'SearchProp'})", 969 \ "call prop_add(1, 11, {'length': 3, 'type': 'search'})", 970 \ "call prop_add(2, 10, {'length': 3, 'type': 'search'})", 971 \ "call prop_add(3, 9, {'length': 3, 'type': 'search'})", 972 \ "call prop_add(4, 8, {'length': 3, 'type': 'search'})", 973 \ "call prop_add(5, 7, {'length': 3, 'type': 'search'})", 974 \ "call prop_add(6, 6, {'length': 3, 'type': 'search'})", 975 \ "call prop_add(7, 5, {'length': 3, 'type': 'search'})", 976 \ "call prop_add(8, 4, {'length': 3, 'type': 'search'})", 977 \ "call prop_add(9, 3, {'length': 3, 'type': 'search'})", 978 \ "call prop_add(10, 2, {'length': 3, 'type': 'search'})", 979 \ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx", 980 \], 'XtestPropVis') 981 let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12}) 982 call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {}) 983 984 " clean up 985 call StopVimInTerminal(buf) 986 call delete('XtestPropVis') 987endfunc 988 989" screenshot test with Visual block mode operations 990func Test_textprop_screenshot_visual() 991 CheckScreendump 992 993 " Delete two columns while text props are three chars wide. 994 call RunTestVisualBlock(2, '01') 995 996 " Same, but delete four columns 997 call RunTestVisualBlock(4, '02') 998endfunc 999 1000func Test_textprop_after_tab() 1001 CheckScreendump 1002 1003 let lines =<< trim END 1004 call setline(1, [ 1005 \ "\txxx", 1006 \ "x\txxx", 1007 \ ]) 1008 hi SearchProp ctermbg=yellow 1009 call prop_type_add('search', {'highlight': 'SearchProp'}) 1010 call prop_add(1, 2, {'length': 3, 'type': 'search'}) 1011 call prop_add(2, 3, {'length': 3, 'type': 'search'}) 1012 END 1013 call writefile(lines, 'XtestPropTab') 1014 let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6}) 1015 call VerifyScreenDump(buf, 'Test_textprop_tab', {}) 1016 1017 " clean up 1018 call StopVimInTerminal(buf) 1019 call delete('XtestPropTab') 1020endfunc 1021 1022func Test_textprop_with_syntax() 1023 CheckScreendump 1024 1025 let lines =<< trim END 1026 call setline(1, [ 1027 \ "(abc)", 1028 \ ]) 1029 syn match csParens "[()]" display 1030 hi! link csParens MatchParen 1031 1032 call prop_type_add('TPTitle', #{ highlight: 'Title' }) 1033 call prop_add(1, 2, #{type: 'TPTitle', end_col: 5}) 1034 END 1035 call writefile(lines, 'XtestPropSyn') 1036 let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6}) 1037 call VerifyScreenDump(buf, 'Test_textprop_syn_1', {}) 1038 1039 " clean up 1040 call StopVimInTerminal(buf) 1041 call delete('XtestPropSyn') 1042endfunc 1043 1044" Adding a text property to a new buffer should not fail 1045func Test_textprop_empty_buffer() 1046 call prop_type_add('comment', {'highlight': 'Search'}) 1047 new 1048 call prop_add(1, 1, {'type': 'comment'}) 1049 close 1050 call prop_type_delete('comment') 1051endfunc 1052 1053" Adding a text property with invalid highlight should be ignored. 1054func Test_textprop_invalid_highlight() 1055 call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:') 1056 new 1057 call setline(1, ['asdf','asdf']) 1058 call prop_add(1, 1, {'length': 4, 'type': 'dni'}) 1059 redraw 1060 bwipe! 1061 call prop_type_delete('dni') 1062endfunc 1063 1064" Adding a text property to an empty buffer and then editing another 1065func Test_textprop_empty_buffer_next() 1066 call prop_type_add("xxx", {}) 1067 call prop_add(1, 1, {"type": "xxx"}) 1068 next X 1069 call prop_type_delete('xxx') 1070endfunc 1071 1072func Test_textprop_remove_from_buf() 1073 new 1074 let buf = bufnr('') 1075 call prop_type_add('one', {'bufnr': buf}) 1076 call prop_add(1, 1, {'type': 'one', 'id': 234}) 1077 file x 1078 edit y 1079 call prop_remove({'id': 234, 'bufnr': buf}, 1) 1080 call prop_type_delete('one', {'bufnr': buf}) 1081 bwipe! x 1082 close 1083endfunc 1084 1085func Test_textprop_in_unloaded_buf() 1086 edit Xaaa 1087 call setline(1, 'aaa') 1088 write 1089 edit Xbbb 1090 call setline(1, 'bbb') 1091 write 1092 let bnr = bufnr('') 1093 edit Xaaa 1094 1095 call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'}) 1096 call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:') 1097 exe 'buf ' .. bnr 1098 call assert_equal('bbb', getline(1)) 1099 call assert_equal(0, prop_list(1)->len()) 1100 1101 bwipe! Xaaa 1102 bwipe! Xbbb 1103 cal delete('Xaaa') 1104 cal delete('Xbbb') 1105endfunc 1106 1107func Test_proptype_substitute2() 1108 new 1109 " text_prop.vim 1110 call setline(1, [ 1111 \ 'The num 123 is smaller than 4567.', 1112 \ '123 The number 123 is smaller than 4567.', 1113 \ '123 The number 123 is smaller than 4567.']) 1114 1115 call prop_type_add('number', {'highlight': 'ErrorMsg'}) 1116 1117 call prop_add(1, 12, {'length': 3, 'type': 'number'}) 1118 call prop_add(2, 1, {'length': 3, 'type': 'number'}) 1119 call prop_add(3, 36, {'length': 4, 'type': 'number'}) 1120 set ul& 1121 let expected = [{'id': 0, 'col': 13, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}, 1122 \ {'id': 0, 'col': 1, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}, 1123 \ {'id': 0, 'col': 50, 'end': 1, 'type': 'number', 'length': 4, 'start': 1}] 1124 " Add some text in between 1125 %s/\s\+/ /g 1126 call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3)) 1127 1128 " remove some text 1129 :1s/[a-z]\{3\}//g 1130 let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}] 1131 call assert_equal(expected, prop_list(1)) 1132 bwipe! 1133endfunc 1134 1135" This was causing property corruption. 1136func Test_proptype_substitute3() 1137 new 1138 call setline(1, ['abcxxx', 'def']) 1139 call prop_type_add("test", {"highlight": "Search"}) 1140 call prop_add(1, 2, {"end_lnum": 2, "end_col": 2, "type": "test"}) 1141 %s/x\+$// 1142 redraw 1143 1144 call prop_type_delete('test') 1145 bwipe! 1146endfunc 1147 1148func SaveOptions() 1149 let d = #{tabstop: &tabstop, 1150 \ softtabstop: &softtabstop, 1151 \ shiftwidth: &shiftwidth, 1152 \ expandtab: &expandtab, 1153 \ foldmethod: '"' .. &foldmethod .. '"', 1154 \ } 1155 return d 1156endfunc 1157 1158func RestoreOptions(dict) 1159 for name in keys(a:dict) 1160 exe 'let &' .. name .. ' = ' .. a:dict[name] 1161 endfor 1162endfunc 1163 1164func Test_textprop_noexpandtab() 1165 new 1166 let save_dict = SaveOptions() 1167 1168 set tabstop=8 1169 set softtabstop=4 1170 set shiftwidth=4 1171 set noexpandtab 1172 set foldmethod=marker 1173 1174 call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx") 1175 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1176 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1177 call feedkeys("0i\<tab>", "tx") 1178 call prop_remove({'type': 'test'}) 1179 call prop_add(1, 2, {'end_col': 3, 'type': 'test'}) 1180 call feedkeys("A\<left>\<tab>", "tx") 1181 call prop_remove({'type': 'test'}) 1182 try 1183 " It is correct that this does not pass 1184 call prop_add(1, 6, {'end_col': 7, 'type': 'test'}) 1185 " Has already collapsed here, start_col:6 does not result in an error 1186 call feedkeys("A\<left>\<tab>", "tx") 1187 catch /^Vim\%((\a\+)\)\=:E964/ 1188 endtry 1189 call prop_remove({'type': 'test'}) 1190 call prop_type_delete('test') 1191 1192 call RestoreOptions(save_dict) 1193 bwipe! 1194endfunc 1195 1196func Test_textprop_noexpandtab_redraw() 1197 new 1198 let save_dict = SaveOptions() 1199 1200 set tabstop=8 1201 set softtabstop=4 1202 set shiftwidth=4 1203 set noexpandtab 1204 set foldmethod=marker 1205 1206 call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx") 1207 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1208 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1209 call feedkeys("0i\<tab>", "tx") 1210 " Internally broken at the next line 1211 call feedkeys("A\<left>\<tab>", "tx") 1212 redraw 1213 " Index calculation failed internally on next line 1214 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1215 call prop_remove({'type': 'test', 'all': v:true}) 1216 call prop_type_delete('test') 1217 call prop_type_delete('test') 1218 1219 call RestoreOptions(save_dict) 1220 bwipe! 1221endfunc 1222 1223func Test_textprop_ins_str() 1224 new 1225 call setline(1, 'just some text') 1226 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1227 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1228 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1)) 1229 1230 call feedkeys("foi\<F8>\<Esc>", "tx") 1231 call assert_equal('just s<F8>ome text', getline(1)) 1232 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1)) 1233 1234 bwipe! 1235 call prop_remove({'type': 'test'}) 1236 call prop_type_delete('test') 1237endfunc 1238 1239func Test_find_prop_later_in_line() 1240 new 1241 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1242 call setline(1, 'just some text') 1243 call prop_add(1, 1, {'length': 4, 'type': 'test'}) 1244 call prop_add(1, 10, {'length': 3, 'type': 'test'}) 1245 1246 call assert_equal({'id': 0, 'lnum': 1, 'col': 10, 'end': 1, 'type': 'test', 'length': 3, 'start': 1}, 1247 \ prop_find(#{type: 'test', lnum: 1, col: 6})) 1248 1249 bwipe! 1250 call prop_type_delete('test') 1251endfunc 1252 1253func Test_find_zerowidth_prop_sol() 1254 new 1255 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1256 call setline(1, 'just some text') 1257 call prop_add(1, 1, {'length': 0, 'type': 'test'}) 1258 1259 call assert_equal({'id': 0, 'lnum': 1, 'col': 1, 'end': 1, 'type': 'test', 'length': 0, 'start': 1}, 1260 \ prop_find(#{type: 'test', lnum: 1})) 1261 1262 bwipe! 1263 call prop_type_delete('test') 1264endfunc 1265 1266" Test for passing invalid arguments to prop_xxx() functions 1267func Test_prop_func_invalid_args() 1268 call assert_fails('call prop_clear(1, 2, [])', 'E715:') 1269 call assert_fails('call prop_clear(-1, 2)', 'E16:') 1270 call assert_fails('call prop_find(test_null_dict())', 'E474:') 1271 call assert_fails('call prop_find({"bufnr" : []})', 'E730:') 1272 call assert_fails('call prop_find({})', 'E968:') 1273 call assert_fails('call prop_find({}, "x")', 'E474:') 1274 call assert_fails('call prop_find({"lnum" : -2})', 'E16:') 1275 call assert_fails('call prop_list(1, [])', 'E715:') 1276 call assert_fails('call prop_list(-1, {})', 'E16:') 1277 call assert_fails('call prop_remove([])', 'E474:') 1278 call assert_fails('call prop_remove({}, -2)', 'E16:') 1279 call assert_fails('call prop_remove({})', 'E968:') 1280 call assert_fails('call prop_type_add([], {})', 'E730:') 1281 call assert_fails("call prop_type_change('long', {'xyz' : 10})", 'E971:') 1282 call assert_fails("call prop_type_delete([])", 'E730:') 1283 call assert_fails("call prop_type_delete('xyz', [])", 'E715:') 1284 call assert_fails("call prop_type_get([])", 'E730:') 1285 call assert_fails("call prop_type_get('', [])", 'E474:') 1286 call assert_fails("call prop_type_list([])", 'E715:') 1287endfunc 1288 1289func Test_prop_split_join() 1290 new 1291 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1292 call setline(1, 'just some text') 1293 call prop_add(1, 6, {'length': 4, 'type': 'test'}) 1294 1295 " Split in middle of "some" 1296 execute "normal! 8|i\<CR>" 1297 call assert_equal([{'id': 0, 'col': 6, 'end': 0, 'type': 'test', 'length': 2, 'start': 1}], 1298 \ prop_list(1)) 1299 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 2, 'start': 0}], 1300 \ prop_list(2)) 1301 1302 " Join the two lines back together 1303 normal! 1GJ 1304 call assert_equal([{'id': 0, 'col': 6, 'end': 1, 'type': 'test', 'length': 5, 'start': 1}], prop_list(1)) 1305 1306 bwipe! 1307 call prop_type_delete('test') 1308endfunc 1309 1310func Test_prop_increment_decrement() 1311 new 1312 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1313 call setline(1, 'its 998 times') 1314 call prop_add(1, 5, {'length': 3, 'type': 'test'}) 1315 1316 exe "normal! 0f9\<C-A>" 1317 eval getline(1)->assert_equal('its 999 times') 1318 eval prop_list(1)->assert_equal([ 1319 \ #{id: 0, col: 5, end: 1, type: 'test', length: 3, start: 1}]) 1320 1321 exe "normal! 0f9\<C-A>" 1322 eval getline(1)->assert_equal('its 1000 times') 1323 eval prop_list(1)->assert_equal([ 1324 \ #{id: 0, col: 5, end: 1, type: 'test', length: 4, start: 1}]) 1325 1326 bwipe! 1327 call prop_type_delete('test') 1328endfunc 1329 1330func Test_prop_block_insert() 1331 new 1332 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1333 call setline(1, ['one ', 'two ']) 1334 call prop_add(1, 1, {'length': 3, 'type': 'test'}) 1335 call prop_add(2, 1, {'length': 3, 'type': 'test'}) 1336 1337 " insert "xx" in the first column of both lines 1338 exe "normal! gg0\<C-V>jIxx\<Esc>" 1339 eval getline(1, 2)->assert_equal(['xxone ', 'xxtwo ']) 1340 let expected = [#{id: 0, col: 3, end: 1, type: 'test', length: 3, start: 1}] 1341 eval prop_list(1)->assert_equal(expected) 1342 eval prop_list(2)->assert_equal(expected) 1343 1344 " insert "yy" inside the text props to make them longer 1345 exe "normal! gg03l\<C-V>jIyy\<Esc>" 1346 eval getline(1, 2)->assert_equal(['xxoyyne ', 'xxtyywo ']) 1347 let expected[0].length = 5 1348 eval prop_list(1)->assert_equal(expected) 1349 eval prop_list(2)->assert_equal(expected) 1350 1351 " insert "zz" after the text props, text props don't change 1352 exe "normal! gg07l\<C-V>jIzz\<Esc>" 1353 eval getline(1, 2)->assert_equal(['xxoyynezz ', 'xxtyywozz ']) 1354 eval prop_list(1)->assert_equal(expected) 1355 eval prop_list(2)->assert_equal(expected) 1356 1357 bwipe! 1358 call prop_type_delete('test') 1359endfunc 1360 1361" vim: shiftwidth=2 sts=2 expandtab 1362