# HG changeset patch # User Bram Moolenaar # Date 1553966105 -3600 # Node ID aef0f93d3ebaa42f94d8d040c0cacea880d95fe2 # Parent 0062198dc347877a1c0842ab3a996bad1d24ae33 patch 8.1.1084: cannot delete a match from another window commit https://github.com/vim/vim/commit/aff749145e23c0f20b5158d1d3a942948ed138e3 Author: Bram Moolenaar Date: Sat Mar 30 18:11:49 2019 +0100 patch 8.1.1084: cannot delete a match from another window Problem: Cannot delete a match from another window. (Paul Jolly) Solution: Add window ID argument to matchdelete(), clearmatches(), getmatches() and setmatches(). (Andy Massimino, closes #4178) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.1. Last change: 2019 Mar 29 +*eval.txt* For Vim version 8.1. Last change: 2019 Mar 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -625,8 +625,11 @@ Functions that can be used with a Dictio 1.5 Blobs ~ *blob* *Blob* *Blobs* *E978* -A Blob mostly behaves like a |List| of numbers, where the numbers have an -8-bit value, from 0 to 255. +A Blob is a binary object. It can be used to read an image from a file and +send it over a channel, for example. + +A Blob mostly behaves like a |List| of numbers, where each number has the +value of an 8-bit byte, from 0 to 255. Blob creation ~ @@ -2262,7 +2265,7 @@ ch_status({handle} [, {options}]) changenr() Number current change number char2nr({expr} [, {utf8}]) Number ASCII/UTF8 value of first char in {expr} cindent({lnum}) Number C indent for line {lnum} -clearmatches() none clear all matches +clearmatches([{win}]) none clear all matches col({expr}) Number column nr of cursor or mark complete({startcol}, {matches}) none set Insert mode completion complete_add({expr}) Number add completion match @@ -2356,7 +2359,7 @@ getjumplist([{winnr} [, {tabnr}]]) getline({lnum}) String line {lnum} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer getloclist({nr} [, {what}]) List list of location list items -getmatches() List list of current matches +getmatches([{win}]) List list of current matches getpid() Number process ID of Vim getpos({expr}) List position of cursor, mark, etc. getqflist([{what}]) List list of quickfix items @@ -2447,7 +2450,7 @@ matchadd({group}, {pattern} [, {priority matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]]) Number highlight positions with {group} matcharg({nr}) List arguments of |:match| -matchdelete({id}) Number delete match identified by {id} +matchdelete({id} [, {win}]) Number delete match identified by {id} matchend({expr}, {pat} [, {start} [, {count}]]) Number position where {pat} ends in {expr} matchlist({expr}, {pat} [, {start} [, {count}]]) @@ -2553,7 +2556,7 @@ setfperm({fname}, {mode}) Number set {fn setline({lnum}, {line}) Number set line {lnum} to {line} setloclist({nr}, {list} [, {action} [, {what}]]) Number modify location list using {list} -setmatches({list}) Number restore a list of matches +setmatches({list} [, {win}]) Number restore a list of matches setpos({expr}, {list}) Number set the {expr} position to {list} setqflist({list} [, {action} [, {what}]]) Number modify quickfix list using {list} @@ -3444,6 +3447,10 @@ char2nr({expr} [, {utf8}]) *char2nr( < With {utf8} set to 1, always treat as utf-8 characters. A combining character is a separate character. |nr2char()| does the opposite. + To turn a string into a list of character numbers: > + let str = "ABC" + let list = map(split(str, '\zs'), {_, val -> char2nr(val)}) +< Result: [65, 66, 67] cindent({lnum}) *cindent()* Get the amount of indent for line {lnum} according the C @@ -3454,9 +3461,11 @@ cindent({lnum}) *cindent()* feature, -1 is returned. See |C-indenting|. -clearmatches() *clearmatches()* +clearmatches([{win}]) *clearmatches()* Clears all matches previously defined for the current window by |matchadd()| and the |:match| commands. + If {win} is specified, use the window with this number or + window ID instead of the current window. *col()* col({expr}) The result is a Number, which is the byte index of the column @@ -5029,7 +5038,7 @@ getloclist({nr} [, {what}]) *getlocli |location-list-file-window| for more details. -getmatches() *getmatches()* +getmatches([{win}]) *getmatches()* Returns a |List| with all matches previously defined for the current window by |matchadd()| and the |:match| commands. |getmatches()| is useful in combination with |setmatches()|, @@ -6399,7 +6408,7 @@ matchadd({group}, {pattern} [, {priority Defines a pattern to be highlighted in the current window (a "match"). It will be highlighted with {group}. Returns an identification number (ID), which can be used to delete the - match using |matchdelete()|. + match using |matchdelete()|. The ID is bound to the window. Matching is case sensitive and magic, unless case sensitivity or magicness are explicitly overridden in {pattern}. The 'magic', 'smartcase' and 'ignorecase' options are not used. @@ -6495,11 +6504,13 @@ matcharg({nr}) *matcharg()* Highlighting matches using the |:match| commands are limited to three matches. |matchadd()| does not have this limitation. -matchdelete({id}) *matchdelete()* *E802* *E803* +matchdelete({id} [, {win}) *matchdelete()* *E802* *E803* Deletes a match with ID {id} previously defined by |matchadd()| or one of the |:match| commands. Returns 0 if successful, otherwise -1. See example for |matchadd()|. All matches can be deleted in one operation by |clearmatches()|. + If {win} is specified, use the window with this number or + window ID instead of the current window. matchend({expr}, {pat} [, {start} [, {count}]]) *matchend()* Same as |match()|, but return the index of first character @@ -6688,6 +6699,10 @@ nr2char({expr} [, {utf8}]) *nr2char() nr2char(10), because NULs are represented with newline characters. nr2char(0) is a real NUL and terminates the string, thus results in an empty string. + To turn a list of character numbers into a string: > + let list = [65, 66, 67] + let str = join(map(list, {_, val -> nr2char(val)}), '') +< Result: "ABC" or({expr}, {expr}) *or()* Bitwise OR on the two arguments. The arguments are converted @@ -7906,11 +7921,13 @@ setloclist({nr}, {list} [, {action} [, { only the items listed in {what} are set. Refer to |setqflist()| for the list of supported keys in {what}. -setmatches({list}) *setmatches()* +setmatches({list} [, {win}]) *setmatches()* Restores a list of matches saved by |getmatches() for the current window|. Returns 0 if successful, otherwise -1. All current matches are cleared before the list is restored. See example for |getmatches()|. + If {win} is specified, use the window with this number or + window ID instead of the current window. *setpos()* setpos({expr}, {list}) diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -31,6 +31,7 @@ static char *e_listarg = N_("E686: Argument of %s must be a List"); static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static char *e_stringreq = N_("E928: String required"); +static char *e_invalwindow = N_("E957: Invalid window number"); #ifdef FEAT_FLOAT static void f_abs(typval_T *argvars, typval_T *rettv); @@ -590,7 +591,7 @@ static struct fst {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 2, f_char2nr}, {"cindent", 1, 1, f_cindent}, - {"clearmatches", 0, 0, f_clearmatches}, + {"clearmatches", 0, 1, f_clearmatches}, {"col", 1, 1, f_col}, #if defined(FEAT_INS_EXPAND) {"complete", 2, 2, f_complete}, @@ -677,7 +678,7 @@ static struct fst {"getjumplist", 0, 2, f_getjumplist}, {"getline", 1, 2, f_getline}, {"getloclist", 1, 2, f_getloclist}, - {"getmatches", 0, 0, f_getmatches}, + {"getmatches", 0, 1, f_getmatches}, {"getpid", 0, 0, f_getpid}, {"getpos", 1, 1, f_getpos}, {"getqflist", 0, 1, f_getqflist}, @@ -761,7 +762,7 @@ static struct fst {"matchadd", 2, 5, f_matchadd}, {"matchaddpos", 2, 5, f_matchaddpos}, {"matcharg", 1, 1, f_matcharg}, - {"matchdelete", 1, 1, f_matchdelete}, + {"matchdelete", 1, 2, f_matchdelete}, {"matchend", 2, 4, f_matchend}, {"matchlist", 2, 4, f_matchlist}, {"matchstr", 2, 4, f_matchstr}, @@ -859,7 +860,7 @@ static struct fst {"setfperm", 2, 2, f_setfperm}, {"setline", 2, 2, f_setline}, {"setloclist", 2, 4, f_setloclist}, - {"setmatches", 1, 1, f_setmatches}, + {"setmatches", 1, 2, f_setmatches}, {"setpos", 2, 2, f_setpos}, {"setqflist", 1, 3, f_setqflist}, {"setreg", 2, 3, f_setreg}, @@ -2496,6 +2497,23 @@ f_cindent(typval_T *argvars UNUSED, typv rettv->vval.v_number = -1; } + static win_T * +get_optional_window(typval_T *argvars, int idx) +{ + win_T *win = curwin; + + if (argvars[idx].v_type != VAR_UNKNOWN) + { + win = find_win_by_nr_or_id(&argvars[idx]); + if (win == NULL) + { + emsg(_(e_invalwindow)); + return NULL; + } + } + return win; +} + /* * "clearmatches()" function */ @@ -2503,7 +2521,10 @@ f_cindent(typval_T *argvars UNUSED, typv f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA - clear_matches(curwin); + win_T *win = get_optional_window(argvars, 0); + + if (win != NULL) + clear_matches(win); #endif } @@ -5412,60 +5433,62 @@ f_getmatches(typval_T *argvars UNUSED, t { #ifdef FEAT_SEARCH_EXTRA dict_T *dict; - matchitem_T *cur = curwin->w_match_head; + matchitem_T *cur; int i; - - if (rettv_list_alloc(rettv) == OK) - { - while (cur != NULL) - { - dict = dict_alloc(); - if (dict == NULL) - return; - if (cur->match.regprog == NULL) - { - /* match added with matchaddpos() */ - for (i = 0; i < MAXPOSMATCH; ++i) + win_T *win = get_optional_window(argvars, 0); + + if (rettv_list_alloc(rettv) == FAIL || win == NULL) + return; + + cur = win->w_match_head; + while (cur != NULL) + { + dict = dict_alloc(); + if (dict == NULL) + return; + if (cur->match.regprog == NULL) + { + /* match added with matchaddpos() */ + for (i = 0; i < MAXPOSMATCH; ++i) + { + llpos_T *llpos; + char buf[6]; + list_T *l; + + llpos = &cur->pos.pos[i]; + if (llpos->lnum == 0) + break; + l = list_alloc(); + if (l == NULL) + break; + list_append_number(l, (varnumber_T)llpos->lnum); + if (llpos->col > 0) { - llpos_T *llpos; - char buf[6]; - list_T *l; - - llpos = &cur->pos.pos[i]; - if (llpos->lnum == 0) - break; - l = list_alloc(); - if (l == NULL) - break; - list_append_number(l, (varnumber_T)llpos->lnum); - if (llpos->col > 0) - { - list_append_number(l, (varnumber_T)llpos->col); - list_append_number(l, (varnumber_T)llpos->len); - } - sprintf(buf, "pos%d", i + 1); - dict_add_list(dict, buf, l); + list_append_number(l, (varnumber_T)llpos->col); + list_append_number(l, (varnumber_T)llpos->len); } - } - else - { - dict_add_string(dict, "pattern", cur->pattern); - } - dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); - dict_add_number(dict, "priority", (long)cur->priority); - dict_add_number(dict, "id", (long)cur->id); + sprintf(buf, "pos%d", i + 1); + dict_add_list(dict, buf, l); + } + } + else + { + dict_add_string(dict, "pattern", cur->pattern); + } + dict_add_string(dict, "group", syn_id2name(cur->hlg_id)); + dict_add_number(dict, "priority", (long)cur->priority); + dict_add_number(dict, "id", (long)cur->id); # if defined(FEAT_CONCEAL) - if (cur->conceal_char) - { - char_u buf[MB_MAXBYTES + 1]; - - buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; - dict_add_string(dict, "conceal", (char_u *)&buf); - } + if (cur->conceal_char) + { + char_u buf[MB_MAXBYTES + 1]; + + buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; + dict_add_string(dict, "conceal", (char_u *)&buf); + } # endif - list_append_dict(rettv->vval.v_list, dict); - cur = cur->next; - } + list_append_dict(rettv->vval.v_list, dict); + cur = cur->next; } #endif } @@ -8245,7 +8268,7 @@ matchadd_dict_arg(typval_T *tv, char_u * *win = find_win_by_nr_or_id(&di->di_tv); if (*win == NULL) { - emsg(_("E957: Invalid window number")); + emsg(_(e_invalwindow)); return FAIL; } } @@ -8393,7 +8416,12 @@ f_matcharg(typval_T *argvars UNUSED, typ f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA - rettv->vval.v_number = match_delete(curwin, + win_T *win = get_optional_window(argvars, 1); + + if (win == NULL) + rettv->vval.v_number = -1; + else + rettv->vval.v_number = match_delete(win, (int)tv_get_number(&argvars[0]), TRUE); #endif } @@ -11206,6 +11234,7 @@ f_setmatches(typval_T *argvars UNUSED, t listitem_T *li; dict_T *d; list_T *s = NULL; + win_T *win = get_optional_window(argvars, 1); rettv->vval.v_number = -1; if (argvars[0].v_type != VAR_LIST) @@ -11213,9 +11242,11 @@ f_setmatches(typval_T *argvars UNUSED, t emsg(_(e_listreq)); return; } + if (win == NULL) + return; + if ((l = argvars[0].vval.v_list) != NULL) { - /* To some extent make sure that we are dealing with a list from * "getmatches()". */ li = l->lv_first; @@ -11239,7 +11270,7 @@ f_setmatches(typval_T *argvars UNUSED, t li = li->li_next; } - clear_matches(curwin); + clear_matches(win); li = l->lv_first; while (li != NULL) { @@ -11286,13 +11317,13 @@ f_setmatches(typval_T *argvars UNUSED, t : NULL; if (i == 0) { - match_add(curwin, group, + match_add(win, group, dict_get_string(d, (char_u *)"pattern", FALSE), priority, id, NULL, conceal); } else { - match_add(curwin, group, NULL, priority, id, s, conceal); + match_add(win, group, NULL, priority, id, s, conceal); list_unref(s); s = NULL; } diff --git a/src/testdir/test_match.vim b/src/testdir/test_match.vim --- a/src/testdir/test_match.vim +++ b/src/testdir/test_match.vim @@ -205,6 +205,19 @@ func Test_matchaddpos_otherwin() call assert_equal(screenattr(1,2), screenattr(2,2)) call assert_notequal(screenattr(1,2), screenattr(1,4)) + let savematches = getmatches(winid) + let expect = [ + \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 4}, + \ {'group': 'Error', 'id': 5, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]}, + \] + call assert_equal(expect, savematches) + + call clearmatches(winid) + call assert_equal([], getmatches(winid)) + + call setmatches(savematches, winid) + call assert_equal(expect, savematches) + wincmd w bwipe! call clearmatches() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -776,6 +776,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1084, +/**/ 1083, /**/ 1082,