blob: f7718124b346e83500702537653a06438344966d [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 Moolenaar98aefe72018-12-13 22:20:09 +01009func 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()))
Bram Moolenaara5a78822019-09-04 21:57:18 +020026 let proptype = 'one'->prop_type_get()
Bram Moolenaar98aefe72018-12-13 22:20:09 +010027 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})
Bram Moolenaara5a78822019-09-04 21:57:18 +020054 call assert_equal(0, len({'bufnr': bufnr}->prop_type_list()))
Bram Moolenaar98aefe72018-12-13 22:20:09 +010055
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})))
Bram Moolenaarf0884c52019-05-24 21:22:29 +020069
70 call assert_fails("call prop_type_add('one', {'bufnr': 98764})", "E158:")
Bram Moolenaar98aefe72018-12-13 22:20:09 +010071endfunc
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'})
Bram Moolenaara5a78822019-09-04 21:57:18 +020090 eval 1->prop_add(5, {'length': 3, 'id': 12, 'type': 'two'})
Bram Moolenaar4164bb22019-01-04 23:09:49 +010091 call prop_add(1, 9, {'length': 5, 'id': 13, 'type': 'three'})
Bram Moolenaar98aefe72018-12-13 22:20:09 +010092 call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'})
93endfunc
94
Bram Moolenaar4164bb22019-01-04 23:09:49 +010095func Get_expected_props()
96 return [
97 \ {'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1},
Bram Moolenaar98aefe72018-12-13 22:20:09 +010098 \ {'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},
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100100 \ {'col': 9, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100101 \ ]
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100102endfunc
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100103
Bram Moolenaare05a89a2020-01-10 19:56:46 +0100104func 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')
Bram Moolenaar4da7a252020-09-02 19:59:00 +0200214
Bram Moolenaar4da7a252020-09-02 19:59:00 +0200215 bwipe!
Bram Moolenaare05a89a2020-01-10 19:56:46 +0100216endfunc
217
Bram Moolenaareb245562020-09-03 22:33:44 +0200218def Test_prop_find2()
219 # Multiple props per line, start on the first, should find the second.
220 new
221 ['the quikc bronw fox jumsp over the layz dog']->repeat(2)->setline(1)
222 prop_type_add('misspell', #{highlight: 'ErrorMsg'})
223 for lnum in [1, 2]
224 for col in [8, 14, 24, 38]
225 prop_add(lnum, col, #{type: 'misspell', length: 2})
226 endfor
227 endfor
228 cursor(1, 8)
229 let expected = {'lnum': 1, 'id': 0, 'col': 14, 'end': 1, 'type': 'misspell', 'length': 2, 'start': 1}
230 let result = prop_find(#{type: 'misspell', skipstart: true}, 'f')
231 assert_equal(expected, result)
232
233 prop_type_delete('misspell')
234 bwipe!
235enddef
236
Bram Moolenaar346f18e2020-03-13 21:36:40 +0100237func Test_prop_find_smaller_len_than_match_col()
238 new
239 call prop_type_add('test', {'highlight': 'ErrorMsg'})
240 call setline(1, ['xxxx', 'x'])
241 call prop_add(1, 4, {'type': 'test'})
242 call assert_equal({'id': 0, 'lnum': 1, 'col': 4, 'type': 'test', 'length': 0, 'start': 1, 'end': 1},
243 \ prop_find({'type': 'test', 'lnum': 2, 'col': 1}, 'b'))
244 bwipe!
245 call prop_type_delete('test')
246endfunc
247
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100248func Test_prop_add()
249 new
250 call AddPropTypes()
251 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100252 let expected_props = Get_expected_props()
253 call assert_equal(expected_props, prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100254 call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:')
255 call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:')
256
257 " Insert a line above, text props must still be there.
258 call append(0, 'empty')
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100259 call assert_equal(expected_props, prop_list(2))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100260 " Delete a line above, text props must still be there.
261 1del
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100262 call assert_equal(expected_props, prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100263
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100264 " Prop without length or end column is zero length
265 call prop_clear(1)
Bram Moolenaar12f20032020-02-26 22:06:00 +0100266 call prop_type_add('included', {'start_incl': 1, 'end_incl': 1})
267 call prop_add(1, 5, #{type: 'included'})
268 let expected = [#{col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}]
269 call assert_equal(expected, prop_list(1))
270
271 " Inserting text makes the prop bigger.
272 exe "normal 5|ixx\<Esc>"
273 let expected = [#{col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}]
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100274 call assert_equal(expected, prop_list(1))
275
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200276 call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:')
277
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100278 call DeletePropTypes()
Bram Moolenaar12f20032020-02-26 22:06:00 +0100279 call prop_type_delete('included')
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100280 bwipe!
281endfunc
282
283func Test_prop_remove()
284 new
285 call AddPropTypes()
286 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100287 let props = Get_expected_props()
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100288 call assert_equal(props, prop_list(1))
289
290 " remove by id
Bram Moolenaara5a78822019-09-04 21:57:18 +0200291 call assert_equal(1, {'id': 12}->prop_remove(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100292 unlet props[2]
293 call assert_equal(props, prop_list(1))
294
295 " remove by type
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200296 call assert_equal(1, prop_remove({'type': 'one'}, 1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100297 unlet props[1]
298 call assert_equal(props, prop_list(1))
299
Bram Moolenaarf0884c52019-05-24 21:22:29 +0200300 " remove from unknown buffer
301 call assert_fails("call prop_remove({'type': 'one', 'bufnr': 123456}, 1)", 'E158:')
302
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100303 call DeletePropTypes()
304 bwipe!
Bram Moolenaar49b79bd2020-03-05 21:52:55 +0100305
306 new
307 call AddPropTypes()
308 call SetupPropsInFirstLine()
309 call prop_add(1, 6, {'length': 2, 'id': 11, 'type': 'three'})
310 let props = Get_expected_props()
311 call insert(props, {'col': 6, 'length': 2, 'id': 11, 'type': 'three', 'start': 1, 'end': 1}, 3)
312 call assert_equal(props, prop_list(1))
313 call assert_equal(1, prop_remove({'type': 'three', 'id': 11, 'both': 1, 'all': 1}, 1))
314 unlet props[3]
315 call assert_equal(props, prop_list(1))
316
Bram Moolenaare2e40752020-09-04 21:18:46 +0200317 call assert_fails("call prop_remove({'id': 11, 'both': 1})", 'E860:')
318 call assert_fails("call prop_remove({'type': 'three', 'both': 1})", 'E860:')
Bram Moolenaar49b79bd2020-03-05 21:52:55 +0100319
320 call DeletePropTypes()
321 bwipe!
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100322endfunc
323
Bram Moolenaara5a40c52020-09-05 20:50:49 +0200324def Test_prop_remove_vim9()
325 new
326 call AddPropTypes()
327 call SetupPropsInFirstLine()
328 call assert_equal(1, prop_remove({'type': 'three', 'id': 13, 'both': true, 'all': true}))
329 call DeletePropTypes()
330 bwipe!
331enddef
332
Bram Moolenaar196d1572019-01-02 23:47:18 +0100333func SetupOneLine()
334 call setline(1, 'xonex xtwoxx')
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200335 normal gg0
Bram Moolenaar196d1572019-01-02 23:47:18 +0100336 call AddPropTypes()
337 call prop_add(1, 2, {'length': 3, 'id': 11, 'type': 'one'})
338 call prop_add(1, 8, {'length': 3, 'id': 12, 'type': 'two'})
339 let expected = [
340 \ {'col': 2, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
341 \ {'col': 8, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
342 \]
343 call assert_equal(expected, prop_list(1))
344 return expected
345endfunc
346
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100347func Test_prop_add_remove_buf()
348 new
349 let bufnr = bufnr('')
350 call AddPropTypes()
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100351 for lnum in range(1, 4)
352 call setline(lnum, 'one two three')
353 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100354 wincmd w
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100355 for lnum in range(1, 4)
356 call prop_add(lnum, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr})
357 call prop_add(lnum, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr})
358 call prop_add(lnum, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr})
359 endfor
360
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100361 let props = [
362 \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1},
363 \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1},
364 \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1},
365 \]
366 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100367
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100368 " remove by id
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100369 let before_props = deepcopy(props)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100370 unlet props[1]
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100371
372 call prop_remove({'id': 12, 'bufnr': bufnr}, 1)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100373 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100374 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
375 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
376 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
377
378 call prop_remove({'id': 12, 'bufnr': bufnr}, 3, 4)
379 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
380 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
381 call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
382 call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
383
384 call prop_remove({'id': 12, 'bufnr': bufnr})
385 for lnum in range(1, 4)
386 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
387 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100388
389 " remove by type
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100390 let before_props = deepcopy(props)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100391 unlet props[0]
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100392
393 call prop_remove({'type': 'one', 'bufnr': bufnr}, 1)
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100394 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100395 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
396 call assert_equal(before_props, prop_list(3, {'bufnr': bufnr}))
397 call assert_equal(before_props, prop_list(4, {'bufnr': bufnr}))
398
399 call prop_remove({'type': 'one', 'bufnr': bufnr}, 3, 4)
400 call assert_equal(props, prop_list(1, {'bufnr': bufnr}))
401 call assert_equal(before_props, prop_list(2, {'bufnr': bufnr}))
402 call assert_equal(props, prop_list(3, {'bufnr': bufnr}))
403 call assert_equal(props, prop_list(4, {'bufnr': bufnr}))
404
405 call prop_remove({'type': 'one', 'bufnr': bufnr})
406 for lnum in range(1, 4)
407 call assert_equal(props, prop_list(lnum, {'bufnr': bufnr}))
408 endfor
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100409
410 call DeletePropTypes()
411 wincmd w
412 bwipe!
413endfunc
414
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100415func Test_prop_backspace()
416 new
417 set bs=2
Bram Moolenaar196d1572019-01-02 23:47:18 +0100418 let expected = SetupOneLine() " 'xonex xtwoxx'
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100419
420 exe "normal 0li\<BS>\<Esc>fxli\<BS>\<Esc>"
421 call assert_equal('one xtwoxx', getline(1))
422 let expected[0].col = 1
423 let expected[1].col = 6
424 call assert_equal(expected, prop_list(1))
425
426 call DeletePropTypes()
427 bwipe!
428 set bs&
429endfunc
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100430
Bram Moolenaar196d1572019-01-02 23:47:18 +0100431func Test_prop_replace()
432 new
433 set bs=2
434 let expected = SetupOneLine() " 'xonex xtwoxx'
435
436 exe "normal 0Ryyy\<Esc>"
437 call assert_equal('yyyex xtwoxx', getline(1))
438 call assert_equal(expected, prop_list(1))
439
440 exe "normal ftRyy\<BS>"
441 call assert_equal('yyyex xywoxx', getline(1))
442 call assert_equal(expected, prop_list(1))
443
444 exe "normal 0fwRyy\<BS>"
445 call assert_equal('yyyex xyyoxx', getline(1))
446 call assert_equal(expected, prop_list(1))
447
448 exe "normal 0foRyy\<BS>\<BS>"
449 call assert_equal('yyyex xyyoxx', getline(1))
450 call assert_equal(expected, prop_list(1))
451
452 call DeletePropTypes()
453 bwipe!
454 set bs&
455endfunc
456
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200457func Test_prop_open_line()
458 new
459
460 " open new line, props stay in top line
461 let expected = SetupOneLine() " 'xonex xtwoxx'
462 exe "normal o\<Esc>"
463 call assert_equal('xonex xtwoxx', getline(1))
464 call assert_equal('', getline(2))
465 call assert_equal(expected, prop_list(1))
466 call DeletePropTypes()
467
468 " move all props to next line
469 let expected = SetupOneLine() " 'xonex xtwoxx'
470 exe "normal 0i\<CR>\<Esc>"
471 call assert_equal('', getline(1))
472 call assert_equal('xonex xtwoxx', getline(2))
473 call assert_equal(expected, prop_list(2))
474 call DeletePropTypes()
475
476 " split just before prop, move all props to next line
477 let expected = SetupOneLine() " 'xonex xtwoxx'
478 exe "normal 0li\<CR>\<Esc>"
479 call assert_equal('x', getline(1))
480 call assert_equal('onex xtwoxx', getline(2))
481 let expected[0].col -= 1
482 let expected[1].col -= 1
483 call assert_equal(expected, prop_list(2))
484 call DeletePropTypes()
485
486 " split inside prop, split first prop
487 let expected = SetupOneLine() " 'xonex xtwoxx'
488 exe "normal 0lli\<CR>\<Esc>"
489 call assert_equal('xo', getline(1))
490 call assert_equal('nex xtwoxx', getline(2))
491 let exp_first = [deepcopy(expected[0])]
492 let exp_first[0].length = 1
Bram Moolenaar87be9be2020-05-30 15:32:02 +0200493 let exp_first[0].end = 0
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200494 call assert_equal(exp_first, prop_list(1))
495 let expected[0].col = 1
496 let expected[0].length = 2
Bram Moolenaar87be9be2020-05-30 15:32:02 +0200497 let expected[0].start = 0
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200498 let expected[1].col -= 2
499 call assert_equal(expected, prop_list(2))
500 call DeletePropTypes()
501
Bram Moolenaar5c65e6a2019-05-17 11:08:56 +0200502 " split just after first prop, second prop move to next line
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200503 let expected = SetupOneLine() " 'xonex xtwoxx'
504 exe "normal 0fea\<CR>\<Esc>"
505 call assert_equal('xone', getline(1))
506 call assert_equal('x xtwoxx', getline(2))
507 let exp_first = expected[0:0]
508 call assert_equal(exp_first, prop_list(1))
Bram Moolenaar5c65e6a2019-05-17 11:08:56 +0200509 let expected = expected[1:1]
510 let expected[0].col -= 4
Bram Moolenaar45dd07f2019-05-15 22:45:37 +0200511 call assert_equal(expected, prop_list(2))
512 call DeletePropTypes()
513
514 bwipe!
515 set bs&
516endfunc
517
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100518func Test_prop_clear()
519 new
520 call AddPropTypes()
521 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100522 call assert_equal(Get_expected_props(), prop_list(1))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100523
Bram Moolenaara5a78822019-09-04 21:57:18 +0200524 eval 1->prop_clear()
525 call assert_equal([], 1->prop_list())
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100526
527 call DeletePropTypes()
528 bwipe!
529endfunc
530
531func Test_prop_clear_buf()
532 new
533 call AddPropTypes()
534 call SetupPropsInFirstLine()
535 let bufnr = bufnr('')
536 wincmd w
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100537 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100538
539 call prop_clear(1, 1, {'bufnr': bufnr})
540 call assert_equal([], prop_list(1, {'bufnr': bufnr}))
541
542 wincmd w
543 call DeletePropTypes()
544 bwipe!
545endfunc
546
Bram Moolenaar21b50382019-01-04 18:07:24 +0100547func Test_prop_setline()
548 new
549 call AddPropTypes()
550 call SetupPropsInFirstLine()
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100551 call assert_equal(Get_expected_props(), prop_list(1))
Bram Moolenaar21b50382019-01-04 18:07:24 +0100552
553 call setline(1, 'foobar')
554 call assert_equal([], prop_list(1))
555
556 call DeletePropTypes()
557 bwipe!
558endfunc
559
560func Test_prop_setbufline()
561 new
562 call AddPropTypes()
563 call SetupPropsInFirstLine()
564 let bufnr = bufnr('')
565 wincmd w
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100566 call assert_equal(Get_expected_props(), prop_list(1, {'bufnr': bufnr}))
Bram Moolenaar21b50382019-01-04 18:07:24 +0100567
568 call setbufline(bufnr, 1, 'foobar')
569 call assert_equal([], prop_list(1, {'bufnr': bufnr}))
570
571 wincmd w
572 call DeletePropTypes()
573 bwipe!
574endfunc
575
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100576func Test_prop_substitute()
577 new
578 " Set first line to 'one two three'
579 call AddPropTypes()
580 call SetupPropsInFirstLine()
581 let expected_props = Get_expected_props()
582 call assert_equal(expected_props, prop_list(1))
583
584 " Change "n" in "one" to XX: 'oXXe two three'
585 s/n/XX/
586 let expected_props[0].length += 1
587 let expected_props[1].length += 1
588 let expected_props[2].col += 1
589 let expected_props[3].col += 1
590 call assert_equal(expected_props, prop_list(1))
591
592 " Delete "t" in "two" and "three" to XX: 'oXXe wo hree'
593 s/t//g
594 let expected_props[0].length -= 2
595 let expected_props[2].length -= 1
596 let expected_props[3].length -= 1
597 let expected_props[3].col -= 1
598 call assert_equal(expected_props, prop_list(1))
599
600 " Split the line by changing w to line break: 'oXXe ', 'o hree'
601 " The long prop is split and spans both lines.
602 " The props on "two" and "three" move to the next line.
603 s/w/\r/
604 let new_props = [
605 \ copy(expected_props[0]),
606 \ copy(expected_props[2]),
607 \ copy(expected_props[3]),
608 \ ]
609 let expected_props[0].length = 5
Bram Moolenaar87be9be2020-05-30 15:32:02 +0200610 let expected_props[0].end = 0
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100611 unlet expected_props[3]
612 unlet expected_props[2]
613 call assert_equal(expected_props, prop_list(1))
614
615 let new_props[0].length = 6
Bram Moolenaar87be9be2020-05-30 15:32:02 +0200616 let new_props[0].start = 0
Bram Moolenaar4164bb22019-01-04 23:09:49 +0100617 let new_props[1].col = 1
618 let new_props[1].length = 1
619 let new_props[2].col = 3
620 call assert_equal(new_props, prop_list(2))
621
622 call DeletePropTypes()
623 bwipe!
624endfunc
625
Bram Moolenaar663bc892019-01-08 23:07:24 +0100626func Test_prop_change_indent()
627 call prop_type_add('comment', {'highlight': 'Directory'})
628 new
629 call setline(1, [' xxx', 'yyyyy'])
630 call prop_add(2, 2, {'length': 2, 'type': 'comment'})
631 let expect = {'col': 2, 'length': 2, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
632 call assert_equal([expect], prop_list(2))
633
634 set shiftwidth=3
635 normal 2G>>
636 call assert_equal(' yyyyy', getline(2))
637 let expect.col += 3
638 call assert_equal([expect], prop_list(2))
639
640 normal 2G==
641 call assert_equal(' yyyyy', getline(2))
642 let expect.col = 6
643 call assert_equal([expect], prop_list(2))
644
645 call prop_clear(2)
646 call prop_add(2, 2, {'length': 5, 'type': 'comment'})
647 let expect.col = 2
648 let expect.length = 5
649 call assert_equal([expect], prop_list(2))
650
651 normal 2G<<
652 call assert_equal(' yyyyy', getline(2))
653 let expect.length = 2
654 call assert_equal([expect], prop_list(2))
655
656 set shiftwidth&
657 call prop_type_delete('comment')
658endfunc
659
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100660" Setup a three line prop in lines 2 - 4.
661" Add short props in line 1 and 5.
662func Setup_three_line_prop()
663 new
664 call setline(1, ['one', 'twotwo', 'three', 'fourfour', 'five'])
665 call prop_add(1, 2, {'length': 1, 'type': 'comment'})
666 call prop_add(2, 4, {'end_lnum': 4, 'end_col': 5, 'type': 'comment'})
667 call prop_add(5, 2, {'length': 1, 'type': 'comment'})
668endfunc
669
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100670func Test_prop_multiline()
Bram Moolenaara5a78822019-09-04 21:57:18 +0200671 eval 'comment'->prop_type_add({'highlight': 'Directory'})
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100672 new
673 call setline(1, ['xxxxxxx', 'yyyyyyyyy', 'zzzzzzzz'])
674
675 " start halfway line 1, end halfway line 3
676 call prop_add(1, 3, {'end_lnum': 3, 'end_col': 5, 'type': 'comment'})
677 let expect1 = {'col': 3, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
678 call assert_equal([expect1], prop_list(1))
679 let expect2 = {'col': 1, 'length': 10, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
680 call assert_equal([expect2], prop_list(2))
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100681 let expect3 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100682 call assert_equal([expect3], prop_list(3))
683 call prop_clear(1, 3)
684
685 " include all three lines
686 call prop_add(1, 1, {'end_lnum': 3, 'end_col': 999, 'type': 'comment'})
687 let expect1.col = 1
688 let expect1.length = 8
689 call assert_equal([expect1], prop_list(1))
690 call assert_equal([expect2], prop_list(2))
691 let expect3.length = 9
692 call assert_equal([expect3], prop_list(3))
693 call prop_clear(1, 3)
694
695 bwipe!
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100696
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100697 " Test deleting the first line of a multi-line prop.
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100698 call Setup_three_line_prop()
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100699 let expect_short = {'col': 2, 'length': 1, 'type': 'comment', 'start': 1, 'end': 1, 'id': 0}
700 call assert_equal([expect_short], prop_list(1))
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100701 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
702 call assert_equal([expect2], prop_list(2))
703 2del
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100704 call assert_equal([expect_short], prop_list(1))
705 let expect2 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
706 call assert_equal([expect2], prop_list(2))
707 bwipe!
708
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100709 " Test deleting the last line of a multi-line prop.
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100710 call Setup_three_line_prop()
711 let expect3 = {'col': 1, 'length': 6, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
712 call assert_equal([expect3], prop_list(3))
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100713 let expect4 = {'col': 1, 'length': 4, 'type': 'comment', 'start': 0, 'end': 1, 'id': 0}
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100714 call assert_equal([expect4], prop_list(4))
715 4del
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100716 let expect3.end = 1
Bram Moolenaarc1a9bc12018-12-28 21:59:29 +0100717 call assert_equal([expect3], prop_list(3))
718 call assert_equal([expect_short], prop_list(4))
719 bwipe!
720
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100721 " Test appending a line below the multi-line text prop start.
Bram Moolenaarb56ac042018-12-28 23:22:40 +0100722 call Setup_three_line_prop()
723 let expect2 = {'col': 4, 'length': 4, 'type': 'comment', 'start': 1, 'end': 0, 'id': 0}
724 call assert_equal([expect2], prop_list(2))
725 call append(2, "new line")
726 call assert_equal([expect2], prop_list(2))
727 let expect3 = {'col': 1, 'length': 9, 'type': 'comment', 'start': 0, 'end': 0, 'id': 0}
728 call assert_equal([expect3], prop_list(3))
729 bwipe!
730
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100731 call prop_type_delete('comment')
732endfunc
733
Bram Moolenaar9df53b62020-01-13 20:40:51 +0100734func Test_prop_line2byte()
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100735 call prop_type_add('comment', {'highlight': 'Directory'})
736 new
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100737 call setline(1, ['line1', 'second line', ''])
Bram Moolenaar8cf734e2018-12-26 01:09:00 +0100738 set ff=unix
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100739 call assert_equal(19, line2byte(3))
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100740 call prop_add(1, 1, {'end_col': 3, 'type': 'comment'})
Bram Moolenaar00b1e042018-12-26 23:42:10 +0100741 call assert_equal(19, line2byte(3))
Bram Moolenaarb413d2e2018-12-25 23:15:46 +0100742
743 bwipe!
744 call prop_type_delete('comment')
745endfunc
746
Bram Moolenaar9df53b62020-01-13 20:40:51 +0100747func Test_prop_byte2line()
748 new
749 set ff=unix
750 call setline(1, ['one one', 'two two', 'three three', 'four four', 'five'])
751 call assert_equal(4, byte2line(line2byte(4)))
752 call assert_equal(5, byte2line(line2byte(5)))
753
754 call prop_type_add('prop', {'highlight': 'Directory'})
755 call prop_add(3, 1, {'length': 5, 'type': 'prop'})
756 call assert_equal(4, byte2line(line2byte(4)))
757 call assert_equal(5, byte2line(line2byte(5)))
758
759 bwipe!
760 call prop_type_delete('prop')
761endfunc
762
Bram Moolenaar7f1664e2019-01-04 17:21:24 +0100763func Test_prop_undo()
764 new
765 call prop_type_add('comment', {'highlight': 'Directory'})
766 call setline(1, ['oneone', 'twotwo', 'three'])
767 " Set 'undolevels' to break changes into undo-able pieces.
768 set ul&
769
770 call prop_add(1, 3, {'end_col': 5, 'type': 'comment'})
771 let expected = [{'col': 3, 'length': 2, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
772 call assert_equal(expected, prop_list(1))
773
774 " Insert a character, then undo.
775 exe "normal 0lllix\<Esc>"
776 set ul&
777 let expected[0].length = 3
778 call assert_equal(expected, prop_list(1))
779 undo
780 let expected[0].length = 2
781 call assert_equal(expected, prop_list(1))
782
783 " Delete a character, then undo
784 exe "normal 0lllx"
785 set ul&
786 let expected[0].length = 1
787 call assert_equal(expected, prop_list(1))
788 undo
789 let expected[0].length = 2
790 call assert_equal(expected, prop_list(1))
791
792 " Delete the line, then undo
793 1d
794 set ul&
795 call assert_equal([], prop_list(1))
796 undo
797 call assert_equal(expected, prop_list(1))
798
799 " Insert a character, delete two characters, then undo with "U"
800 exe "normal 0lllix\<Esc>"
801 set ul&
802 let expected[0].length = 3
803 call assert_equal(expected, prop_list(1))
804 exe "normal 0lllxx"
805 set ul&
806 let expected[0].length = 1
807 call assert_equal(expected, prop_list(1))
808 normal U
809 let expected[0].length = 2
810 call assert_equal(expected, prop_list(1))
811
Bram Moolenaar338dfda2019-05-19 15:19:57 +0200812 " substitute a word, then undo
813 call setline(1, 'the number 123 is highlighted.')
814 call prop_add(1, 12, {'length': 3, 'type': 'comment'})
815 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
816 call assert_equal(expected, prop_list(1))
817 set ul&
818 1s/number/foo
819 let expected[0].col = 9
820 call assert_equal(expected, prop_list(1))
821 undo
822 let expected[0].col = 12
823 call assert_equal(expected, prop_list(1))
Bram Moolenaarf3333b02019-05-19 22:53:40 +0200824 call prop_clear(1)
825
826 " substitute with backslash
827 call setline(1, 'the number 123 is highlighted.')
828 call prop_add(1, 12, {'length': 3, 'type': 'comment'})
829 let expected = [{'col': 12, 'length': 3, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
830 call assert_equal(expected, prop_list(1))
831 1s/the/\The
832 call assert_equal(expected, prop_list(1))
833 1s/^/\\
834 let expected[0].col += 1
835 call assert_equal(expected, prop_list(1))
836 1s/^/\~
837 let expected[0].col += 1
838 call assert_equal(expected, prop_list(1))
839 1s/123/12\\3
840 let expected[0].length += 1
841 call assert_equal(expected, prop_list(1))
842 call prop_clear(1)
Bram Moolenaar338dfda2019-05-19 15:19:57 +0200843
Bram Moolenaar7f1664e2019-01-04 17:21:24 +0100844 bwipe!
845 call prop_type_delete('comment')
846endfunc
847
Bram Moolenaarecafcc12019-11-16 20:41:51 +0100848func Test_prop_delete_text()
849 new
850 call prop_type_add('comment', {'highlight': 'Directory'})
851 call setline(1, ['oneone', 'twotwo', 'three'])
852
853 " zero length property
854 call prop_add(1, 3, {'type': 'comment'})
855 let expected = [{'col': 3, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
856 call assert_equal(expected, prop_list(1))
857
858 " delete one char moves the property
859 normal! x
860 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
861 call assert_equal(expected, prop_list(1))
862
863 " delete char of the property has no effect
864 normal! lx
865 let expected = [{'col': 2, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
866 call assert_equal(expected, prop_list(1))
867
868 " delete more chars moves property to first column, is not deleted
869 normal! 0xxxx
870 let expected = [{'col': 1, 'length': 0, 'id': 0, 'type': 'comment', 'start': 1, 'end': 1} ]
871 call assert_equal(expected, prop_list(1))
872
873 bwipe!
874 call prop_type_delete('comment')
875endfunc
876
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100877" screenshot test with textprop highlighting
Bram Moolenaar8055d172019-05-17 22:57:26 +0200878func Test_textprop_screenshot_various()
Bram Moolenaar34390282019-10-16 14:38:26 +0200879 CheckScreendump
Bram Moolenaared79d1e2019-02-22 14:38:58 +0100880 " The Vim running in the terminal needs to use utf-8.
Bram Moolenaar34390282019-10-16 14:38:26 +0200881 if g:orig_encoding != 'utf-8'
882 throw 'Skipped: not using utf-8'
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100883 endif
884 call writefile([
Bram Moolenaarde24a872019-05-05 15:48:00 +0200885 \ "call setline(1, ["
886 \ .. "'One two',"
887 \ .. "'Numbér 123 änd thœn 4¾7.',"
888 \ .. "'--aa--bb--cc--dd--',"
889 \ .. "'// comment with error in it',"
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200890 \ .. "'first line',"
891 \ .. "' second line ',"
892 \ .. "'third line',"
893 \ .. "' fourth line',"
Bram Moolenaarde24a872019-05-05 15:48:00 +0200894 \ .. "])",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100895 \ "hi NumberProp ctermfg=blue",
896 \ "hi LongProp ctermbg=yellow",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200897 \ "hi BackgroundProp ctermbg=lightgrey",
898 \ "hi UnderlineProp cterm=underline",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100899 \ "call prop_type_add('number', {'highlight': 'NumberProp'})",
Bram Moolenaara5a78822019-09-04 21:57:18 +0200900 \ "call prop_type_add('long', {'highlight': 'NumberProp'})",
901 \ "call prop_type_change('long', {'highlight': 'LongProp'})",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100902 \ "call prop_type_add('start', {'highlight': 'NumberProp', 'start_incl': 1})",
903 \ "call prop_type_add('end', {'highlight': 'NumberProp', 'end_incl': 1})",
904 \ "call prop_type_add('both', {'highlight': 'NumberProp', 'start_incl': 1, 'end_incl': 1})",
Bram Moolenaardbd43162019-11-09 21:28:14 +0100905 \ "call prop_type_add('background', {'highlight': 'BackgroundProp', 'combine': 0})",
906 \ "call prop_type_add('backgroundcomb', {'highlight': 'NumberProp', 'combine': 1})",
907 \ "eval 'backgroundcomb'->prop_type_change({'highlight': 'BackgroundProp'})",
Bram Moolenaar58e32ab2019-11-12 22:44:22 +0100908 \ "call prop_type_add('error', {'highlight': 'UnderlineProp'})",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100909 \ "call prop_add(1, 4, {'end_lnum': 3, 'end_col': 3, 'type': 'long'})",
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100910 \ "call prop_add(2, 9, {'length': 3, 'type': 'number'})",
911 \ "call prop_add(2, 24, {'length': 4, 'type': 'number'})",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100912 \ "call prop_add(3, 3, {'length': 2, 'type': 'number'})",
913 \ "call prop_add(3, 7, {'length': 2, 'type': 'start'})",
914 \ "call prop_add(3, 11, {'length': 2, 'type': 'end'})",
915 \ "call prop_add(3, 15, {'length': 2, 'type': 'both'})",
Bram Moolenaardbd43162019-11-09 21:28:14 +0100916 \ "call prop_add(4, 6, {'length': 3, 'type': 'background'})",
917 \ "call prop_add(4, 12, {'length': 10, 'type': 'backgroundcomb'})",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200918 \ "call prop_add(4, 17, {'length': 5, 'type': 'error'})",
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200919 \ "call prop_add(5, 7, {'length': 4, 'type': 'long'})",
920 \ "call prop_add(6, 1, {'length': 8, 'type': 'long'})",
921 \ "call prop_add(8, 1, {'length': 1, 'type': 'long'})",
922 \ "call prop_add(8, 11, {'length': 4, 'type': 'long'})",
Bram Moolenaarbfd45122019-05-17 13:05:07 +0200923 \ "set number cursorline",
Bram Moolenaarb9c67a52019-01-01 19:49:20 +0100924 \ "hi clear SpellBad",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100925 \ "set spell",
Bram Moolenaarde24a872019-05-05 15:48:00 +0200926 \ "syn match Comment '//.*'",
927 \ "hi Comment ctermfg=green",
Bram Moolenaar44746aa2019-01-02 00:02:11 +0100928 \ "normal 3G0llix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>lllix\<Esc>",
Bram Moolenaar33c8ca92019-01-02 18:00:27 +0100929 \ "normal 3G0lli\<BS>\<Esc>",
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200930 \ "normal 6G0i\<BS>\<Esc>",
931 \ "normal 3J",
932 \ "normal 3G",
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100933 \], 'XtestProp')
Bram Moolenaar80e737c2019-05-17 19:56:34 +0200934 let buf = RunVimInTerminal('-S XtestProp', {'rows': 8})
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100935 call VerifyScreenDump(buf, 'Test_textprop_01', {})
Bram Moolenaare3d31b02018-12-24 23:07:04 +0100936
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100937 " clean up
938 call StopVimInTerminal(buf)
Bram Moolenaar2f21fa82018-12-31 20:05:56 +0100939 call delete('XtestProp')
Bram Moolenaarc6d86dc2018-12-31 13:57:36 +0100940endfunc
Bram Moolenaar8055d172019-05-17 22:57:26 +0200941
942func RunTestVisualBlock(width, dump)
943 call writefile([
944 \ "call setline(1, ["
945 \ .. "'xxxxxxxxx 123 x',"
946 \ .. "'xxxxxxxx 123 x',"
947 \ .. "'xxxxxxx 123 x',"
948 \ .. "'xxxxxx 123 x',"
949 \ .. "'xxxxx 123 x',"
950 \ .. "'xxxx 123 xx',"
951 \ .. "'xxx 123 xxx',"
952 \ .. "'xx 123 xxxx',"
953 \ .. "'x 123 xxxxx',"
954 \ .. "' 123 xxxxxx',"
955 \ .. "])",
956 \ "hi SearchProp ctermbg=yellow",
957 \ "call prop_type_add('search', {'highlight': 'SearchProp'})",
958 \ "call prop_add(1, 11, {'length': 3, 'type': 'search'})",
959 \ "call prop_add(2, 10, {'length': 3, 'type': 'search'})",
960 \ "call prop_add(3, 9, {'length': 3, 'type': 'search'})",
961 \ "call prop_add(4, 8, {'length': 3, 'type': 'search'})",
962 \ "call prop_add(5, 7, {'length': 3, 'type': 'search'})",
963 \ "call prop_add(6, 6, {'length': 3, 'type': 'search'})",
964 \ "call prop_add(7, 5, {'length': 3, 'type': 'search'})",
965 \ "call prop_add(8, 4, {'length': 3, 'type': 'search'})",
966 \ "call prop_add(9, 3, {'length': 3, 'type': 'search'})",
967 \ "call prop_add(10, 2, {'length': 3, 'type': 'search'})",
968 \ "normal 1G6|\<C-V>" .. repeat('l', a:width - 1) .. "10jx",
969 \], 'XtestPropVis')
970 let buf = RunVimInTerminal('-S XtestPropVis', {'rows': 12})
971 call VerifyScreenDump(buf, 'Test_textprop_vis_' .. a:dump, {})
972
973 " clean up
974 call StopVimInTerminal(buf)
975 call delete('XtestPropVis')
976endfunc
977
978" screenshot test with Visual block mode operations
979func Test_textprop_screenshot_visual()
Bram Moolenaar34390282019-10-16 14:38:26 +0200980 CheckScreendump
Bram Moolenaar8055d172019-05-17 22:57:26 +0200981
982 " Delete two columns while text props are three chars wide.
983 call RunTestVisualBlock(2, '01')
984
985 " Same, but delete four columns
986 call RunTestVisualBlock(4, '02')
987endfunc
Bram Moolenaard79eef22019-05-24 20:41:55 +0200988
Bram Moolenaara956bf62019-06-19 17:34:24 +0200989func Test_textprop_after_tab()
Bram Moolenaar34390282019-10-16 14:38:26 +0200990 CheckScreendump
Bram Moolenaar37e66cf2019-06-19 18:16:10 +0200991
Bram Moolenaara956bf62019-06-19 17:34:24 +0200992 let lines =<< trim END
993 call setline(1, [
994 \ "\txxx",
995 \ "x\txxx",
996 \ ])
997 hi SearchProp ctermbg=yellow
998 call prop_type_add('search', {'highlight': 'SearchProp'})
999 call prop_add(1, 2, {'length': 3, 'type': 'search'})
1000 call prop_add(2, 3, {'length': 3, 'type': 'search'})
1001 END
1002 call writefile(lines, 'XtestPropTab')
1003 let buf = RunVimInTerminal('-S XtestPropTab', {'rows': 6})
1004 call VerifyScreenDump(buf, 'Test_textprop_tab', {})
1005
1006 " clean up
1007 call StopVimInTerminal(buf)
1008 call delete('XtestPropTab')
1009endfunc
1010
Bram Moolenaar34390282019-10-16 14:38:26 +02001011func Test_textprop_with_syntax()
1012 CheckScreendump
1013
1014 let lines =<< trim END
1015 call setline(1, [
1016 \ "(abc)",
1017 \ ])
1018 syn match csParens "[()]" display
1019 hi! link csParens MatchParen
1020
1021 call prop_type_add('TPTitle', #{ highlight: 'Title' })
1022 call prop_add(1, 2, #{type: 'TPTitle', end_col: 5})
1023 END
1024 call writefile(lines, 'XtestPropSyn')
1025 let buf = RunVimInTerminal('-S XtestPropSyn', {'rows': 6})
1026 call VerifyScreenDump(buf, 'Test_textprop_syn_1', {})
1027
1028 " clean up
1029 call StopVimInTerminal(buf)
1030 call delete('XtestPropSyn')
1031endfunc
1032
Bram Moolenaard79eef22019-05-24 20:41:55 +02001033" Adding a text property to a new buffer should not fail
1034func Test_textprop_empty_buffer()
1035 call prop_type_add('comment', {'highlight': 'Search'})
1036 new
1037 call prop_add(1, 1, {'type': 'comment'})
1038 close
Bram Moolenaaradfde112019-05-25 22:11:45 +02001039 call prop_type_delete('comment')
1040endfunc
1041
Bram Moolenaard74af422019-06-28 21:38:00 +02001042" Adding a text property with invalid highlight should be ignored.
1043func Test_textprop_invalid_highlight()
1044 call assert_fails("call prop_type_add('dni', {'highlight': 'DoesNotExist'})", 'E970:')
1045 new
1046 call setline(1, ['asdf','asdf'])
1047 call prop_add(1, 1, {'length': 4, 'type': 'dni'})
1048 redraw
1049 bwipe!
1050 call prop_type_delete('dni')
1051endfunc
1052
Bram Moolenaaradfde112019-05-25 22:11:45 +02001053" Adding a text property to an empty buffer and then editing another
1054func Test_textprop_empty_buffer_next()
1055 call prop_type_add("xxx", {})
1056 call prop_add(1, 1, {"type": "xxx"})
1057 next X
1058 call prop_type_delete('xxx')
Bram Moolenaard79eef22019-05-24 20:41:55 +02001059endfunc
Bram Moolenaarf0884c52019-05-24 21:22:29 +02001060
1061func Test_textprop_remove_from_buf()
1062 new
1063 let buf = bufnr('')
1064 call prop_type_add('one', {'bufnr': buf})
1065 call prop_add(1, 1, {'type': 'one', 'id': 234})
1066 file x
1067 edit y
1068 call prop_remove({'id': 234, 'bufnr': buf}, 1)
1069 call prop_type_delete('one', {'bufnr': buf})
1070 bwipe! x
1071 close
1072endfunc
Bram Moolenaar45311b52019-08-13 22:27:32 +02001073
1074func Test_textprop_in_unloaded_buf()
1075 edit Xaaa
1076 call setline(1, 'aaa')
1077 write
1078 edit Xbbb
1079 call setline(1, 'bbb')
1080 write
1081 let bnr = bufnr('')
1082 edit Xaaa
1083
1084 call prop_type_add('ErrorMsg', #{highlight:'ErrorMsg'})
1085 call assert_fails("call prop_add(1, 1, #{end_lnum: 1, endcol: 2, type: 'ErrorMsg', bufnr: bnr})", 'E275:')
1086 exe 'buf ' .. bnr
1087 call assert_equal('bbb', getline(1))
1088 call assert_equal(0, prop_list(1)->len())
1089
1090 bwipe! Xaaa
1091 bwipe! Xbbb
1092 cal delete('Xaaa')
1093 cal delete('Xbbb')
1094endfunc
Bram Moolenaar1fd30d72019-10-25 22:13:29 +02001095
1096func Test_proptype_substitute2()
1097 new
1098 " text_prop.vim
1099 call setline(1, [
1100 \ 'The num 123 is smaller than 4567.',
1101 \ '123 The number 123 is smaller than 4567.',
1102 \ '123 The number 123 is smaller than 4567.'])
1103
1104 call prop_type_add('number', {'highlight': 'ErrorMsg'})
1105
1106 call prop_add(1, 12, {'length': 3, 'type': 'number'})
1107 call prop_add(2, 1, {'length': 3, 'type': 'number'})
1108 call prop_add(3, 36, {'length': 4, 'type': 'number'})
1109 set ul&
1110 let expected = [{'id': 0, 'col': 13, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1111 \ {'id': 0, 'col': 1, 'end': 1, 'type': 'number', 'length': 3, 'start': 1},
1112 \ {'id': 0, 'col': 50, 'end': 1, 'type': 'number', 'length': 4, 'start': 1}]
1113 " Add some text in between
1114 %s/\s\+/ /g
1115 call assert_equal(expected, prop_list(1) + prop_list(2) + prop_list(3))
1116
1117 " remove some text
1118 :1s/[a-z]\{3\}//g
1119 let expected = [{'id': 0, 'col': 10, 'end': 1, 'type': 'number', 'length': 3, 'start': 1}]
1120 call assert_equal(expected, prop_list(1))
1121 bwipe!
1122endfunc
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001123
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001124func SaveOptions()
1125 let d = #{tabstop: &tabstop,
1126 \ softtabstop: &softtabstop,
1127 \ shiftwidth: &shiftwidth,
1128 \ expandtab: &expandtab,
1129 \ foldmethod: '"' .. &foldmethod .. '"',
1130 \ }
1131 return d
1132endfunc
1133
1134func RestoreOptions(dict)
1135 for name in keys(a:dict)
1136 exe 'let &' .. name .. ' = ' .. a:dict[name]
1137 endfor
1138endfunc
1139
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001140func Test_textprop_noexpandtab()
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001141 new
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001142 let save_dict = SaveOptions()
1143
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001144 set tabstop=8
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001145 set softtabstop=4
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001146 set shiftwidth=4
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001147 set noexpandtab
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001148 set foldmethod=marker
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001149
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001150 call feedkeys("\<esc>\<esc>0Ca\<cr>\<esc>\<up>", "tx")
1151 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1152 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1153 call feedkeys("0i\<tab>", "tx")
1154 call prop_remove({'type': 'test'})
1155 call prop_add(1, 2, {'end_col': 3, 'type': 'test'})
1156 call feedkeys("A\<left>\<tab>", "tx")
1157 call prop_remove({'type': 'test'})
1158 try
1159 " It is correct that this does not pass
1160 call prop_add(1, 6, {'end_col': 7, 'type': 'test'})
1161 " Has already collapsed here, start_col:6 does not result in an error
1162 call feedkeys("A\<left>\<tab>", "tx")
1163 catch /^Vim\%((\a\+)\)\=:E964/
1164 endtry
1165 call prop_remove({'type': 'test'})
Bram Moolenaarac15fd82020-01-09 21:35:48 +01001166 call prop_type_delete('test')
1167
1168 call RestoreOptions(save_dict)
1169 bwipe!
1170endfunc
1171
1172func Test_textprop_noexpandtab_redraw()
1173 new
1174 let save_dict = SaveOptions()
1175
1176 set tabstop=8
1177 set softtabstop=4
1178 set shiftwidth=4
1179 set noexpandtab
1180 set foldmethod=marker
1181
1182 call feedkeys("\<esc>\<esc>0Ca\<cr>\<space>\<esc>\<up>", "tx")
1183 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1184 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1185 call feedkeys("0i\<tab>", "tx")
1186 " Internally broken at the next line
1187 call feedkeys("A\<left>\<tab>", "tx")
1188 redraw
1189 " Index calculation failed internally on next line
1190 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1191 call prop_remove({'type': 'test', 'all': v:true})
1192 call prop_type_delete('test')
1193 call prop_type_delete('test')
1194
1195 call RestoreOptions(save_dict)
1196 bwipe!
1197endfunc
1198
1199func Test_textprop_ins_str()
1200 new
1201 call setline(1, 'just some text')
1202 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1203 call prop_add(1, 1, {'end_col': 2, 'type': 'test'})
1204 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1205
1206 call feedkeys("foi\<F8>\<Esc>", "tx")
1207 call assert_equal('just s<F8>ome text', getline(1))
1208 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 1, 'start': 1}], prop_list(1))
1209
1210 bwipe!
1211 call prop_remove({'type': 'test'})
1212 call prop_type_delete('test')
Bram Moolenaar5cb0b932020-01-03 21:25:59 +01001213endfunc
Bram Moolenaar66b98852020-03-11 19:15:52 +01001214
1215func Test_find_prop_later_in_line()
1216 new
1217 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1218 call setline(1, 'just some text')
1219 call prop_add(1, 1, {'length': 4, 'type': 'test'})
1220 call prop_add(1, 10, {'length': 3, 'type': 'test'})
1221
1222 call assert_equal({'id': 0, 'lnum': 1, 'col': 10, 'end': 1, 'type': 'test', 'length': 3, 'start': 1},
1223 \ prop_find(#{type: 'test', lnum: 1, col: 6}))
1224
1225 bwipe!
1226 call prop_type_delete('test')
1227endfunc
1228
1229func Test_find_zerowidth_prop_sol()
1230 new
1231 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1232 call setline(1, 'just some text')
1233 call prop_add(1, 1, {'length': 0, 'type': 'test'})
1234
1235 call assert_equal({'id': 0, 'lnum': 1, 'col': 1, 'end': 1, 'type': 'test', 'length': 0, 'start': 1},
1236 \ prop_find(#{type: 'test', lnum: 1}))
1237
1238 bwipe!
1239 call prop_type_delete('test')
1240endfunc
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001241
1242" Test for passing invalid arguments to prop_xxx() functions
1243func Test_prop_func_invalid_args()
1244 call assert_fails('call prop_clear(1, 2, [])', 'E715:')
1245 call assert_fails('call prop_clear(-1, 2)', 'E16:')
1246 call assert_fails('call prop_find(test_null_dict())', 'E474:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02001247 call assert_fails('call prop_find({"bufnr" : []})', 'E730:')
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001248 call assert_fails('call prop_find({})', 'E968:')
1249 call assert_fails('call prop_find({}, "x")', 'E474:')
1250 call assert_fails('call prop_find({"lnum" : -2})', 'E16:')
1251 call assert_fails('call prop_list(1, [])', 'E715:')
Bram Moolenaar9d489562020-07-30 20:08:50 +02001252 call assert_fails('call prop_list(-1, {})', 'E16:')
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001253 call assert_fails('call prop_remove([])', 'E474:')
1254 call assert_fails('call prop_remove({}, -2)', 'E16:')
1255 call assert_fails('call prop_remove({})', 'E968:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02001256 call assert_fails('call prop_type_add([], {})', 'E730:')
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001257 call assert_fails("call prop_type_change('long', {'xyz' : 10})", 'E971:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02001258 call assert_fails("call prop_type_delete([])", 'E730:')
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001259 call assert_fails("call prop_type_delete('xyz', [])", 'E715:')
Bram Moolenaar9b7bf9e2020-07-11 22:14:59 +02001260 call assert_fails("call prop_type_get([])", 'E730:')
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001261 call assert_fails("call prop_type_get('', [])", 'E474:')
1262 call assert_fails("call prop_type_list([])", 'E715:')
1263endfunc
1264
Bram Moolenaar87be9be2020-05-30 15:32:02 +02001265func Test_split_join()
1266 new
1267 call prop_type_add('test', {'highlight': 'ErrorMsg'})
1268 call setline(1, 'just some text')
1269 call prop_add(1, 6, {'length': 4, 'type': 'test'})
1270
1271 " Split in middle of "some"
1272 execute "normal! 8|i\<CR>"
1273 call assert_equal([{'id': 0, 'col': 6, 'end': 0, 'type': 'test', 'length': 2, 'start': 1}],
1274 \ prop_list(1))
1275 call assert_equal([{'id': 0, 'col': 1, 'end': 1, 'type': 'test', 'length': 2, 'start': 0}],
1276 \ prop_list(2))
1277
1278 " Join the two lines back together
1279 normal! 1GJ
1280 call assert_equal([{'id': 0, 'col': 6, 'end': 1, 'type': 'test', 'length': 5, 'start': 1}], prop_list(1))
1281
1282 bwipe!
1283 call prop_type_delete('test')
1284endfunc
1285
Bram Moolenaar99fa7212020-04-26 15:59:55 +02001286" vim: shiftwidth=2 sts=2 expandtab