0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 9.0.0233: removing multiple text properties takes many calls

Problem:    Removing multiple text properties takes many calls.
Solution:   Pass a list to prop_remove(). (Ben Jackson, closes #10945)
This commit is contained in:
Ben Jackson 2022-08-20 20:54:51 +01:00 committed by Bram Moolenaar
parent 38ea5bda2b
commit a7704226a2
4 changed files with 111 additions and 19 deletions

View File

@ -2208,8 +2208,8 @@ EXTERN char e_failed_to_convert_returned_python_object_to_vim_value[]
INIT(= N_("E859: Failed to convert returned python object to a Vim value"));
#endif
#ifdef FEAT_PROP_POPUP
EXTERN char e_need_id_and_type_with_both[]
INIT(= N_("E860: Need 'id' and 'type' with 'both'"));
EXTERN char e_need_id_and_type_or_types_with_both[]
INIT(= N_("E860: Need 'id' and 'type' or 'types' with 'both'"));
# ifdef FEAT_TERMINAL
EXTERN char e_cannot_open_second_popup_with_terminal[]
INIT(= N_("E861: Cannot open a second popup with a terminal"));
@ -3316,3 +3316,7 @@ EXTERN char e_cannot_use_negative_id_after_adding_textprop_with_text[]
EXTERN char e_can_only_use_text_align_when_column_is_zero[]
INIT(= N_("E1294: Can only use text_align when column is zero"));
#endif
#ifdef FEAT_PROP_POPUP
EXTERN char e_cannot_specify_both_type_and_types[]
INIT(= N_("E1295: Cannot specify both 'type' and 'types'"));
#endif

View File

@ -426,6 +426,37 @@ func Test_prop_remove()
call DeletePropTypes()
bwipe!
new
call AddPropTypes()
call SetupPropsInFirstLine()
let props = Get_expected_props() " [whole, one, two, three]
call assert_equal(props, prop_list(1))
" remove one by types
call assert_equal(1, prop_remove({'types': ['one', 'two', 'three']}, 1))
unlet props[1] " [whole, two, three]
call assert_equal(props, prop_list(1))
" remove 'all' by types
call assert_equal(2, prop_remove({'types': ['three', 'whole'], 'all': 1}, 1))
unlet props[0] " [two, three]
unlet props[1] " [three]
call assert_equal(props, prop_list(1))
" remove none by types
call assert_equal(0, prop_remove({'types': ['three', 'whole'], 'all': 1}, 1))
call assert_equal(props, prop_list(1))
" no types
call assert_fails("call prop_remove({'types': []}, 1)", 'E968:')
call assert_fails("call prop_remove({'types': ['not_a_real_type']}, 1)", 'E971:')
" only one of types and type can be supplied
call assert_fails("call prop_remove({'type': 'one', 'types': ['three'], 'all': 1}, 1)", 'E1295:')
call DeletePropTypes()
bwipe!
endfunc
def Test_prop_add_vim9()

View File

@ -1010,7 +1010,7 @@ f_prop_find(typval_T *argvars, typval_T *rettv)
}
if (both && (!id_found || type_id == -1))
{
emsg(_(e_need_id_and_type_with_both));
emsg(_(e_need_id_and_type_or_types_with_both));
return;
}
@ -1378,7 +1378,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
buf_T *buf = curbuf;
int do_all;
int id = -MAXCOL;
int type_id = -1;
int type_id = -1; // for a single "type"
int *type_ids = NULL; // array, for a list of "types", allocated
int num_type_ids = 0; // number of elements in "type_ids"
int both;
int did_remove_text = FALSE;
@ -1420,6 +1422,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
if (dict_has_key(dict, "id"))
id = dict_get_number(dict, "id");
// if a specific type was supplied "type": check that (and ignore "types".
// Otherwise check against the list of "types".
if (dict_has_key(dict, "type"))
{
char_u *name = dict_get_string(dict, "type", FALSE);
@ -1429,17 +1434,48 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
return;
type_id = type->pt_id;
}
if (dict_has_key(dict, "types"))
{
typval_T types;
listitem_T *li = NULL;
dict_get_tv(dict, "types", &types);
if (types.v_type == VAR_LIST && types.vval.v_list->lv_len > 0)
{
type_ids = alloc( sizeof(int) * types.vval.v_list->lv_len );
FOR_ALL_LIST_ITEMS(types.vval.v_list, li)
{
proptype_T *prop_type;
if (li->li_tv.v_type != VAR_STRING)
continue;
prop_type = lookup_prop_type(li->li_tv.vval.v_string, buf);
if (!prop_type)
goto cleanup_prop_remove;
type_ids[num_type_ids++] = prop_type->pt_id;
}
}
}
both = dict_get_bool(dict, "both", FALSE);
if (id == -MAXCOL && type_id == -1)
if (id == -MAXCOL && (type_id == -1 && num_type_ids == 0))
{
emsg(_(e_need_at_least_one_of_id_or_type));
return;
goto cleanup_prop_remove;
}
if (both && (id == -MAXCOL || type_id == -1))
if (both && (id == -MAXCOL || (type_id == -1 && num_type_ids == 0)))
{
emsg(_(e_need_id_and_type_with_both));
return;
emsg(_(e_need_id_and_type_or_types_with_both));
goto cleanup_prop_remove;
}
if (type_id != -1 && num_type_ids > 0)
{
emsg(_(e_cannot_specify_both_type_and_types));
goto cleanup_prop_remove;
}
if (end == 0)
@ -1464,10 +1500,26 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
char_u *cur_prop = buf->b_ml.ml_line_ptr + len
+ idx * sizeof(textprop_T);
size_t taillen;
int matches_id = 0;
int matches_type = 0;
mch_memmove(&textprop, cur_prop, sizeof(textprop_T));
if (both ? textprop.tp_id == id && textprop.tp_type == type_id
: textprop.tp_id == id || textprop.tp_type == type_id)
matches_id = textprop.tp_id == id;
if (num_type_ids > 0)
{
int idx2;
for (idx2 = 0; !matches_type && idx2 < num_type_ids; ++idx2)
matches_type = textprop.tp_type == type_ids[idx2];
}
else
{
matches_type = textprop.tp_type == type_id;
}
if (both ? matches_id && matches_type
: matches_id || matches_type)
{
if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY))
{
@ -1475,7 +1527,7 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
// need to allocate the line to be able to change it
if (newptr == NULL)
return;
goto cleanup_prop_remove;
mch_memmove(newptr, buf->b_ml.ml_line_ptr,
buf->b_ml.ml_line_len);
if (buf->b_ml.ml_flags & ML_ALLOCATED)
@ -1537,6 +1589,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv)
&& ((char_u **)gap->ga_data)[gap->ga_len - 1] == NULL)
--gap->ga_len;
}
cleanup_prop_remove:
vim_free(type_ids);
}
/*

View File

@ -731,6 +731,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
233,
/**/
232,
/**/