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".