To: vim_dev@googlegroups.com Subject: Patch 8.1.1084 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.1084 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) Files: runtime/doc/eval.txt, src/evalfunc.c, src/testdir/test_match.vim *** ../vim-8.1.1083/runtime/doc/eval.txt 2019-03-29 14:16:34.138861795 +0100 --- runtime/doc/eval.txt 2019-03-30 17:50:40.288425654 +0100 *************** *** 2237,2243 **** 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 col({expr}) Number column nr of cursor or mark complete({startcol}, {matches}) none set Insert mode completion complete_add({expr}) Number add completion match --- 2265,2271 ---- 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([{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 *************** *** 2331,2337 **** 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 getpid() Number process ID of Vim getpos({expr}) List position of cursor, mark, etc. getqflist([{what}]) List list of quickfix items --- 2359,2365 ---- 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([{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 *************** *** 2422,2428 **** 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} matchend({expr}, {pat} [, {start} [, {count}]]) Number position where {pat} ends in {expr} matchlist({expr}, {pat} [, {start} [, {count}]]) --- 2450,2456 ---- matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]]) Number highlight positions with {group} matcharg({nr}) List arguments of |:match| ! 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}]]) *************** *** 2528,2534 **** 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 setpos({expr}, {list}) Number set the {expr} position to {list} setqflist({list} [, {action} [, {what}]]) Number modify quickfix list using {list} --- 2556,2562 ---- setline({lnum}, {line}) Number set line {lnum} to {line} setloclist({nr}, {list} [, {action} [, {what}]]) Number modify location list using {list} ! 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} *************** *** 3428,3436 **** feature, -1 is returned. See |C-indenting|. ! clearmatches() *clearmatches()* ! Clears all matches previously defined by |matchadd()| and the ! |:match| commands. *col()* col({expr}) The result is a Number, which is the byte index of the column --- 3461,3471 ---- feature, -1 is returned. See |C-indenting|. ! 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 *************** *** 4998,5008 **** |location-list-file-window| for more details. ! getmatches() *getmatches()* ! Returns a |List| with all matches previously defined by ! |matchadd()| and the |:match| commands. |getmatches()| is ! useful in combination with |setmatches()|, as |setmatches()| ! can restore a list of matches saved by |getmatches()|. Example: > :echo getmatches() < [{'group': 'MyGroup1', 'pattern': 'TODO', --- 5038,5049 ---- |location-list-file-window| for more details. ! 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()|, ! as |setmatches()| can restore a list of matches saved by ! |getmatches()|. Example: > :echo getmatches() < [{'group': 'MyGroup1', 'pattern': 'TODO', *************** *** 6303,6313 **** --- 6349,6362 ---- When {expr} is a |List| then this returns the index of the first item where {pat} matches. Each item is used as a String, |Lists| and |Dictionaries| are used as echoed. + Otherwise, {expr} is used as a String. The result is a Number, which gives the index (byte offset) in {expr} where {pat} matches. + A match at the first character or |List| item returns zero. If there is no match -1 is returned. + For getting submatches see |matchlist()|. Example: > :echo match("testing", "ing") " results in 4 *************** *** 6359,6365 **** 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()|. 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. --- 6408,6414 ---- 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()|. 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. *************** *** 6455,6465 **** Highlighting matches using the |:match| commands are limited to three matches. |matchadd()| does not have this limitation. ! matchdelete({id}) *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()|. matchend({expr}, {pat} [, {start} [, {count}]]) *matchend()* Same as |match()|, but return the index of first character --- 6504,6516 ---- Highlighting matches using the |:match| commands are limited to three matches. |matchadd()| does not have this limitation. ! 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 *************** *** 7852,7861 **** only the items listed in {what} are set. Refer to |setqflist()| for the list of supported keys in {what}. ! setmatches({list}) *setmatches()* ! Restores a list of matches saved by |getmatches()|. Returns 0 ! if successful, otherwise -1. All current matches are cleared ! before the list is restored. See example for |getmatches()|. *setpos()* setpos({expr}, {list}) --- 7921,7933 ---- only the items listed in {what} are set. Refer to |setqflist()| for the list of supported keys in {what}. ! 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}) *** ../vim-8.1.1083/src/evalfunc.c 2019-03-30 14:26:15.268619122 +0100 --- src/evalfunc.c 2019-03-30 18:04:15.531433052 +0100 *************** *** 31,36 **** --- 31,37 ---- 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,596 **** {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 2, f_char2nr}, {"cindent", 1, 1, f_cindent}, ! {"clearmatches", 0, 0, f_clearmatches}, {"col", 1, 1, f_col}, #if defined(FEAT_INS_EXPAND) {"complete", 2, 2, f_complete}, --- 591,597 ---- {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 2, f_char2nr}, {"cindent", 1, 1, f_cindent}, ! {"clearmatches", 0, 1, f_clearmatches}, {"col", 1, 1, f_col}, #if defined(FEAT_INS_EXPAND) {"complete", 2, 2, f_complete}, *************** *** 677,683 **** {"getjumplist", 0, 2, f_getjumplist}, {"getline", 1, 2, f_getline}, {"getloclist", 1, 2, f_getloclist}, ! {"getmatches", 0, 0, f_getmatches}, {"getpid", 0, 0, f_getpid}, {"getpos", 1, 1, f_getpos}, {"getqflist", 0, 1, f_getqflist}, --- 678,684 ---- {"getjumplist", 0, 2, f_getjumplist}, {"getline", 1, 2, f_getline}, {"getloclist", 1, 2, f_getloclist}, ! {"getmatches", 0, 1, f_getmatches}, {"getpid", 0, 0, f_getpid}, {"getpos", 1, 1, f_getpos}, {"getqflist", 0, 1, f_getqflist}, *************** *** 761,767 **** {"matchadd", 2, 5, f_matchadd}, {"matchaddpos", 2, 5, f_matchaddpos}, {"matcharg", 1, 1, f_matcharg}, ! {"matchdelete", 1, 1, f_matchdelete}, {"matchend", 2, 4, f_matchend}, {"matchlist", 2, 4, f_matchlist}, {"matchstr", 2, 4, f_matchstr}, --- 762,768 ---- {"matchadd", 2, 5, f_matchadd}, {"matchaddpos", 2, 5, f_matchaddpos}, {"matcharg", 1, 1, f_matcharg}, ! {"matchdelete", 1, 2, f_matchdelete}, {"matchend", 2, 4, f_matchend}, {"matchlist", 2, 4, f_matchlist}, {"matchstr", 2, 4, f_matchstr}, *************** *** 859,865 **** {"setfperm", 2, 2, f_setfperm}, {"setline", 2, 2, f_setline}, {"setloclist", 2, 4, f_setloclist}, ! {"setmatches", 1, 1, f_setmatches}, {"setpos", 2, 2, f_setpos}, {"setqflist", 1, 3, f_setqflist}, {"setreg", 2, 3, f_setreg}, --- 860,866 ---- {"setfperm", 2, 2, f_setfperm}, {"setline", 2, 2, f_setline}, {"setloclist", 2, 4, f_setloclist}, ! {"setmatches", 1, 2, f_setmatches}, {"setpos", 2, 2, f_setpos}, {"setqflist", 1, 3, f_setqflist}, {"setreg", 2, 3, f_setreg}, *************** *** 2496,2501 **** --- 2497,2519 ---- 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,2509 **** f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA ! clear_matches(curwin); #endif } --- 2521,2530 ---- f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA ! win_T *win = get_optional_window(argvars, 0); ! ! if (win != NULL) ! clear_matches(win); #endif } *************** *** 5412,5471 **** { #ifdef FEAT_SEARCH_EXTRA dict_T *dict; ! matchitem_T *cur = curwin->w_match_head; 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) ! { ! 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); } } ! 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); ! } ! # endif ! list_append_dict(rettv->vval.v_list, dict); ! cur = cur->next; } } #endif } --- 5433,5494 ---- { #ifdef FEAT_SEARCH_EXTRA dict_T *dict; ! matchitem_T *cur; int 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) ! { ! 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); } ! } ! 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); } + # endif + list_append_dict(rettv->vval.v_list, dict); + cur = cur->next; } #endif } *************** *** 8245,8251 **** *win = find_win_by_nr_or_id(&di->di_tv); if (*win == NULL) { ! emsg(_("E957: Invalid window number")); return FAIL; } } --- 8268,8274 ---- *win = find_win_by_nr_or_id(&di->di_tv); if (*win == NULL) { ! emsg(_(e_invalwindow)); return FAIL; } } *************** *** 8393,8399 **** f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA ! rettv->vval.v_number = match_delete(curwin, (int)tv_get_number(&argvars[0]), TRUE); #endif } --- 8416,8427 ---- f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) { #ifdef FEAT_SEARCH_EXTRA ! 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,11211 **** --- 11234,11240 ---- 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,11221 **** emsg(_(e_listreq)); 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; --- 11242,11252 ---- 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,11245 **** li = li->li_next; } ! clear_matches(curwin); li = l->lv_first; while (li != NULL) { --- 11270,11276 ---- li = li->li_next; } ! clear_matches(win); li = l->lv_first; while (li != NULL) { *************** *** 11286,11298 **** : NULL; if (i == 0) { ! match_add(curwin, group, dict_get_string(d, (char_u *)"pattern", FALSE), priority, id, NULL, conceal); } else { ! match_add(curwin, group, NULL, priority, id, s, conceal); list_unref(s); s = NULL; } --- 11317,11329 ---- : NULL; if (i == 0) { ! match_add(win, group, dict_get_string(d, (char_u *)"pattern", FALSE), priority, id, NULL, conceal); } else { ! match_add(win, group, NULL, priority, id, s, conceal); list_unref(s); s = NULL; } *** ../vim-8.1.1083/src/testdir/test_match.vim 2019-01-24 17:59:35.139217458 +0100 --- src/testdir/test_match.vim 2019-03-30 17:48:06.817387861 +0100 *************** *** 205,210 **** --- 205,223 ---- 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() *** ../vim-8.1.1083/src/version.c 2019-03-30 17:28:11.920987602 +0100 --- src/version.c 2019-03-30 17:51:29.572116891 +0100 *************** *** 777,778 **** --- 777,780 ---- { /* Add new patch number below this line */ + /**/ + 1084, /**/ -- hundred-and-one symptoms of being an internet addict: 162. You go outside and look for a brightness knob to turn down the sun. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///