vim-patch:8.1.1084: cannot delete a match from another window (#12325)

Problem:    Cannot delete a match from another window. (Paul Jolly)
Solution:   Add window ID argument to matchdelete(), clearmatches(),
            getmatches() and setmatches(). (Andy Massimino, closes vim/vim#4178)
aff749145e
This commit is contained in:
Shougo 2020-05-16 22:25:51 +09:00 committed by GitHub
parent f3d0a1741e
commit d7d69fed18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 25 deletions

View File

@ -2059,7 +2059,7 @@ chanclose({id}[, {stream}]) Number Closes a channel or one of its streams
chansend({id}, {data}) Number Writes {data} to channel chansend({id}, {data}) Number Writes {data} to channel
char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr} char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
cindent({lnum}) Number C indent for line {lnum} 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 col({expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) none set Insert mode completion complete({startcol}, {matches}) none set Insert mode completion
complete_add({expr}) Number add completion match complete_add({expr}) Number add completion match
@ -2167,7 +2167,7 @@ getjumplist([{winnr} [, {tabnr}]])
getline({lnum}) String line {lnum} of current buffer getline({lnum}) String line {lnum} of current buffer
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr} [, {what}]) List list of location list items 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 getpid() Number process ID of Vim
getpos({expr}) List position of cursor, mark, etc. getpos({expr}) List position of cursor, mark, etc.
getqflist([{what}]) List list of quickfix items getqflist([{what}]) List list of quickfix items
@ -2259,7 +2259,7 @@ matchadd({group}, {pattern}[, {priority}[, {id}]])
matchaddpos({group}, {list}[, {priority}[, {id}]]) matchaddpos({group}, {list}[, {priority}[, {id}]])
Number highlight positions with {group} Number highlight positions with {group}
matcharg({nr}) List arguments of |:match| 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}]]) matchend({expr}, {pat}[, {start}[, {count}]])
Number position where {pat} ends in {expr} Number position where {pat} ends in {expr}
matchlist({expr}, {pat}[, {start}[, {count}]]) matchlist({expr}, {pat}[, {start}[, {count}]])
@ -2352,7 +2352,7 @@ setfperm({fname}, {mode} Number set {fname} file permissions to {mode}
setline({lnum}, {line}) Number set line {lnum} to {line} setline({lnum}, {line}) Number set line {lnum} to {line}
setloclist({nr}, {list}[, {action}[, {what}]]) setloclist({nr}, {list}[, {action}[, {what}]])
Number modify location list using {list} 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} setpos({expr}, {list}) Number set the {expr} position to {list}
setqflist({list}[, {action}[, {what}]] setqflist({list}[, {action}[, {what}]]
Number modify quickfix list using {list} Number modify quickfix list using {list}
@ -3005,9 +3005,11 @@ cindent({lnum}) *cindent()*
When {lnum} is invalid -1 is returned. When {lnum} is invalid -1 is returned.
See |C-indenting|. See |C-indenting|.
clearmatches() *clearmatches()* clearmatches([{win}]) *clearmatches()*
Clears all matches previously defined for the current window Clears all matches previously defined for the current window
by |matchadd()| and the |:match| commands. 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()*
col({expr}) The result is a Number, which is the byte index of the column col({expr}) The result is a Number, which is the byte index of the column
@ -4602,7 +4604,7 @@ getloclist({nr},[, {what}]) *getloclist()*
field is applicable only when called from a location list field is applicable only when called from a location list
window. window.
getmatches() *getmatches()* getmatches([{win}]) *getmatches()*
Returns a |List| with all matches previously defined for the Returns a |List| with all matches previously defined for the
current window by |matchadd()| and the |:match| commands. current window by |matchadd()| and the |:match| commands.
|getmatches()| is useful in combination with |setmatches()|, |getmatches()| is useful in combination with |setmatches()|,
@ -5943,7 +5945,7 @@ matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]])
Defines a pattern to be highlighted in the current window (a Defines a pattern to be highlighted in the current window (a
"match"). It will be highlighted with {group}. Returns an "match"). It will be highlighted with {group}. Returns an
identification number (ID), which can be used to delete the 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 Matching is case sensitive and magic, unless case sensitivity
or magicness are explicitly overridden in {pattern}. The or magicness are explicitly overridden in {pattern}. The
'magic', 'smartcase' and 'ignorecase' options are not used. 'magic', 'smartcase' and 'ignorecase' options are not used.
@ -6043,11 +6045,13 @@ matcharg({nr}) *matcharg()*
Highlighting matches using the |:match| commands are limited Highlighting matches using the |:match| commands are limited
to three matches. |matchadd()| does not have this limitation. 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()| Deletes a match with ID {id} previously defined by |matchadd()|
or one of the |:match| commands. Returns 0 if successful, or one of the |:match| commands. Returns 0 if successful,
otherwise -1. See example for |matchadd()|. All matches can otherwise -1. See example for |matchadd()|. All matches can
be deleted in one operation by |clearmatches()|. 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()* matchend({expr}, {pat} [, {start} [, {count}]]) *matchend()*
Same as |match()|, but return the index of first character Same as |match()|, but return the index of first character
@ -7420,11 +7424,13 @@ setloclist({nr}, {list}[, {action}[, {what}]]) *setloclist()*
only the items listed in {what} are set. Refer to |setqflist()| only the items listed in {what} are set. Refer to |setqflist()|
for the list of supported keys in {what}. 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 Restores a list of matches saved by |getmatches() for the
current window|. Returns 0 if successful, otherwise -1. All current window|. Returns 0 if successful, otherwise -1. All
current matches are cleared before the list is restored. See current matches are cleared before the list is restored. See
example for |getmatches()|. example for |getmatches()|.
If {win} is specified, use the window with this number or
window ID instead of the current window.
*setpos()* *setpos()*
setpos({expr}, {list}) setpos({expr}, {list})

