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')
214endfunc
215
216func Test_prop_find_smaller_len_than_match_col()
217  new
218  call prop_type_add('test', {'highlight': 'ErrorMsg'})
219  call setline(1, ['xxxx', 'x'])
220  call prop_add(1, 4, {'type': 'test'})
221  call assert_equal({'id': 0, 'lnum': 1, 'col': 4, 'type': 'test', 'length': 0, 'start': 1, 'end': 1},
222        \ prop_find({'type': 'test', 'lnum': 2, 'col': 1}, 'b'))
223  bwipe!
224  call prop_type_delete('test')
225endfunc
226
227func Test_prop_add()
228  new
229  call AddPropTypes()
230  call SetupPropsInFirstLine()
231  let expected_props = Get_expected_props()
232  call assert_equal(expected_props, prop_list(1))
233  call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:')
234  call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:')
235
236  " Insert a line above, text props must still be there.
237  call append(0, 'empty')
238  call assert_equal(expected_props, prop_list(2))
239  " Delete a line above, text props must still be there.
240  1del
241  call assert_equal(expected_props, prop_list(1))
242
243  " Prop without length or end column is zero length
244  call prop_clear(1)
245  call prop_type_add('included', {'start_incl': 1, 'end_incl': 1})
246  call prop_add(1, 5, #{type: 'included'})
247  let expected = [#{col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}]
248  call assert_equal(expected, prop_list(1))
249
250  " Inserting text makes the prop bigger.
251  exe "normal 5|ixx\<Esc>"
252  let expected = [#{col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}]
253  call assert_equal(expected, prop_list(1))
254
255  call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:')
256
257  call DeletePropTypes()
258  call prop_type_delete('included')
259  bwipe!
260endfunc
261
262func Test_prop_remove()
263  new
264  call AddPropTypes()
265  call SetupPropsInFirstLine()
266  let props = Get_expected_props()
267  call assert_equal(props, prop_list(1))
268
269  " remove by id
270  call assert_equal(1, {'id': 12}->prop_remove(1))
271  unlet props[2]
272  call assert_equal(props, prop_list(1))
273
274  " remove by type
275  call assert_equal(1, prop_remove({'type': 'one'}, 1))
276  unlet props[1]
277  call assert_equal(props, prop_list(1))
278
279  " remove from unknown buffer
280  call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:')
281
282  call DeletePropTypes()
283  bwipe!
284
285  new
286  call AddPropTypes()
287  call SetupPropsInFirstLine()
288  call prop_add(1, 6, {'length': 2, 'id': 11, 'type': 'three'})
289  let props = Get_expected_props()
290  call insert(props, {'col': 6, 'length': 2, 'id': 11, 'type': 'three', 'start': 1, 'end': 1}, 3)
291  call assert_equal(props, prop_list(1))
292  call assert_equal(1, prop_remove({'type': 'three', 'id': 11, 'both': 1, 'all': 1}, 1))
293  unlet props[3]
294  call assert_equal(props, prop_list(1))
295
296  call assert_fails("call prop_remove({'id': 11, 'both': 1})", 'E860')
297  call assert_fails("call prop_remove({'type': 'three', 'both': 1})", 'E860')
298
299  call DeletePropTypes()
300  bwipe!
301endfunc
302
303func SetupOneLine()
304  call setline(1, 'xonex xtwoxx')
305  normal gg0
306  call AddPropTypes()
307  call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
308  call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
309  let expected = [
310	\ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
311	\ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
312	\]
313  call assert_equal(expected, prop_list(1))
314  return expected
315endfunc
316
317func Test_prop_add_remove_buf()
318  new
319  let bufnr = bufnr('')
320  call AddPropTypes()
321  for lnum in range(1, 4)
322    call setline(lnum, 'one two three')
323  endfor
324  wincmd w
325  for lnum in range(1, 4)
326    call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr})
327    call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr})
328    call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr})
329  endfor
330
331  let props = [
332	\ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
333	\ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
334	\ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
335	\]
336  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
337
338  " remove by id
339  let before_props = deepcopy(props)
340  unlet props[1]
341
342  call prop_remove({'id': 12, 'bufnr': bufnr}, 1)
343  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
344  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
345  call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
346  call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
347
348  call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4)
349  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
350  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
351  call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
352  call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
353
354  call prop_remove({'id': 12, 'bufnr': bufnr})
355  for lnum in range(1, 4)
356    call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
357  endfor
358
359  " remove by type
360  let before_props = deepcopy(props)
361  unlet props[0]
362
363  call prop_remove({'type': 'one', 'bufnr': bufnr}, 1)
364  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
365  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
366  call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
367  call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
368
369  call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4)
370  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
371  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
372  call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
373  call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
374
375  call prop_remove({'type': 'one', 'bufnr': bufnr})
376  for lnum in range(1, 4)
377    call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
378  endfor
379
380  call DeletePropTypes()
381  wincmd w
382  bwipe!
383endfunc
384
385func Test_prop_backspace()
386  new
387  set bs=2
388  let expected = SetupOneLine() " 'xonex xtwoxx'
389
390  exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>"
391  call assert_equal('one xtwoxx', getline(1))
392  let expected[0].col = 1
393  let expected[1].col = 6
394  call assert_equal(expected, prop_list(1))
395
396  call DeletePropTypes()
397  bwipe!
398  set bs&
399endfunc
400
401func Test_prop_replace()
402  new
403  set bs=2
404  let expected = SetupOneLine() " 'xonex xtwoxx'
405
406  exe "normal 0Ryyy\<Esc>"
407  call assert_equal('yyyex xtwoxx', getline(1))
408  call assert_equal(expected, prop_list(1))
409
410  exe "normal ftRyy\<BS>"
411  call assert_equal('yyyex xywoxx', getline(1))
412  call assert_equal(expected, prop_list(1))
413
414  exe "normal 0fwRyy\<BS>"
415  call assert_equal('yyyex xyyoxx', getline(1))
416  call assert_equal(expected, prop_list(1))
417
418  exe "normal 0foRyy\<BS>\<BS>"
419  call assert_equal('yyyex xyyoxx', getline(1))
420  call assert_equal(expected, prop_list(1))
421
422  call DeletePropTypes()
423  bwipe!
424  set bs&
425endfunc
426
427func Test_prop_open_line()
428  new
429
430  " open new line, props stay in top line
431  let expected = SetupOneLine() " 'xonex xtwoxx'
432  exe "normal o\<Esc>"
433  call assert_equal('xonex xtwoxx', getline(1))
434  call assert_equal('', getline(2))
435  call assert_equal(expected, prop_list(1))
436  call DeletePropTypes()
437
438  " move all props to next line
439  let expected = SetupOneLine() " 'xonex xtwoxx'
440  exe "normal 0i\<CR>\<Esc>"
441  call assert_equal('', getline(1))
442  call assert_equal('xonex xtwoxx', getline(2))
443  call assert_equal(expected, prop_list(2))
444  call DeletePropTypes()
445
446  " split just before prop, move all props to next line
447  let expected = SetupOneLine() " 'xonex xtwoxx'
448  exe "normal 0li\<CR>\<Esc>"
449  call assert_equal('x', getline(1))
450  call assert_equal('onex xtwoxx', getline(2))
451  let expected[0].col -= 1
452  let expected[1].col -= 1
453  call assert_equal(expected, prop_list(2))
454  call DeletePropTypes()
455
456  " split inside prop, split first prop
457  let expected = SetupOneLine() " 'xonex xtwoxx'
458  exe "normal 0lli\<CR>\<Esc>"
459  call assert_equal('xo', getline(1))
460  call assert_equal('nex xtwoxx', getline(2))
461  let exp_first = [deepcopy(expected[0])]
462  let exp_first[0].length = 1
463  call assert_equal(exp_first, prop_list(1))
464  let expected[0].col = 1
465  let expected[0].length = 2
466  let expected[1].col -= 2
467  call assert_equal(expected, prop_list(2))
468  call DeletePropTypes()
469
470  " split just after first prop, second prop move to next line
471  let expected = SetupOneLine() " 'xonex xtwoxx'
472  exe "normal 0fea\<CR>\<Esc>"
473  call assert_equal('xone', getline(1))
474  call assert_equal('x xtwoxx', getline(2))
475  let exp_first = expected[0:0]
476  call assert_equal(exp_first, prop_list(1))
477  let expected = expected[1:1]
478  let expected[0].col -= 4
479  call assert_equal(expected, prop_list(2))
480  call DeletePropTypes()
481
482  bwipe!
483  set bs&
484endfunc
485
486func Test_prop_clear()
487  new
488  call AddPropTypes()
489  call SetupPropsInFirstLine()
490  call assert_equal(Get_expected_props(), prop_list(1))
491
492  eval 1->prop_clear()
493  call assert_equal([], 1->prop_list())
494
495  call DeletePropTypes()
496  bwipe!
497endfunc
498
499func Test_prop_clear_buf()
500  new
501  call AddPropTypes()
502  call SetupPropsInFirstLine()
503  let bufnr = bufnr('')
504  wincmd w
505  call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
506
507  call prop_clear(1, 1, {'bufnr': bufnr})
508  call assert_equal([], prop_list(1, {'bufnr': bufnr}))
509
510  wincmd w
511  call DeletePropTypes()
512  bwipe!
513endfunc
514
515func Test_prop_setline()
516  new
517  call AddPropTypes()
518  call SetupPropsInFirstLine()
519  call assert_equal(Get_expected_props(), prop_list(1))
520
521  call setline(1, 'foobar')
522  call assert_equal([], prop_list(1))
523
524  call DeletePropTypes()
525  bwipe!
526endfunc
527
528func Test_prop_setbufline()
529  new
530  call AddPropTypes()
531  call SetupPropsInFirstLine()
532  let bufnr = bufnr('')
533  wincmd w
534  call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
535
536  call setbufline(bufnr, 1, 'foobar')
537  call assert_equal([], prop_list(1, {'bufnr': bufnr}))
538
539  wincmd w
540  call DeletePropTypes()
541  bwipe!
542endfunc
543
544func Test_prop_substitute()
545  new
546  " Set first line to 'one two three'
547  call AddPropTypes()
548  call SetupPropsInFirstLine()
549  let expected_props = Get_expected_props()
550  call assert_equal(expected_props, prop_list(1))
551
552  " Change "n" in "one" to XX: 'oXXe two three'
553  s/n/XX/
554  let expected_props[0].length += 1
555  let expected_props[1].length += 1
556  let expected_props[2].col += 1
557  let expected_props[3].col += 1
558  call assert_equal(expected_props, prop_list(1))
559
560  " Delete "t" in "two" and "three" to XX: 'oXXe wo hree'
561  s/t//g
562  let expected_props[0].length -= 2
563  let expected_props[2].length -= 1
564  let expected_props[3].length -= 1
565  let expected_props[3].col -= 1
566  call assert_equal(expected_props, prop_list(1))
567
568  " Split the line by changing w to line break: 'oXXe ', 'o hree'
569  " The long prop is split and spans both lines.
570  " The props on "two" and "three" move to the next line.
571  s/w/\r/
572  let new_props = [
573	\ copy(expected_props[0]),
574	\ copy(expected_props[2]),
575	\ copy(expected_props[3]),
576	\ ]
577  let expected_props[0].length = 5
578  unlet expected_props[3]
579  unlet expected_props[2]
580  call assert_equal(expected_props, prop_list(1))
581
582  let new_props[0].length = 6
583  let new_props[1].col = 1
584  let new_props[1].length = 1
585  let new_props[2].col = 3
586  call assert_equal(new_props, prop_list(2))
587
588  call DeletePropTypes()
589  bwipe!
590endfunc
591
592func Test_prop_change_indent()
593  call prop_type_add('comment', {'highlight': 'Directory'})
594  new
595  call setline(1, ['    xxx', 'yyyyy'])
596  call prop_add(2, 2, {'length': 2, 'type': 'comment'})
597  let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
598  call assert_equal([expect], prop_list(2))
599
600  set shiftwidth=3
601  normal 2G>>
602  call assert_equal('   yyyyy', getline(2))
603  let expect.col += 3
604  call assert_equal([expect], prop_list(2))
605
606  normal 2G==
607  call assert_equal('    yyyyy', getline(2))
608  let expect.col = 6
609  call assert_equal([expect], prop_list(2))
610
611  call prop_clear(2)
612  call prop_add(2, 2, {'length': 5, 'type': 'comment'})
613  let expect.col = 2
614  let expect.length = 5
615  call assert_equal([expect], prop_list(2))
616
617  normal 2G<<
618  call assert_equal(' yyyyy', getline(2))
619  let expect.length = 2
620  call assert_equal([expect], prop_list(2))
621
622  set shiftwidth&
623  call prop_type_delete('comment')
624endfunc
625
626" Setup a three line prop in lines 2 - 4.
627" Add short props in line 1 and 5.
628func Setup_three_line_prop()
629  new
630  call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five'])
631  call prop_add(1, 2, {'length': 1, 'type': 'comment'})
632  call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'})
633  call prop_add(5, 2, {'length': 1, 'type': 'comment'})
634endfunc
635
636func Test_prop_multiline()
637  eval 'comment'->prop_type_add({'highlight': 'Directory'})
638  new
639  call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz'])
640
641  " start halfway line 1, end halfway line 3
642  call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'})
643  let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
644  call assert_equal([expect1], prop_list(1))
645  let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
646  call assert_equal([expect2], prop_list(2))
647  let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
648  call assert_equal([expect3], prop_list(3))
649  call prop_clear(1, 3)
650
651  " include all three lines
652  call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'})
653  let expect1.col = 1
654  let expect1.length = 8
655  call assert_equal([expect1], prop_list(1))
656  call assert_equal([expect2], prop_list(2))
657  let expect3.length = 9
658  call assert_equal([expect3], prop_list(3))
659  call prop_clear(1, 3)
660
661  bwipe!
662
663  " Test deleting the first line of a multi-line prop.
664  call Setup_three_line_prop()
665  let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
666  call assert_equal([expect_short], prop_list(1))
667  let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
668  call assert_equal([expect2], prop_list(2))
669  2del
670  call assert_equal([expect_short], prop_list(1))
671  let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
672  call assert_equal([expect2], prop_list(2))
673  bwipe!
674
675  " Test deleting the last line of a multi-line prop.
676  call Setup_three_line_prop()
677  let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
678  call assert_equal([expect3], prop_list(3))
679  let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
680  call assert_equal([expect4], prop_list(4))
681  4del
682  let expect3.end = 1
683  call assert_equal([expect3], prop_list(3))
684  call assert_equal([expect_short], prop_list(4))
685  bwipe!
686
687  " Test appending a line below the multi-line text prop start.
688  call Setup_three_line_prop()
689  let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
690  call assert_equal([expect2], prop_list(2))
691  call append(2, "new line")
692  call assert_equal([expect2], prop_list(2))
693  let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
694  call assert_equal([expect3], prop_list(3))
695  bwipe!
696
697  call prop_type_delete('comment')
698endfunc
699
700func Test_prop_line2byte()
701  call prop_type_add('comment', {'highlight': 'Directory'})
702  new
703  call setline(1, ['line1', 'second line', ''])
704  set ff=unix
705  call assert_equal(19, line2byte(3))
706  call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
707  call assert_equal(19, line2byte(3))
708
709  bwipe!
710  call prop_type_delete('comment')
711endfunc
712
713func Test_prop_byte2line()
714  new
715  set ff=unix
716  call setline(1, ['one one', 'two two', 'three three', 'four four', 'five'])
717  call assert_equal(4, byte2line(line2byte(4)))
718  call assert_equal(5, byte2line(line2byte(5)))
719
720  call prop_type_add('prop', {'highlight': 'Directory'})
721  call prop_add(3, 1, {'length': 5, 'type': 'prop'})
722  call assert_equal(4, byte2line(line2byte(4)))
723  call assert_equal(5, byte2line(line2byte(5)))
724
725  bwipe!
726  call prop_type_delete('prop')
727endfunc
728
729func Test_prop_undo()
730  new
731  call prop_type_add('comment', {'highlight': 'Directory'})
732  call setline(1, ['oneone', 'twotwo', 'three'])
733  " Set 'undolevels' to break changes into undo-able pieces.
734  set ul&
735
736  call prop_add(1, 3, {'end_col': 5, 'type': 'comment'})
737  let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
738  call assert_equal(expected, prop_list(1))
739
740  " Insert a character, then undo.
741  exe "normal 0lllix\<Esc>"
742  set ul&
743  let expected[0].length = 3
744  call assert_equal(expected, prop_list(1))
745  undo
746  let expected[0].length = 2
747  call assert_equal(expected, prop_list(1))
748
749  " Delete a character, then undo
750  exe "normal 0lllx"
751  set ul&
752  let expected[0].length = 1
753  call assert_equal(expected, prop_list(1))
754  undo
755  let expected[0].length = 2
756  call assert_equal(expected, prop_list(1))
757
758  " Delete the line, then undo
759  1d
760  set ul&
761  call assert_equal([], prop_list(1))
762  undo
763  call assert_equal(expected, prop_list(1))
764
765  " Insert a character, delete two characters, then undo with "U"
766  exe "normal 0lllix\<Esc>"
767  set ul&
768  let expected[0].length = 3
769  call assert_equal(expected, prop_list(1))
770  exe "normal 0lllxx"
771  set ul&
772  let expected[0].length = 1
773  call assert_equal(expected, prop_list(1))
774  normal U
775  let expected[0].length = 2
776  call assert_equal(expected, prop_list(1))
777
778  " substitute a word, then undo
779  call setline(1, 'the number 123 is highlighted.')
780  call prop_add(1, 12, {'length': 3, 'type': 'comment'})
781  let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
782  call assert_equal(expected, prop_list(1))
783  set ul&
784  1s/number/foo
785  let expected[0].col = 9
786  call assert_equal(expected, prop_list(1))
787  undo
788  let expected[0].col = 12
789  call assert_equal(expected, prop_list(1))
790  call prop_clear(1)
791
792  " substitute with backslash
793  call setline(1, 'the number 123 is highlighted.')
794  call prop_add(1, 12, {'length': 3, 'type': 'comment'})
795  let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
796  call assert_equal(expected, prop_list(1))
797  1s/the/\The
798  call assert_equal(expected, prop_list(1))
799  1s/^/\\
800  let expected[0].col += 1
801  call assert_equal(expected, prop_list(1))
802  1s/^/\~
803  let expected[0].col += 1
804  call assert_equal(expected, prop_list(1))
805  1s/123/12\\3
806  let expected[0].length += 1
807  call assert_equal(expected, prop_list(1))
808  call prop_clear(1)
809
810  bwipe!
811  call prop_type_delete('comment')
812endfunc
813
814func Test_prop_delete_text()
815  new
816  call prop_type_add('comment', {'highlight': 'Directory'})
817  call setline(1, ['oneone', 'twotwo', 'three'])
818
819  " zero length property
820  call prop_add(1, 3, {'type': 'comment'})
821  let expected = [{'col': 3, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
822  call assert_equal(expected, prop_list(1))
823
824  " delete one char moves the property
825  normal! x
826  let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
827  call assert_equal(expected, prop_list(1))
828
829  " delete char of the property has no effect
830  normal! lx
831  let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
832  call assert_equal(expected, prop_list(1))
833
834  " delete more chars moves property to first column, is not deleted
835  normal! 0xxxx
836  let expected = [{'col': 1, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
837  call assert_equal(expected, prop_list(1))
838
839  bwipe!
840  call prop_type_delete('comment')
841endfunc
842
843" screenshot test with textprop highlighting
844func Test_textprop_screenshot_various()
845  CheckScreendump
846  " The Vim running in the terminal needs to use utf-8.
847  if g:orig_encoding != 'utf-8'
848    throw 'Skipped: not using utf-8'
849  endif
850  call writefile([
851	\ "call setline(1, ["
852	\	.. "'One two',"
853	\	.. "'Numbér 123 änd thœn 4¾7.',"
854	\	.. "'--aa--bb--cc--dd--',"
855	\	.. "'// comment with error in it',"
856	\	.. "'first line',"
857	\	.. "'  second line  ',"
858	\	.. "'third line',"
859	\	.. "'   fourth line',"
860	\	.. "])",
861	\ "hi NumberProp ctermfg=blue",
862	\ "hi LongProp ctermbg=yellow",
863	\ "hi BackgroundProp ctermbg=lightgrey",
864	\ "hi UnderlineProp cterm=underline",
865	\ "call prop_type_add('number', {'highlight': 'NumberProp'})",
866	\ "call prop_type_add('long', {'highlight': 'NumberProp'})",
867	\ "call prop_type_change('long', {'highlight': 'LongProp'})",
868	\ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})",
869	\ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})",
870	\ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})",
871	\ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})",
872	\ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})",
873	\ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})",
874	\ "call prop_type_add('error', {'highlight': 'UnderlineProp'})",
875	\ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})",
876	\ "call prop_add(2, 9, {'length': 3, 'type': 'number'})",
877	\ "call prop_add(2, 24, {'length': 4, 'type': 'number'})",
878	\ "call prop_add(3, 3, {'length': 2, 'type': 'number'})",
879	\ "call prop_add(3, 7, {'length': 2, 'type': 'start'})",
880	\ "call prop_add(3, 11, {'length': 2, 'type': 'end'})",
881	\ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
882	\ "call prop_add(4, 6, {'length': 3, 'type': 'background'})",
883	\ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})",
884	\ "call prop_add(4, 17, {'length': 5, 'type': 'error'})",
885	\ "call prop_add(5, 7, {'length': 4, 'type': 'long'})",
886	\ "call prop_add(6, 1, {'length': 8, 'type': 'long'})",
887	\ "call prop_add(8, 1, {'length': 1, 'type': 'long'})",
888	\ "call prop_add(8, 11, {'length': 4, 'type': 'long'})",
889	\ "set number cursorline",
890	\ "hi clear SpellBad",
891	\ "set spell",
892	\ "syn match Comment '//.*'",
893	\ "hi Comment ctermfg=green",
894	\ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
895	\ "normal 3G0lli\<BS>\<Esc>",
896	\ "normal 6G0i\<BS>\<Esc>",
897	\ "normal 3J",
898	\ "normal 3G",
899	\], 'XtestProp')
900  let buf = RunVimInTerminal('-S XtestProp', {'rows': 8})
901  call VerifyScreenDump(buf, 'Test_textprop_01', {})
902
903  " clean up
904  call StopVimInTerminal(buf)
905  call delete('XtestProp')
906endfunc
907
908func RunTestVisualBlock(width, dump)
909  call writefile([
910	\ "call setline(1, ["
911	\	.. "'xxxxxxxxx 123 x',"
912	\	.. "'xxxxxxxx 123 x',"
913	\	.. "'xxxxxxx 123 x',"
914	\	.. "'xxxxxx 123 x',"
915	\	.. "'xxxxx 123 x',"
916	\	.. "'xxxx 123 xx',"
917	\	.. "'xxx 123 xxx',"
918	\	.. "'xx 123 xxxx',"
919	\	.. "'x 123 xxxxx',"
920	\	.. "' 123 xxxxxx',"
921	\	.. "])",
922	\ "hi SearchProp ctermbg=yellow",
923	\ "call prop_type_add('search', {'highlight': 'SearchProp'})",
924	\ "call prop_add(1, 11, {'length': 3, 'type': 'search'})",
925	\ "call prop_add(2, 10, {'length': 3, 'type': 'search'})",
926	\ "call prop_add(3, 9, {'length': 3, 'type': 'search'})",
927	\ "call prop_add(4, 8, {'length': 3, 'type': 'search'})",
928	\ "call prop_add(5, 7, {'length': 3, 'type': 'search'})",
929	\ "call prop_add(6, 6, {'length': 3, 'type': 'search'})",
930	\ "call prop_add(7, 5, {'length': 3, 'type': 'search'})",
931	\ "call prop_add(8, 4, {'length': 3, 'type': 'search'})",
932	\ "call prop_add(9, 3, {'length': 3, 'type': 'search'})",
933	\ "call prop_add(10, 2, {'length': 3, 'type': 'search'})",
934	\ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx",
935	\], 'XtestPropVis')
936  let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12})
937  call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {})
938
939  " clean up
940  call StopVimInTerminal(buf)
941  call delete('XtestPropVis')
942endfunc
943
944" screenshot test with Visual block mode operations
945func Test_textprop_screenshot_visual()
946  CheckScreendump
947
948  " Delete two columns while text props are three chars wide.
949  call RunTestVisualBlock(2, '01')
950
951  " Same, but delete four columns
952  call RunTestVisualBlock(4, '02')
953endfunc
954
955func Test_textprop_after_tab()
956  CheckScreendump
957
958  let lines =<< trim END
959       call setline(1, [
960             \ "\txxx",
961             \ "x\txxx",
962             \ ])
963       hi SearchProp ctermbg=yellow
964       call prop_type_add('search', {'highlight': 'SearchProp'})
965       call prop_add(1, 2, {'length': 3, 'type': 'search'})
966       call prop_add(2, 3, {'length': 3, 'type': 'search'})
967  END
968  call writefile(lines, 'XtestPropTab')
969  let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6})
970  call VerifyScreenDump(buf, 'Test_textprop_tab', {})
971
972  " clean up
973  call StopVimInTerminal(buf)
974  call delete('XtestPropTab')
975endfunc
976
977func Test_textprop_with_syntax()
978  CheckScreendump
979
980  let lines =<< trim END
981       call setline(1, [
982             \ "(abc)",
983             \ ])
984       syn match csParens "[()]" display
985       hi! link csParens MatchParen
986
987       call prop_type_add('TPTitle', #{ highlight: 'Title' })
988       call prop_add(1, 2, #{type: 'TPTitle', end_col: 5})
989  END
990  call writefile(lines, 'XtestPropSyn')
991  let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6})
992  call VerifyScreenDump(buf, 'Test_textprop_syn_1', {})
993
994  " clean up
995  call StopVimInTerminal(buf)
996  call delete('XtestPropSyn')
997endfunc
998
999" Adding a text property to a new buffer should not fail
1000func Test_textprop_empty_buffer()
1001  call prop_type_add('comment', {'highlight': 'Search'})
1002  new
1003  call prop_add(1, 1, {'type': 'comment'})
1004  close
1005  call prop_type_delete('comment')
1006endfunc
1007
1008" Adding a text property with invalid highlight should be ignored.
1009func Test_textprop_invalid_highlight()
1010  call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:')
1011  new
1012  call setline(1, ['asdf','asdf'])
1013  call prop_add(1, 1, {'length': 4, 'type': 'dni'})
1014  redraw
1015  bwipe!
1016  call prop_type_delete('dni')
1017endfunc
1018
1019" Adding a text property to an empty buffer and then editing another
1020func Test_textprop_empty_buffer_next()
1021  call prop_type_add("xxx", {})
1022  call prop_add(1, 1, {"type": "xxx"})
1023  next X
1024  call prop_type_delete('xxx')
1025endfunc
1026
1027func Test_textprop_remove_from_buf()
1028  new
1029  let buf = bufnr('')
1030  call prop_type_add('one', {'bufnr': buf})
1031  call prop_add(1, 1, {'type': 'one', 'id': 234})
1032  file x
1033  edit y
1034  call prop_remove({'id': 234, 'bufnr': buf}, 1)
1035  call prop_type_delete('one', {'bufnr': buf})
1036  bwipe! x
1037  close
1038endfunc
1039
1040func Test_textprop_in_unloaded_buf()
1041  edit Xaaa
1042  call setline(1, 'aaa')
1043  write
1044  edit Xbbb
1045  call setline(1, 'bbb')
1046  write
1047  let bnr = bufnr('')
1048  edit Xaaa
1049
1050  call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'})
1051  call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:')
1052  exe 'buf ' .. bnr
1053  call assert_equal('bbb', getline(1))
1054  call assert_equal(0, prop_list(1)->len())
1055
1056  bwipe! Xaaa
1057  bwipe! Xbbb
1058  cal delete('Xaaa')
1059  cal delete('Xbbb')
1060endfunc
1061
1062func Test_proptype_substitute2()
1063  new
1064  " text_prop.vim
1065  call setline(1, [
1066        \ 'The   num  123 is smaller than 4567.',
1067        \ '123 The number 123 is smaller than 4567.',
1068        \ '123 The number 123 is smaller than 4567.'])
1069
1070  call prop_type_add('number', {'highlight': 'ErrorMsg'})
1071
1072  call prop_add(1, 12, {'length': 3, 'type': 'number'})
1073  call prop_add(2, 1, {'length': 3, 'type': 'number'})
1074  call prop_add(3, 36, {'length': 4, 'type': 'number'})
1075  set ul&
1076  let expected = [{'id': 0, 'col': 13, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1077        \ {'id': 0, 'col': 1, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1078        \ {'id': 0, 'col': 50, 'end': 1, 'type': 'number', 'length': 4, 'start': 1}]
1079  " Add some text in between
1080  %s/\s\+/   /g
1081  call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3))
1082
1083  " remove some text
1084  :1s/[a-z]\{3\}//g
1085  let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}]
1086  call assert_equal(expected, prop_list(1))
1087  bwipe!
1088endfunc
1089
1090func SaveOptions()
1091  let d = #{tabstop: &tabstop,
1092	  \ softtabstop: &softtabstop,
1093	  \ shiftwidth: &shiftwidth,
1094	  \ expandtab: &expandtab,
1095	  \ foldmethod: '"' .. &foldmethod .. '"',
1096	  \ }
1097  return d
1098endfunc
1099
1100func RestoreOptions(dict)
1101  for name in keys(a:dict)
1102    exe 'let &' .. name .. ' = ' .. a:dict[name]
1103  endfor
1104endfunc
1105
1106func Test_textprop_noexpandtab()
1107  new
1108  let save_dict = SaveOptions()
1109
1110  set tabstop=8
1111  set softtabstop=4
1112  set shiftwidth=4
1113  set noexpandtab
1114  set foldmethod=marker
1115
1116  call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx")
1117  call prop_type_add('test', {'highlight': 'ErrorMsg'})
1118  call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1119  call feedkeys("0i\<tab>", "tx")
1120  call prop_remove({'type': 'test'})
1121  call prop_add(1, 2, {'end_col': 3, 'type': 'test'})
1122  call feedkeys("A\<left>\<tab>", "tx")
1123  call prop_remove({'type': 'test'})
1124  try
1125    " It is correct that this does not pass
1126    call prop_add(1, 6, {'end_col': 7, 'type': 'test'})
1127    " Has already collapsed here, start_col:6 does not result in an error
1128    call feedkeys("A\<left>\<tab>", "tx")
1129  catch /^Vim\%((\a\+)\)\=:E964/
1130  endtry
1131  call prop_remove({'type': 'test'})
1132  call prop_type_delete('test')
1133
1134  call RestoreOptions(save_dict)
1135  bwipe!
1136endfunc
1137
1138func Test_textprop_noexpandtab_redraw()
1139  new
1140  let save_dict = SaveOptions()
1141
1142  set tabstop=8
1143  set softtabstop=4
1144  set shiftwidth=4
1145  set noexpandtab
1146  set foldmethod=marker
1147
1148  call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx")
1149  call prop_type_add('test', {'highlight': 'ErrorMsg'})
1150  call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1151  call feedkeys("0i\<tab>", "tx")
1152  " Internally broken at the next line
1153  call feedkeys("A\<left>\<tab>", "tx")
1154  redraw
1155  " Index calculation failed internally on next line
1156  call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1157  call prop_remove({'type': 'test', 'all': v:true})
1158  call prop_type_delete('test')
1159  call prop_type_delete('test')
1160
1161  call RestoreOptions(save_dict)
1162  bwipe!
1163endfunc
1164
1165func Test_textprop_ins_str()
1166  new
1167  call setline(1, 'just some text')
1168  call prop_type_add('test', {'highlight': 'ErrorMsg'})
1169  call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1170  call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1171
1172  call feedkeys("foi\<F8>\<Esc>", "tx")
1173  call assert_equal('just s<F8>ome text', getline(1))
1174  call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1175
1176  bwipe!
1177  call prop_remove({'type': 'test'})
1178  call prop_type_delete('test')
1179endfunc
1180
1181func Test_find_prop_later_in_line()
1182  new
1183  call prop_type_add('test', {'highlight': 'ErrorMsg'})
1184  call setline(1, 'just some text')
1185  call prop_add(1, 1, {'length': 4, 'type': 'test'})
1186  call prop_add(1, 10, {'length': 3, 'type': 'test'})
1187
1188  call assert_equal({'id': 0, 'lnum': 1, 'col': 10, 'end': 1, 'type': 'test', 'length': 3, 'start': 1},
1189			  \ prop_find(#{type: 'test', lnum: 1, col: 6}))
1190
1191  bwipe!
1192  call prop_type_delete('test')
1193endfunc
1194
1195func Test_find_zerowidth_prop_sol()
1196  new
1197  call prop_type_add('test', {'highlight': 'ErrorMsg'})
1198  call setline(1, 'just some text')
1199  call prop_add(1, 1, {'length': 0, 'type': 'test'})
1200
1201  call assert_equal({'id': 0, 'lnum': 1, 'col': 1, 'end': 1, 'type': 'test', 'length': 0, 'start': 1},
1202			  \ prop_find(#{type: 'test', lnum: 1}))
1203
1204  bwipe!
1205  call prop_type_delete('test')
1206endfunc
1207