1" Tests for defining text property types and adding text properties to the 2" buffer. 3 4if !has('textprop') 5 finish 6endif 7 8source screendump.vim 9 10" test length zero 11 12func Test_proptype_global() 13 call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) 14 let proptypes = prop_type_list() 15 call assert_equal(1, len(proptypes)) 16 call assert_equal('comment', proptypes[0]) 17 18 let proptype = prop_type_get('comment') 19 call assert_equal('Directory', proptype['highlight']) 20 call assert_equal(123, proptype['priority']) 21 call assert_equal(1, proptype['start_incl']) 22 call assert_equal(1, proptype['end_incl']) 23 24 call prop_type_delete('comment') 25 call assert_equal(0, len(prop_type_list())) 26 27 call prop_type_add('one', {}) 28 call assert_equal(1, len(prop_type_list())) 29 let proptype = prop_type_get('one') 30 call assert_false(has_key(proptype, 'highlight')) 31 call assert_equal(0, proptype['priority']) 32 call assert_equal(0, proptype['start_incl']) 33 call assert_equal(0, proptype['end_incl']) 34 35 call prop_type_add('two', {}) 36 call assert_equal(2, len(prop_type_list())) 37 call prop_type_delete('one') 38 call assert_equal(1, len(prop_type_list())) 39 call prop_type_delete('two') 40 call assert_equal(0, len(prop_type_list())) 41endfunc 42 43func Test_proptype_buf() 44 let bufnr = bufnr('') 45 call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) 46 let proptypes = prop_type_list({'bufnr': bufnr}) 47 call assert_equal(1, len(proptypes)) 48 call assert_equal('comment', proptypes[0]) 49 50 let proptype = prop_type_get('comment', {'bufnr': bufnr}) 51 call assert_equal('Directory', proptype['highlight']) 52 call assert_equal(123, proptype['priority']) 53 call assert_equal(1, proptype['start_incl']) 54 call assert_equal(1, proptype['end_incl']) 55 56 call prop_type_delete('comment', {'bufnr': bufnr}) 57 call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) 58 59 call prop_type_add('one', {'bufnr': bufnr}) 60 let proptype = prop_type_get('one', {'bufnr': bufnr}) 61 call assert_false(has_key(proptype, 'highlight')) 62 call assert_equal(0, proptype['priority']) 63 call assert_equal(0, proptype['start_incl']) 64 call assert_equal(0, proptype['end_incl']) 65 66 call prop_type_add('two', {'bufnr': bufnr}) 67 call assert_equal(2, len(prop_type_list({'bufnr': bufnr}))) 68 call prop_type_delete('one', {'bufnr': bufnr}) 69 call assert_equal(1, len(prop_type_list({'bufnr': bufnr}))) 70 call prop_type_delete('two', {'bufnr': bufnr}) 71 call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) 72endfunc 73 74func AddPropTypes() 75 call prop_type_add('one', {}) 76 call prop_type_add('two', {}) 77 call prop_type_add('three', {}) 78 call prop_type_add('whole', {}) 79endfunc 80 81func DeletePropTypes() 82 call prop_type_delete('one') 83 call prop_type_delete('two') 84 call prop_type_delete('three') 85 call prop_type_delete('whole') 86endfunc 87 88func SetupPropsInFirstLine() 89 call setline(1, 'one two three') 90 call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'}) 91 call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two'}) 92 call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'}) 93 call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'}) 94endfunc 95 96func Get_expected_props() 97 return [ 98 \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1}, 99 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 100 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 101 \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, 102 \ ] 103endfunc 104 105func Test_prop_add() 106 new 107 call AddPropTypes() 108 call SetupPropsInFirstLine() 109 let expected_props = Get_expected_props() 110 call assert_equal(expected_props, prop_list(1)) 111 call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:') 112 call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:') 113 114 " Insert a line above, text props must still be there. 115 call append(0, 'empty') 116 call assert_equal(expected_props, prop_list(2)) 117 " Delete a line above, text props must still be there. 118 1del 119 call assert_equal(expected_props, prop_list(1)) 120 121 " Prop without length or end column is zero length 122 call prop_clear(1) 123 call prop_add(1, 5, {'type': 'two'}) 124 let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}] 125 call assert_equal(expected, prop_list(1)) 126 127 call DeletePropTypes() 128 bwipe! 129endfunc 130 131func Test_prop_remove() 132 new 133 call AddPropTypes() 134 call SetupPropsInFirstLine() 135 let props = Get_expected_props() 136 call assert_equal(props, prop_list(1)) 137 138 " remove by id 139 call prop_remove({'id': 12}, 1) 140 unlet props[2] 141 call assert_equal(props, prop_list(1)) 142 143 " remove by type 144 call prop_remove({'type': 'one'}, 1) 145 unlet props[1] 146 call assert_equal(props, prop_list(1)) 147 148 call DeletePropTypes() 149 bwipe! 150endfunc 151 152func SetupOneLine() 153 call setline(1, 'xonex xtwoxx') 154 call AddPropTypes() 155 call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) 156 call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) 157 let expected = [ 158 \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 159 \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 160 \] 161 call assert_equal(expected, prop_list(1)) 162 return expected 163endfunc 164 165func Test_prop_add_remove_buf() 166 new 167 let bufnr = bufnr('') 168 call AddPropTypes() 169 for lnum in range(1, 4) 170 call setline(lnum, 'one two three') 171 endfor 172 wincmd w 173 for lnum in range(1, 4) 174 call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr}) 175 call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr}) 176 call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr}) 177 endfor 178 179 let props = [ 180 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, 181 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, 182 \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, 183 \] 184 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 185 186 " remove by id 187 let before_props = deepcopy(props) 188 unlet props[1] 189 190 call prop_remove({'id': 12, 'bufnr': bufnr}, 1) 191 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 192 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 193 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 194 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 195 196 call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4) 197 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 198 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 199 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 200 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 201 202 call prop_remove({'id': 12, 'bufnr': bufnr}) 203 for lnum in range(1, 4) 204 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 205 endfor 206 207 " remove by type 208 let before_props = deepcopy(props) 209 unlet props[0] 210 211 call prop_remove({'type': 'one', 'bufnr': bufnr}, 1) 212 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 213 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 214 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 215 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 216 217 call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4) 218 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 219 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 220 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 221 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 222 223 call prop_remove({'type': 'one', 'bufnr': bufnr}) 224 for lnum in range(1, 4) 225 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 226 endfor 227 228 call DeletePropTypes() 229 wincmd w 230 bwipe! 231endfunc 232 233func Test_prop_backspace() 234 new 235 set bs=2 236 let expected = SetupOneLine() " 'xonex xtwoxx' 237 238 exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>" 239 call assert_equal('one xtwoxx', getline(1)) 240 let expected[0].col = 1 241 let expected[1].col = 6 242 call assert_equal(expected, prop_list(1)) 243 244 call DeletePropTypes() 245 bwipe! 246 set bs& 247endfunc 248 249func Test_prop_replace() 250 new 251 set bs=2 252 let expected = SetupOneLine() " 'xonex xtwoxx' 253 254 exe "normal 0Ryyy\<Esc>" 255 call assert_equal('yyyex xtwoxx', getline(1)) 256 call assert_equal(expected, prop_list(1)) 257 258 exe "normal ftRyy\<BS>" 259 call assert_equal('yyyex xywoxx', getline(1)) 260 call assert_equal(expected, prop_list(1)) 261 262 exe "normal 0fwRyy\<BS>" 263 call assert_equal('yyyex xyyoxx', getline(1)) 264 call assert_equal(expected, prop_list(1)) 265 266 exe "normal 0foRyy\<BS>\<BS>" 267 call assert_equal('yyyex xyyoxx', getline(1)) 268 call assert_equal(expected, prop_list(1)) 269 270 call DeletePropTypes() 271 bwipe! 272 set bs& 273endfunc 274 275func Test_prop_clear() 276 new 277 call AddPropTypes() 278 call SetupPropsInFirstLine() 279 call assert_equal(Get_expected_props(), prop_list(1)) 280 281 call prop_clear(1) 282 call assert_equal([], prop_list(1)) 283 284 call DeletePropTypes() 285 bwipe! 286endfunc 287 288func Test_prop_clear_buf() 289 new 290 call AddPropTypes() 291 call SetupPropsInFirstLine() 292 let bufnr = bufnr('') 293 wincmd w 294 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 295 296 call prop_clear(1, 1, {'bufnr': bufnr}) 297 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 298 299 wincmd w 300 call DeletePropTypes() 301 bwipe! 302endfunc 303 304func Test_prop_setline() 305 new 306 call AddPropTypes() 307 call SetupPropsInFirstLine() 308 call assert_equal(Get_expected_props(), prop_list(1)) 309 310 call setline(1, 'foobar') 311 call assert_equal([], prop_list(1)) 312 313 call DeletePropTypes() 314 bwipe! 315endfunc 316 317func Test_prop_setbufline() 318 new 319 call AddPropTypes() 320 call SetupPropsInFirstLine() 321 let bufnr = bufnr('') 322 wincmd w 323 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 324 325 call setbufline(bufnr, 1, 'foobar') 326 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 327 328 wincmd w 329 call DeletePropTypes() 330 bwipe! 331endfunc 332 333func Test_prop_substitute() 334 new 335 " Set first line to 'one two three' 336 call AddPropTypes() 337 call SetupPropsInFirstLine() 338 let expected_props = Get_expected_props() 339 call assert_equal(expected_props, prop_list(1)) 340 341 " Change "n" in "one" to XX: 'oXXe two three' 342 s/n/XX/ 343 let expected_props[0].length += 1 344 let expected_props[1].length += 1 345 let expected_props[2].col += 1 346 let expected_props[3].col += 1 347 call assert_equal(expected_props, prop_list(1)) 348 349 " Delete "t" in "two" and "three" to XX: 'oXXe wo hree' 350 s/t//g 351 let expected_props[0].length -= 2 352 let expected_props[2].length -= 1 353 let expected_props[3].length -= 1 354 let expected_props[3].col -= 1 355 call assert_equal(expected_props, prop_list(1)) 356 357 " Split the line by changing w to line break: 'oXXe ', 'o hree' 358 " The long prop is split and spans both lines. 359 " The props on "two" and "three" move to the next line. 360 s/w/\r/ 361 let new_props = [ 362 \ copy(expected_props[0]), 363 \ copy(expected_props[2]), 364 \ copy(expected_props[3]), 365 \ ] 366 let expected_props[0].length = 5 367 unlet expected_props[3] 368 unlet expected_props[2] 369 call assert_equal(expected_props, prop_list(1)) 370 371 let new_props[0].length = 6 372 let new_props[1].col = 1 373 let new_props[1].length = 1 374 let new_props[2].col = 3 375 call assert_equal(new_props, prop_list(2)) 376 377 call DeletePropTypes() 378 bwipe! 379endfunc 380 381func Test_prop_change_indent() 382 call prop_type_add('comment', {'highlight': 'Directory'}) 383 new 384 call setline(1, [' xxx', 'yyyyy']) 385 call prop_add(2, 2, {'length': 2, 'type': 'comment'}) 386 let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0} 387 call assert_equal([expect], prop_list(2)) 388 389 set shiftwidth=3 390 normal 2G>> 391 call assert_equal(' yyyyy', getline(2)) 392 let expect.col += 3 393 call assert_equal([expect], prop_list(2)) 394 395 normal 2G== 396 call assert_equal(' yyyyy', getline(2)) 397 let expect.col = 6 398 call assert_equal([expect], prop_list(2)) 399 400 call prop_clear(2) 401 call prop_add(2, 2, {'length': 5, 'type': 'comment'}) 402 let expect.col = 2 403 let expect.length = 5 404 call assert_equal([expect], prop_list(2)) 405 406 normal 2G<< 407 call assert_equal(' yyyyy', getline(2)) 408 let expect.length = 2 409 call assert_equal([expect], prop_list(2)) 410 411 set shiftwidth& 412 call prop_type_delete('comment') 413endfunc 414 415" Setup a three line prop in lines 2 - 4. 416" Add short props in line 1 and 5. 417func Setup_three_line_prop() 418 new 419 call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five']) 420 call prop_add(1, 2, {'length': 1, 'type': 'comment'}) 421 call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'}) 422 call prop_add(5, 2, {'length': 1, 'type': 'comment'}) 423endfunc 424 425func Test_prop_multiline() 426 call prop_type_add('comment', {'highlight': 'Directory'}) 427 new 428 call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz']) 429 430 " start halfway line 1, end halfway line 3 431 call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'}) 432 let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 433 call assert_equal([expect1], prop_list(1)) 434 let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 435 call assert_equal([expect2], prop_list(2)) 436 let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0} 437 call assert_equal([expect3], prop_list(3)) 438 call prop_clear(1, 3) 439 440 " include all three lines 441 call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'}) 442 let expect1.col = 1 443 let expect1.length = 8 444 call assert_equal([expect1], prop_list(1)) 445 call assert_equal([expect2], prop_list(2)) 446 let expect3.length = 9 447 call assert_equal([expect3], prop_list(3)) 448 call prop_clear(1, 3) 449 450 bwipe! 451 452 " Test deleting the first line of a multi-line prop. 453 call Setup_three_line_prop() 454 let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0} 455 call assert_equal([expect_short], prop_list(1)) 456 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 457 call assert_equal([expect2], prop_list(2)) 458 2del 459 call assert_equal([expect_short], prop_list(1)) 460 let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 461 call assert_equal([expect2], prop_list(2)) 462 bwipe! 463 464 " Test deleting the last line of a multi-line prop. 465 call Setup_three_line_prop() 466 let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 467 call assert_equal([expect3], prop_list(3)) 468 let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0} 469 call assert_equal([expect4], prop_list(4)) 470 4del 471 let expect3.end = 1 472 call assert_equal([expect3], prop_list(3)) 473 call assert_equal([expect_short], prop_list(4)) 474 bwipe! 475 476 " Test appending a line below the multi-line text prop start. 477 call Setup_three_line_prop() 478 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0} 479 call assert_equal([expect2], prop_list(2)) 480 call append(2, "new line") 481 call assert_equal([expect2], prop_list(2)) 482 let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0} 483 call assert_equal([expect3], prop_list(3)) 484 bwipe! 485 486 call prop_type_delete('comment') 487endfunc 488 489func Test_prop_byteoff() 490 call prop_type_add('comment', {'highlight': 'Directory'}) 491 new 492 call setline(1, ['line1', 'second line', '']) 493 set ff=unix 494 call assert_equal(19, line2byte(3)) 495 call prop_add(1, 1, {'end_col': 3, 'type': 'comment'}) 496 call assert_equal(19, line2byte(3)) 497 498 bwipe! 499 call prop_type_delete('comment') 500endfunc 501 502func Test_prop_undo() 503 new 504 call prop_type_add('comment', {'highlight': 'Directory'}) 505 call setline(1, ['oneone', 'twotwo', 'three']) 506 " Set 'undolevels' to break changes into undo-able pieces. 507 set ul& 508 509 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'}) 510 let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ] 511 call assert_equal(expected, prop_list(1)) 512 513 " Insert a character, then undo. 514 exe "normal 0lllix\<Esc>" 515 set ul& 516 let expected[0].length = 3 517 call assert_equal(expected, prop_list(1)) 518 undo 519 let expected[0].length = 2 520 call assert_equal(expected, prop_list(1)) 521 522 " Delete a character, then undo 523 exe "normal 0lllx" 524 set ul& 525 let expected[0].length = 1 526 call assert_equal(expected, prop_list(1)) 527 undo 528 let expected[0].length = 2 529 call assert_equal(expected, prop_list(1)) 530 531 " Delete the line, then undo 532 1d 533 set ul& 534 call assert_equal([], prop_list(1)) 535 undo 536 call assert_equal(expected, prop_list(1)) 537 538 " Insert a character, delete two characters, then undo with "U" 539 exe "normal 0lllix\<Esc>" 540 set ul& 541 let expected[0].length = 3 542 call assert_equal(expected, prop_list(1)) 543 exe "normal 0lllxx" 544 set ul& 545 let expected[0].length = 1 546 call assert_equal(expected, prop_list(1)) 547 normal U 548 let expected[0].length = 2 549 call assert_equal(expected, prop_list(1)) 550 551 bwipe! 552 call prop_type_delete('comment') 553endfunc 554 555" screenshot test with textprop highlighting 556funct Test_textprop_screenshots() 557 " The Vim running in the terminal needs to use utf-8. 558 if !CanRunVimInTerminal() || g:orig_encoding != 'utf-8' 559 return 560 endif 561 call writefile([ 562 \ "call setline(1, ['One two', 'Numbér 123 änd thœn 4¾7.', '--aa--bb--cc--dd--'])", 563 \ "hi NumberProp ctermfg=blue", 564 \ "hi LongProp ctermbg=yellow", 565 \ "call prop_type_add('number', {'highlight': 'NumberProp'})", 566 \ "call prop_type_add('long', {'highlight': 'LongProp'})", 567 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})", 568 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})", 569 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})", 570 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})", 571 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})", 572 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})", 573 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})", 574 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})", 575 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})", 576 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})", 577 \ "set number", 578 \ "hi clear SpellBad", 579 \ "set spell", 580 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>", 581 \ "normal 3G0lli\<BS>\<Esc>", 582 \], 'XtestProp') 583 let buf = RunVimInTerminal('-S XtestProp', {'rows': 6}) 584 call VerifyScreenDump(buf, 'Test_textprop_01', {}) 585 586 " clean up 587 call StopVimInTerminal(buf) 588 call delete('XtestProp') 589endfunc 590