1" Tests for defining text property types and adding text properties to the
2" buffer.
3
4if !has('textprop')
5  finish
6endif
7
8source screendump.vim
9
10" test length zero
11
12func Test_proptype_global()
13  call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
14  let proptypes = prop_type_list()
15  call assert_equal(1, len(proptypes))
16  call assert_equal('comment', proptypes[0])
17
18  let proptype = prop_type_get('comment')
19  call assert_equal('Directory', proptype['highlight'])
20  call assert_equal(123, proptype['priority'])
21  call assert_equal(1, proptype['start_incl'])
22  call assert_equal(1, proptype['end_incl'])
23
24  call prop_type_delete('comment')
25  call assert_equal(0, len(prop_type_list()))
26
27  call prop_type_add('one', {})
28  call assert_equal(1, len(prop_type_list()))
29  let proptype = prop_type_get('one')
30  call assert_false(has_key(proptype, 'highlight'))
31  call assert_equal(0, proptype['priority'])
32  call assert_equal(0, proptype['start_incl'])
33  call assert_equal(0, proptype['end_incl'])
34
35  call prop_type_add('two', {})
36  call assert_equal(2, len(prop_type_list()))
37  call prop_type_delete('one')
38  call assert_equal(1, len(prop_type_list()))
39  call prop_type_delete('two')
40  call assert_equal(0, len(prop_type_list()))
41endfunc
42
43func Test_proptype_buf()
44  let bufnr = bufnr('')
45  call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
46  let proptypes = prop_type_list({'bufnr': bufnr})
47  call assert_equal(1, len(proptypes))
48  call assert_equal('comment', proptypes[0])
49
50  let proptype = prop_type_get('comment', {'bufnr': bufnr})
51  call assert_equal('Directory', proptype['highlight'])
52  call assert_equal(123, proptype['priority'])
53  call assert_equal(1, proptype['start_incl'])
54  call assert_equal(1, proptype['end_incl'])
55
56  call prop_type_delete('comment', {'bufnr': bufnr})
57  call assert_equal(0, len(prop_type_list({'bufnr': bufnr})))
58
59  call prop_type_add('one', {'bufnr': bufnr})
60  let proptype = prop_type_get('one', {'bufnr': bufnr})
61  call assert_false(has_key(proptype, 'highlight'))
62  call assert_equal(0, proptype['priority'])
63  call assert_equal(0, proptype['start_incl'])
64  call assert_equal(0, proptype['end_incl'])
65
66  call prop_type_add('two', {'bufnr': bufnr})
67  call assert_equal(2, len(prop_type_list({'bufnr': bufnr})))
68  call prop_type_delete('one', {'bufnr': bufnr})
69  call assert_equal(1, len(prop_type_list({'bufnr': bufnr})))
70  call prop_type_delete('two', {'bufnr': bufnr})
71  call assert_equal(0, len(prop_type_list({'bufnr': bufnr})))
72
73  call assert_fails("call prop_type_add('one', {'bufnr': 98764})", "E158:")
74endfunc
75
76func AddPropTypes()
77  call prop_type_add('one', {})
78  call prop_type_add('two', {})
79  call prop_type_add('three', {})
80  call prop_type_add('whole', {})
81endfunc
82
83func DeletePropTypes()
84  call prop_type_delete('one')
85  call prop_type_delete('two')
86  call prop_type_delete('three')
87  call prop_type_delete('whole')
88endfunc
89
90func SetupPropsInFirstLine()
91  call setline(1, 'one two three')
92  call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'})
93  call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two'})
94  call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'})
95  call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'})
96endfunc
97
98func Get_expected_props()
99  return [
100      \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1},
101      \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
102      \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
103      \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
104      \ ]
105endfunc
106
107func Test_prop_add()
108  new
109  call AddPropTypes()
110  call SetupPropsInFirstLine()
111  let expected_props = Get_expected_props()
112  call assert_equal(expected_props, prop_list(1))
113  call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:')
114  call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:')
115
116  " Insert a line above, text props must still be there.
117  call append(0, 'empty')
118  call assert_equal(expected_props, prop_list(2))
119  " Delete a line above, text props must still be there.
120  1del
121  call assert_equal(expected_props, prop_list(1))
122
123  " Prop without length or end column is zero length
124  call prop_clear(1)
125  call prop_add(1, 5, {'type': 'two'})
126  let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}]
127  call assert_equal(expected, prop_list(1))
128
129  call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:')
130
131  call DeletePropTypes()
132  bwipe!
133endfunc
134
135func Test_prop_remove()
136  new
137  call AddPropTypes()
138  call SetupPropsInFirstLine()
139  let props = Get_expected_props()
140  call assert_equal(props, prop_list(1))
141
142  " remove by id
143  call assert_equal(1, prop_remove({'id': 12}, 1))
144  unlet props[2]
145  call assert_equal(props, prop_list(1))
146
147  " remove by type
148  call assert_equal(1, prop_remove({'type': 'one'}, 1))
149  unlet props[1]
150  call assert_equal(props, prop_list(1))
151
152  " remove from unknown buffer
153  call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:')
154
155  call DeletePropTypes()
156  bwipe!
157endfunc
158
159func SetupOneLine()
160  call setline(1, 'xonex xtwoxx')
161  normal gg0
162  call AddPropTypes()
163  call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
164  call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
165  let expected = [
166	\ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
167	\ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
168	\]
169  call assert_equal(expected, prop_list(1))
170  return expected
171endfunc
172
173func Test_prop_add_remove_buf()
174  new
175  let bufnr = bufnr('')
176  call AddPropTypes()
177  for lnum in range(1, 4)
178    call setline(lnum, 'one two three')
179  endfor
180  wincmd w
181  for lnum in range(1, 4)
182    call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr})
183    call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr})
184    call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr})
185  endfor
186
187  let props = [
188	\ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
189	\ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
190	\ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
191	\]
192  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
193
194  " remove by id
195  let before_props = deepcopy(props)
196  unlet props[1]
197
198  call prop_remove({'id': 12, 'bufnr': bufnr}, 1)
199  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
200  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
201  call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
202  call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
203
204  call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4)
205  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
206  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
207  call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
208  call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
209
210  call prop_remove({'id': 12, 'bufnr': bufnr})
211  for lnum in range(1, 4)
212    call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
213  endfor
214
215  " remove by type
216  let before_props = deepcopy(props)
217  unlet props[0]
218
219  call prop_remove({'type': 'one', 'bufnr': bufnr}, 1)
220  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
221  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
222  call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
223  call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
224
225  call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4)
226  call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
227  call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
228  call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
229  call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
230
231  call prop_remove({'type': 'one', 'bufnr': bufnr})
232  for lnum in range(1, 4)
233    call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
234  endfor
235
236  call DeletePropTypes()
237  wincmd w
238  bwipe!
239endfunc
240
241func Test_prop_backspace()
242  new
243  set bs=2
244  let expected = SetupOneLine() " 'xonex xtwoxx'
245
246  exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>"
247  call assert_equal('one xtwoxx', getline(1))
248  let expected[0].col = 1
249  let expected[1].col = 6
250  call assert_equal(expected, prop_list(1))
251
252  call DeletePropTypes()
253  bwipe!
254  set bs&
255endfunc
256
257func Test_prop_replace()
258  new
259  set bs=2
260  let expected = SetupOneLine() " 'xonex xtwoxx'
261
262  exe "normal 0Ryyy\<Esc>"
263  call assert_equal('yyyex xtwoxx', getline(1))
264  call assert_equal(expected, prop_list(1))
265
266  exe "normal ftRyy\<BS>"
267  call assert_equal('yyyex xywoxx', getline(1))
268  call assert_equal(expected, prop_list(1))
269
270  exe "normal 0fwRyy\<BS>"
271  call assert_equal('yyyex xyyoxx', getline(1))
272  call assert_equal(expected, prop_list(1))
273
274  exe "normal 0foRyy\<BS>\<BS>"
275  call assert_equal('yyyex xyyoxx', getline(1))
276  call assert_equal(expected, prop_list(1))
277
278  call DeletePropTypes()
279  bwipe!
280  set bs&
281endfunc
282
283func Test_prop_open_line()
284  new
285
286  " open new line, props stay in top line
287  let expected = SetupOneLine() " 'xonex xtwoxx'
288  exe "normal o\<Esc>"
289  call assert_equal('xonex xtwoxx', getline(1))
290  call assert_equal('', getline(2))
291  call assert_equal(expected, prop_list(1))
292  call DeletePropTypes()
293
294  " move all props to next line
295  let expected = SetupOneLine() " 'xonex xtwoxx'
296  exe "normal 0i\<CR>\<Esc>"
297  call assert_equal('', getline(1))
298  call assert_equal('xonex xtwoxx', getline(2))
299  call assert_equal(expected, prop_list(2))
300  call DeletePropTypes()
301
302  " split just before prop, move all props to next line
303  let expected = SetupOneLine() " 'xonex xtwoxx'
304  exe "normal 0li\<CR>\<Esc>"
305  call assert_equal('x', getline(1))
306  call assert_equal('onex xtwoxx', getline(2))
307  let expected[0].col -= 1
308  let expected[1].col -= 1
309  call assert_equal(expected, prop_list(2))
310  call DeletePropTypes()
311
312  " split inside prop, split first prop
313  let expected = SetupOneLine() " 'xonex xtwoxx'
314  exe "normal 0lli\<CR>\<Esc>"
315  call assert_equal('xo', getline(1))
316  call assert_equal('nex xtwoxx', getline(2))
317  let exp_first = [deepcopy(expected[0])]
318  let exp_first[0].length = 1
319  call assert_equal(exp_first, prop_list(1))
320  let expected[0].col = 1
321  let expected[0].length = 2
322  let expected[1].col -= 2
323  call assert_equal(expected, prop_list(2))
324  call DeletePropTypes()
325
326  " split just after first prop, second prop move to next line
327  let expected = SetupOneLine() " 'xonex xtwoxx'
328  exe "normal 0fea\<CR>\<Esc>"
329  call assert_equal('xone', getline(1))
330  call assert_equal('x xtwoxx', getline(2))
331  let exp_first = expected[0:0]
332  call assert_equal(exp_first, prop_list(1))
333  let expected = expected[1:1]
334  let expected[0].col -= 4
335  call assert_equal(expected, prop_list(2))
336  call DeletePropTypes()
337
338  bwipe!
339  set bs&
340endfunc
341
342func Test_prop_clear()
343  new
344  call AddPropTypes()
345  call SetupPropsInFirstLine()
346  call assert_equal(Get_expected_props(), prop_list(1))
347
348  call prop_clear(1)
349  call assert_equal([], prop_list(1))
350
351  call DeletePropTypes()
352  bwipe!
353endfunc
354
355func Test_prop_clear_buf()
356  new
357  call AddPropTypes()
358  call SetupPropsInFirstLine()
359  let bufnr = bufnr('')
360  wincmd w
361  call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
362
363  call prop_clear(1, 1, {'bufnr': bufnr})
364  call assert_equal([], prop_list(1, {'bufnr': bufnr}))
365
366  wincmd w
367  call DeletePropTypes()
368  bwipe!
369endfunc
370
371func Test_prop_setline()
372  new
373  call AddPropTypes()
374  call SetupPropsInFirstLine()
375  call assert_equal(Get_expected_props(), prop_list(1))
376
377  call setline(1, 'foobar')
378  call assert_equal([], prop_list(1))
379
380  call DeletePropTypes()
381  bwipe!
382endfunc
383
384func Test_prop_setbufline()
385  new
386  call AddPropTypes()
387  call SetupPropsInFirstLine()
388  let bufnr = bufnr('')
389  wincmd w
390  call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
391
392  call setbufline(bufnr, 1, 'foobar')
393  call assert_equal([], prop_list(1, {'bufnr': bufnr}))
394
395  wincmd w
396  call DeletePropTypes()
397  bwipe!
398endfunc
399
400func Test_prop_substitute()
401  new
402  " Set first line to 'one two three'
403  call AddPropTypes()
404  call SetupPropsInFirstLine()
405  let expected_props = Get_expected_props()
406  call assert_equal(expected_props, prop_list(1))
407
408  " Change "n" in "one" to XX: 'oXXe two three'
409  s/n/XX/
410  let expected_props[0].length += 1
411  let expected_props[1].length += 1
412  let expected_props[2].col += 1
413  let expected_props[3].col += 1
414  call assert_equal(expected_props, prop_list(1))
415
416  " Delete "t" in "two" and "three" to XX: 'oXXe wo hree'
417  s/t//g
418  let expected_props[0].length -= 2
419  let expected_props[2].length -= 1
420  let expected_props[3].length -= 1
421  let expected_props[3].col -= 1
422  call assert_equal(expected_props, prop_list(1))
423
424  " Split the line by changing w to line break: 'oXXe ', 'o hree'
425  " The long prop is split and spans both lines.
426  " The props on "two" and "three" move to the next line.
427  s/w/\r/
428  let new_props = [
429	\ copy(expected_props[0]),
430	\ copy(expected_props[2]),
431	\ copy(expected_props[3]),
432	\ ]
433  let expected_props[0].length = 5
434  unlet expected_props[3]
435  unlet expected_props[2]
436  call assert_equal(expected_props, prop_list(1))
437
438  let new_props[0].length = 6
439  let new_props[1].col = 1
440  let new_props[1].length = 1
441  let new_props[2].col = 3
442  call assert_equal(new_props, prop_list(2))
443
444  call DeletePropTypes()
445  bwipe!
446endfunc
447
448func Test_prop_change_indent()
449  call prop_type_add('comment', {'highlight': 'Directory'})
450  new
451  call setline(1, ['    xxx', 'yyyyy'])
452  call prop_add(2, 2, {'length': 2, 'type': 'comment'})
453  let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
454  call assert_equal([expect], prop_list(2))
455
456  set shiftwidth=3
457  normal 2G>>
458  call assert_equal('   yyyyy', getline(2))
459  let expect.col += 3
460  call assert_equal([expect], prop_list(2))
461
462  normal 2G==
463  call assert_equal('    yyyyy', getline(2))
464  let expect.col = 6
465  call assert_equal([expect], prop_list(2))
466
467  call prop_clear(2)
468  call prop_add(2, 2, {'length': 5, 'type': 'comment'})
469  let expect.col = 2
470  let expect.length = 5
471  call assert_equal([expect], prop_list(2))
472
473  normal 2G<<
474  call assert_equal(' yyyyy', getline(2))
475  let expect.length = 2
476  call assert_equal([expect], prop_list(2))
477
478  set shiftwidth&
479  call prop_type_delete('comment')
480endfunc
481
482" Setup a three line prop in lines 2 - 4.
483" Add short props in line 1 and 5.
484func Setup_three_line_prop()
485  new
486  call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five'])
487  call prop_add(1, 2, {'length': 1, 'type': 'comment'})
488  call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'})
489  call prop_add(5, 2, {'length': 1, 'type': 'comment'})
490endfunc
491
492func Test_prop_multiline()
493  call prop_type_add('comment', {'highlight': 'Directory'})
494  new
495  call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz'])
496
497  " start halfway line 1, end halfway line 3
498  call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'})
499  let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
500  call assert_equal([expect1], prop_list(1))
501  let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
502  call assert_equal([expect2], prop_list(2))
503  let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
504  call assert_equal([expect3], prop_list(3))
505  call prop_clear(1, 3)
506
507  " include all three lines
508  call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'})
509  let expect1.col = 1
510  let expect1.length = 8
511  call assert_equal([expect1], prop_list(1))
512  call assert_equal([expect2], prop_list(2))
513  let expect3.length = 9
514  call assert_equal([expect3], prop_list(3))
515  call prop_clear(1, 3)
516
517  bwipe!
518
519  " Test deleting the first line of a multi-line prop.
520  call Setup_three_line_prop()
521  let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
522  call assert_equal([expect_short], prop_list(1))
523  let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
524  call assert_equal([expect2], prop_list(2))
525  2del
526  call assert_equal([expect_short], prop_list(1))
527  let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
528  call assert_equal([expect2], prop_list(2))
529  bwipe!
530
531  " Test deleting the last line of a multi-line prop.
532  call Setup_three_line_prop()
533  let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
534  call assert_equal([expect3], prop_list(3))
535  let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
536  call assert_equal([expect4], prop_list(4))
537  4del
538  let expect3.end = 1
539  call assert_equal([expect3], prop_list(3))
540  call assert_equal([expect_short], prop_list(4))
541  bwipe!
542
543  " Test appending a line below the multi-line text prop start.
544  call Setup_three_line_prop()
545  let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
546  call assert_equal([expect2], prop_list(2))
547  call append(2, "new line")
548  call assert_equal([expect2], prop_list(2))
549  let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
550  call assert_equal([expect3], prop_list(3))
551  bwipe!
552
553  call prop_type_delete('comment')
554endfunc
555
556func Test_prop_byteoff()
557  call prop_type_add('comment', {'highlight': 'Directory'})
558  new
559  call setline(1, ['line1', 'second line', ''])
560  set ff=unix
561  call assert_equal(19, line2byte(3))
562  call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
563  call assert_equal(19, line2byte(3))
564
565  bwipe!
566  call prop_type_delete('comment')
567endfunc
568
569func Test_prop_undo()
570  new
571  call prop_type_add('comment', {'highlight': 'Directory'})
572  call setline(1, ['oneone', 'twotwo', 'three'])
573  " Set 'undolevels' to break changes into undo-able pieces.
574  set ul&
575
576  call prop_add(1, 3, {'end_col': 5, 'type': 'comment'})
577  let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
578  call assert_equal(expected, prop_list(1))
579
580  " Insert a character, then undo.
581  exe "normal 0lllix\<Esc>"
582  set ul&
583  let expected[0].length = 3
584  call assert_equal(expected, prop_list(1))
585  undo
586  let expected[0].length = 2
587  call assert_equal(expected, prop_list(1))
588
589  " Delete a character, then undo
590  exe "normal 0lllx"
591  set ul&
592  let expected[0].length = 1
593  call assert_equal(expected, prop_list(1))
594  undo
595  let expected[0].length = 2
596  call assert_equal(expected, prop_list(1))
597
598  " Delete the line, then undo
599  1d
600  set ul&
601  call assert_equal([], prop_list(1))
602  undo
603  call assert_equal(expected, prop_list(1))
604
605  " Insert a character, delete two characters, then undo with "U"
606  exe "normal 0lllix\<Esc>"
607  set ul&
608  let expected[0].length = 3
609  call assert_equal(expected, prop_list(1))
610  exe "normal 0lllxx"
611  set ul&
612  let expected[0].length = 1
613  call assert_equal(expected, prop_list(1))
614  normal U
615  let expected[0].length = 2
616  call assert_equal(expected, prop_list(1))
617
618  " substitute a word, then undo
619  call setline(1, 'the number 123 is highlighted.')
620  call prop_add(1, 12, {'length': 3, 'type': 'comment'})
621  let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
622  call assert_equal(expected, prop_list(1))
623  set ul&
624  1s/number/foo
625  let expected[0].col = 9
626  call assert_equal(expected, prop_list(1))
627  undo
628  let expected[0].col = 12
629  call assert_equal(expected, prop_list(1))
630  call prop_clear(1)
631
632  " substitute with backslash
633  call setline(1, 'the number 123 is highlighted.')
634  call prop_add(1, 12, {'length': 3, 'type': 'comment'})
635  let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
636  call assert_equal(expected, prop_list(1))
637  1s/the/\The
638  call assert_equal(expected, prop_list(1))
639  1s/^/\\
640  let expected[0].col += 1
641  call assert_equal(expected, prop_list(1))
642  1s/^/\~
643  let expected[0].col += 1
644  call assert_equal(expected, prop_list(1))
645  1s/123/12\\3
646  let expected[0].length += 1
647  call assert_equal(expected, prop_list(1))
648  call prop_clear(1)
649
650  bwipe!
651  call prop_type_delete('comment')
652endfunc
653
654" screenshot test with textprop highlighting
655func Test_textprop_screenshot_various()
656  " The Vim running in the terminal needs to use utf-8.
657  if !CanRunVimInTerminal() || g:orig_encoding != 'utf-8'
658    throw 'Skipped: cannot make screendumps or not using utf-8'
659  endif
660  call writefile([
661	\ "call setline(1, ["
662	\	.. "'One two',"
663	\	.. "'Numbér 123 änd thœn 4¾7.',"
664	\	.. "'--aa--bb--cc--dd--',"
665	\	.. "'// comment with error in it',"
666	\	.. "'first line',"
667	\	.. "'  second line  ',"
668	\	.. "'third line',"
669	\	.. "'   fourth line',"
670	\	.. "])",
671	\ "hi NumberProp ctermfg=blue",
672	\ "hi LongProp ctermbg=yellow",
673	\ "hi BackgroundProp ctermbg=lightgrey",
674	\ "hi UnderlineProp cterm=underline",
675	\ "call prop_type_add('number', {'highlight': 'NumberProp'})",
676	\ "call prop_type_add('long', {'highlight': 'LongProp'})",
677	\ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})",
678	\ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})",
679	\ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})",
680	\ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 1})",
681	\ "call prop_type_add('error', {'highlight': 'UnderlineProp', 'combine': 1})",
682	\ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})",
683	\ "call prop_add(2, 9, {'length': 3, 'type': 'number'})",
684	\ "call prop_add(2, 24, {'length': 4, 'type': 'number'})",
685	\ "call prop_add(3, 3, {'length': 2, 'type': 'number'})",
686	\ "call prop_add(3, 7, {'length': 2, 'type': 'start'})",
687	\ "call prop_add(3, 11, {'length': 2, 'type': 'end'})",
688	\ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
689	\ "call prop_add(4, 12, {'length': 10, 'type': 'background'})",
690	\ "call prop_add(4, 17, {'length': 5, 'type': 'error'})",
691	\ "call prop_add(5, 7, {'length': 4, 'type': 'long'})",
692	\ "call prop_add(6, 1, {'length': 8, 'type': 'long'})",
693	\ "call prop_add(8, 1, {'length': 1, 'type': 'long'})",
694	\ "call prop_add(8, 11, {'length': 4, 'type': 'long'})",
695	\ "set number cursorline",
696	\ "hi clear SpellBad",
697	\ "set spell",
698	\ "syn match Comment '//.*'",
699	\ "hi Comment ctermfg=green",
700	\ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
701	\ "normal 3G0lli\<BS>\<Esc>",
702	\ "normal 6G0i\<BS>\<Esc>",
703	\ "normal 3J",
704	\ "normal 3G",
705	\], 'XtestProp')
706  let buf = RunVimInTerminal('-S XtestProp', {'rows': 8})
707  call VerifyScreenDump(buf, 'Test_textprop_01', {})
708
709  " clean up
710  call StopVimInTerminal(buf)
711  call delete('XtestProp')
712endfunc
713
714func RunTestVisualBlock(width, dump)
715  call writefile([
716	\ "call setline(1, ["
717	\	.. "'xxxxxxxxx 123 x',"
718	\	.. "'xxxxxxxx 123 x',"
719	\	.. "'xxxxxxx 123 x',"
720	\	.. "'xxxxxx 123 x',"
721	\	.. "'xxxxx 123 x',"
722	\	.. "'xxxx 123 xx',"
723	\	.. "'xxx 123 xxx',"
724	\	.. "'xx 123 xxxx',"
725	\	.. "'x 123 xxxxx',"
726	\	.. "' 123 xxxxxx',"
727	\	.. "])",
728	\ "hi SearchProp ctermbg=yellow",
729	\ "call prop_type_add('search', {'highlight': 'SearchProp'})",
730	\ "call prop_add(1, 11, {'length': 3, 'type': 'search'})",
731	\ "call prop_add(2, 10, {'length': 3, 'type': 'search'})",
732	\ "call prop_add(3, 9, {'length': 3, 'type': 'search'})",
733	\ "call prop_add(4, 8, {'length': 3, 'type': 'search'})",
734	\ "call prop_add(5, 7, {'length': 3, 'type': 'search'})",
735	\ "call prop_add(6, 6, {'length': 3, 'type': 'search'})",
736	\ "call prop_add(7, 5, {'length': 3, 'type': 'search'})",
737	\ "call prop_add(8, 4, {'length': 3, 'type': 'search'})",
738	\ "call prop_add(9, 3, {'length': 3, 'type': 'search'})",
739	\ "call prop_add(10, 2, {'length': 3, 'type': 'search'})",
740	\ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx",
741	\], 'XtestPropVis')
742  let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12})
743  call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {})
744
745  " clean up
746  call StopVimInTerminal(buf)
747  call delete('XtestPropVis')
748endfunc
749
750" screenshot test with Visual block mode operations
751func Test_textprop_screenshot_visual()
752  if !CanRunVimInTerminal()
753    throw 'Skipped: cannot make screendumps'
754  endif
755
756  " Delete two columns while text props are three chars wide.
757  call RunTestVisualBlock(2, '01')
758
759  " Same, but delete four columns
760  call RunTestVisualBlock(4, '02')
761endfunc
762
763" Adding a text property to a new buffer should not fail
764func Test_textprop_empty_buffer()
765  call prop_type_add('comment', {'highlight': 'Search'})
766  new
767  call prop_add(1, 1, {'type': 'comment'})
768  close
769  call prop_type_delete('comment')
770endfunc
771
772" Adding a text property to an empty buffer and then editing another
773func Test_textprop_empty_buffer_next()
774  call prop_type_add("xxx", {})
775  call prop_add(1, 1, {"type": "xxx"})
776  next X
777  call prop_type_delete('xxx')
778endfunc
779
780func Test_textprop_remove_from_buf()
781  new
782  let buf = bufnr('')
783  call prop_type_add('one', {'bufnr': buf})
784  call prop_add(1, 1, {'type': 'one', 'id': 234})
785  file x
786  edit y
787  call prop_remove({'id': 234, 'bufnr': buf}, 1)
788  call prop_type_delete('one', {'bufnr': buf})
789  bwipe! x
790  close
791endfunc
792