Patch 8.1.1969
Problem:    Popup window filter is used in all modes.
Solution:   Add the "filtermode" property.
Files:      src/popupwin.c, src/vim.h, src/map.c, src/proto/map.pro,
            src/structs.h, runtime/doc/popup.txt,
            src/testdir/test_popupwin.vim


*** ../vim-8.1.1968/src/popupwin.c      2019-09-01 23:27:02.142724494 +0200
--- src/popupwin.c      2019-09-03 21:53:07.749751760 +0200
***************
*** 845,850 ****
--- 845,859 ----
            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,1856 ****
--- 1860,1866 ----
        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,2773 ****
--- 2778,2784 ----
      int               res = FALSE;
      win_T     *wp;
      int               save_KeyTyped = KeyTyped;
+     int               state;
  
      if (recursive)
        return FALSE;
***************
*** 2785,2792 ****
            res = TRUE;
      }
  
      while (!res && (wp = find_next_popup(FALSE)) != NULL)
!       if (wp->w_filter_cb.cb_name != NULL)
            res = invoke_popup_filter(wp, c);
  
      recursive = FALSE;
--- 2796,2805 ----
            res = TRUE;
      }
  
+     state = get_real_state();
      while (!res && (wp = find_next_popup(FALSE)) != NULL)
!       if (wp->w_filter_cb.cb_name != NULL
!               && (wp->w_filter_mode & state) != 0)
            res = invoke_popup_filter(wp, c);
  
      recursive = FALSE;
*** ../vim-8.1.1968/src/vim.h   2019-09-01 16:24:53.297677674 +0200
--- src/vim.h   2019-09-03 20:32:03.603661019 +0200
***************
*** 680,685 ****
--- 680,686 ----
  #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)
*** ../vim-8.1.1968/src/map.c   2019-09-02 22:31:08.010296361 +0200
--- src/map.c   2019-09-03 20:57:17.809042184 +0200
***************
*** 897,916 ****
  }
  
  #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)
  {
      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;
--- 897,906 ----
  }
  
  #if defined(FEAT_EVAL) || defined(PROTO)
      int
! mode_str2flags(char_u *modechars)
  {
      int               mode = 0;
  
      if (vim_strchr(modechars, 'n') != NULL)
        mode |= NORMAL;
***************
*** 929,935 ****
      if (vim_strchr(modechars, 'c') != NULL)
        mode |= CMDLINE;
  
!     retval = map_to_exists_mode(rhs, mode, abbr);
      vim_free(buf);
  
      return retval;
--- 919,942 ----
      if (vim_strchr(modechars, 'c') != NULL)
        mode |= CMDLINE;
  
!     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;
*** ../vim-8.1.1968/src/proto/map.pro   2019-09-02 22:31:08.010296361 +0200
--- src/proto/map.pro   2019-09-03 20:57:48.912904537 +0200
***************
*** 4,9 ****
--- 4,10 ----
  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);
*** ../vim-8.1.1968/src/structs.h       2019-08-25 22:24:58.871357010 +0200
--- src/structs.h       2019-09-03 21:05:03.349791534 +0200
***************
*** 3054,3059 ****
--- 3054,3060 ----
                                      // 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
*** ../vim-8.1.1968/runtime/doc/popup.txt       2019-08-25 22:24:58.867357027 
+0200
--- runtime/doc/popup.txt       2019-09-03 21:52:35.377923218 +0200
***************
*** 125,131 ****
  It is possible to change the specifically mentioned options, but anything
  might break then, so better leave them alone.
  
! The window does have a cursor position, but the cursor is not displayed.
  
  To execute a command in the context of the popup window and buffer use
  `win_execute()`.  Example: >
--- 125,133 ----
  It is possible to change the specifically mentioned options, but anything
  might break then, so better leave them alone.
  
! The window does have a cursor position, but the cursor is not displayed.  In
! fact, the cursor in the underlying window is displayed, as if it peeks through
! the popup, so you can see where it is.
  
  To execute a command in the context of the popup window and buffer use
  `win_execute()`.  Example: >
