changeset 17946:ec4248c4b92c v8.1.1969

patch 8.1.1969: popup window filter is used in all modes Commit: https://github.com/vim/vim/commit/581ba39aefe837298a9943b04a1dab13a7ec6772 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Sep 3 22:08:33 2019 +0200 patch 8.1.1969: popup window filter is used in all modes Problem: Popup window filter is used in all modes. Solution: Add the "filtermode" property.
author Bram Moolenaar <Bram@vim.org>
date Tue, 03 Sep 2019 22:15:03 +0200
parents dffad5c9361e
children 8ad762c15b0f
files runtime/doc/popup.txt src/map.c src/popupwin.c src/proto/map.pro src/structs.h src/testdir/test_popupwin.vim src/version.c src/vim.h
diffstat 8 files changed, 132 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -1,4 +1,4 @@
-*popup.txt*  For Vim version 8.1.  Last change: 2019 Aug 31
+*popup.txt*  For Vim version 8.1.  Last change: 2019 Sep 03
 
 
 		  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -442,7 +442,7 @@ popup_notification({what}, {options})			
 <		The PopupNotification highlight group is used instead of
 		WarningMsg if it is defined.
 
-		Without the |+timers| feature the poup will not disappear
+		Without the |+timers| feature the popup will not disappear
 		automatically, the user has to click in it.
 
 		The position will be adjusted to avoid overlap with other
@@ -486,7 +486,7 @@ popup_setoptions({id}, {options})			*pop
 		"tabpage" cannot be changed.
 
 popup_settext({id}, {text})				*popup_settext()*
-		Set the text of the buffer in poup win {id}. {text} is the
+		Set the text of the buffer in popup win {id}. {text} is the
 		same as supplied to |popup_create()|, except that a buffer
 		number is not allowed.
 		Does not change the window size or position, other than caused
@@ -583,13 +583,13 @@ The second argument of |popup_create()| 
 			start and end as padding.
 	wrap		TRUE to make the lines wrap (default TRUE).
 	drag		TRUE to allow the popup to be dragged with the mouse
-			by grabbing at at the border.  Has no effect if the
+			by grabbing at the border.  Has no effect if the
 			popup does not have a border. As soon as dragging
 			starts and "pos" is "center" it is changed to
 			"topleft".
 	resize		TRUE to allow the popup to be resized with the mouse
-			by grabbing at at the bottom right cornder.  Has no
-			effect if the popup does not have a border.
+			by grabbing at the bottom right corner.  Has no effect
+			if the popup does not have a border.
 	close		When "button" an X is displayed in the top-right, on
 			top of any border, padding or text.  When clicked on
 			the X the popup will close.  Any callback is invoked
@@ -662,6 +662,18 @@ The second argument of |popup_create()| 
 	mapping		Allow for key mapping.  When FALSE and the popup is
 			visible and has a filter callback key mapping is
 			disabled.  Default value is TRUE.
+	filtermode	In which modes the filter is used (same flags as with
+			|hasmapto()| plus "a"):
+				n	Normal mode
+				v	Visual and Select mode
+				x	Visual mode
+				s	Select mode
+				o	Operator-pending mode
+				i	Insert mode
+				l	Language-Argument ("r", "f", "t", etc.)
+				c	Command-line mode
+				a	all modes
+			The default value is "a".
 	callback	A callback that is called when the popup closes, e.g.
 			when using |popup_filter_menu()|, see |popup-callback|.
 
@@ -784,13 +796,20 @@ key as a string, e.g.: >
 	  endif
 	  return 0
 	endfunc
-<							*popup-mapping*
+<							*popup-filter-mode*
+The "filtermode" property can be used to specify in what mode the filter is
+invoked.  The default is "a": all modes.  When using "nvi" Command-line mode
+is not included, so that any command typed on the command line is not
+filtered.  However, to get to Command-line mode the filter must not consume
+":".  Just like it must not consume "v" to allow for entering Visual mode.
+
+							*popup-mapping*
 Normally the key is what results after any mapping, since the keys pass on as
 normal input if the filter does not use it.  If the filter consumes all the
 keys, set the "mapping" property to zero so that mappings do not get in the
 way.  This is default for |popup_menu()| and |popup_dialog()|.
 
