Mercurial > vim
comparison src/textprop.c @ 25640:78ef12e0ce8c v8.2.3356
patch 8.2.3356: adding many text properties requires a lot of function calls
Commit: https://github.com/vim/vim/commit/ccfb7c6758510e0fe5f390149ea14aee6ff4f55e
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Mon Aug 16 21:39:09 2021 +0200
patch 8.2.3356: adding many text properties requires a lot of function calls
Problem: Adding many text properties requires a lot of function calls.
Solution: Add the prop_add_list() function. (Yegappan Lakshmanan,
closes #8751)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 16 Aug 2021 21:45:03 +0200 |
parents | 3678a11e71fa |
children | 685206b54ecf |
comparison
equal
deleted
inserted
replaced
25639:b5eedbdaca91 | 25640:78ef12e0ce8c |
---|---|
181 prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict, | 181 prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict, |
182 curbuf, &argvars[2]); | 182 curbuf, &argvars[2]); |
183 } | 183 } |
184 | 184 |
185 /* | 185 /* |
186 * Shared between prop_add() and popup_create(). | 186 * Attach a text property 'type_name' to the text starting |
187 * "dict_arg" is the function argument of a dict containing "bufnr". | 187 * at [start_lnum, start_col] and ending at [end_lnum, end_col] in |
188 * it is NULL for popup_create(). | 188 * the buffer 'buf' and assign identifier 'id'. |
189 */ | 189 */ |
190 void | 190 static int |
191 prop_add_common( | 191 prop_add_one( |
192 linenr_T start_lnum, | 192 buf_T *buf, |
193 colnr_T start_col, | 193 char_u *type_name, |
194 dict_T *dict, | 194 int id, |
195 buf_T *default_buf, | 195 linenr_T start_lnum, |
196 typval_T *dict_arg) | 196 linenr_T end_lnum, |
197 { | 197 colnr_T start_col, |
198 colnr_T end_col) | |
199 { | |
200 proptype_T *type; | |
198 linenr_T lnum; | 201 linenr_T lnum; |
199 linenr_T end_lnum; | |
200 colnr_T end_col; | |
201 char_u *type_name; | |
202 proptype_T *type; | |
203 buf_T *buf = default_buf; | |
204 int id = 0; | |
205 char_u *newtext; | |
206 int proplen; | 202 int proplen; |
207 size_t textlen; | |
208 char_u *props = NULL; | 203 char_u *props = NULL; |
209 char_u *newprops; | 204 char_u *newprops; |
205 size_t textlen; | |
206 char_u *newtext; | |
207 int i; | |
210 textprop_T tmp_prop; | 208 textprop_T tmp_prop; |
211 int i; | |
212 | |
213 if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL) | |
214 { | |
215 emsg(_("E965: missing property type name")); | |
216 return; | |
217 } | |
218 type_name = dict_get_string(dict, (char_u *)"type", FALSE); | |
219 | |
220 if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL) | |
221 { | |
222 end_lnum = dict_get_number(dict, (char_u *)"end_lnum"); | |
223 if (end_lnum < start_lnum) | |
224 { | |
225 semsg(_(e_invargval), "end_lnum"); | |
226 return; | |
227 } | |
228 } | |
229 else | |
230 end_lnum = start_lnum; | |
231 | |
232 if (dict_find(dict, (char_u *)"length", -1) != NULL) | |
233 { | |
234 long length = dict_get_number(dict, (char_u *)"length"); | |
235 | |
236 if (length < 0 || end_lnum > start_lnum) | |
237 { | |
238 semsg(_(e_invargval), "length"); | |
239 return; | |
240 } | |
241 end_col = start_col + length; | |
242 } | |
243 else if (dict_find(dict, (char_u *)"end_col", -1) != NULL) | |
244 { | |
245 end_col = dict_get_number(dict, (char_u *)"end_col"); | |
246 if (end_col <= 0) | |
247 { | |
248 semsg(_(e_invargval), "end_col"); | |
249 return; | |
250 } | |
251 } | |
252 else if (start_lnum == end_lnum) | |
253 end_col = start_col; | |
254 else | |
255 end_col = 1; | |
256 | |
257 if (dict_find(dict, (char_u *)"id", -1) != NULL) | |
258 id = dict_get_number(dict, (char_u *)"id"); | |
259 | |
260 if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL) | |
261 return; | |
262 | 209 |
263 type = lookup_prop_type(type_name, buf); | 210 type = lookup_prop_type(type_name, buf); |
264 if (type == NULL) | 211 if (type == NULL) |
265 return; | 212 return FAIL; |
266 | 213 |
267 if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count) | 214 if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count) |
268 { | 215 { |
269 semsg(_(e_invalid_lnum), (long)start_lnum); | 216 semsg(_(e_invalid_lnum), (long)start_lnum); |
270 return; | 217 return FAIL; |
271 } | 218 } |
272 if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count) | 219 if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count) |
273 { | 220 { |
274 semsg(_(e_invalid_lnum), (long)end_lnum); | 221 semsg(_(e_invalid_lnum), (long)end_lnum); |
275 return; | 222 return FAIL; |
276 } | 223 } |
277 | 224 |
278 if (buf->b_ml.ml_mfp == NULL) | 225 if (buf->b_ml.ml_mfp == NULL) |
279 { | 226 { |
280 emsg(_("E275: Cannot add text property to unloaded buffer")); | 227 emsg(_("E275: Cannot add text property to unloaded buffer")); |
281 return; | 228 return FAIL; |
282 } | 229 } |
283 | 230 |
284 for (lnum = start_lnum; lnum <= end_lnum; ++lnum) | 231 for (lnum = start_lnum; lnum <= end_lnum; ++lnum) |
285 { | 232 { |
286 colnr_T col; // start column | 233 colnr_T col; // start column |
295 else | 242 else |
296 col = 1; | 243 col = 1; |
297 if (col - 1 > (colnr_T)textlen) | 244 if (col - 1 > (colnr_T)textlen) |
298 { | 245 { |
299 semsg(_(e_invalid_col), (long)start_col); | 246 semsg(_(e_invalid_col), (long)start_col); |
300 return; | 247 return FAIL; |
301 } | 248 } |
302 | 249 |
303 if (lnum == end_lnum) | 250 if (lnum == end_lnum) |
304 length = end_col - col; | 251 length = end_col - col; |
305 else | 252 else |
310 length = 0; // zero-width property | 257 length = 0; // zero-width property |
311 | 258 |
312 // Allocate the new line with space for the new property. | 259 // Allocate the new line with space for the new property. |
313 newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T)); | 260 newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T)); |
314 if (newtext == NULL) | 261 if (newtext == NULL) |
315 return; | 262 return FAIL; |
316 // Copy the text, including terminating NUL. | 263 // Copy the text, including terminating NUL. |
317 mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen); | 264 mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen); |
318 | 265 |
319 // Find the index where to insert the new property. | 266 // Find the index where to insert the new property. |
320 // Since the text properties are not aligned properly when stored with | 267 // Since the text properties are not aligned properly when stored with |
349 buf->b_ml.ml_line_ptr = newtext; | 296 buf->b_ml.ml_line_ptr = newtext; |
350 buf->b_ml.ml_line_len += sizeof(textprop_T); | 297 buf->b_ml.ml_line_len += sizeof(textprop_T); |
351 buf->b_ml.ml_flags |= ML_LINE_DIRTY; | 298 buf->b_ml.ml_flags |= ML_LINE_DIRTY; |
352 } | 299 } |
353 | 300 |
301 changed_lines_buf(buf, start_lnum, end_lnum + 1, 0); | |
302 return OK; | |
303 } | |
304 | |
305 /* | |
306 * prop_add_list() | |
307 * First argument specifies the text property: | |
308 * {'type': <str>, 'id': <num>, 'bufnr': <num>} | |
309 * Second argument is a List where each item is a List with the following | |
310 * entries: [lnum, start_col, end_col] | |
311 */ | |
312 void | |
313 f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED) | |
314 { | |
315 dict_T *dict; | |
316 char_u *type_name; | |
317 buf_T *buf = curbuf; | |
318 int id = 0; | |
319 listitem_T *li; | |
320 list_T *pos_list; | |
321 linenr_T start_lnum; | |
322 colnr_T start_col; | |
323 linenr_T end_lnum; | |
324 colnr_T end_col; | |
325 int error = FALSE; | |
326 | |
327 if (check_for_dict_arg(argvars, 0) == FAIL | |
328 || check_for_list_arg(argvars, 1) == FAIL) | |
329 return; | |
330 | |
331 if (argvars[1].vval.v_list == NULL) | |
332 { | |
333 emsg(_(e_listreq)); | |
334 return; | |
335 } | |
336 | |
337 dict = argvars[0].vval.v_dict; | |
338 if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL) | |
339 { | |
340 emsg(_("E965: missing property type name")); | |
341 return; | |
342 } | |
343 type_name = dict_get_string(dict, (char_u *)"type", FALSE); | |
344 | |
345 if (dict_find(dict, (char_u *)"id", -1) != NULL) | |
346 id = dict_get_number(dict, (char_u *)"id"); | |
347 | |
348 if (get_bufnr_from_arg(&argvars[0], &buf) == FAIL) | |
349 return; | |
350 | |
351 FOR_ALL_LIST_ITEMS(argvars[1].vval.v_list, li) | |
352 { | |
353 if (li->li_tv.v_type != VAR_LIST || li->li_tv.vval.v_list == NULL) | |
354 { | |
355 emsg(_(e_listreq)); | |
356 return; | |
357 } | |
358 | |
359 pos_list = li->li_tv.vval.v_list; | |
360 start_lnum = list_find_nr(pos_list, 0L, &error); | |
361 start_col = list_find_nr(pos_list, 1L, &error); | |
362 end_lnum = list_find_nr(pos_list, 2L, &error); | |
363 end_col = list_find_nr(pos_list, 3L, &error); | |
364 if (error || start_lnum <= 0 || start_col <= 0 | |
365 || end_lnum <= 0 || end_col <= 0) | |
366 { | |
367 emsg(_(e_invarg)); | |
368 return; | |
369 } | |
370 if (prop_add_one(buf, type_name, id, start_lnum, end_lnum, | |
371 start_col, end_col) == FAIL) | |
372 return; | |
373 } | |
374 | |
354 buf->b_has_textprop = TRUE; // this is never reset | 375 buf->b_has_textprop = TRUE; // this is never reset |
355 changed_lines_buf(buf, start_lnum, end_lnum + 1, 0); | 376 redraw_buf_later(buf, VALID); |
377 } | |
378 | |
379 /* | |
380 * Shared between prop_add() and popup_create(). | |
381 * "dict_arg" is the function argument of a dict containing "bufnr". | |
382 * it is NULL for popup_create(). | |
383 */ | |
384 void | |
385 prop_add_common( | |
386 linenr_T start_lnum, | |
387 colnr_T start_col, | |
388 dict_T *dict, | |
389 buf_T *default_buf, | |
390 typval_T *dict_arg) | |
391 { | |
392 linenr_T end_lnum; | |
393 colnr_T end_col; | |
394 char_u *type_name; | |
395 buf_T *buf = default_buf; | |
396 int id = 0; | |
397 | |
398 if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL) | |
399 { | |
400 emsg(_("E965: missing property type name")); | |
401 return; | |
402 } | |
403 type_name = dict_get_string(dict, (char_u *)"type", FALSE); | |
404 | |
405 if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL) | |
406 { | |
407 end_lnum = dict_get_number(dict, (char_u *)"end_lnum"); | |
408 if (end_lnum < start_lnum) | |
409 { | |
410 semsg(_(e_invargval), "end_lnum"); | |
411 return; | |
412 } | |
413 } | |
414 else | |
415 end_lnum = start_lnum; | |
416 | |
417 if (dict_find(dict, (char_u *)"length", -1) != NULL) | |
418 { | |
419 long length = dict_get_number(dict, (char_u *)"length"); | |
420 | |
421 if (length < 0 || end_lnum > start_lnum) | |
422 { | |
423 semsg(_(e_invargval), "length"); | |
424 return; | |
425 } | |
426 end_col = start_col + length; | |
427 } | |
428 else if (dict_find(dict, (char_u *)"end_col", -1) != NULL) | |
429 { | |
430 end_col = dict_get_number(dict, (char_u *)"end_col"); | |
431 if (end_col <= 0) | |
432 { | |
433 semsg(_(e_invargval), "end_col"); | |
434 return; | |
435 } | |
436 } | |
437 else if (start_lnum == end_lnum) | |
438 end_col = start_col; | |
439 else | |
440 end_col = 1; | |
441 | |
442 if (dict_find(dict, (char_u *)"id", -1) != NULL) | |
443 id = dict_get_number(dict, (char_u *)"id"); | |
444 | |
445 if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL) | |
446 return; | |
447 | |
448 prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col, end_col); | |
449 | |
450 buf->b_has_textprop = TRUE; // this is never reset | |
356 redraw_buf_later(buf, VALID); | 451 redraw_buf_later(buf, VALID); |
357 } | 452 } |
358 | 453 |
359 /* | 454 /* |
360 * Fetch the text properties for line "lnum" in buffer "buf". | 455 * Fetch the text properties for line "lnum" in buffer "buf". |