blob: 32001b3622b576ff5a30a606c1721a369a1e2c8b [file] [log] [blame]
Bram Moolenaar98aefe72018-12-13 22:20:09 +01001" Tests for defining text property types and adding text properties to the
2" buffer.
3
Bram Moolenaarb46fecd2019-06-15 17:58:09 +02004source check.vim
5CheckFeature textprop
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +01007source screendump.vim
8
Bram Moolenaarb9c67a52019-01-01 19:49:20 +01009" test length zero
10
Bram Moolenaar98aefe72018-12-13 22:20:09 +010011func Test_proptype_global()
12 call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
13 let proptypes = prop_type_list()
14 call assert_equal(1, len(proptypes))
15 call assert_equal('comment', proptypes[0])
16
17 let proptype = prop_type_get('comment')
18 call assert_equal('Directory', proptype['highlight'])
19 call assert_equal(123, proptype['priority'])
20 call assert_equal(1, proptype['start_incl'])
21 call assert_equal(1, proptype['end_incl'])
22
23 call prop_type_delete('comment')
24 call assert_equal(0, len(prop_type_list()))
25
26 call prop_type_add('one', {})
27 call assert_equal(1, len(prop_type_list()))
Bram Moolenaara5a78822019-09-04 21:57:18 +020028 let proptype = 'one'->prop_type_get()
Bram Moolenaar98aefe72018-12-13 22:20:09 +010029 call assert_false(has_key(proptype, 'highlight'))
30 call assert_equal(0, proptype['priority'])
31 call assert_equal(0, proptype['start_incl'])
32 call assert_equal(0, proptype['end_incl'])
33
34 call prop_type_add('two', {})
35 call assert_equal(2, len(prop_type_list()))
36 call prop_type_delete('one')
37 call assert_equal(1, len(prop_type_list()))
38 call prop_type_delete('two')
39 call assert_equal(0, len(prop_type_list()))
40endfunc
41
42func Test_proptype_buf()
43 let bufnr = bufnr('')
44 call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1})
45 let proptypes = prop_type_list({'bufnr': bufnr})
46 call assert_equal(1, len(proptypes))
47 call assert_equal('comment', proptypes[0])
48
49 let proptype = prop_type_get('comment', {'bufnr': bufnr})
50 call assert_equal('Directory', proptype['highlight'])
51 call assert_equal(123, proptype['priority'])
52 call assert_equal(1, proptype['start_incl'])
53 call assert_equal(1, proptype['end_incl'])
54
55 call prop_type_delete('comment', {'bufnr': bufnr})
Bram Moolenaara5a78822019-09-04 21:57:18 +020056 call assert_equal(0, len({'bufnr': bufnr}->prop_type_list()))
Bram Moolenaar98aefe72018-12-13 22:20:09 +010057
58 call prop_type_add('one', {'bufnr': bufnr})
59 let proptype = prop_type_get('one', {'bufnr': bufnr})
60 call assert_false(has_key(proptype, 'highlight'))
61 call assert_equal(0, proptype['priority'])
62 call assert_equal(0, proptype['start_incl'])
63 call assert_equal(0, proptype['end_incl'])
64
65 call prop_type_add('two', {'bufnr': bufnr})
66 call assert_equal(2, len(prop_type_list({'bufnr': bufnr})))
67 call prop_type_delete('one', {'bufnr': bufnr})
68 call assert_equal(1, len(prop_type_list({'bufnr': bufnr})))
69 call prop_type_delete('two', {'bufnr': bufnr})
70 call assert_equal(0, len(prop_type_list({'bufnr': bufnr})))
Bram Moolenaarf0884c52019-05-24 21:22:29 +020071
72 call assert_fails("call prop_type_add('one', {'bufnr': 98764})", "E158:")
Bram Moolenaar98aefe72018-12-13 22:20:09 +010073endfunc
74
75func AddPropTypes()
76 call prop_type_add('one', {})
77 call prop_type_add('two', {})
78 call prop_type_add('three', {})
79 call prop_type_add('whole', {})
80endfunc
81
82func DeletePropTypes()
83 call prop_type_delete('one')
84 call prop_type_delete('two')
85 call prop_type_delete('three')
86 call prop_type_delete('whole')
87endfunc
88
89func SetupPropsInFirstLine()
90 call setline(1, 'one two three')
91 call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'})
Bram Moolenaara5a78822019-09-04 21:57:18 +020092 eval 1->prop_add(5, {'length': 3, 'id': 12, 'type': 'two'})
Bram Moolenaar4164bb22019-01-04 23:09:49 +010093 call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'})
Bram Moolenaar98aefe72018-12-13 22:20:09 +010094 call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'})
95endfunc
96
Bram Moolenaar4164bb22019-01-04 23:09:49 +010097func Get_expected_props()
98 return [
99 \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100100 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
101 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100102 \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100103 \ ]
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100104endfunc
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100105
Bram Moolenaare05a89a2020-01-10 19:56:46 +0100106func Test_prop_find()
107 new
108 call setline(1, ['one one one', 'twotwo', 'three', 'fourfour', 'five', 'sixsix'])
109
110 " Add two text props on lines 1 and 5, and one spanning lines 2 to 4.
111 call prop_type_add('prop_name', {'highlight': 'Directory'})
112 call prop_add(1, 5, {'type': 'prop_name', 'id': 10, 'length': 3})
113 call prop_add(2, 4, {'type': 'prop_name', 'id': 11, 'end_lnum': 4, 'end_col': 9})
114 call prop_add(5, 4, {'type': 'prop_name', 'id': 12, 'length': 1})
115
116 let expected = [
117 \ {'lnum': 1, 'col': 5, 'length': 3, 'id': 10, 'type': 'prop_name', 'start': 1, 'end': 1},
118 \ {'lnum': 2, 'col': 4, 'id': 11, 'type': 'prop_name', 'start': 1, 'end': 0},
119 \ {'lnum': 5, 'col': 4, 'length': 1, 'id': 12, 'type': 'prop_name', 'start': 1, 'end': 1}
120 \ ]
121
122 " Starting at line 5 col 1 this should find the prop at line 5 col 4.
123 call cursor(5,1)
124 let result = prop_find({'type': 'prop_name'}, 'f')
125 call assert_equal(expected[2], result)
126
127 " With skipstart left at false (default), this should find the prop at line
128 " 5 col 4.
129 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4}, 'b')
130 call assert_equal(expected[2], result)
131
132 " With skipstart set to true, this should skip the prop at line 5 col 4.
133 let result = prop_find({'type': 'prop_name', 'lnum': 5, 'col': 4, 'skipstart': 1}, 'b')
134 unlet result.length
135 call assert_equal(expected[1], result)
136
137 " Search backwards from line 1 col 10 to find the prop on the same line.
138 let result = prop_find({'type': 'prop_name', 'lnum': 1, 'col': 10}, 'b')
139 call assert_equal(expected[0], result)
140
141 " with skipstart set to false, if the start position is anywhere between the
142 " start and end lines of a text prop (searching forward or backward), the
143 " result should be the prop on the first line (the line with 'start' set to 1).
144 call cursor(3,1)
145 let result = prop_find({'type': 'prop_name'}, 'f')
146 unlet result.length
147 call assert_equal(expected[1], result)
148 let result = prop_find({'type': 'prop_name'}, 'b')
149 unlet result.length
150 call assert_equal(expected[1], result)
151
152 " with skipstart set to true, if the start position is anywhere between the
153 " start and end lines of a text prop (searching forward or backward), all lines
154 " of the prop will be skipped.
155 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'b')
156 call assert_equal(expected[0], result)
157 let result = prop_find({'type': 'prop_name', 'skipstart': 1}, 'f')
158 call assert_equal(expected[2], result)
159
160 " Use skipstart to search through all props with type name 'prop_name'.
161 " First forward...
162 let lnum = 1
163 let col = 1
164 let i = 0
165 for exp in expected
166 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'f')
167 if !has_key(exp, "length")
168 unlet result.length
169 endif
170 call assert_equal(exp, result)
171 let lnum = result.lnum
172 let col = result.col
173 let i = i + 1
174 endfor
175
176 " ...then backwards.
177 let lnum = 6
178 let col = 4
179 let i = 2
180 while i >= 0
181 let result = prop_find({'type': 'prop_name', 'lnum': lnum, 'col': col, 'skipstart': 1}, 'b')
182 if !has_key(expected[i], "length")
183 unlet result.length
184 endif
185 call assert_equal(expected[i], result)
186 let lnum = result.lnum
187 let col = result.col
188 let i = i - 1
189 endwhile
190
191 " Starting from line 6 col 1 search backwards for prop with id 10.
192 call cursor(6,1)
193 let result = prop_find({'id': 10, 'skipstart': 1}, 'b')
194 call assert_equal(expected[0], result)
195
196 " Starting from line 1 col 1 search forwards for prop with id 12.
197 call cursor(1,1)
198 let result = prop_find({'id': 12}, 'f')
199 call assert_equal(expected[2], result)
200
201 " Search for a prop with an unknown id.
202 let result = prop_find({'id': 999}, 'f')
203 call assert_equal({}, result)
204
205 " Search backwards from the proceeding position of the prop with id 11
206 " (at line num 2 col 4). This should return an empty dict.
207 let result = prop_find({'id': 11, 'lnum': 2, 'col': 3}, 'b')
208 call assert_equal({}, result)
209
210 " When lnum is given and col is omitted, use column 1.
211 let result = prop_find({'type': 'prop_name', 'lnum': 1}, 'f')
212 call assert_equal(expected[0], result)
213
214 call prop_clear(1,6)
215 call prop_type_delete('prop_name')
216endfunc
217
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100218func Test_prop_add()
219 new
220 call AddPropTypes()
221 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100222 let expected_props = Get_expected_props()
223 call assert_equal(expected_props, prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100224 call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:')
225 call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:')
226
227 " Insert a line above, text props must still be there.
228 call append(0, 'empty')
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100229 call assert_equal(expected_props, prop_list(2))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100230 " Delete a line above, text props must still be there.
231 1del
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100232 call assert_equal(expected_props, prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100233
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100234 " Prop without length or end column is zero length
235 call prop_clear(1)
236 call prop_add(1, 5, {'type': 'two'})
237 let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}]
238 call assert_equal(expected, prop_list(1))
239
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200240 call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:')
241
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100242 call DeletePropTypes()
243 bwipe!
244endfunc
245
246func Test_prop_remove()
247 new
248 call AddPropTypes()
249 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100250 let props = Get_expected_props()
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100251 call assert_equal(props, prop_list(1))
252
253 " remove by id
Bram Moolenaara5a78822019-09-04 21:57:18 +0200254 call assert_equal(1, {'id': 12}->prop_remove(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100255 unlet props[2]
256 call assert_equal(props, prop_list(1))
257
258 " remove by type
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200259 call assert_equal(1, prop_remove({'type': 'one'}, 1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100260 unlet props[1]
261 call assert_equal(props, prop_list(1))
262
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200263 " remove from unknown buffer
264 call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:')
265
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100266 call DeletePropTypes()
267 bwipe!
268endfunc
269
Bram Moolenaar196d1572019-01-02 23:47:18 +0100270func SetupOneLine()
271 call setline(1, 'xonex xtwoxx')
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200272 normal gg0
Bram Moolenaar196d1572019-01-02 23:47:18 +0100273 call AddPropTypes()
274 call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
275 call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
276 let expected = [
277 \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
278 \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
279 \]
280 call assert_equal(expected, prop_list(1))
281 return expected
282endfunc
283
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100284func Test_prop_add_remove_buf()
285 new
286 let bufnr = bufnr('')
287 call AddPropTypes()
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100288 for lnum in range(1, 4)
289 call setline(lnum, 'one two three')
290 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100291 wincmd w
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100292 for lnum in range(1, 4)
293 call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr})
294 call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr})
295 call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr})
296 endfor
297
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100298 let props = [
299 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
300 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
301 \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
302 \]
303 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100304
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100305 " remove by id
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100306 let before_props = deepcopy(props)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100307 unlet props[1]
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100308
309 call prop_remove({'id': 12, 'bufnr': bufnr}, 1)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100310 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100311 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
312 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
313 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
314
315 call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4)
316 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
317 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
318 call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
319 call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
320
321 call prop_remove({'id': 12, 'bufnr': bufnr})
322 for lnum in range(1, 4)
323 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
324 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100325
326 " remove by type
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100327 let before_props = deepcopy(props)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100328 unlet props[0]
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100329
330 call prop_remove({'type': 'one', 'bufnr': bufnr}, 1)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100331 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100332 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
333 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
334 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
335
336 call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4)
337 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
338 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
339 call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
340 call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
341
342 call prop_remove({'type': 'one', 'bufnr': bufnr})
343 for lnum in range(1, 4)
344 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
345 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100346
347 call DeletePropTypes()
348 wincmd w
349 bwipe!
350endfunc
351
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100352func Test_prop_backspace()
353 new
354 set bs=2
Bram Moolenaar196d1572019-01-02 23:47:18 +0100355 let expected = SetupOneLine() " 'xonex xtwoxx'
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100356
357 exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>"
358 call assert_equal('one xtwoxx', getline(1))
359 let expected[0].col = 1
360 let expected[1].col = 6
361 call assert_equal(expected, prop_list(1))
362
363 call DeletePropTypes()
364 bwipe!
365 set bs&
366endfunc
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100367
Bram Moolenaar196d1572019-01-02 23:47:18 +0100368func Test_prop_replace()
369 new
370 set bs=2
371 let expected = SetupOneLine() " 'xonex xtwoxx'
372
373 exe "normal 0Ryyy\<Esc>"
374 call assert_equal('yyyex xtwoxx', getline(1))
375 call assert_equal(expected, prop_list(1))
376
377 exe "normal ftRyy\<BS>"
378 call assert_equal('yyyex xywoxx', getline(1))
379 call assert_equal(expected, prop_list(1))
380
381 exe "normal 0fwRyy\<BS>"
382 call assert_equal('yyyex xyyoxx', getline(1))
383 call assert_equal(expected, prop_list(1))
384
385 exe "normal 0foRyy\<BS>\<BS>"
386 call assert_equal('yyyex xyyoxx', getline(1))
387 call assert_equal(expected, prop_list(1))
388
389 call DeletePropTypes()
390 bwipe!
391 set bs&
392endfunc
393
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200394func Test_prop_open_line()
395 new
396
397 " open new line, props stay in top line
398 let expected = SetupOneLine() " 'xonex xtwoxx'
399 exe "normal o\<Esc>"
400 call assert_equal('xonex xtwoxx', getline(1))
401 call assert_equal('', getline(2))
402 call assert_equal(expected, prop_list(1))
403 call DeletePropTypes()
404
405 " move all props to next line
406 let expected = SetupOneLine() " 'xonex xtwoxx'
407 exe "normal 0i\<CR>\<Esc>"
408 call assert_equal('', getline(1))
409 call assert_equal('xonex xtwoxx', getline(2))
410 call assert_equal(expected, prop_list(2))
411 call DeletePropTypes()
412
413 " split just before prop, move all props to next line
414 let expected = SetupOneLine() " 'xonex xtwoxx'
415 exe "normal 0li\<CR>\<Esc>"
416 call assert_equal('x', getline(1))
417 call assert_equal('onex xtwoxx', getline(2))
418 let expected[0].col -= 1
419 let expected[1].col -= 1
420 call assert_equal(expected, prop_list(2))
421 call DeletePropTypes()
422
423 " split inside prop, split first prop
424 let expected = SetupOneLine() " 'xonex xtwoxx'
425 exe "normal 0lli\<CR>\<Esc>"
426 call assert_equal('xo', getline(1))
427 call assert_equal('nex xtwoxx', getline(2))
428 let exp_first = [deepcopy(expected[0])]
429 let exp_first[0].length = 1
430 call assert_equal(exp_first, prop_list(1))
431 let expected[0].col = 1
432 let expected[0].length = 2
433 let expected[1].col -= 2
434 call assert_equal(expected, prop_list(2))
435 call DeletePropTypes()
436
Bram Moolenaar5c65e6a2019-05-17 11:08:56 +0200437 " split just after first prop, second prop move to next line
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200438 let expected = SetupOneLine() " 'xonex xtwoxx'
439 exe "normal 0fea\<CR>\<Esc>"
440 call assert_equal('xone', getline(1))
441 call assert_equal('x xtwoxx', getline(2))
442 let exp_first = expected[0:0]
443 call assert_equal(exp_first, prop_list(1))
Bram Moolenaar5c65e6a2019-05-17 11:08:56 +0200444 let expected = expected[1:1]
445 let expected[0].col -= 4
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200446 call assert_equal(expected, prop_list(2))
447 call DeletePropTypes()
448
449 bwipe!
450 set bs&
451endfunc
452
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100453func Test_prop_clear()
454 new
455 call AddPropTypes()
456 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100457 call assert_equal(Get_expected_props(), prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100458
Bram Moolenaara5a78822019-09-04 21:57:18 +0200459 eval 1->prop_clear()
460 call assert_equal([], 1->prop_list())
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100461
462 call DeletePropTypes()
463 bwipe!
464endfunc
465
466func Test_prop_clear_buf()
467 new
468 call AddPropTypes()
469 call SetupPropsInFirstLine()
470 let bufnr = bufnr('')
471 wincmd w
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100472 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100473
474 call prop_clear(1, 1, {'bufnr': bufnr})
475 call assert_equal([], prop_list(1, {'bufnr': bufnr}))
476
477 wincmd w
478 call DeletePropTypes()
479 bwipe!
480endfunc
481
Bram Moolenaar21b50382019-01-04 18:07:24 +0100482func Test_prop_setline()
483 new
484 call AddPropTypes()
485 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100486 call assert_equal(Get_expected_props(), prop_list(1))
Bram Moolenaar21b50382019-01-04 18:07:24 +0100487
488 call setline(1, 'foobar')
489 call assert_equal([], prop_list(1))
490
491 call DeletePropTypes()
492 bwipe!
493endfunc
494
495func Test_prop_setbufline()
496 new
497 call AddPropTypes()
498 call SetupPropsInFirstLine()
499 let bufnr = bufnr('')
500 wincmd w
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100501 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar21b50382019-01-04 18:07:24 +0100502
503 call setbufline(bufnr, 1, 'foobar')
504 call assert_equal([], prop_list(1, {'bufnr': bufnr}))
505
506 wincmd w
507 call DeletePropTypes()
508 bwipe!
509endfunc
510
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100511func Test_prop_substitute()
512 new
513 " Set first line to 'one two three'
514 call AddPropTypes()
515 call SetupPropsInFirstLine()
516 let expected_props = Get_expected_props()
517 call assert_equal(expected_props, prop_list(1))
518
519 " Change "n" in "one" to XX: 'oXXe two three'
520 s/n/XX/
521 let expected_props[0].length += 1
522 let expected_props[1].length += 1
523 let expected_props[2].col += 1
524 let expected_props[3].col += 1
525 call assert_equal(expected_props, prop_list(1))
526
527 " Delete "t" in "two" and "three" to XX: 'oXXe wo hree'
528 s/t//g
529 let expected_props[0].length -= 2
530 let expected_props[2].length -= 1
531 let expected_props[3].length -= 1
532 let expected_props[3].col -= 1
533 call assert_equal(expected_props, prop_list(1))
534
535 " Split the line by changing w to line break: 'oXXe ', 'o hree'
536 " The long prop is split and spans both lines.
537 " The props on "two" and "three" move to the next line.
538 s/w/\r/
539 let new_props = [
540 \ copy(expected_props[0]),
541 \ copy(expected_props[2]),
542 \ copy(expected_props[3]),
543 \ ]
544 let expected_props[0].length = 5
545 unlet expected_props[3]
546 unlet expected_props[2]
547 call assert_equal(expected_props, prop_list(1))
548
549 let new_props[0].length = 6
550 let new_props[1].col = 1
551 let new_props[1].length = 1
552 let new_props[2].col = 3
553 call assert_equal(new_props, prop_list(2))
554
555 call DeletePropTypes()
556 bwipe!
557endfunc
558
Bram Moolenaar663bc892019-01-08 23:07:24 +0100559func Test_prop_change_indent()
560 call prop_type_add('comment', {'highlight': 'Directory'})
561 new
562 call setline(1, [' xxx', 'yyyyy'])
563 call prop_add(2, 2, {'length': 2, 'type': 'comment'})
564 let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
565 call assert_equal([expect], prop_list(2))
566
567 set shiftwidth=3
568 normal 2G>>
569 call assert_equal(' yyyyy', getline(2))
570 let expect.col += 3
571 call assert_equal([expect], prop_list(2))
572
573 normal 2G==
574 call assert_equal(' yyyyy', getline(2))
575 let expect.col = 6
576 call assert_equal([expect], prop_list(2))
577
578 call prop_clear(2)
579 call prop_add(2, 2, {'length': 5, 'type': 'comment'})
580 let expect.col = 2
581 let expect.length = 5
582 call assert_equal([expect], prop_list(2))
583
584 normal 2G<<
585 call assert_equal(' yyyyy', getline(2))
586 let expect.length = 2
587 call assert_equal([expect], prop_list(2))
588
589 set shiftwidth&
590 call prop_type_delete('comment')
591endfunc
592
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100593" Setup a three line prop in lines 2 - 4.
594" Add short props in line 1 and 5.
595func Setup_three_line_prop()
596 new
597 call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five'])
598 call prop_add(1, 2, {'length': 1, 'type': 'comment'})
599 call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'})
600 call prop_add(5, 2, {'length': 1, 'type': 'comment'})
601endfunc
602
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100603func Test_prop_multiline()
Bram Moolenaara5a78822019-09-04 21:57:18 +0200604 eval 'comment'->prop_type_add({'highlight': 'Directory'})
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100605 new
606 call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz'])
607
608 " start halfway line 1, end halfway line 3
609 call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'})
610 let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
611 call assert_equal([expect1], prop_list(1))
612 let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
613 call assert_equal([expect2], prop_list(2))
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100614 let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100615 call assert_equal([expect3], prop_list(3))
616 call prop_clear(1, 3)
617
618 " include all three lines
619 call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'})
620 let expect1.col = 1
621 let expect1.length = 8
622 call assert_equal([expect1], prop_list(1))
623 call assert_equal([expect2], prop_list(2))
624 let expect3.length = 9
625 call assert_equal([expect3], prop_list(3))
626 call prop_clear(1, 3)
627
628 bwipe!
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100629
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100630 " Test deleting the first line of a multi-line prop.
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100631 call Setup_three_line_prop()
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100632 let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
633 call assert_equal([expect_short], prop_list(1))
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100634 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
635 call assert_equal([expect2], prop_list(2))
636 2del
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100637 call assert_equal([expect_short], prop_list(1))
638 let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
639 call assert_equal([expect2], prop_list(2))
640 bwipe!
641
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100642 " Test deleting the last line of a multi-line prop.
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100643 call Setup_three_line_prop()
644 let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
645 call assert_equal([expect3], prop_list(3))
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100646 let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100647 call assert_equal([expect4], prop_list(4))
648 4del
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100649 let expect3.end = 1
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100650 call assert_equal([expect3], prop_list(3))
651 call assert_equal([expect_short], prop_list(4))
652 bwipe!
653
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100654 " Test appending a line below the multi-line text prop start.
Bram Moolenaarb56ac042018-12-28 23:22:40 +0100655 call Setup_three_line_prop()
656 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
657 call assert_equal([expect2], prop_list(2))
658 call append(2, "new line")
659 call assert_equal([expect2], prop_list(2))
660 let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
661 call assert_equal([expect3], prop_list(3))
662 bwipe!
663
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100664 call prop_type_delete('comment')
665endfunc
666
Bram Moolenaar9df53b62020-01-13 20:40:51 +0100667func Test_prop_line2byte()
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100668 call prop_type_add('comment', {'highlight': 'Directory'})
669 new
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100670 call setline(1, ['line1', 'second line', ''])
Bram Moolenaar8cf734e2018-12-26 01:09:00 +0100671 set ff=unix
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100672 call assert_equal(19, line2byte(3))
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100673 call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100674 call assert_equal(19, line2byte(3))
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100675
676 bwipe!
677 call prop_type_delete('comment')
678endfunc
679
Bram Moolenaar9df53b62020-01-13 20:40:51 +0100680func Test_prop_byte2line()
681 new
682 set ff=unix
683 call setline(1, ['one one', 'two two', 'three three', 'four four', 'five'])
684 call assert_equal(4, byte2line(line2byte(4)))
685 call assert_equal(5, byte2line(line2byte(5)))
686
687 call prop_type_add('prop', {'highlight': 'Directory'})
688 call prop_add(3, 1, {'length': 5, 'type': 'prop'})
689 call assert_equal(4, byte2line(line2byte(4)))
690 call assert_equal(5, byte2line(line2byte(5)))
691
692 bwipe!
693 call prop_type_delete('prop')
694endfunc
695
Bram Moolenaar7f1664e2019-01-04 17:21:24 +0100696func Test_prop_undo()
697 new
698 call prop_type_add('comment', {'highlight': 'Directory'})
699 call setline(1, ['oneone', 'twotwo', 'three'])
700 " Set 'undolevels' to break changes into undo-able pieces.
701 set ul&
702
703 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'})
704 let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
705 call assert_equal(expected, prop_list(1))
706
707 " Insert a character, then undo.
708 exe "normal 0lllix\<Esc>"
709 set ul&
710 let expected[0].length = 3
711 call assert_equal(expected, prop_list(1))
712 undo
713 let expected[0].length = 2
714 call assert_equal(expected, prop_list(1))
715
716 " Delete a character, then undo
717 exe "normal 0lllx"
718 set ul&
719 let expected[0].length = 1
720 call assert_equal(expected, prop_list(1))
721 undo
722 let expected[0].length = 2
723 call assert_equal(expected, prop_list(1))
724
725 " Delete the line, then undo
726 1d
727 set ul&
728 call assert_equal([], prop_list(1))
729 undo
730 call assert_equal(expected, prop_list(1))
731
732 " Insert a character, delete two characters, then undo with "U"
733 exe "normal 0lllix\<Esc>"
734 set ul&
735 let expected[0].length = 3
736 call assert_equal(expected, prop_list(1))
737 exe "normal 0lllxx"
738 set ul&
739 let expected[0].length = 1
740 call assert_equal(expected, prop_list(1))
741 normal U
742 let expected[0].length = 2
743 call assert_equal(expected, prop_list(1))
744
Bram Moolenaar338dfda2019-05-19 15:19:57 +0200745 " substitute a word, then undo
746 call setline(1, 'the number 123 is highlighted.')
747 call prop_add(1, 12, {'length': 3, 'type': 'comment'})
748 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
749 call assert_equal(expected, prop_list(1))
750 set ul&
751 1s/number/foo
752 let expected[0].col = 9
753 call assert_equal(expected, prop_list(1))
754 undo
755 let expected[0].col = 12
756 call assert_equal(expected, prop_list(1))
Bram Moolenaarf3333b02019-05-19 22:53:40 +0200757 call prop_clear(1)
758
759 " substitute with backslash
760 call setline(1, 'the number 123 is highlighted.')
761 call prop_add(1, 12, {'length': 3, 'type': 'comment'})
762 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
763 call assert_equal(expected, prop_list(1))
764 1s/the/\The
765 call assert_equal(expected, prop_list(1))
766 1s/^/\\
767 let expected[0].col += 1
768 call assert_equal(expected, prop_list(1))
769 1s/^/\~
770 let expected[0].col += 1
771 call assert_equal(expected, prop_list(1))
772 1s/123/12\\3
773 let expected[0].length += 1
774 call assert_equal(expected, prop_list(1))
775 call prop_clear(1)
Bram Moolenaar338dfda2019-05-19 15:19:57 +0200776
Bram Moolenaar7f1664e2019-01-04 17:21:24 +0100777 bwipe!
778 call prop_type_delete('comment')
779endfunc
780
Bram Moolenaarecafcc12019-11-16 20:41:51 +0100781func Test_prop_delete_text()
782 new
783 call prop_type_add('comment', {'highlight': 'Directory'})
784 call setline(1, ['oneone', 'twotwo', 'three'])
785
786 " zero length property
787 call prop_add(1, 3, {'type': 'comment'})
788 let expected = [{'col': 3, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
789 call assert_equal(expected, prop_list(1))
790
791 " delete one char moves the property
792 normal! x
793 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
794 call assert_equal(expected, prop_list(1))
795
796 " delete char of the property has no effect
797 normal! lx
798 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
799 call assert_equal(expected, prop_list(1))
800
801 " delete more chars moves property to first column, is not deleted
802 normal! 0xxxx
803 let expected = [{'col': 1, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
804 call assert_equal(expected, prop_list(1))
805
806 bwipe!
807 call prop_type_delete('comment')
808endfunc
809
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100810" screenshot test with textprop highlighting
Bram Moolenaar8055d172019-05-17 22:57:26 +0200811func Test_textprop_screenshot_various()
Bram Moolenaar34390282019-10-16 14:38:26 +0200812 CheckScreendump
Bram Moolenaared79d1e2019-02-22 14:38:58 +0100813 " The Vim running in the terminal needs to use utf-8.
Bram Moolenaar34390282019-10-16 14:38:26 +0200814 if g:orig_encoding != 'utf-8'
815 throw 'Skipped: not using utf-8'
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100816 endif
817 call writefile([
Bram Moolenaarde24a872019-05-05 15:48:00 +0200818 \ "call setline(1, ["
819 \ .. "'One two',"
820 \ .. "'Numbér 123 änd thœn 4¾7.',"
821 \ .. "'--aa--bb--cc--dd--',"
822 \ .. "'// comment with error in it',"
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200823 \ .. "'first line',"
824 \ .. "' second line ',"
825 \ .. "'third line',"
826 \ .. "' fourth line',"
Bram Moolenaarde24a872019-05-05 15:48:00 +0200827 \ .. "])",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100828 \ "hi NumberProp ctermfg=blue",
829 \ "hi LongProp ctermbg=yellow",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200830 \ "hi BackgroundProp ctermbg=lightgrey",
831 \ "hi UnderlineProp cterm=underline",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100832 \ "call prop_type_add('number', {'highlight': 'NumberProp'})",
Bram Moolenaara5a78822019-09-04 21:57:18 +0200833 \ "call prop_type_add('long', {'highlight': 'NumberProp'})",
834 \ "call prop_type_change('long', {'highlight': 'LongProp'})",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100835 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})",
836 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})",
837 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})",
Bram Moolenaardbd43162019-11-09 21:28:14 +0100838 \ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})",
839 \ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})",
840 \ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})",
Bram Moolenaar58e32ab2019-11-12 22:44:22 +0100841 \ "call prop_type_add('error', {'highlight': 'UnderlineProp'})",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100842 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})",
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100843 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})",
844 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100845 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})",
846 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})",
847 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})",
848 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
Bram Moolenaardbd43162019-11-09 21:28:14 +0100849 \ "call prop_add(4, 6, {'length': 3, 'type': 'background'})",
850 \ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200851 \ "call prop_add(4, 17, {'length': 5, 'type': 'error'})",
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200852 \ "call prop_add(5, 7, {'length': 4, 'type': 'long'})",
853 \ "call prop_add(6, 1, {'length': 8, 'type': 'long'})",
854 \ "call prop_add(8, 1, {'length': 1, 'type': 'long'})",
855 \ "call prop_add(8, 11, {'length': 4, 'type': 'long'})",
Bram Moolenaarbfd45122019-05-17 13:05:07 +0200856 \ "set number cursorline",
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100857 \ "hi clear SpellBad",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100858 \ "set spell",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200859 \ "syn match Comment '//.*'",
860 \ "hi Comment ctermfg=green",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100861 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100862 \ "normal 3G0lli\<BS>\<Esc>",
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200863 \ "normal 6G0i\<BS>\<Esc>",
864 \ "normal 3J",
865 \ "normal 3G",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100866 \], 'XtestProp')
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200867 let buf = RunVimInTerminal('-S XtestProp', {'rows': 8})
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100868 call VerifyScreenDump(buf, 'Test_textprop_01', {})
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100869
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100870 " clean up
871 call StopVimInTerminal(buf)
Bram Moolenaar2f21fa82018-12-31 20:05:56 +0100872 call delete('XtestProp')
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100873endfunc
Bram Moolenaar8055d172019-05-17 22:57:26 +0200874
875func RunTestVisualBlock(width, dump)
876 call writefile([
877 \ "call setline(1, ["
878 \ .. "'xxxxxxxxx 123 x',"
879 \ .. "'xxxxxxxx 123 x',"
880 \ .. "'xxxxxxx 123 x',"
881 \ .. "'xxxxxx 123 x',"
882 \ .. "'xxxxx 123 x',"
883 \ .. "'xxxx 123 xx',"
884 \ .. "'xxx 123 xxx',"
885 \ .. "'xx 123 xxxx',"
886 \ .. "'x 123 xxxxx',"
887 \ .. "' 123 xxxxxx',"
888 \ .. "])",
889 \ "hi SearchProp ctermbg=yellow",
890 \ "call prop_type_add('search', {'highlight': 'SearchProp'})",
891 \ "call prop_add(1, 11, {'length': 3, 'type': 'search'})",
892 \ "call prop_add(2, 10, {'length': 3, 'type': 'search'})",
893 \ "call prop_add(3, 9, {'length': 3, 'type': 'search'})",
894 \ "call prop_add(4, 8, {'length': 3, 'type': 'search'})",
895 \ "call prop_add(5, 7, {'length': 3, 'type': 'search'})",
896 \ "call prop_add(6, 6, {'length': 3, 'type': 'search'})",
897 \ "call prop_add(7, 5, {'length': 3, 'type': 'search'})",
898 \ "call prop_add(8, 4, {'length': 3, 'type': 'search'})",
899 \ "call prop_add(9, 3, {'length': 3, 'type': 'search'})",
900 \ "call prop_add(10, 2, {'length': 3, 'type': 'search'})",
901 \ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx",
902 \], 'XtestPropVis')
903 let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12})
904 call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {})
905
906 " clean up
907 call StopVimInTerminal(buf)
908 call delete('XtestPropVis')
909endfunc
910
911" screenshot test with Visual block mode operations
912func Test_textprop_screenshot_visual()
Bram Moolenaar34390282019-10-16 14:38:26 +0200913 CheckScreendump
Bram Moolenaar8055d172019-05-17 22:57:26 +0200914
915 " Delete two columns while text props are three chars wide.
916 call RunTestVisualBlock(2, '01')
917
918 " Same, but delete four columns
919 call RunTestVisualBlock(4, '02')
920endfunc
Bram Moolenaard79eef22019-05-24 20:41:55 +0200921
Bram Moolenaara956bf62019-06-19 17:34:24 +0200922func Test_textprop_after_tab()
Bram Moolenaar34390282019-10-16 14:38:26 +0200923 CheckScreendump
Bram Moolenaar37e66cf2019-06-19 18:16:10 +0200924
Bram Moolenaara956bf62019-06-19 17:34:24 +0200925 let lines =<< trim END
926 call setline(1, [
927 \ "\txxx",
928 \ "x\txxx",
929 \ ])
930 hi SearchProp ctermbg=yellow
931 call prop_type_add('search', {'highlight': 'SearchProp'})
932 call prop_add(1, 2, {'length': 3, 'type': 'search'})
933 call prop_add(2, 3, {'length': 3, 'type': 'search'})
934 END
935 call writefile(lines, 'XtestPropTab')
936 let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6})
937 call VerifyScreenDump(buf, 'Test_textprop_tab', {})
938
939 " clean up
940 call StopVimInTerminal(buf)
941 call delete('XtestPropTab')
942endfunc
943
Bram Moolenaar34390282019-10-16 14:38:26 +0200944func Test_textprop_with_syntax()
945 CheckScreendump
946
947 let lines =<< trim END
948 call setline(1, [
949 \ "(abc)",
950 \ ])
951 syn match csParens "[()]" display
952 hi! link csParens MatchParen
953
954 call prop_type_add('TPTitle', #{ highlight: 'Title' })
955 call prop_add(1, 2, #{type: 'TPTitle', end_col: 5})
956 END
957 call writefile(lines, 'XtestPropSyn')
958 let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6})
959 call VerifyScreenDump(buf, 'Test_textprop_syn_1', {})
960
961 " clean up
962 call StopVimInTerminal(buf)
963 call delete('XtestPropSyn')
964endfunc
965
Bram Moolenaard79eef22019-05-24 20:41:55 +0200966" Adding a text property to a new buffer should not fail
967func Test_textprop_empty_buffer()
968 call prop_type_add('comment', {'highlight': 'Search'})
969 new
970 call prop_add(1, 1, {'type': 'comment'})
971 close
Bram Moolenaaradfde112019-05-25 22:11:45 +0200972 call prop_type_delete('comment')
973endfunc
974
Bram Moolenaard74af422019-06-28 21:38:00 +0200975" Adding a text property with invalid highlight should be ignored.
976func Test_textprop_invalid_highlight()
977 call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:')
978 new
979 call setline(1, ['asdf','asdf'])
980 call prop_add(1, 1, {'length': 4, 'type': 'dni'})
981 redraw
982 bwipe!
983 call prop_type_delete('dni')
984endfunc
985
Bram Moolenaaradfde112019-05-25 22:11:45 +0200986" Adding a text property to an empty buffer and then editing another
987func Test_textprop_empty_buffer_next()
988 call prop_type_add("xxx", {})
989 call prop_add(1, 1, {"type": "xxx"})
990 next X
991 call prop_type_delete('xxx')
Bram Moolenaard79eef22019-05-24 20:41:55 +0200992endfunc
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200993
994func Test_textprop_remove_from_buf()
995 new
996 let buf = bufnr('')
997 call prop_type_add('one', {'bufnr': buf})
998 call prop_add(1, 1, {'type': 'one', 'id': 234})
999 file x
1000 edit y
1001 call prop_remove({'id': 234, 'bufnr': buf}, 1)
1002 call prop_type_delete('one', {'bufnr': buf})
1003 bwipe! x
1004 close
1005endfunc
Bram Moolenaar45311b52019-08-13 22:27:32 +02001006
1007func Test_textprop_in_unloaded_buf()
1008 edit Xaaa
1009 call setline(1, 'aaa')
1010 write
1011 edit Xbbb
1012 call setline(1, 'bbb')
1013 write
1014 let bnr = bufnr('')
1015 edit Xaaa
1016
1017 call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'})
1018 call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:')
1019 exe 'buf ' .. bnr
1020 call assert_equal('bbb', getline(1))
1021 call assert_equal(0, prop_list(1)->len())
1022
1023 bwipe! Xaaa
1024 bwipe! Xbbb
1025 cal delete('Xaaa')
1026 cal delete('Xbbb')
1027endfunc
Bram Moolenaar1fd30d72019-10-25 22:13:29 +02001028
1029func Test_proptype_substitute2()
1030 new
1031 " text_prop.vim
1032 call setline(1, [
1033 \ 'The num 123 is smaller than 4567.',
1034 \ '123 The number 123 is smaller than 4567.',
1035 \ '123 The number 123 is smaller than 4567.'])
1036
1037 call prop_type_add('number', {'highlight': 'ErrorMsg'})
1038
1039 call prop_add(1, 12, {'length': 3, 'type': 'number'})
1040 call prop_add(2, 1, {'length': 3, 'type': 'number'})
1041 call prop_add(3, 36, {'length': 4, 'type': 'number'})
1042 set ul&
1043 let expected = [{'id': 0, 'col': 13, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1044 \ {'id': 0, 'col': 1, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1045 \ {'id': 0, 'col': 50, 'end': 1, 'type': 'number', 'length': 4, 'start': 1}]
1046 " Add some text in between
1047 %s/\s\+/ /g
1048 call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3))
1049
1050 " remove some text
1051 :1s/[a-z]\{3\}//g
1052 let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}]
1053 call assert_equal(expected, prop_list(1))
1054 bwipe!
1055endfunc
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001056
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001057func SaveOptions()
1058 let d = #{tabstop: &tabstop,
1059 \ softtabstop: &softtabstop,
1060 \ shiftwidth: &shiftwidth,
1061 \ expandtab: &expandtab,
1062 \ foldmethod: '"' .. &foldmethod .. '"',
1063 \ }
1064 return d
1065endfunc
1066
1067func RestoreOptions(dict)
1068 for name in keys(a:dict)
1069 exe 'let &' .. name .. ' = ' .. a:dict[name]
1070 endfor
1071endfunc
1072
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001073func Test_textprop_noexpandtab()
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001074 new
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001075 let save_dict = SaveOptions()
1076
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001077 set tabstop=8
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001078 set softtabstop=4
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001079 set shiftwidth=4
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001080 set noexpandtab
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001081 set foldmethod=marker
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001082
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001083 call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx")
1084 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1085 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1086 call feedkeys("0i\<tab>", "tx")
1087 call prop_remove({'type': 'test'})
1088 call prop_add(1, 2, {'end_col': 3, 'type': 'test'})
1089 call feedkeys("A\<left>\<tab>", "tx")
1090 call prop_remove({'type': 'test'})
1091 try
1092 " It is correct that this does not pass
1093 call prop_add(1, 6, {'end_col': 7, 'type': 'test'})
1094 " Has already collapsed here, start_col:6 does not result in an error
1095 call feedkeys("A\<left>\<tab>", "tx")
1096 catch /^Vim\%((\a\+)\)\=:E964/
1097 endtry
1098 call prop_remove({'type': 'test'})
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001099 call prop_type_delete('test')
1100
1101 call RestoreOptions(save_dict)
1102 bwipe!
1103endfunc
1104
1105func Test_textprop_noexpandtab_redraw()
1106 new
1107 let save_dict = SaveOptions()
1108
1109 set tabstop=8
1110 set softtabstop=4
1111 set shiftwidth=4
1112 set noexpandtab
1113 set foldmethod=marker
1114
1115 call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx")
1116 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1117 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1118 call feedkeys("0i\<tab>", "tx")
1119 " Internally broken at the next line
1120 call feedkeys("A\<left>\<tab>", "tx")
1121 redraw
1122 " Index calculation failed internally on next line
1123 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1124 call prop_remove({'type': 'test', 'all': v:true})
1125 call prop_type_delete('test')
1126 call prop_type_delete('test')
1127
1128 call RestoreOptions(save_dict)
1129 bwipe!
1130endfunc
1131
1132func Test_textprop_ins_str()
1133 new
1134 call setline(1, 'just some text')
1135 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1136 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1137 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1138
1139 call feedkeys("foi\<F8>\<Esc>", "tx")
1140 call assert_equal('just s<F8>ome text', getline(1))
1141 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1142
1143 bwipe!
1144 call prop_remove({'type': 'test'})
1145 call prop_type_delete('test')
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001146endfunc