-Some common key actions:
+Some recommended key actions:
 	x		close the popup (see note below)
 	cursor keys	select another entry
 	Tab		accept current suggestion
@@ -941,7 +960,7 @@ this example simulated with a timer call
 	    call popup_close(s:winid)
 	    let s:winid = 0
 	  endif
-	  " simulate an asynchronous loopup for the text to display
+	  " simulate an asynchronous lookup for the text to display
 	  let s:balloonText = v:beval_text
 	  call timer_start(100, 'ShowPopup')
 	  return ''
--- a/src/map.c
+++ b/src/map.c
@@ -897,20 +897,10 @@ map_clear_int(
 }
 
 #if defined(FEAT_EVAL) || defined(PROTO)
-/*
- * Return TRUE if a map exists that has "str" in the rhs for mode "modechars".
- * Recognize termcap codes in "str".
- * Also checks mappings local to the current buffer.
- */
     int
-map_to_exists(char_u *str, char_u *modechars, int abbr)
+mode_str2flags(char_u *modechars)
 {
     int		mode = 0;
-    char_u	*rhs;
-    char_u	*buf;
-    int		retval;
-
-    rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
 
     if (vim_strchr(modechars, 'n') != NULL)
 	mode |= NORMAL;
@@ -929,7 +919,24 @@ map_to_exists(char_u *str, char_u *modec
     if (vim_strchr(modechars, 'c') != NULL)
 	mode |= CMDLINE;
 
-    retval = map_to_exists_mode(rhs, mode, abbr);
+    return mode;
+}
+
+/*
+ * Return TRUE if a map exists that has "str" in the rhs for mode "modechars".
+ * Recognize termcap codes in "str".
+ * Also checks mappings local to the current buffer.
+ */
+    int
+map_to_exists(char_u *str, char_u *modechars, int abbr)
+{
+    char_u	*rhs;
+    char_u	*buf;
+    int		retval;
+
+    rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
+
+    retval = map_to_exists_mode(rhs, mode_str2flags(modechars), abbr);
     vim_free(buf);
 
     return retval;
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -845,6 +845,15 @@ apply_general_options(win_T *wp, dict_T 
 	    wp->w_popup_flags &= ~POPF_MAPPING;
     }
 
+    str = dict_get_string(dict, (char_u *)"filtermode", FALSE);
+    if (str != NULL)
+    {
+	if (STRCMP(str, "a") == 0)
+	    wp->w_filter_mode = MODE_ALL;
+	else
+	    wp->w_filter_mode = mode_str2flags(str);
+    }
+
     di = dict_find(dict, (char_u *)"callback", -1);
     if (di != NULL)
     {
@@ -1851,6 +1860,7 @@ popup_create(typval_T *argvars, typval_T
 	wp->w_border_char[i] = 0;
     wp->w_want_scrollbar = 1;
     wp->w_popup_fixed = 0;
+    wp->w_filter_mode = MODE_ALL;
 
     if (d != NULL)
 	// Deal with options.
@@ -2768,6 +2778,7 @@ popup_do_filter(int c)
     int		res = FALSE;
     win_T	*wp;
     int		save_KeyTyped = KeyTyped;
+    int		state;
 
     if (recursive)
 	return FALSE;
@@ -2785,8 +2796,10 @@ popup_do_filter(int c)
 	    res = TRUE;
     }
 
+    state = get_real_state();
     while (!res && (wp = find_next_popup(FALSE)) != NULL)
-	if (wp->w_filter_cb.cb_name != NULL)
+	if (wp->w_filter_cb.cb_name != NULL
+		&& (wp->w_filter_mode & state) != 0)
 	    res = invoke_popup_filter(wp, c);
 
     recursive = FALSE;
--- a/src/proto/map.pro
+++ b/src/proto/map.pro
@@ -4,6 +4,7 @@ mapblock_T *get_buf_maphash_list(int sta
 int is_maphash_valid(void);
 int do_map(int maptype, char_u *arg, int mode, int abbrev);
 void map_clear_int(buf_T *buf, int mode, int local, int abbr);
+int mode_str2flags(char_u *modechars);
 int map_to_exists(char_u *str, char_u *modechars, int abbr);
 int map_to_exists_mode(char_u *rhs, int mode, int abbr);
 char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx);
--- a/src/structs.h
+++ b/src/structs.h
@@ -3054,6 +3054,7 @@ struct window_S
 				      // computed
     callback_T	w_close_cb;	    // popup close callback
     callback_T	w_filter_cb;	    // popup filter callback
+    int		w_filter_mode;	    // mode when filter callback is used
 
     win_T	*w_popup_curwin;    // close popup if curwin differs
     linenr_T	w_popup_lnum;	    // close popup if cursor not on this line
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -1892,6 +1892,72 @@ func Test_popupwin_garbage_collect()
   delfunc MyPopupFilter
 endfunc
 
+func Test_popupwin_filter_mode()
+  func MyPopupFilter(winid, c)
+    let s:typed = a:c
+    if a:c == ':' || a:c == "\r" || a:c == 'v'
+      " can start cmdline mode, get out, and start/stop Visual mode
+      return 0
+    endif
+    return 1
+  endfunc
+
+  " Normal, Visual and Insert mode
+  let winid = popup_create('something', #{filter: 'MyPopupFilter', filtermode: 'nvi'})
+  redraw
+  call feedkeys('x', 'xt')
+  call assert_equal('x', s:typed)
+
+  call feedkeys(":let g:foo = 'foo'\<CR>", 'xt')
+  call assert_equal(':', s:typed)
+  call assert_equal('foo', g:foo)
+
+  let @x = 'something'
+  call feedkeys('v$"xy', 'xt')
+  call assert_equal('y', s:typed)
+  call assert_equal('something', @x)  " yank command is filtered out
+  call feedkeys('v', 'xt')  " end Visual mode
+
+  call popup_close(winid)
+
+  " only Normal mode
+  let winid = popup_create('something', #{filter: 'MyPopupFilter', filtermode: 'n'})
+  redraw
+  call feedkeys('x', 'xt')
+  call assert_equal('x', s:typed)
+
+  call feedkeys(":let g:foo = 'foo'\<CR>", 'xt')
+  call assert_equal(':', s:typed)
+  call assert_equal('foo', g:foo)
+
+  let @x = 'something'
+  call feedkeys('v$"xy', 'xt')
+  call assert_equal('v', s:typed)
+  call assert_notequal('something', @x)
+
+  call popup_close(winid)
+
+  " default: all modes
+  let winid = popup_create('something', #{filter: 'MyPopupFilter'})
+  redraw
+  call feedkeys('x', 'xt')
+  call assert_equal('x', s:typed)
+
+  let g:foo = 'bar'
+  call feedkeys(":let g:foo = 'foo'\<CR>", 'xt')
+  call assert_equal("\r", s:typed)
+  call assert_equal('bar', g:foo)
+
+  let @x = 'something'
+  call feedkeys('v$"xy', 'xt')
+  call assert_equal('y', s:typed)
+  call assert_equal('something', @x)  " yank command is filtered out
+  call feedkeys('v', 'xt')  " end Visual mode
+
+  call popup_close(winid)
+  delfunc MyPopupFilter
+endfunc
+
 func Test_popupwin_with_buffer()
   call writefile(['some text', 'in a buffer'], 'XsomeFile')
   let buf = bufadd('XsomeFile')
--- a/src/version.c
+++ b/src/version.c
@@ -762,6 +762,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1969,
+/**/
     1968,
 /**/
     1967,
--- a/src/vim.h
+++ b/src/vim.h
@@ -680,6 +680,7 @@ extern int (*dyn_libintl_wputenv)(const 
 #define CONFIRM		0x800	// ":confirm" prompt
 #define SELECTMODE	0x1000	// Select mode, only for mappings
 #define TERMINAL        0x2000  // Terminal mode
+#define MODE_ALL	0xffff
 
 // all mode bits used for mapping
 #define MAP_ALL_MODES	(0x3f | SELECTMODE | TERMINAL)