View File

@ -63,6 +63,7 @@ static char *e_missbrac = N_("E111: Missing ']'");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
static char *e_illvar = N_("E461: Illegal variable name: %s"); static char *e_illvar = N_("E461: Illegal variable name: %s");
static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
static char *e_invalwindow = N_("E957: Invalid window number");
// TODO(ZyX-I): move to eval/executor // TODO(ZyX-I): move to eval/executor
static char *e_letwrong = N_("E734: Wrong variable type for %s="); static char *e_letwrong = N_("E734: Wrong variable type for %s=");
@ -6776,7 +6777,7 @@ int matchadd_dict_arg(typval_T *tv, const char **conceal_char,
if ((di = tv_dict_find(tv->vval.v_dict, S_LEN("window"))) != NULL) { if ((di = tv_dict_find(tv->vval.v_dict, S_LEN("window"))) != NULL) {
*win = find_win_by_nr_or_id(&di->di_tv); *win = find_win_by_nr_or_id(&di->di_tv);
if (*win == NULL) { if (*win == NULL) {
EMSG(_("E957: Invalid window number")); EMSG(_(e_invalwindow));
return FAIL; return FAIL;
} }
} }

View File

@ -64,7 +64,7 @@ return {
chansend={args=2}, chansend={args=2},
char2nr={args={1, 2}}, char2nr={args={1, 2}},
cindent={args=1}, cindent={args=1},
clearmatches={}, clearmatches={args={0, 1}},
col={args=1}, col={args=1},
complete={args=2}, complete={args=2},
complete_add={args=1}, complete_add={args=1},
@ -149,7 +149,7 @@ return {
getjumplist={args={0, 2}}, getjumplist={args={0, 2}},
getline={args={1, 2}}, getline={args={1, 2}},
getloclist={args={1, 2}}, getloclist={args={1, 2}},
getmatches={}, getmatches={args={0, 1}},
getpid={}, getpid={},
getpos={args=1}, getpos={args=1},
getqflist={args={0, 1}}, getqflist={args={0, 1}},
@ -227,7 +227,7 @@ return {
matchadd={args={2, 5}}, matchadd={args={2, 5}},
matchaddpos={args={2, 5}}, matchaddpos={args={2, 5}},
matcharg={args=1}, matcharg={args=1},
matchdelete={args=1}, matchdelete={args={1, 2}},
matchend={args={2, 4}}, matchend={args={2, 4}},
matchlist={args={2, 4}}, matchlist={args={2, 4}},
matchstr={args={2, 4}}, matchstr={args={2, 4}},
@ -293,7 +293,7 @@ return {
setfperm={args=2}, setfperm={args=2},
setline={args=2}, setline={args=2},
setloclist={args={2, 4}}, setloclist={args={2, 4}},
setmatches={args=1}, setmatches={args={1, 2}},
setpos={args=2}, setpos={args=2},
setqflist={args={1, 3}}, setqflist={args={1, 3}},
setreg={args={2, 3}}, setreg={args={2, 3}},

View File

@ -93,6 +93,7 @@ PRAGMA_DIAG_POP
static char *e_listarg = N_("E686: Argument of %s must be a List"); static char *e_listarg = N_("E686: Argument of %s must be a List");
static char *e_stringreq = N_("E928: String required"); static char *e_stringreq = N_("E928: String required");
static char *e_invalwindow = N_("E957: Invalid window number");
/// Dummy va_list for passing to vim_snprintf /// Dummy va_list for passing to vim_snprintf
/// ///
@ -952,12 +953,30 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1; 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 * "clearmatches()" function
*/ */
static void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {
clear_matches(curwin); win_T *win = get_optional_window(argvars, 0);
if (win != NULL) {
clear_matches(win);
}
} }
/* /*
@ -3452,10 +3471,16 @@ static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/ */
static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {
matchitem_T *cur = curwin->w_match_head; matchitem_T *cur;
int i; int i;
win_T *win = get_optional_window(argvars, 0);
if (win == NULL) {
return;
}
tv_list_alloc_ret(rettv, kListLenMayKnow); tv_list_alloc_ret(rettv, kListLenMayKnow);
cur = win->w_match_head;
while (cur != NULL) { while (cur != NULL) {
dict_T *dict = tv_dict_alloc(); dict_T *dict = tv_dict_alloc();
if (cur->match.regprog == NULL) { if (cur->match.regprog == NULL) {
@ -5771,8 +5796,13 @@ static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/ */
static void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {
rettv->vval.v_number = match_delete(curwin, win_T *win = get_optional_window(argvars, 1);
(int)tv_get_number(&argvars[0]), true); if (win == NULL) {
rettv->vval.v_number = -1;
} else {
rettv->vval.v_number = match_delete(curwin,
(int)tv_get_number(&argvars[0]), true);
}
} }
/* /*
@ -8136,14 +8166,19 @@ static void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/ */
static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{ {
dict_T *d; dict_T *d;
list_T *s = NULL; list_T *s = NULL;
win_T *win = get_optional_window(argvars, 1);
rettv->vval.v_number = -1; rettv->vval.v_number = -1;
if (argvars[0].v_type != VAR_LIST) { if (argvars[0].v_type != VAR_LIST) {
EMSG(_(e_listreq)); EMSG(_(e_listreq));
return; return;
} }
if (win == NULL) {
return;
}
list_T *const l = argvars[0].vval.v_list; list_T *const l = argvars[0].vval.v_list;
// To some extent make sure that we are dealing with a list from // To some extent make sure that we are dealing with a list from
// "getmatches()". // "getmatches()".
@ -8167,7 +8202,7 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
li_idx++; li_idx++;
}); });
clear_matches(curwin); clear_matches(win);
bool match_add_failed = false; bool match_add_failed = false;
TV_LIST_ITER_CONST(l, li, { TV_LIST_ITER_CONST(l, li, {
int i = 0; int i = 0;
@ -8213,13 +8248,13 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
? tv_get_string(&conceal_di->di_tv) ? tv_get_string(&conceal_di->di_tv)
: NULL); : NULL);
if (i == 0) { if (i == 0) {
if (match_add(curwin, group, if (match_add(win, group,
tv_dict_get_string(d, "pattern", false), tv_dict_get_string(d, "pattern", false),
priority, id, NULL, conceal) != id) { priority, id, NULL, conceal) != id) {
match_add_failed = true; match_add_failed = true;
} }
} else { } else {
if (match_add(curwin, group, NULL, priority, id, s, conceal) != id) { if (match_add(win, group, NULL, priority, id, s, conceal) != id) {
match_add_failed = true; match_add_failed = true;
} }
tv_list_unref(s); tv_list_unref(s);

View File

@ -217,6 +217,19 @@ func Test_matchaddpos_otherwin()
call assert_equal(screenattr(1,2), screenattr(2,2)) call assert_equal(screenattr(1,2), screenattr(2,2))
call assert_notequal(screenattr(1,2), screenattr(1,4)) 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 wincmd w
bwipe! bwipe!
call clearmatches() call clearmatches()