***************
*** 315,320 ****
--- 317,326 ----
                The "mousemoved" entry is a list with screen row, minimum and
                maximum screen column, [0, 0, 0] when not set.
  
+               "firstline" is the property set on the popup, unlike the
+               "firstline" obtained with |popup_getpos()| which is the actual
+               buffer line at the top of the popup window.
+ 
                "border" and "padding" are not included when all values are
                zero.  When all values are one then an empty list is included.
  
***************
*** 344,349 ****
--- 350,356 ----
                    core_width  width of the text box in screen cells
                    core_height height of the text box in screen cells
                    firstline   line of the buffer at top (1 unless scrolled)
+                               (not the value of the "firstline" property)
                    scrollbar   non-zero if a scrollbar is displayed
                    visible     one if the popup is displayed, zero if hidden
                Note that these are the actual screen positions.  They differ
***************
*** 435,441 ****
  <             The PopupNotification highlight group is used instead of
                WarningMsg if it is defined.
  
!               Without the |+timers| feature the poup will not disappear
                automatically, the user has to click in it.
  
                The position will be adjusted to avoid overlap with other
--- 442,448 ----
  <             The PopupNotification highlight group is used instead of
                WarningMsg if it is defined.
  
!               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
***************
*** 479,485 ****
                "tabpage" cannot be changed.
  
  popup_settext({id}, {text})                           *popup_settext()*
!               Set the text of the buffer in poup 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
--- 486,492 ----
                "tabpage" cannot be changed.
  
  popup_settext({id}, {text})                           *popup_settext()*
!               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
***************
*** 559,564 ****
--- 566,572 ----
        firstline       First buffer line to display.  When larger than one it
                        looks like the text scrolled up.  When out of range
                        the last buffer line will at the top of the window.
+                       Set to zero to leave the position as set by commands.
                        Also see "scrollbar".
        hidden          When TRUE the popup exists but is not displayed; use
                        `popup_show()` to unhide it.
***************
*** 575,587 ****
                        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
                        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.
        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
--- 583,595 ----
                        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 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 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
***************
*** 654,659 ****
--- 662,679 ----
        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|.
  
***************
*** 776,788 ****
          endif
          return 0
        endfunc
! <                                                     *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:
        x               close the popup (see note below)
        cursor keys     select another entry
        Tab             accept current suggestion
--- 796,815 ----
          endif
          return 0
        endfunc
! <                                                     *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 recommended key actions:
        x               close the popup (see note below)
        cursor keys     select another entry
        Tab             accept current suggestion
***************
*** 933,939 ****
            call popup_close(s:winid)
            let s:winid = 0
          endif
!         " simulate an asynchronous loopup for the text to display
          let s:balloonText = v:beval_text
          call timer_start(100, 'ShowPopup')
          return ''
--- 960,966 ----
            call popup_close(s:winid)
            let s:winid = 0
          endif
!         " simulate an asynchronous lookup for the text to display
          let s:balloonText = v:beval_text
          call timer_start(100, 'ShowPopup')
          return ''
*** ../vim-8.1.1968/src/testdir/test_popupwin.vim       2019-09-02 
22:56:20.992583887 +0200
--- src/testdir/test_popupwin.vim       2019-09-03 21:54:09.981423105 +0200
***************
*** 1892,1897 ****
--- 1892,1963 ----
    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')
*** ../vim-8.1.1968/src/version.c       2019-09-03 17:13:32.040528491 +0200
--- src/version.c       2019-09-03 21:54:38.369273583 +0200
***************
*** 763,764 ****
--- 763,766 ----
  {   /* Add new patch number below this line */
+ /**/
+     1969,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
171. You invent another person and chat with yourself in empty chat rooms.

 /// Bram Moolenaar -- [email protected] -- 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    ///

-- 
-- 
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/201909032014.x83KERma020175%40masaka.moolenaar.net.

Raspunde prin e-mail lui