This patch doesn't appear to have made it to github; the version number
updated but the rest of the patch is MIA.

On Sat, Aug 20, 2022 at 1:55 PM Bram Moolenaar <[email protected]> wrote:

>
> Patch 9.0.0233
> Problem:    Removing multiple text properties takes many calls.
> Solution:   Pass a list to prop_remove(). (Ben Jackson, closes #10945)
> Files:      runtime/doc/textprop.txt, src/textprop.c, src/errors.h,
>             src/testdir/test_textprop.vim
>
>
> *** ../vim-9.0.0232/runtime/doc/textprop.txt    2022-08-05
> 17:04:43.402914763 +0100
> --- runtime/doc/textprop.txt    2022-08-20 20:54:00.459011754 +0100
> ***************
> *** 143,154 ****
>                                 zero is used
>                    text         text to be displayed before {col}, or
> after the
>                                 line if {col} is zero
>                    text_align   when "text" is present and {col} is zero
>                                 specifies where to display the text:
>                                    after   after the end of the line
> !                                  right   right aligned in the window
>                                    below   in the next screen line
> !                               When omitted "after" is used.
>                    text_wrap    when "text" is present and {col} is zero,
>                                 specifies what happens if the text doesn't
>                                 fit:
> --- 143,158 ----
>                                 zero is used
>                    text         text to be displayed before {col}, or
> after the
>                                 line if {col} is zero
> +                                                       *E1294*
>                    text_align   when "text" is present and {col} is zero
>                                 specifies where to display the text:
>                                    after   after the end of the line
> !                                  right   right aligned in the window
> (unless
> !                                          the text wraps to the next
> screen
> !                                          line)
>                                    below   in the next screen line
> !                               When omitted "after" is used.  Only one
> !                               "right" property can fit in earch line.
>                    text_wrap    when "text" is present and {col} is zero,
>                                 specifies what happens if the text doesn't
>                                 fit:
> ***************
> *** 186,194 ****
>                 buffer line, the cursor cannot be placed on it.  A mouse
> click
>                 in the text will move the cursor to the first character
> after
>                 the text, or the last character of the line.
>                 A negative "id" will be chosen and is returned.  Once a
> -               Any Tab in the text will be changed to a space (Rationale:
> -               otherwise the size of the text is difficult to compute).
>                 property with "text" has been added for a buffer then
> using a
>                 negative "id" for any other property will give an error:
>                 *E1293*
> --- 190,199 ----
>                 buffer line, the cursor cannot be placed on it.  A mouse
> click
>                 in the text will move the cursor to the first character
> after
>                 the text, or the last character of the line.
> +               Any Tab and other control character in the text will be
> +               changed to a space (Rationale: otherwise the size of the
> text
> +               is difficult to compute).
>                 A negative "id" will be chosen and is returned.  Once a
>                 property with "text" has been added for a buffer then
> using a
>                 negative "id" for any other property will give an error:
>                 *E1293*
> ***************
> *** 347,357 ****
>                 {props} is a dictionary with these fields:
>                    id           remove text properties with this ID
>                    type         remove text properties with this type name
> !                  both         "id" and "type" must both match
>                    bufnr        use this buffer instead of the current one
>                    all          when TRUE remove all matching text
> properties,
>                                 not just the first one
> !               A property matches when either "id" or "type" matches.
>                 If buffer "bufnr" does not exist you get an error message.
>                 If buffer "bufnr" is not loaded then nothing happens.
>
> --- 352,367 ----
>                 {props} is a dictionary with these fields:
>                    id           remove text properties with this ID
>                    type         remove text properties with this type name
> !                  types        remove text properties with type names in
> this
> !                               List
> !                  both         "id" and "type"/"types" must both match
>                    bufnr        use this buffer instead of the current one
>                    all          when TRUE remove all matching text
> properties,
>                                 not just the first one
> !               Only one of "type" and "types" may be supplied. *E1295*
> !
> !               A property matches when either "id" or one of the supplied
> !               types matches.
>                 If buffer "bufnr" does not exist you get an error message.
>                 If buffer "bufnr" is not loaded then nothing happens.
>
> *** ../vim-9.0.0232/src/textprop.c      2022-08-15 15:54:45.710375583 +0100
> --- src/textprop.c      2022-08-20 20:47:49.903395746 +0100
> ***************
> *** 1010,1016 ****
>       }
>       if (both && (!id_found || type_id == -1))
>       {
> !       emsg(_(e_need_id_and_type_with_both));
>         return;
>       }
>
> --- 1010,1016 ----
>       }
>       if (both && (!id_found || type_id == -1))
>       {
> !       emsg(_(e_need_id_and_type_or_types_with_both));
>         return;
>       }
>
> ***************
> *** 1378,1384 ****
>       buf_T     *buf = curbuf;
>       int               do_all;
>       int               id = -MAXCOL;
> !     int               type_id = -1;
>       int               both;
>       int               did_remove_text = FALSE;
>
> --- 1378,1386 ----
>       buf_T     *buf = curbuf;
>       int               do_all;
>       int               id = -MAXCOL;
> !     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,1425 ****
> --- 1422,1430 ----
>
>       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,1445 ****
>             return;
>         type_id = type->pt_id;
>       }
>       both = dict_get_bool(dict, "both", FALSE);
>
> !     if (id == -MAXCOL && type_id == -1)
>       {
>         emsg(_(e_need_at_least_one_of_id_or_type));
> !       return;
>       }
> !     if (both && (id == -MAXCOL || type_id == -1))
>       {
> !       emsg(_(e_need_id_and_type_with_both));
> !       return;
>       }
>
>       if (end == 0)
> --- 1434,1481 ----
>             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 && num_type_ids == 0))
>       {
>         emsg(_(e_need_at_least_one_of_id_or_type));
> !       goto cleanup_prop_remove;
>       }
> !     if (both && (id == -MAXCOL || (type_id == -1 && num_type_ids == 0)))
>       {
> !       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,1473 ****
>                 char_u *cur_prop = buf->b_ml.ml_line_ptr + len
>                                                     + idx *
> sizeof(textprop_T);
>                 size_t  taillen;
>
>                 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)
>                 {
>                     if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY))
>                     {
> --- 1500,1525 ----
>                 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));
> !
> !               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,1481 ****
>
>                         // need to allocate the line to be able to change
> it
>                         if (newptr == NULL)
> !                           return;
>                         mch_memmove(newptr, buf->b_ml.ml_line_ptr,
>
> buf->b_ml.ml_line_len);
>                         if (buf->b_ml.ml_flags & ML_ALLOCATED)
> --- 1527,1533 ----
>
>                         // need to allocate the line to be able to change
> it
>                         if (newptr == NULL)
> !                           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,1542 ****
> --- 1589,1597 ----
>                          && ((char_u **)gap->ga_data)[gap->ga_len - 1] ==
> NULL)
>             --gap->ga_len;
>       }
> +
> + cleanup_prop_remove:
> +     vim_free(type_ids);
>   }
>
>   /*
> *** ../vim-9.0.0232/src/errors.h        2022-08-20 12:07:55.098022792 +0100
> --- src/errors.h        2022-08-20 20:40:30.507911267 +0100
> ***************
> *** 2208,2215 ****
>         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'"));
>   # ifdef FEAT_TERMINAL
>   EXTERN char e_cannot_open_second_popup_with_terminal[]
>         INIT(= N_("E861: Cannot open a second popup with a terminal"));
> --- 2208,2215 ----
>         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_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,3318 ****
> --- 3316,3322 ----
>   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
> *** ../vim-9.0.0232/src/testdir/test_textprop.vim       2022-08-15
> 15:54:45.710375583 +0100
> --- src/testdir/test_textprop.vim       2022-08-20 20:44:18.895631843 +0100
> ***************
> *** 161,167 ****
>       \ ]
>
>     " Starting at line 5 col 1 this should find the prop at line 5 col 4.
> !   call cursor(5,1)
>     let result = prop_find({'type': 'prop_name'}, 'f')
>     call assert_equal(expected[2], result)
>
> --- 161,167 ----
>       \ ]
>
>     " Starting at line 5 col 1 this should find the prop at line 5 col 4.
> !   call cursor(5, 1)
>     let result = prop_find({'type': 'prop_name'}, 'f')
>     call assert_equal(expected[2], result)
>
> ***************
> *** 182,188 ****
>     " with skipstart set to false, if the start position is anywhere
> between the
>     " start and end lines of a text prop (searching forward or backward),
> the
>     " result should be the prop on the first line (the line with 'start'
> set to 1).
> !   call cursor(3,1)
>     let result = prop_find({'type': 'prop_name'}, 'f')
>     unlet result.length
>     call assert_equal(expected[1], result)
> --- 182,188 ----
>     " with skipstart set to false, if the start position is anywhere
> between the
>     " start and end lines of a text prop (searching forward or backward),
> the
>     " result should be the prop on the first line (the line with 'start'
> set to 1).
> !   call cursor(3, 1)
>     let result = prop_find({'type': 'prop_name'}, 'f')
>     unlet result.length
>     call assert_equal(expected[1], result)
> ***************
> *** 230,241 ****
>     endwhile
>
>     " Starting from line 6 col 1 search backwards for prop with id 10.
> !   call cursor(6,1)
>     let result = prop_find({'id': 10, 'skipstart': 1}, 'b')
>     call assert_equal(expected[0], result)
>
>     " Starting from line 1 col 1 search forwards for prop with id 12.
> !   call cursor(1,1)
>     let result = prop_find({'id': 12}, 'f')
>     call assert_equal(expected[2], result)
>
> --- 230,241 ----
>     endwhile
>
>     " Starting from line 6 col 1 search backwards for prop with id 10.
> !   call cursor(6, 1)
>     let result = prop_find({'id': 10, 'skipstart': 1}, 'b')
>     call assert_equal(expected[0], result)
>
>     " Starting from line 1 col 1 search forwards for prop with id 12.
> !   call cursor(1, 1)
>     let result = prop_find({'id': 12}, 'f')
>     call assert_equal(expected[2], result)
>
> ***************
> *** 426,431 ****
> --- 426,462 ----
>
>     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()
> ***************
> *** 1396,1402 ****
>   func Test_textprop_invalid_highlight()
>     call assert_fails("call prop_type_add('dni', {'highlight':
> 'DoesNotExist'})", 'E970:')
>     new
> !   call setline(1, ['asdf','asdf'])
>     call prop_add(1, 1, {'length': 4, 'type': 'dni'})
>     redraw
>     bwipe!
> --- 1427,1433 ----
>   func Test_textprop_invalid_highlight()
>     call assert_fails("call prop_type_add('dni', {'highlight':
> 'DoesNotExist'})", 'E970:')
>     new
> !   call setline(1, ['asdf', 'asdf'])
>     call prop_add(1, 1, {'length': 4, 'type': 'dni'})
>     redraw
>     bwipe!
> ***************
> *** 2207,2213 ****
>       call prop_add(1, col, #{type: 'misspell', length: 2})
>     endfor
>
> !   call cursor(1,18)
>     let expected = [
>       \ #{lnum: 1, id: 0, col: 14, end: 1, type: 'misspell', type_bufnr:
> 0, length: 2, start: 1},
>       \ #{lnum: 1, id: 0, col: 24, end: 1, type: 'misspell', type_bufnr:
> 0, length: 2, start: 1}
> --- 2238,2244 ----
>       call prop_add(1, col, #{type: 'misspell', length: 2})
>     endfor
>
> !   call cursor(1, 18)
>     let expected = [
>       \ #{lnum: 1, id: 0, col: 14, end: 1, type: 'misspell', type_bufnr:
> 0, length: 2, start: 1},
>       \ #{lnum: 1, id: 0, col: 24, end: 1, type: 'misspell', type_bufnr:
> 0, length: 2, start: 1}
> ***************
> *** 2310,2316 ****
>     call assert_equal(lines, getline(1, '$'))
>     let expected = [
>         \ {'lnum': 1, 'id': 0, 'col': 4, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
> !       \ 'length': 4 ,'start': 1},
>         \ {'lnum': 2, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
>         \ 'length': 7, 'start': 0},
>         \ {'lnum': 3, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
> --- 2341,2347 ----
>     call assert_equal(lines, getline(1, '$'))
>     let expected = [
>         \ {'lnum': 1, 'id': 0, 'col': 4, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
> !       \ 'length': 4 , 'start': 1},
>         \ {'lnum': 2, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
>         \ 'length': 7, 'start': 0},
>         \ {'lnum': 3, 'id': 0, 'col': 1, 'type_bufnr': 0, 'end': 0,
> 'type': 'one',
> *** ../vim-9.0.0232/src/version.c       2022-08-20 20:09:10.598693210 +0100
> --- src/version.c       2022-08-20 20:38:36.820063346 +0100
> ***************
> *** 733,734 ****
> --- 733,736 ----
>   {   /* Add new patch number below this line */
> + /**/
> +     233,
>   /**/
>
> --
> Be nice to your kids...  they'll be the ones choosing your nursing home.
>
>  /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net
>  \\\
> ///
> \\\
> \\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/
> ///
>  \\\            help me help AIDS victims -- http://ICCF-Holland.org
> ///
>
> --
> --
> You received this message from the "vim_dev" maillist.
> Do not top-post! Type your reply below the text you are replying to.
> For more information, visit http://www.vim.org/maillist.php
>
> ---
> You received this message because you are subscribed to the Google Groups
> "vim_dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/vim_dev/20220820195527.7E2261C0ADA%40moolenaar.net
> .
>


-- 
Christian J. Robinson <[email protected]>

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/CAK14FZJ%3DDAkeYhrgNZpYd_ai%3DY65a%2BTbBV1W5rPFrfShXUooHA%40mail.gmail.com.

Raspunde prin e-mail lui