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 8source vim9.vim 9 10func Test_proptype_global() 11 call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) 12 let proptypes = prop_type_list() 13 call assert_equal(1, len(proptypes)) 14 call assert_equal('comment', proptypes[0]) 15 16 let proptype = prop_type_get('comment') 17 call assert_equal('Directory', proptype['highlight']) 18 call assert_equal(123, proptype['priority']) 19 call assert_equal(1, proptype['start_incl']) 20 call assert_equal(1, proptype['end_incl']) 21 22 call prop_type_delete('comment') 23 call assert_equal(0, len(prop_type_list())) 24 25 call prop_type_add('one', {}) 26 call assert_equal(1, len(prop_type_list())) 27 let proptype = 'one'->prop_type_get() 28 call assert_false(has_key(proptype, 'highlight')) 29 call assert_equal(0, proptype['priority']) 30 call assert_equal(0, proptype['start_incl']) 31 call assert_equal(0, proptype['end_incl']) 32 33 call prop_type_add('two', {}) 34 call assert_equal(2, len(prop_type_list())) 35 call prop_type_delete('one') 36 call assert_equal(1, len(prop_type_list())) 37 call prop_type_delete('two') 38 call assert_equal(0, len(prop_type_list())) 39endfunc 40 41func Test_proptype_buf() 42 let bufnr = bufnr('') 43 call prop_type_add('comment', #{bufnr: bufnr, highlight: 'Directory', priority: 123, start_incl: 1, end_incl: 1}) 44 let proptypes = prop_type_list({'bufnr': bufnr}) 45 call assert_equal(1, len(proptypes)) 46 call assert_equal('comment', proptypes[0]) 47 48 let proptype = prop_type_get('comment', {'bufnr': bufnr}) 49 call assert_equal('Directory', proptype['highlight']) 50 call assert_equal(123, proptype['priority']) 51 call assert_equal(1, proptype['start_incl']) 52 call assert_equal(1, proptype['end_incl']) 53 54 call prop_type_delete('comment', {'bufnr': bufnr}) 55 call assert_equal(0, len({'bufnr': bufnr}->prop_type_list())) 56 57 call prop_type_add('one', {'bufnr': bufnr}) 58 let proptype = prop_type_get('one', {'bufnr': bufnr}) 59 call assert_false(has_key(proptype, 'highlight')) 60 call assert_equal(0, proptype['priority']) 61 call assert_equal(0, proptype['start_incl']) 62 call assert_equal(0, proptype['end_incl']) 63 64 call prop_type_add('two', {'bufnr': bufnr}) 65 call assert_equal(2, len(prop_type_list({'bufnr': bufnr}))) 66 call prop_type_delete('one', {'bufnr': bufnr}) 67 call assert_equal(1, len(prop_type_list({'bufnr': bufnr}))) 68 call prop_type_delete('two', {'bufnr': bufnr}) 69 call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) 70 71 call assert_fails("call prop_type_add('one', {'bufnr': 98764})", "E158:") 72endfunc 73 74def Test_proptype_buf_list() 75 new 76 var bufnr = bufnr('') 77 try 78 prop_type_add('global', {}) 79 prop_type_add('local', {bufnr: bufnr}) 80 81 prop_add(1, 1, {type: 'global'}) 82 prop_add(1, 1, {type: 'local'}) 83 84 assert_equal([ 85 {type: 'local', type_bufnr: bufnr, id: 0, col: 1, end: 1, length: 0, start: 1}, 86 {type: 'global', type_bufnr: 0, id: 0, col: 1, end: 1, length: 0, start: 1}, 87 ], prop_list(1)) 88 assert_equal( 89 {lnum: 1, id: 0, col: 1, type_bufnr: bufnr, end: 1, type: 'local', length: 0, start: 1}, 90 prop_find({lnum: 1, type: 'local'})) 91 assert_equal( 92 {lnum: 1, id: 0, col: 1, type_bufnr: 0, end: 1, type: 'global', length: 0, start: 1}, 93 prop_find({lnum: 1, type: 'global'})) 94 95 prop_remove({type: 'global'}, 1) 96 prop_remove({type: 'local'}, 1) 97 finally 98 prop_type_delete('global') 99 prop_type_delete('local', {bufnr: bufnr}) 100 bwipe! 101 endtry 102enddef 103 104func AddPropTypes() 105 call prop_type_add('one', {}) 106 call prop_type_add('two', {}) 107 call prop_type_add('three', {}) 108 call prop_type_add('whole', {}) 109endfunc 110 111func DeletePropTypes() 112 call prop_type_delete('one') 113 call prop_type_delete('two') 114 call prop_type_delete('three') 115 call prop_type_delete('whole') 116endfunc 117 118func SetupPropsInFirstLine() 119 call setline(1, 'one two three') 120 call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'}) 121 eval 1->prop_add(5, {'length': 3, 'id': 12, 'type': 'two'}) 122 call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'}) 123 call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'}) 124endfunc 125 126func Get_expected_props() 127 return [ 128 \ #{type_bufnr: 0, col: 1, length: 13, id: 14, type: 'whole', start: 1, end: 1}, 129 \ #{type_bufnr: 0, col: 1, length: 3, id: 11, type: 'one', start: 1, end: 1}, 130 \ #{type_bufnr: 0, col: 5, length: 3, id: 12, type: 'two', start: 1, end: 1}, 131 \ #{type_bufnr: 0, col: 9, length: 5, id: 13, type: 'three', start: 1, end: 1}, 132 \ ] 133endfunc 134 135func Test_prop_find() 136 new 137 call setline(1, ['one one one', 'twotwo', 'three', 'fourfour', 'five', 'sixsix']) 138 139 " Add two text props on lines 1 and 5, and one spanning lines 2 to 4. 140 call prop_type_add('prop_name', {'highlight': 'Directory'}) 141 call prop_add(1, 5, {'type': 'prop_name', 'id': 10, 'length': 3}) 142 call prop_add(2, 4, {'type': 'prop_name', 'id': 11, 'end_lnum': 4, 'end_col': 9}) 143 call prop_add(5, 4, {'type': 'prop_name', 'id': 12, 'length': 1}) 144 145 let expected = [ 146 \ #{type_bufnr: 0, lnum: 1, col: 5, length: 3, id: 10, type: 'prop_name', start: 1, end: 1}, 147 \ #{type_bufnr: 0, lnum: 2, col: 4, id: 11, type: 'prop_name', start: 1, end: 0}, 148 \ #{type_bufnr: 0, lnum: 5, col: 4, length: 1, id: 12, type: 'prop_name', start: 1, end: 1} 149 \ ] 150 151 " Starting at line 5 col 1 this should find the prop at line 5 col 4. 152 call cursor(5,1) 153 let result = prop_find({'type': 'prop_name'}, 'f') 154 call assert_equal(expected[2], result) 155 156 " With skipstart left at false (default), this should find the prop at line 157 " 5 col 4. 158 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4}, 'b') 159 call assert_equal(expected[2], result) 160 161 " With skipstart set to true, this should skip the prop at line 5 col 4. 162 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4, 'skipstart': 1}, 'b') 163 unlet result.length 164 call assert_equal(expected[1], result) 165 166 " Search backwards from line 1 col 10 to find the prop on the same line. 167 let result = prop_find({'type': 'prop_name', 'lnum': 1, 'col': 10}, 'b') 168 call assert_equal(expected[0], result) 169 170 " with skipstart set to false, if the start position is anywhere between the 171 " start and end lines of a text prop (searching forward or backward), the 172 " result should be the prop on the first line (the line with 'start' set to 1). 173 call cursor(3,1) 174 let result = prop_find({'type': 'prop_name'}, 'f') 175 unlet result.length 176 call assert_equal(expected[1], result) 177 let result = prop_find({'type': 'prop_name'}, 'b') 178 unlet result.length 179 call assert_equal(expected[1], result) 180 181 " with skipstart set to true, if the start position is anywhere between the 182 " start and end lines of a text prop (searching forward or backward), all lines 183 " of the prop will be skipped. 184 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'b') 185 call assert_equal(expected[0], result) 186 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'f') 187 call assert_equal(expected[2], result) 188 189 " Use skipstart to search through all props with type name 'prop_name'. 190 " First forward... 191 let lnum = 1 192 let col = 1 193 let i = 0 194 for exp in expected 195 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'f') 196 if !has_key(exp, "length") 197 unlet result.length 198 endif 199 call assert_equal(exp, result) 200 let lnum = result.lnum 201 let col = result.col 202 let i = i + 1 203 endfor 204 205 " ...then backwards. 206 let lnum = 6 207 let col = 4 208 let i = 2 209 while i >= 0 210 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'b') 211 if !has_key(expected[i], "length") 212 unlet result.length 213 endif 214 call assert_equal(expected[i], result) 215 let lnum = result.lnum 216 let col = result.col 217 let i = i - 1 218 endwhile 219 220 " Starting from line 6 col 1 search backwards for prop with id 10. 221 call cursor(6,1) 222 let result = prop_find({'id': 10, 'skipstart': 1}, 'b') 223 call assert_equal(expected[0], result) 224 225 " Starting from line 1 col 1 search forwards for prop with id 12. 226 call cursor(1,1) 227 let result = prop_find({'id': 12}, 'f') 228 call assert_equal(expected[2], result) 229 230 " Search for a prop with an unknown id. 231 let result = prop_find({'id': 999}, 'f') 232 call assert_equal({}, result) 233 234 " Search backwards from the proceeding position of the prop with id 11 235 " (at line num 2 col 4). This should return an empty dict. 236 let result = prop_find({'id': 11, 'lnum': 2, 'col': 3}, 'b') 237 call assert_equal({}, result) 238 239 " When lnum is given and col is omitted, use column 1. 240 let result = prop_find({'type': 'prop_name', 'lnum': 1}, 'f') 241 call assert_equal(expected[0], result) 242 243 " Negative ID is possible, just like prop is not found. 244 call assert_equal({}, prop_find({'id': -1})) 245 call assert_equal({}, prop_find({'id': -2})) 246 247 call prop_clear(1, 6) 248 249 " Default ID is zero 250 call prop_add(5, 4, {'type': 'prop_name', 'length': 1}) 251 call assert_equal(#{lnum: 5, id: 0, col: 4, type_bufnr: 0, end: 1, type: 'prop_name', length: 1, start: 1}, prop_find({'id': 0})) 252 253 call prop_type_delete('prop_name') 254 call prop_clear(1, 6) 255 bwipe! 256endfunc 257 258def Test_prop_find2() 259 # Multiple props per line, start on the first, should find the second. 260 new 261 ['the quikc bronw fox jumsp over the layz dog']->repeat(2)->setline(1) 262 prop_type_add('misspell', {highlight: 'ErrorMsg'}) 263 for lnum in [1, 2] 264 for col in [8, 14, 24, 38] 265 prop_add(lnum, col, {type: 'misspell', length: 2}) 266 endfor 267 endfor 268 cursor(1, 8) 269 var expected = {type_bufnr: 0, lnum: 1, id: 0, col: 14, end: 1, type: 'misspell', length: 2, start: 1} 270 var result = prop_find({type: 'misspell', skipstart: true}, 'f') 271 assert_equal(expected, result) 272 273 prop_type_delete('misspell') 274 bwipe! 275enddef 276 277func Test_prop_find_smaller_len_than_match_col() 278 new 279 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 280 call setline(1, ['xxxx', 'x']) 281 call prop_add(1, 4, {'type': 'test'}) 282 call assert_equal( 283 \ #{type_bufnr: 0, id: 0, lnum: 1, col: 4, type: 'test', length: 0, start: 1, end: 1}, 284 \ prop_find({'type': 'test', 'lnum': 2, 'col': 1}, 'b')) 285 bwipe! 286 call prop_type_delete('test') 287endfunc 288 289func Test_prop_find_with_both_option_enabled() 290 " Initialize 291 new 292 call AddPropTypes() 293 call SetupPropsInFirstLine() 294 let props = Get_expected_props()->map({_, v -> extend(v, {'lnum': 1})}) 295 " Test 296 call assert_fails("call prop_find({'both': 1})", 'E968:') 297 call assert_fails("call prop_find({'id': 11, 'both': 1})", 'E860:') 298 call assert_fails("call prop_find({'type': 'three', 'both': 1})", 'E860:') 299 call assert_equal({}, prop_find({'id': 11, 'type': 'three', 'both': 1})) 300 call assert_equal({}, prop_find({'id': 130000, 'type': 'one', 'both': 1})) 301 call assert_equal(props[2], prop_find({'id': 12, 'type': 'two', 'both': 1})) 302 call assert_equal(props[0], prop_find({'id': 14, 'type': 'whole', 'both': 1})) 303 " Clean up 304 call DeletePropTypes() 305 bwipe! 306endfunc 307 308func Test_prop_add() 309 new 310 call AddPropTypes() 311 call SetupPropsInFirstLine() 312 let expected_props = Get_expected_props() 313 call assert_equal(expected_props, prop_list(1)) 314 call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:') 315 call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:') 316 317 " Insert a line above, text props must still be there. 318 call append(0, 'empty') 319 call assert_equal(expected_props, prop_list(2)) 320 " Delete a line above, text props must still be there. 321 1del 322 call assert_equal(expected_props, prop_list(1)) 323 324 " Prop without length or end column is zero length 325 call prop_clear(1) 326 call prop_type_add('included', {'start_incl': 1, 'end_incl': 1}) 327 call prop_add(1, 5, #{type: 'included'}) 328 let expected = [#{type_bufnr: 0, col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}] 329 call assert_equal(expected, prop_list(1)) 330 331 " Inserting text makes the prop bigger. 332 exe "normal 5|ixx\<Esc>" 333 let expected = [#{type_bufnr: 0, col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}] 334 call assert_equal(expected, prop_list(1)) 335 336 call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:') 337 338 call DeletePropTypes() 339 call prop_type_delete('included') 340 bwipe! 341endfunc 342 343" Test for the prop_add_list() function 344func Test_prop_add_list() 345 new 346 call AddPropTypes() 347 call setline(1, ['one one one', 'two two two', 'six six six', 'ten ten ten']) 348 call prop_add_list(#{type: 'one', id: 2}, 349 \ [[1, 1, 1, 3], [2, 5, 2, 7], [3, 6, 4, 6]]) 350 call assert_equal([#{id: 2, col: 1, type_bufnr: 0, end: 1, type: 'one', 351 \ length: 2, start: 1}], prop_list(1)) 352 call assert_equal([#{id: 2, col: 5, type_bufnr: 0, end: 1, type: 'one', 353 \ length: 2, start: 1}], prop_list(2)) 354 call assert_equal([#{id: 2, col: 6, type_bufnr: 0, end: 0, type: 'one', 355 \ length: 7, start: 1}], prop_list(3)) 356 call assert_equal([#{id: 2, col: 1, type_bufnr: 0, end: 1, type: 'one', 357 \ length: 5, start: 0}], prop_list(4)) 358 call assert_fails('call prop_add_list([1, 2], [[1, 1, 3]])', 'E1206:') 359 call assert_fails('call prop_add_list({}, {})', 'E1211:') 360 call assert_fails('call prop_add_list({}, [[1, 1, 3]])', 'E965:') 361 call assert_fails('call prop_add_list(#{type: "abc"}, [[1, 1, 1, 3]])', 'E971:') 362 call assert_fails('call prop_add_list(#{type: "one"}, [[]])', 'E474:') 363 call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 1, 1], {}])', 'E714:') 364 call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, "a"]])', 'E474:') 365 call assert_fails('call prop_add_list(#{type: "one"}, [[2, 2]])', 'E474:') 366 call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 2], [2, 2]])', 'E474:') 367 call assert_fails('call prop_add_list(#{type: "one"}, [[1, 1, 1, 2], [4, 1, 5, 2]])', 'E966:') 368 call assert_fails('call prop_add_list(#{type: "one"}, [[3, 1, 1, 2]])', 'E966:') 369 call assert_fails('call prop_add_list(#{type: "one"}, [[2, 2, 2, 2], [3, 20, 3, 22]])', 'E964:') 370 call assert_fails('eval #{type: "one"}->prop_add_list([[2, 2, 2, 2], [3, 20, 3, 22]])', 'E964:') 371 call assert_fails('call prop_add_list(test_null_dict(), [[2, 2, 2]])', 'E965:') 372 call assert_fails('call prop_add_list(#{type: "one"}, test_null_list())', 'E714:') 373 call assert_fails('call prop_add_list(#{type: "one"}, [test_null_list()])', 'E714:') 374 call DeletePropTypes() 375 bw! 376endfunc 377 378func Test_prop_remove() 379 new 380 call AddPropTypes() 381 call SetupPropsInFirstLine() 382 let props = Get_expected_props() 383 call assert_equal(props, prop_list(1)) 384 385 " remove by id 386 call assert_equal(1, {'id': 12}->prop_remove(1)) 387 unlet props[2] 388 call assert_equal(props, prop_list(1)) 389 390 " remove by type 391 call assert_equal(1, prop_remove({'type': 'one'}, 1)) 392 unlet props[1] 393 call assert_equal(props, prop_list(1)) 394 395 " remove from unknown buffer 396 call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:') 397 398 call DeletePropTypes() 399 bwipe! 400 401 new 402 call AddPropTypes() 403 call SetupPropsInFirstLine() 404 call prop_add(1, 6, {'length': 2, 'id': 11, 'type': 'three'}) 405 let props = Get_expected_props() 406 call insert(props, #{type_bufnr: 0, col: 6, length: 2, id: 11, type: 'three', start: 1, end: 1}, 3) 407 call assert_equal(props, prop_list(1)) 408 call assert_equal(1, prop_remove({'type': 'three', 'id': 11, 'both': 1, 'all': 1}, 1)) 409 unlet props[3] 410 call assert_equal(props, prop_list(1)) 411 412 call assert_fails("call prop_remove({'id': 11, 'both': 1})", 'E860:') 413 call assert_fails("call prop_remove({'type': 'three', 'both': 1})", 'E860:') 414 415 call DeletePropTypes() 416 bwipe! 417endfunc 418 419def Test_prop_add_vim9() 420 prop_type_add('comment', { 421 highlight: 'Directory', 422 priority: 123, 423 start_incl: true, 424 end_incl: true, 425 combine: false, 426 }) 427 prop_type_delete('comment') 428enddef 429 430def Test_prop_remove_vim9() 431 new 432 AddPropTypes() 433 SetupPropsInFirstLine() 434 assert_equal(1, prop_remove({type: 'three', id: 13, both: true, all: true})) 435 DeletePropTypes() 436 bwipe! 437enddef 438 439func SetupOneLine() 440 call setline(1, 'xonex xtwoxx') 441 normal gg0 442 call AddPropTypes() 443 call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'}) 444 call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'}) 445 let expected = [ 446 \ #{type_bufnr: 0, col: 2, length: 3, id: 11, type: 'one', start: 1, end: 1}, 447 \ #{type_bufnr: 0, col: 8, length: 3, id: 12, type: 'two', start: 1, end: 1}, 448 \] 449 call assert_equal(expected, prop_list(1)) 450 return expected 451endfunc 452 453func Test_prop_add_remove_buf() 454 new 455 let bufnr = bufnr('') 456 call AddPropTypes() 457 for lnum in range(1, 4) 458 call setline(lnum, 'one two three') 459 endfor 460 wincmd w 461 for lnum in range(1, 4) 462 call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr}) 463 call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr}) 464 call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr}) 465 endfor 466 467 let props = [ 468 \ #{type_bufnr: 0, col: 1, length: 3, id: 11, type: 'one', start: 1, end: 1}, 469 \ #{type_bufnr: 0, col: 5, length: 3, id: 12, type: 'two', start: 1, end: 1}, 470 \ #{type_bufnr: 0, col: 11, length: 3, id: 13, type: 'three', start: 1, end: 1}, 471 \] 472 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 473 474 " remove by id 475 let before_props = deepcopy(props) 476 unlet props[1] 477 478 call prop_remove({'id': 12, 'bufnr': bufnr}, 1) 479 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 480 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 481 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 482 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 483 484 call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4) 485 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 486 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 487 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 488 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 489 490 call prop_remove({'id': 12, 'bufnr': bufnr}) 491 for lnum in range(1, 4) 492 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 493 endfor 494 495 " remove by type 496 let before_props = deepcopy(props) 497 unlet props[0] 498 499 call prop_remove({'type': 'one', 'bufnr': bufnr}, 1) 500 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 501 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 502 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr})) 503 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr})) 504 505 call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4) 506 call assert_equal(props, prop_list(1, {'bufnr': bufnr})) 507 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr})) 508 call assert_equal(props, prop_list(3, {'bufnr': bufnr})) 509 call assert_equal(props, prop_list(4, {'bufnr': bufnr})) 510 511 call prop_remove({'type': 'one', 'bufnr': bufnr}) 512 for lnum in range(1, 4) 513 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr})) 514 endfor 515 516 call DeletePropTypes() 517 wincmd w 518 bwipe! 519endfunc 520 521func Test_prop_backspace() 522 new 523 set bs=2 524 let expected = SetupOneLine() " 'xonex xtwoxx' 525 526 exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>" 527 call assert_equal('one xtwoxx', getline(1)) 528 let expected[0].col = 1 529 let expected[1].col = 6 530 call assert_equal(expected, prop_list(1)) 531 532 call DeletePropTypes() 533 bwipe! 534 set bs& 535endfunc 536 537func Test_prop_replace() 538 new 539 set bs=2 540 let expected = SetupOneLine() " 'xonex xtwoxx' 541 542 exe "normal 0Ryyy\<Esc>" 543 call assert_equal('yyyex xtwoxx', getline(1)) 544 call assert_equal(expected, prop_list(1)) 545 546 exe "normal ftRyy\<BS>" 547 call assert_equal('yyyex xywoxx', getline(1)) 548 call assert_equal(expected, prop_list(1)) 549 550 exe "normal 0fwRyy\<BS>" 551 call assert_equal('yyyex xyyoxx', getline(1)) 552 call assert_equal(expected, prop_list(1)) 553 554 exe "normal 0foRyy\<BS>\<BS>" 555 call assert_equal('yyyex xyyoxx', getline(1)) 556 call assert_equal(expected, prop_list(1)) 557 558 call DeletePropTypes() 559 bwipe! 560 set bs& 561endfunc 562 563func Test_prop_open_line() 564 new 565 566 " open new line, props stay in top line 567 let expected = SetupOneLine() " 'xonex xtwoxx' 568 exe "normal o\<Esc>" 569 call assert_equal('xonex xtwoxx', getline(1)) 570 call assert_equal('', getline(2)) 571 call assert_equal(expected, prop_list(1)) 572 call DeletePropTypes() 573 574 " move all props to next line 575 let expected = SetupOneLine() " 'xonex xtwoxx' 576 exe "normal 0i\<CR>\<Esc>" 577 call assert_equal('', getline(1)) 578 call assert_equal('xonex xtwoxx', getline(2)) 579 call assert_equal(expected, prop_list(2)) 580 call DeletePropTypes() 581 582 " split just before prop, move all props to next line 583 let expected = SetupOneLine() " 'xonex xtwoxx' 584 exe "normal 0li\<CR>\<Esc>" 585 call assert_equal('x', getline(1)) 586 call assert_equal('onex xtwoxx', getline(2)) 587 let expected[0].col -= 1 588 let expected[1].col -= 1 589 call assert_equal(expected, prop_list(2)) 590 call DeletePropTypes() 591 592 " split inside prop, split first prop 593 let expected = SetupOneLine() " 'xonex xtwoxx' 594 exe "normal 0lli\<CR>\<Esc>" 595 call assert_equal('xo', getline(1)) 596 call assert_equal('nex xtwoxx', getline(2)) 597 let exp_first = [deepcopy(expected[0])] 598 let exp_first[0].length = 1 599 let exp_first[0].end = 0 600 call assert_equal(exp_first, prop_list(1)) 601 let expected[0].col = 1 602 let expected[0].length = 2 603 let expected[0].start = 0 604 let expected[1].col -= 2 605 call assert_equal(expected, prop_list(2)) 606 call DeletePropTypes() 607 608 " split just after first prop, second prop move to next line 609 let expected = SetupOneLine() " 'xonex xtwoxx' 610 exe "normal 0fea\<CR>\<Esc>" 611 call assert_equal('xone', getline(1)) 612 call assert_equal('x xtwoxx', getline(2)) 613 let exp_first = expected[0:0] 614 call assert_equal(exp_first, prop_list(1)) 615 let expected = expected[1:1] 616 let expected[0].col -= 4 617 call assert_equal(expected, prop_list(2)) 618 call DeletePropTypes() 619 620 bwipe! 621 set bs& 622endfunc 623 624func Test_prop_clear() 625 new 626 call AddPropTypes() 627 call SetupPropsInFirstLine() 628 call assert_equal(Get_expected_props(), prop_list(1)) 629 630 eval 1->prop_clear() 631 call assert_equal([], 1->prop_list()) 632 633 call DeletePropTypes() 634 bwipe! 635endfunc 636 637func Test_prop_clear_buf() 638 new 639 call AddPropTypes() 640 call SetupPropsInFirstLine() 641 let bufnr = bufnr('') 642 wincmd w 643 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 644 645 call prop_clear(1, 1, {'bufnr': bufnr}) 646 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 647 648 wincmd w 649 call DeletePropTypes() 650 bwipe! 651endfunc 652 653func Test_prop_setline() 654 new 655 call AddPropTypes() 656 call SetupPropsInFirstLine() 657 call assert_equal(Get_expected_props(), prop_list(1)) 658 659 call setline(1, 'foobar') 660 call assert_equal([], prop_list(1)) 661 662 call DeletePropTypes() 663 bwipe! 664endfunc 665 666func Test_prop_setbufline() 667 new 668 call AddPropTypes() 669 call SetupPropsInFirstLine() 670 let bufnr = bufnr('') 671 wincmd w 672 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr})) 673 674 call setbufline(bufnr, 1, 'foobar') 675 call assert_equal([], prop_list(1, {'bufnr': bufnr})) 676 677 wincmd w 678 call DeletePropTypes() 679 bwipe! 680endfunc 681 682func Test_prop_substitute() 683 new 684 " Set first line to 'one two three' 685 call AddPropTypes() 686 call SetupPropsInFirstLine() 687 let expected_props = Get_expected_props() 688 call assert_equal(expected_props, prop_list(1)) 689 690 " Change "n" in "one" to XX: 'oXXe two three' 691 s/n/XX/ 692 let expected_props[0].length += 1 693 let expected_props[1].length += 1 694 let expected_props[2].col += 1 695 let expected_props[3].col += 1 696 call assert_equal(expected_props, prop_list(1)) 697 698 " Delete "t" in "two" and "three" to XX: 'oXXe wo hree' 699 s/t//g 700 let expected_props[0].length -= 2 701 let expected_props[2].length -= 1 702 let expected_props[3].length -= 1 703 let expected_props[3].col -= 1 704 call assert_equal(expected_props, prop_list(1)) 705 706 " Split the line by changing w to line break: 'oXXe ', 'o hree' 707 " The long prop is split and spans both lines. 708 " The props on "two" and "three" move to the next line. 709 s/w/\r/ 710 let new_props = [ 711 \ copy(expected_props[0]), 712 \ copy(expected_props[2]), 713 \ copy(expected_props[3]), 714 \ ] 715 let expected_props[0].length = 5 716 let expected_props[0].end = 0 717 unlet expected_props[3] 718 unlet expected_props[2] 719 call assert_equal(expected_props, prop_list(1)) 720 721 let new_props[0].length = 6 722 let new_props[0].start = 0 723 let new_props[1].col = 1 724 let new_props[1].length = 1 725 let new_props[2].col = 3 726 call assert_equal(new_props, prop_list(2)) 727 728 call DeletePropTypes() 729 bwipe! 730endfunc 731 732func Test_prop_change_indent() 733 call prop_type_add('comment', {'highlight': 'Directory'}) 734 new 735 call setline(1, [' xxx', 'yyyyy']) 736 call prop_add(2, 2, {'length': 2, 'type': 'comment'}) 737 let expect = #{type_bufnr: 0, col: 2, length: 2, type: 'comment', start: 1, end: 1, id: 0} 738 call assert_equal([expect], prop_list(2)) 739 740 set shiftwidth=3 741 normal 2G>> 742 call assert_equal(' yyyyy', getline(2)) 743 let expect.col += 3 744 call assert_equal([expect], prop_list(2)) 745 746 normal 2G== 747 call assert_equal(' yyyyy', getline(2)) 748 let expect.col = 6 749 call assert_equal([expect], prop_list(2)) 750 751 call prop_clear(2) 752 call prop_add(2, 2, {'length': 5, 'type': 'comment'}) 753 let expect.col = 2 754 let expect.length = 5 755 call assert_equal([expect], prop_list(2)) 756 757 normal 2G<< 758 call assert_equal(' yyyyy', getline(2)) 759 let expect.length = 2 760 call assert_equal([expect], prop_list(2)) 761 762 set shiftwidth& 763 call prop_type_delete('comment') 764endfunc 765 766" Setup a three line prop in lines 2 - 4. 767" Add short props in line 1 and 5. 768func Setup_three_line_prop() 769 new 770 call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five']) 771 call prop_add(1, 2, {'length': 1, 'type': 'comment'}) 772 call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'}) 773 call prop_add(5, 2, {'length': 1, 'type': 'comment'}) 774endfunc 775 776func Test_prop_multiline() 777 eval 'comment'->prop_type_add({'highlight': 'Directory'}) 778 new 779 call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz']) 780 781 " start halfway line 1, end halfway line 3 782 call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'}) 783 let expect1 = #{type_bufnr: 0, col: 3, length: 6, type: 'comment', start: 1, end: 0, id: 0} 784 call assert_equal([expect1], prop_list(1)) 785 let expect2 = #{type_bufnr: 0, col: 1, length: 10, type: 'comment', start: 0, end: 0, id: 0} 786 call assert_equal([expect2], prop_list(2)) 787 let expect3 = #{type_bufnr: 0, col: 1, length: 4, type: 'comment', start: 0, end: 1, id: 0} 788 call assert_equal([expect3], prop_list(3)) 789 call prop_clear(1, 3) 790 791 " include all three lines 792 call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'}) 793 let expect1.col = 1 794 let expect1.length = 8 795 call assert_equal([expect1], prop_list(1)) 796 call assert_equal([expect2], prop_list(2)) 797 let expect3.length = 9 798 call assert_equal([expect3], prop_list(3)) 799 call prop_clear(1, 3) 800 801 bwipe! 802 803 " Test deleting the first line of a multi-line prop. 804 call Setup_three_line_prop() 805 let expect_short = #{type_bufnr: 0, col: 2, length: 1, type: 'comment', start: 1, end: 1, id: 0} 806 call assert_equal([expect_short], prop_list(1)) 807 let expect2 = #{type_bufnr: 0, col: 4, length: 4, type: 'comment', start: 1, end: 0, id: 0} 808 call assert_equal([expect2], prop_list(2)) 809 2del 810 call assert_equal([expect_short], prop_list(1)) 811 let expect2 = #{type_bufnr: 0, col: 1, length: 6, type: 'comment', start: 1, end: 0, id: 0} 812 call assert_equal([expect2], prop_list(2)) 813 bwipe! 814 815 " Test deleting the last line of a multi-line prop. 816 call Setup_three_line_prop() 817 let expect3 = #{type_bufnr: 0, col: 1, length: 6, type: 'comment', start: 0, end: 0, id: 0} 818 call assert_equal([expect3], prop_list(3)) 819 let expect4 = #{type_bufnr: 0, col: 1, length: 4, type: 'comment', start: 0, end: 1, id: 0} 820 call assert_equal([expect4], prop_list(4)) 821 4del 822 let expect3.end = 1 823 call assert_equal([expect3], prop_list(3)) 824 call assert_equal([expect_short], prop_list(4)) 825 bwipe! 826 827 " Test appending a line below the multi-line text prop start. 828 call Setup_three_line_prop() 829 let expect2 = #{type_bufnr: 0, col: 4, length: 4, type: 'comment', start: 1, end: 0, id: 0} 830 call assert_equal([expect2], prop_list(2)) 831 call append(2, "new line") 832 call assert_equal([expect2], prop_list(2)) 833 let expect3 = #{type_bufnr: 0, col: 1, length: 9, type: 'comment', start: 0, end: 0, id: 0} 834 call assert_equal([expect3], prop_list(3)) 835 bwipe! 836 837 call prop_type_delete('comment') 838endfunc 839 840func Test_prop_line2byte() 841 call prop_type_add('comment', {'highlight': 'Directory'}) 842 new 843 call setline(1, ['line1', 'second line', '']) 844 set ff=unix 845 call assert_equal(19, line2byte(3)) 846 call prop_add(1, 1, {'end_col': 3, 'type': 'comment'}) 847 call assert_equal(19, line2byte(3)) 848 bwipe! 849 850 new 851 setlocal ff=unix 852 call setline(1, range(500)) 853 call assert_equal(1491, line2byte(401)) 854 call prop_add(2, 1, {'type': 'comment'}) 855 call prop_add(222, 1, {'type': 'comment'}) 856 call assert_equal(1491, line2byte(401)) 857 call prop_remove({'type': 'comment'}) 858 call assert_equal(1491, line2byte(401)) 859 bwipe! 860 861 new 862 setlocal ff=unix 863 call setline(1, range(520)) 864 call assert_equal(1491, line2byte(401)) 865 call prop_add(2, 1, {'type': 'comment'}) 866 call assert_equal(1491, line2byte(401)) 867 2delete 868 call assert_equal(1489, line2byte(400)) 869 bwipe! 870 871 call prop_type_delete('comment') 872endfunc 873 874func Test_prop_byte2line() 875 new 876 set ff=unix 877 call setline(1, ['one one', 'two two', 'three three', 'four four', 'five']) 878 call assert_equal(4, byte2line(line2byte(4))) 879 call assert_equal(5, byte2line(line2byte(5))) 880 881 call prop_type_add('prop', {'highlight': 'Directory'}) 882 call prop_add(3, 1, {'length': 5, 'type': 'prop'}) 883 call assert_equal(4, byte2line(line2byte(4))) 884 call assert_equal(5, byte2line(line2byte(5))) 885 886 bwipe! 887 call prop_type_delete('prop') 888endfunc 889 890func Test_prop_goto_byte() 891 new 892 call setline(1, '') 893 call setline(2, 'two three') 894 call setline(3, '') 895 call setline(4, 'four five') 896 897 call prop_type_add('testprop', {'highlight': 'Directory'}) 898 call search('^two') 899 call prop_add(line('.'), col('.'), { 900 \ 'length': len('two'), 901 \ 'type': 'testprop' 902 \ }) 903 904 call search('two \zsthree') 905 let expected_pos = line2byte(line('.')) + col('.') - 1 906 exe expected_pos .. 'goto' 907 let actual_pos = line2byte(line('.')) + col('.') - 1 908 eval actual_pos->assert_equal(expected_pos) 909 910 call search('four \zsfive') 911 let expected_pos = line2byte(line('.')) + col('.') - 1 912 exe expected_pos .. 'goto' 913 let actual_pos = line2byte(line('.')) + col('.') - 1 914 eval actual_pos->assert_equal(expected_pos) 915 916 call prop_type_delete('testprop') 917 bwipe! 918endfunc 919 920func Test_prop_undo() 921 new 922 call prop_type_add('comment', {'highlight': 'Directory'}) 923 call setline(1, ['oneone', 'twotwo', 'three']) 924 " Set 'undolevels' to break changes into undo-able pieces. 925 set ul& 926 927 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'}) 928 let expected = [#{type_bufnr: 0, col: 3, length: 2, id: 0, type: 'comment', start: 1, end: 1}] 929 call assert_equal(expected, prop_list(1)) 930 931 " Insert a character, then undo. 932 exe "normal 0lllix\<Esc>" 933 set ul& 934 let expected[0].length = 3 935 call assert_equal(expected, prop_list(1)) 936 undo 937 let expected[0].length = 2 938 call assert_equal(expected, prop_list(1)) 939 940 " Delete a character, then undo 941 exe "normal 0lllx" 942 set ul& 943 let expected[0].length = 1 944 call assert_equal(expected, prop_list(1)) 945 undo 946 let expected[0].length = 2 947 call assert_equal(expected, prop_list(1)) 948 949 " Delete the line, then undo 950 1d 951 set ul& 952 call assert_equal([], prop_list(1)) 953 undo 954 call assert_equal(expected, prop_list(1)) 955 956 " Insert a character, delete two characters, then undo with "U" 957 exe "normal 0lllix\<Esc>" 958 set ul& 959 let expected[0].length = 3 960 call assert_equal(expected, prop_list(1)) 961 exe "normal 0lllxx" 962 set ul& 963 let expected[0].length = 1 964 call assert_equal(expected, prop_list(1)) 965 normal U 966 let expected[0].length = 2 967 call assert_equal(expected, prop_list(1)) 968 969 " substitute a word, then undo 970 call setline(1, 'the number 123 is highlighted.') 971 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 972 let expected = [#{type_bufnr: 0, col: 12, length: 3, id: 0, type: 'comment', start: 1, end: 1} ] 973 call assert_equal(expected, prop_list(1)) 974 set ul& 975 1s/number/foo 976 let expected[0].col = 9 977 call assert_equal(expected, prop_list(1)) 978 undo 979 let expected[0].col = 12 980 call assert_equal(expected, prop_list(1)) 981 call prop_clear(1) 982 983 " substitute with backslash 984 call setline(1, 'the number 123 is highlighted.') 985 call prop_add(1, 12, {'length': 3, 'type': 'comment'}) 986 let expected = [#{type_bufnr: 0, col: 12, length: 3, id: 0, type: 'comment', start: 1, end: 1} ] 987 call assert_equal(expected, prop_list(1)) 988 1s/the/\The 989 call assert_equal(expected, prop_list(1)) 990 1s/^/\\ 991 let expected[0].col += 1 992 call assert_equal(expected, prop_list(1)) 993 1s/^/\~ 994 let expected[0].col += 1 995 call assert_equal(expected, prop_list(1)) 996 1s/123/12\\3 997 let expected[0].length += 1 998 call assert_equal(expected, prop_list(1)) 999 call prop_clear(1) 1000 1001 bwipe! 1002 call prop_type_delete('comment') 1003endfunc 1004 1005func Test_prop_delete_text() 1006 new 1007 call prop_type_add('comment', {'highlight': 'Directory'}) 1008 call setline(1, ['oneone', 'twotwo', 'three']) 1009 1010 " zero length property 1011 call prop_add(1, 3, {'type': 'comment'}) 1012 let expected = [#{type_bufnr: 0, col: 3, length: 0, id: 0, type: 'comment', start: 1, end: 1} ] 1013 call assert_equal(expected, prop_list(1)) 1014 1015 " delete one char moves the property 1016 normal! x 1017 let expected = [#{type_bufnr: 0, col: 2, length: 0, id: 0, type: 'comment', start: 1, end: 1} ] 1018 call assert_equal(expected, prop_list(1)) 1019 1020 " delete char of the property has no effect 1021 normal! lx 1022 let expected = [#{type_bufnr: 0, col: 2, length: 0, id: 0, type: 'comment', start: 1, end: 1} ] 1023 call assert_equal(expected, prop_list(1)) 1024 1025 " delete more chars moves property to first column, is not deleted 1026 normal! 0xxxx 1027 let expected = [#{type_bufnr: 0, col: 1, length: 0, id: 0, type: 'comment', start: 1, end: 1} ] 1028 call assert_equal(expected, prop_list(1)) 1029 1030 bwipe! 1031 call prop_type_delete('comment') 1032endfunc 1033 1034" screenshot test with textprop highlighting 1035func Test_textprop_screenshot_various() 1036 CheckScreendump 1037 " The Vim running in the terminal needs to use utf-8. 1038 if g:orig_encoding != 'utf-8' 1039 throw 'Skipped: not using utf-8' 1040 endif 1041 call writefile([ 1042 \ "call setline(1, [" 1043 \ .. "'One two'," 1044 \ .. "'Numbér 123 änd thœn 4¾7.'," 1045 \ .. "'--aa--bb--cc--dd--'," 1046 \ .. "'// comment with error in it'," 1047 \ .. "'first line'," 1048 \ .. "' second line '," 1049 \ .. "'third line'," 1050 \ .. "' fourth line'," 1051 \ .. "])", 1052 \ "hi NumberProp ctermfg=blue", 1053 \ "hi LongProp ctermbg=yellow", 1054 \ "hi BackgroundProp ctermbg=lightgrey", 1055 \ "hi UnderlineProp cterm=underline", 1056 \ "call prop_type_add('number', {'highlight': 'NumberProp'})", 1057 \ "call prop_type_add('long', {'highlight': 'NumberProp'})", 1058 \ "call prop_type_change('long', {'highlight': 'LongProp'})", 1059 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})", 1060 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})", 1061 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})", 1062 \ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})", 1063 \ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})", 1064 \ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})", 1065 \ "call prop_type_add('error', {'highlight': 'UnderlineProp'})", 1066 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})", 1067 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})", 1068 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})", 1069 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})", 1070 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})", 1071 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})", 1072 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})", 1073 \ "call prop_add(4, 6, {'length': 3, 'type': 'background'})", 1074 \ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})", 1075 \ "call prop_add(4, 17, {'length': 5, 'type': 'error'})", 1076 \ "call prop_add(5, 7, {'length': 4, 'type': 'long'})", 1077 \ "call prop_add(6, 1, {'length': 8, 'type': 'long'})", 1078 \ "call prop_add(8, 1, {'length': 1, 'type': 'long'})", 1079 \ "call prop_add(8, 11, {'length': 4, 'type': 'long'})", 1080 \ "set number cursorline", 1081 \ "hi clear SpellBad", 1082 \ "set spell", 1083 \ "syn match Comment '//.*'", 1084 \ "hi Comment ctermfg=green", 1085 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>", 1086 \ "normal 3G0lli\<BS>\<Esc>", 1087 \ "normal 6G0i\<BS>\<Esc>", 1088 \ "normal 3J", 1089 \ "normal 3G", 1090 \], 'XtestProp') 1091 let buf = RunVimInTerminal('-S XtestProp', {'rows': 8}) 1092 call VerifyScreenDump(buf, 'Test_textprop_01', {}) 1093 1094 " clean up 1095 call StopVimInTerminal(buf) 1096 call delete('XtestProp') 1097endfunc 1098 1099func RunTestVisualBlock(width, dump) 1100 call writefile([ 1101 \ "call setline(1, [" 1102 \ .. "'xxxxxxxxx 123 x'," 1103 \ .. "'xxxxxxxx 123 x'," 1104 \ .. "'xxxxxxx 123 x'," 1105 \ .. "'xxxxxx 123 x'," 1106 \ .. "'xxxxx 123 x'," 1107 \ .. "'xxxx 123 xx'," 1108 \ .. "'xxx 123 xxx'," 1109 \ .. "'xx 123 xxxx'," 1110 \ .. "'x 123 xxxxx'," 1111 \ .. "' 123 xxxxxx'," 1112 \ .. "])", 1113 \ "hi SearchProp ctermbg=yellow", 1114 \ "call prop_type_add('search', {'highlight': 'SearchProp'})", 1115 \ "call prop_add(1, 11, {'length': 3, 'type': 'search'})", 1116 \ "call prop_add(2, 10, {'length': 3, 'type': 'search'})", 1117 \ "call prop_add(3, 9, {'length': 3, 'type': 'search'})", 1118 \ "call prop_add(4, 8, {'length': 3, 'type': 'search'})", 1119 \ "call prop_add(5, 7, {'length': 3, 'type': 'search'})", 1120 \ "call prop_add(6, 6, {'length': 3, 'type': 'search'})", 1121 \ "call prop_add(7, 5, {'length': 3, 'type': 'search'})", 1122 \ "call prop_add(8, 4, {'length': 3, 'type': 'search'})", 1123 \ "call prop_add(9, 3, {'length': 3, 'type': 'search'})", 1124 \ "call prop_add(10, 2, {'length': 3, 'type': 'search'})", 1125 \ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx", 1126 \], 'XtestPropVis') 1127 let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12}) 1128 call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {}) 1129 1130 " clean up 1131 call StopVimInTerminal(buf) 1132 call delete('XtestPropVis') 1133endfunc 1134 1135" screenshot test with Visual block mode operations 1136func Test_textprop_screenshot_visual() 1137 CheckScreendump 1138 1139 " Delete two columns while text props are three chars wide. 1140 call RunTestVisualBlock(2, '01') 1141 1142 " Same, but delete four columns 1143 call RunTestVisualBlock(4, '02') 1144endfunc 1145 1146func Test_textprop_after_tab() 1147 CheckScreendump 1148 1149 let lines =<< trim END 1150 call setline(1, [ 1151 \ "\txxx", 1152 \ "x\txxx", 1153 \ ]) 1154 hi SearchProp ctermbg=yellow 1155 call prop_type_add('search', {'highlight': 'SearchProp'}) 1156 call prop_add(1, 2, {'length': 3, 'type': 'search'}) 1157 call prop_add(2, 3, {'length': 3, 'type': 'search'}) 1158 END 1159 call writefile(lines, 'XtestPropTab') 1160 let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6}) 1161 call VerifyScreenDump(buf, 'Test_textprop_tab', {}) 1162 1163 " clean up 1164 call StopVimInTerminal(buf) 1165 call delete('XtestPropTab') 1166endfunc 1167 1168func Test_textprop_nowrap_scrolled() 1169 CheckScreendump 1170 1171 let lines =<< trim END 1172 vim9script 1173 set nowrap 1174 setline(1, 'The number 123 is smaller than 4567.' .. repeat('X', &columns)) 1175 prop_type_add('number', {'highlight': 'ErrorMsg'}) 1176 prop_add(1, 12, {'length': 3, 'type': 'number'}) 1177 prop_add(1, 32, {'length': 4, 'type': 'number'}) 1178 feedkeys('gg20zl', 'nxt') 1179 END 1180 call writefile(lines, 'XtestNowrap') 1181 let buf = RunVimInTerminal('-S XtestNowrap', {'rows': 6}) 1182 call VerifyScreenDump(buf, 'Test_textprop_nowrap_01', {}) 1183 1184 call term_sendkeys(buf, "$") 1185 call VerifyScreenDump(buf, 'Test_textprop_nowrap_02', {}) 1186 1187 " clean up 1188 call StopVimInTerminal(buf) 1189 call delete('XtestNowrap') 1190endfunc 1191 1192func Test_textprop_with_syntax() 1193 CheckScreendump 1194 1195 let lines =<< trim END 1196 call setline(1, [ 1197 \ "(abc)", 1198 \ ]) 1199 syn match csParens "[()]" display 1200 hi! link csParens MatchParen 1201 1202 call prop_type_add('TPTitle', #{ highlight: 'Title' }) 1203 call prop_add(1, 2, #{type: 'TPTitle', end_col: 5}) 1204 END 1205 call writefile(lines, 'XtestPropSyn') 1206 let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6}) 1207 call VerifyScreenDump(buf, 'Test_textprop_syn_1', {}) 1208 1209 " clean up 1210 call StopVimInTerminal(buf) 1211 call delete('XtestPropSyn') 1212endfunc 1213 1214" Adding a text property to a new buffer should not fail 1215func Test_textprop_empty_buffer() 1216 call prop_type_add('comment', {'highlight': 'Search'}) 1217 new 1218 call prop_add(1, 1, {'type': 'comment'}) 1219 close 1220 call prop_type_delete('comment') 1221endfunc 1222 1223" Adding a text property with invalid highlight should be ignored. 1224func Test_textprop_invalid_highlight() 1225 call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:') 1226 new 1227 call setline(1, ['asdf','asdf']) 1228 call prop_add(1, 1, {'length': 4, 'type': 'dni'}) 1229 redraw 1230 bwipe! 1231 call prop_type_delete('dni') 1232endfunc 1233 1234" Adding a text property to an empty buffer and then editing another 1235func Test_textprop_empty_buffer_next() 1236 call prop_type_add("xxx", {}) 1237 call prop_add(1, 1, {"type": "xxx"}) 1238 next X 1239 call prop_type_delete('xxx') 1240endfunc 1241 1242func Test_textprop_remove_from_buf() 1243 new 1244 let buf = bufnr('') 1245 call prop_type_add('one', {'bufnr': buf}) 1246 call prop_add(1, 1, {'type': 'one', 'id': 234}) 1247 file x 1248 edit y 1249 call prop_remove({'id': 234, 'bufnr': buf}, 1) 1250 call prop_type_delete('one', {'bufnr': buf}) 1251 bwipe! x 1252 close 1253endfunc 1254 1255func Test_textprop_in_unloaded_buf() 1256 edit Xaaa 1257 call setline(1, 'aaa') 1258 write 1259 edit Xbbb 1260 call setline(1, 'bbb') 1261 write 1262 let bnr = bufnr('') 1263 edit Xaaa 1264 1265 call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'}) 1266 call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:') 1267 exe 'buf ' .. bnr 1268 call assert_equal('bbb', getline(1)) 1269 call assert_equal(0, prop_list(1)->len()) 1270 1271 bwipe! Xaaa 1272 bwipe! Xbbb 1273 cal delete('Xaaa') 1274 cal delete('Xbbb') 1275endfunc 1276 1277func Test_proptype_substitute2() 1278 new 1279 " text_prop.vim 1280 call setline(1, [ 1281 \ 'The num 123 is smaller than 4567.', 1282 \ '123 The number 123 is smaller than 4567.', 1283 \ '123 The number 123 is smaller than 4567.']) 1284 1285 call prop_type_add('number', {'highlight': 'ErrorMsg'}) 1286 1287 call prop_add(1, 12, {'length': 3, 'type': 'number'}) 1288 call prop_add(2, 1, {'length': 3, 'type': 'number'}) 1289 call prop_add(3, 36, {'length': 4, 'type': 'number'}) 1290 set ul& 1291 let expected = [ 1292 \ #{type_bufnr: 0, id: 0, col: 13, end: 1, type: 'number', length: 3, start: 1}, 1293 \ #{type_bufnr: 0, id: 0, col: 1, end: 1, type: 'number', length: 3, start: 1}, 1294 \ #{type_bufnr: 0, id: 0, col: 50, end: 1, type: 'number', length: 4, start: 1}] 1295 1296 " TODO 1297 return 1298 " Add some text in between 1299 %s/\s\+/ /g 1300 call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3)) 1301 1302 " remove some text 1303 :1s/[a-z]\{3\}//g 1304 let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}] 1305 call assert_equal(expected, prop_list(1)) 1306 bwipe! 1307endfunc 1308 1309" This was causing property corruption. 1310func Test_proptype_substitute3() 1311 new 1312 call setline(1, ['abcxxx', 'def']) 1313 call prop_type_add("test", {"highlight": "Search"}) 1314 call prop_add(1, 2, {"end_lnum": 2, "end_col": 2, "type": "test"}) 1315 %s/x\+$// 1316 redraw 1317 1318 call prop_type_delete('test') 1319 bwipe! 1320endfunc 1321 1322func SaveOptions() 1323 let d = #{tabstop: &tabstop, 1324 \ softtabstop: &softtabstop, 1325 \ shiftwidth: &shiftwidth, 1326 \ expandtab: &expandtab, 1327 \ foldmethod: '"' .. &foldmethod .. '"', 1328 \ } 1329 return d 1330endfunc 1331 1332func RestoreOptions(dict) 1333 for name in keys(a:dict) 1334 exe 'let &' .. name .. ' = ' .. a:dict[name] 1335 endfor 1336endfunc 1337 1338func Test_textprop_noexpandtab() 1339 new 1340 let save_dict = SaveOptions() 1341 1342 set tabstop=8 1343 set softtabstop=4 1344 set shiftwidth=4 1345 set noexpandtab 1346 set foldmethod=marker 1347 1348 call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx") 1349 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1350 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1351 call feedkeys("0i\<tab>", "tx") 1352 call prop_remove({'type': 'test'}) 1353 call prop_add(1, 2, {'end_col': 3, 'type': 'test'}) 1354 call feedkeys("A\<left>\<tab>", "tx") 1355 call prop_remove({'type': 'test'}) 1356 try 1357 " It is correct that this does not pass 1358 call prop_add(1, 6, {'end_col': 7, 'type': 'test'}) 1359 " Has already collapsed here, start_col:6 does not result in an error 1360 call feedkeys("A\<left>\<tab>", "tx") 1361 catch /^Vim\%((\a\+)\)\=:E964/ 1362 endtry 1363 call prop_remove({'type': 'test'}) 1364 call prop_type_delete('test') 1365 1366 call RestoreOptions(save_dict) 1367 bwipe! 1368endfunc 1369 1370func Test_textprop_noexpandtab_redraw() 1371 new 1372 let save_dict = SaveOptions() 1373 1374 set tabstop=8 1375 set softtabstop=4 1376 set shiftwidth=4 1377 set noexpandtab 1378 set foldmethod=marker 1379 1380 call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx") 1381 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1382 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1383 call feedkeys("0i\<tab>", "tx") 1384 " Internally broken at the next line 1385 call feedkeys("A\<left>\<tab>", "tx") 1386 redraw 1387 " Index calculation failed internally on next line 1388 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1389 call prop_remove({'type': 'test', 'all': v:true}) 1390 call prop_type_delete('test') 1391 call prop_type_delete('test') 1392 1393 call RestoreOptions(save_dict) 1394 bwipe! 1395endfunc 1396 1397func Test_textprop_ins_str() 1398 new 1399 call setline(1, 'just some text') 1400 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1401 call prop_add(1, 1, {'end_col': 2, 'type': 'test'}) 1402 call assert_equal([#{type_bufnr: 0, id: 0, col: 1, end: 1, type: 'test', length: 1, start: 1}], prop_list(1)) 1403 1404 call feedkeys("foi\<F8>\<Esc>", "tx") 1405 call assert_equal('just s<F8>ome text', getline(1)) 1406 call assert_equal([#{type_bufnr: 0, id: 0, col: 1, end: 1, type: 'test', length: 1, start: 1}], prop_list(1)) 1407 1408 bwipe! 1409 call prop_remove({'type': 'test'}) 1410 call prop_type_delete('test') 1411endfunc 1412 1413func Test_find_prop_later_in_line() 1414 new 1415 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1416 call setline(1, 'just some text') 1417 call prop_add(1, 1, {'length': 4, 'type': 'test'}) 1418 call prop_add(1, 10, {'length': 3, 'type': 'test'}) 1419 1420 call assert_equal( 1421 \ #{type_bufnr: 0, id: 0, lnum: 1, col: 10, end: 1, type: 'test', length: 3, start: 1}, 1422 \ prop_find(#{type: 'test', lnum: 1, col: 6})) 1423 1424 bwipe! 1425 call prop_type_delete('test') 1426endfunc 1427 1428func Test_find_zerowidth_prop_sol() 1429 new 1430 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1431 call setline(1, 'just some text') 1432 call prop_add(1, 1, {'length': 0, 'type': 'test'}) 1433 1434 call assert_equal( 1435 \ #{type_bufnr: 0, id: 0, lnum: 1, col: 1, end: 1, type: 'test', length: 0, start: 1}, 1436 \ prop_find(#{type: 'test', lnum: 1})) 1437 1438 bwipe! 1439 call prop_type_delete('test') 1440endfunc 1441 1442" Test for passing invalid arguments to prop_xxx() functions 1443func Test_prop_func_invalid_args() 1444 call assert_fails('call prop_clear(1, 2, [])', 'E715:') 1445 call assert_fails('call prop_clear(-1, 2)', 'E16:') 1446 call assert_fails('call prop_find(test_null_dict())', 'E715:') 1447 call assert_fails('call prop_find({"bufnr" : []})', 'E730:') 1448 call assert_fails('call prop_find({})', 'E968:') 1449 call assert_fails('call prop_find({}, "x")', 'E474:') 1450 call assert_fails('call prop_find({"lnum" : -2})', 'E16:') 1451 call assert_fails('call prop_list(1, [])', 'E715:') 1452 call assert_fails('call prop_list(-1, {})', 'E16:') 1453 call assert_fails('call prop_remove([])', 'E474:') 1454 call assert_fails('call prop_remove({}, -2)', 'E16:') 1455 call assert_fails('call prop_remove({})', 'E968:') 1456 call assert_fails('call prop_type_add([], {})', 'E730:') 1457 call assert_fails("call prop_type_change('long', {'xyz' : 10})", 'E971:') 1458 call assert_fails("call prop_type_delete([])", 'E730:') 1459 call assert_fails("call prop_type_delete('xyz', [])", 'E715:') 1460 call assert_fails("call prop_type_get([])", 'E730:') 1461 call assert_fails("call prop_type_get('', [])", 'E474:') 1462 call assert_fails("call prop_type_list([])", 'E715:') 1463 call assert_fails("call prop_type_add('yyy', 'not_a_dict')", 'E715:') 1464 call assert_fails("call prop_add(1, 5, {'type':'missing_type', 'length':1})", 'E971:') 1465 call assert_fails("call prop_add(1, 5, {'type': ''})", 'E971:') 1466 call assert_fails('call prop_add(1, 1, 0)', 'E715:') 1467 1468 new 1469 call setline(1, ['first', 'second']) 1470 call prop_type_add('xxx', {}) 1471 1472 call assert_fails("call prop_type_add('xxx', {})", 'E969:') 1473 call assert_fails("call prop_add(2, 0, {'type': 'xxx'})", 'E964:') 1474 call assert_fails("call prop_add(2, 3, {'type': 'xxx', 'end_lnum':1})", 'E475:') 1475 call assert_fails("call prop_add(2, 3, {'type': 'xxx', 'end_lnum':3})", 'E966:') 1476 call assert_fails("call prop_add(2, 3, {'type': 'xxx', 'length':-1})", 'E475:') 1477 call assert_fails("call prop_add(2, 3, {'type': 'xxx', 'end_col':0})", 'E475:') 1478 call assert_fails("call prop_add(2, 3, {'length':1})", 'E965:') 1479 1480 call prop_type_delete('xxx') 1481 bwipe! 1482endfunc 1483 1484func Test_prop_split_join() 1485 new 1486 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1487 call setline(1, 'just some text') 1488 call prop_add(1, 6, {'length': 4, 'type': 'test'}) 1489 1490 " Split in middle of "some" 1491 execute "normal! 8|i\<CR>" 1492 call assert_equal( 1493 \ [#{type_bufnr: 0, id: 0, col: 6, end: 0, type: 'test', length: 2, start: 1}], 1494 \ prop_list(1)) 1495 call assert_equal( 1496 \ [#{type_bufnr: 0, id: 0, col: 1, end: 1, type: 'test', length: 2, start: 0}], 1497 \ prop_list(2)) 1498 1499 " Join the two lines back together 1500 normal! 1GJ 1501 call assert_equal([#{type_bufnr: 0, id: 0, col: 6, end: 1, type: 'test', length: 5, start: 1}], prop_list(1)) 1502 1503 bwipe! 1504 call prop_type_delete('test') 1505endfunc 1506 1507func Test_prop_increment_decrement() 1508 new 1509 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1510 call setline(1, 'its 998 times') 1511 call prop_add(1, 5, {'length': 3, 'type': 'test'}) 1512 1513 exe "normal! 0f9\<C-A>" 1514 eval getline(1)->assert_equal('its 999 times') 1515 eval prop_list(1)->assert_equal([ 1516 \ #{type_bufnr: 0, id: 0, col: 5, end: 1, type: 'test', length: 3, start: 1}]) 1517 1518 exe "normal! 0f9\<C-A>" 1519 eval getline(1)->assert_equal('its 1000 times') 1520 eval prop_list(1)->assert_equal([ 1521 \ #{type_bufnr: 0, id: 0, col: 5, end: 1, type: 'test', length: 4, start: 1}]) 1522 1523 bwipe! 1524 call prop_type_delete('test') 1525endfunc 1526 1527func Test_prop_block_insert() 1528 new 1529 call prop_type_add('test', {'highlight': 'ErrorMsg'}) 1530 call setline(1, ['one ', 'two ']) 1531 call prop_add(1, 1, {'length': 3, 'type': 'test'}) 1532 call prop_add(2, 1, {'length': 3, 'type': 'test'}) 1533 1534 " insert "xx" in the first column of both lines 1535 exe "normal! gg0\<C-V>jIxx\<Esc>" 1536 eval getline(1, 2)->assert_equal(['xxone ', 'xxtwo ']) 1537 let expected = [#{type_bufnr: 0, id: 0, col: 3, end: 1, type: 'test', length: 3, start: 1}] 1538 eval prop_list(1)->assert_equal(expected) 1539 eval prop_list(2)->assert_equal(expected) 1540 1541 " insert "yy" inside the text props to make them longer 1542 exe "normal! gg03l\<C-V>jIyy\<Esc>" 1543 eval getline(1, 2)->assert_equal(['xxoyyne ', 'xxtyywo ']) 1544 let expected[0].length = 5 1545 eval prop_list(1)->assert_equal(expected) 1546 eval prop_list(2)->assert_equal(expected) 1547 1548 " insert "zz" after the text props, text props don't change 1549 exe "normal! gg07l\<C-V>jIzz\<Esc>" 1550 eval getline(1, 2)->assert_equal(['xxoyynezz ', 'xxtyywozz ']) 1551 eval prop_list(1)->assert_equal(expected) 1552 eval prop_list(2)->assert_equal(expected) 1553 1554 bwipe! 1555 call prop_type_delete('test') 1556endfunc 1557 1558" this was causing an ml_get error because w_botline was wrong 1559func Test_prop_one_line_window() 1560 enew 1561 call range(2)->setline(1) 1562 call prop_type_add('testprop', {}) 1563 call prop_add(1, 1, {'type': 'testprop'}) 1564 call popup_create('popup', {'textprop': 'testprop'}) 1565 $ 1566 new 1567 wincmd _ 1568 call feedkeys("\r", 'xt') 1569 redraw 1570 1571 call popup_clear() 1572 call prop_type_delete('testprop') 1573 close 1574 bwipe! 1575endfunc 1576 1577" This was calling ml_append_int() and copy a text property from a previous 1578" line at the wrong moment. Exact text length matters. 1579def Test_prop_splits_data_block() 1580 new 1581 var lines: list<string> = [repeat('x', 35)]->repeat(41) 1582 + [repeat('!', 35)] 1583 + [repeat('x', 35)]->repeat(56) 1584 lines->setline(1) 1585 prop_type_add('someprop', {highlight: 'ErrorMsg'}) 1586 prop_add(1, 27, {end_lnum: 1, end_col: 70, type: 'someprop'}) 1587 prop_remove({type: 'someprop'}, 1) 1588 prop_add(35, 22, {end_lnum: 43, end_col: 43, type: 'someprop'}) 1589 prop_remove({type: 'someprop'}, 35, 43) 1590 assert_equal([], prop_list(42)) 1591 1592 bwipe! 1593 prop_type_delete('someprop') 1594enddef 1595 1596" This was calling ml_delete_int() and try to change text properties. 1597def Test_prop_add_delete_line() 1598 new 1599 var a = 10 1600 var b = 20 1601 repeat([''], a)->append('$') 1602 prop_type_add('Test', {highlight: 'ErrorMsg'}) 1603 for lnum in range(1, a) 1604 for col in range(1, b) 1605 prop_add(1, 1, {end_lnum: lnum, end_col: col, type: 'Test'}) 1606 endfor 1607 endfor 1608 1609 # check deleting lines is OK 1610 :5del 1611 :1del 1612 :$del 1613 1614 prop_type_delete('Test') 1615 bwipe! 1616enddef 1617 1618func Test_prop_in_linebreak() 1619 CheckRunVimInTerminal 1620 1621 let lines =<< trim END 1622 set breakindent linebreak breakat+=] 1623 call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1) 1624 call prop_type_add('test', #{highlight: 'ErrorMsg'}) 1625 call prop_add(1, 51, #{length: 1, type: 'test'}) 1626 END 1627 call writefile(lines, 'XscriptPropLinebreak') 1628 let buf = RunVimInTerminal('-S XscriptPropLinebreak', #{rows: 10}) 1629 call TermWait(buf) 1630 call VerifyScreenDump(buf, 'Test_prop_linebreak', {}) 1631 1632 call StopVimInTerminal(buf) 1633 call delete('XscriptPropLinebreak') 1634endfunc 1635 1636func Test_prop_after_tab() 1637 CheckRunVimInTerminal 1638 1639 let lines =<< trim END 1640 set breakindent linebreak breakat+=] 1641 call setline(1, "\t[xxx]") 1642 call prop_type_add('test', #{highlight: 'ErrorMsg'}) 1643 call prop_add(1, 2, #{length: 1, type: 'test'}) 1644 END 1645 call writefile(lines, 'XscriptPropAfterTab') 1646 let buf = RunVimInTerminal('-S XscriptPropAfterTab', #{rows: 10}) 1647 call TermWait(buf) 1648 call VerifyScreenDump(buf, 'Test_prop_after_tab', {}) 1649 1650 call StopVimInTerminal(buf) 1651 call delete('XscriptPropAfterTab') 1652endfunc 1653 1654func Test_prop_after_linebreak() 1655 CheckRunVimInTerminal 1656 1657 let lines =<< trim END 1658 set linebreak wrap 1659 call printf('%s+(%s)', 'x'->repeat(&columns / 2), 'x'->repeat(&columns / 2))->setline(1) 1660 call prop_type_add('test', #{highlight: 'ErrorMsg'}) 1661 call prop_add(1, (&columns / 2) + 2, #{length: 1, type: 'test'}) 1662 END 1663 call writefile(lines, 'XscriptPropAfterLinebreak') 1664 let buf = RunVimInTerminal('-S XscriptPropAfterLinebreak', #{rows: 10}) 1665 call TermWait(buf) 1666 call VerifyScreenDump(buf, 'Test_prop_after_linebreak', {}) 1667 1668 call StopVimInTerminal(buf) 1669 call delete('XscriptPropAfterLinebreak') 1670endfunc 1671 1672" Buffer number of 0 should be ignored, as if the parameter wasn't passed. 1673def Test_prop_bufnr_zero() 1674 new 1675 try 1676 var bufnr = bufnr('') 1677 setline(1, 'hello') 1678 prop_type_add('bufnr-global', {highlight: 'ErrorMsg'}) 1679 prop_type_add('bufnr-buffer', {highlight: 'StatusLine', bufnr: bufnr}) 1680 1681 prop_add(1, 1, {type: 'bufnr-global', length: 1}) 1682 prop_add(1, 2, {type: 'bufnr-buffer', length: 1}) 1683 1684 var list = prop_list(1) 1685 assert_equal([ 1686 {id: 0, col: 1, type_bufnr: 0, end: 1, type: 'bufnr-global', length: 1, start: 1}, 1687 {id: 0, col: 2, type_bufnr: bufnr, end: 1, type: 'bufnr-buffer', length: 1, start: 1}, 1688 ], list) 1689 1690 assert_equal( 1691 {highlight: 'ErrorMsg', end_incl: 0, start_incl: 0, priority: 0, combine: 1}, 1692 prop_type_get('bufnr-global', {bufnr: list[0].type_bufnr})) 1693 1694 assert_equal( 1695 {highlight: 'StatusLine', end_incl: 0, start_incl: 0, priority: 0, bufnr: bufnr, combine: 1}, 1696 prop_type_get('bufnr-buffer', {bufnr: list[1].type_bufnr})) 1697 finally 1698 bwipe! 1699 prop_type_delete('bufnr-global') 1700 endtry 1701enddef 1702 1703" Tests for the prop_list() function 1704func Test_prop_list() 1705 let lines =<< trim END 1706 new 1707 call AddPropTypes() 1708 call setline(1, repeat([repeat('a', 60)], 10)) 1709 call prop_add(1, 4, {'type': 'one', 'id': 5, 'end_col': 6}) 1710 call prop_add(1, 5, {'type': 'two', 'id': 10, 'end_col': 7}) 1711 call prop_add(3, 12, {'type': 'one', 'id': 20, 'end_col': 14}) 1712 call prop_add(3, 13, {'type': 'two', 'id': 10, 'end_col': 15}) 1713 call prop_add(5, 20, {'type': 'one', 'id': 10, 'end_col': 22}) 1714 call prop_add(5, 21, {'type': 'two', 'id': 20, 'end_col': 23}) 1715 call assert_equal([ 1716 \ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1717 \ 'type': 'one', 'length': 2, 'start': 1}, 1718 \ {'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1, 1719 \ 'type': 'two', 'length': 2, 'start': 1}], prop_list(1)) 1720 #" text properties between a few lines 1721 call assert_equal([ 1722 \ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1, 1723 \ 'type': 'one', 'length': 2, 'start': 1}, 1724 \ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1, 1725 \ 'type': 'two', 'length': 2, 'start': 1}, 1726 \ {'lnum': 5, 'id': 10, 'col': 20, 'type_bufnr': 0, 'end': 1, 1727 \ 'type': 'one', 'length': 2, 'start': 1}, 1728 \ {'lnum': 5, 'id': 20, 'col': 21, 'type_bufnr': 0, 'end': 1, 1729 \ 'type': 'two', 'length': 2, 'start': 1}], 1730 \ prop_list(2, {'end_lnum': 5})) 1731 #" text properties across all the lines 1732 call assert_equal([ 1733 \ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1734 \ 'type': 'one', 'length': 2, 'start': 1}, 1735 \ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1, 1736 \ 'type': 'one', 'length': 2, 'start': 1}, 1737 \ {'lnum': 5, 'id': 10, 'col': 20, 'type_bufnr': 0, 'end': 1, 1738 \ 'type': 'one', 'length': 2, 'start': 1}], 1739 \ prop_list(1, {'types': ['one'], 'end_lnum': -1})) 1740 #" text properties with the specified identifier 1741 call assert_equal([ 1742 \ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1, 1743 \ 'type': 'one', 'length': 2, 'start': 1}, 1744 \ {'lnum': 5, 'id': 20, 'col': 21, 'type_bufnr': 0, 'end': 1, 1745 \ 'type': 'two', 'length': 2, 'start': 1}], 1746 \ prop_list(1, {'ids': [20], 'end_lnum': 10})) 1747 #" text properties of the specified type and id 1748 call assert_equal([ 1749 \ {'lnum': 1, 'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1, 1750 \ 'type': 'two', 'length': 2, 'start': 1}, 1751 \ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1, 1752 \ 'type': 'two', 'length': 2, 'start': 1}], 1753 \ prop_list(1, {'types': ['two'], 'ids': [10], 'end_lnum': 20})) 1754 call assert_equal([], prop_list(1, {'ids': [40, 50], 'end_lnum': 10})) 1755 call assert_equal([], prop_list(6, {'end_lnum': 10})) 1756 call assert_equal([], prop_list(2, {'end_lnum': 2})) 1757 #" error cases 1758 call assert_fails("echo prop_list(1, {'end_lnum': -20})", 'E16:') 1759 call assert_fails("echo prop_list(4, {'end_lnum': 2})", 'E16:') 1760 call assert_fails("echo prop_list(1, {'end_lnum': '$'})", 'E889:') 1761 call assert_fails("echo prop_list(1, {'types': ['blue'], 'end_lnum': 10})", 1762 \ 'E971:') 1763 call assert_fails("echo prop_list(1, {'types': ['one', 'blue'], 1764 \ 'end_lnum': 10})", 'E971:') 1765 call assert_fails("echo prop_list(1, {'types': ['one', 10], 1766 \ 'end_lnum': 10})", 'E928:') 1767 call assert_fails("echo prop_list(1, {'types': ['']})", 'E971:') 1768 call assert_equal([], prop_list(2, {'types': []})) 1769 call assert_equal([], prop_list(2, {'types': test_null_list()})) 1770 call assert_fails("call prop_list(1, {'types': {}})", 'E714:') 1771 call assert_fails("call prop_list(1, {'types': 'one'})", 'E714:') 1772 call assert_equal([], prop_list(2, {'types': ['one'], 1773 \ 'ids': test_null_list()})) 1774 call assert_equal([], prop_list(2, {'types': ['one'], 'ids': []})) 1775 call assert_fails("call prop_list(1, {'types': ['one'], 'ids': {}})", 1776 \ 'E714:') 1777 call assert_fails("call prop_list(1, {'types': ['one'], 'ids': 10})", 1778 \ 'E714:') 1779 call assert_fails("call prop_list(1, {'types': ['one'], 'ids': [[]]})", 1780 \ 'E745:') 1781 call assert_fails("call prop_list(1, {'types': ['one'], 'ids': [10, []]})", 1782 \ 'E745:') 1783 1784 #" get text properties from a non-current buffer 1785 wincmd w 1786 call assert_equal([ 1787 \ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1788 \ 'type': 'one', 'length': 2, 'start': 1}, 1789 \ {'lnum': 1, 'id': 10, 'col': 5, 'type_bufnr': 0, 'end': 1, 1790 \ 'type': 'two', 'length': 2, 'start': 1}, 1791 \ {'lnum': 3, 'id': 20, 'col': 12, 'type_bufnr': 0, 'end': 1, 1792 \ 'type': 'one', 'length': 2, 'start': 1}, 1793 \ {'lnum': 3, 'id': 10, 'col': 13, 'type_bufnr': 0, 'end': 1, 1794 \ 'type': 'two', 'length': 2, 'start': 1}], 1795 \ prop_list(1, {'bufnr': winbufnr(1), 'end_lnum': 4})) 1796 wincmd w 1797 1798 #" get text properties after clearing all the properties 1799 call prop_clear(1, line('$')) 1800 call assert_equal([], prop_list(1, {'end_lnum': 10})) 1801 1802 call prop_add(2, 4, {'type': 'one', 'id': 5, 'end_col': 6}) 1803 call prop_add(2, 4, {'type': 'two', 'id': 10, 'end_col': 6}) 1804 call prop_add(2, 4, {'type': 'three', 'id': 15, 'end_col': 6}) 1805 #" get text properties with a list of types 1806 call assert_equal([ 1807 \ {'id': 10, 'col': 4, 'type_bufnr': 0, 'end': 1, 1808 \ 'type': 'two', 'length': 2, 'start': 1}, 1809 \ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1810 \ 'type': 'one', 'length': 2, 'start': 1}], 1811 \ prop_list(2, {'types': ['one', 'two']})) 1812 call assert_equal([ 1813 \ {'id': 15, 'col': 4, 'type_bufnr': 0, 'end': 1, 1814 \ 'type': 'three', 'length': 2, 'start': 1}, 1815 \ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1816 \ 'type': 'one', 'length': 2, 'start': 1}], 1817 \ prop_list(2, {'types': ['one', 'three']})) 1818 #" get text properties with a list of identifiers 1819 call assert_equal([ 1820 \ {'id': 10, 'col': 4, 'type_bufnr': 0, 'end': 1, 1821 \ 'type': 'two', 'length': 2, 'start': 1}, 1822 \ {'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1823 \ 'type': 'one', 'length': 2, 'start': 1}], 1824 \ prop_list(2, {'ids': [5, 10, 20]})) 1825 call prop_clear(1, line('$')) 1826 call assert_equal([], prop_list(2, {'types': ['one', 'two']})) 1827 call assert_equal([], prop_list(2, {'ids': [5, 10, 20]})) 1828 1829 #" get text properties from a hidden buffer 1830 edit! Xaaa 1831 call setline(1, repeat([repeat('b', 60)], 10)) 1832 call prop_add(1, 4, {'type': 'one', 'id': 5, 'end_col': 6}) 1833 call prop_add(4, 8, {'type': 'two', 'id': 10, 'end_col': 10}) 1834 VAR bnr = bufnr() 1835 hide edit Xbbb 1836 call assert_equal([ 1837 \ {'lnum': 1, 'id': 5, 'col': 4, 'type_bufnr': 0, 'end': 1, 1838 \ 'type': 'one', 'length': 2, 'start': 1}, 1839 \ {'lnum': 4, 'id': 10, 'col': 8, 'type_bufnr': 0, 'end': 1, 1840 \ 'type': 'two', 'length': 2, 'start': 1}], 1841 \ prop_list(1, {'bufnr': bnr, 1842 \ 'types': ['one', 'two'], 'ids': [5, 10], 'end_lnum': -1})) 1843 #" get text properties from an unloaded buffer 1844 bunload! Xaaa 1845 call assert_equal([], prop_list(1, {'bufnr': bnr, 'end_lnum': -1})) 1846 1847 call DeletePropTypes() 1848 :%bw! 1849 END 1850 call CheckLegacyAndVim9Success(lines) 1851endfunc 1852 1853" vim: shiftwidth=2 sts=2 expandtab 1854