]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.1.1453: popup window "moved" property not implemented yet v8.1.1453
authorBram Moolenaar <Bram@vim.org>
Sun, 2 Jun 2019 16:40:06 +0000 (18:40 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 2 Jun 2019 16:40:06 +0000 (18:40 +0200)
Problem:    Popup window "moved" property not implemented yet.
Solution:   Implement it.

runtime/doc/popup.txt
src/edit.c
src/globals.h
src/gui.c
src/main.c
src/popupwin.c
src/proto/popupwin.pro
src/screen.c
src/structs.h
src/testdir/test_popupwin.vim
src/version.c

index 86476d0d80ad81f72b89d1d9f006a24f0309bda9..7fa172c88b06569f33f34d5a62fd98fe06b64d21 100644 (file)
@@ -90,7 +90,6 @@ Probably 2. is the best choice.
 
 IMPLEMENTATION:
 - Code is in popupwin.c
-- Fix positioning with border and padding.
 - Why does 'nrformats' leak from the popup window buffer???
 - Make redrawing more efficient and avoid flicker.
     First draw popups, creating a mask, use the mask in screen_line() when
@@ -410,13 +409,14 @@ The second argument of |popup_create()| is a dictionary with options:
        zindex          Priority for the popup, default 50.
        time            Time in milliseconds after which the popup will close.
                        When omitted |popup_close()| must be used.
-       moved           "cell": close the popup if the cursor moved at least
-                       one screen cell.
-                       "word" allows for moving the cursor within |<cword>|
-                       "WORD" allows for moving the cursor within |<cWORD>|
-                       a list with two numbers specifies the start and end
-                       column outside of which the popup will close
-                       {not implemented yet}
+       moved           Specifies to close the popup if the cursor moved:
+                       - "any": if the cursor moved at all
+                       - "word": if the cursor moved outside |<cword>|
+                       - "WORD": if the cursor moved outside |<cWORD>|
+                       - [{start}, {end}]: if the cursor moved before column
+                         {start} or after {end}
+                       The popup also closes if the cursor moves to another
+                       line or to another window.
        filter          A callback that can filter typed characters, see 
                        |popup-filter|.
        callback        A callback that is called when the popup closes, e.g.
@@ -510,6 +510,9 @@ The callback is invoked with two arguments: the ID of the popup window and the
 result, which could be an index in the popup lines, or whatever was passed as
 the second argument of `popup_close()`.
 
+If the popup is closed because the cursor moved, the number -1 is passed to
+the callback.
+
 ==============================================================================
 3. Examples                                            *popup-examples*
 
index 6e4b4743c47744d05908132337d51a12e998b3b3..ad25252e7ec6df52f785326793ef4630d3ef79c1 100644 (file)
@@ -1456,8 +1456,7 @@ ins_need_undo_get(void)
  * inserting sequences of characters (e.g., for CTRL-R).
  */
     void
-ins_redraw(
-    int                ready UNUSED)       /* not busy with something */
+ins_redraw(int ready)      // not busy with something
 {
 #ifdef FEAT_CONCEAL
     linenr_T   conceal_old_cursor_line = 0;
@@ -1468,10 +1467,12 @@ ins_redraw(
     if (char_avail())
        return;
 
-#if defined(FEAT_CONCEAL)
     /* Trigger CursorMoved if the cursor moved.  Not when the popup menu is
      * visible, the command might delete it. */
     if (ready && (has_cursormovedI()
+# ifdef FEAT_TEXT_PROP
+               || popup_visible
+# endif
 # if defined(FEAT_CONCEAL)
                || curwin->w_p_cole > 0
 # endif
@@ -1497,6 +1498,10 @@ ins_redraw(
            update_curswant();
            ins_apply_autocmds(EVENT_CURSORMOVEDI);
        }
+#ifdef FEAT_TEXT_PROP
+       if (popup_visible)
+           popup_check_cursor_pos();
+#endif
 # ifdef FEAT_CONCEAL
        if (curwin->w_p_cole > 0)
        {
@@ -1507,7 +1512,6 @@ ins_redraw(
 # endif
        last_cursormoved = curwin->w_cursor;
     }
-#endif
 
     /* Trigger TextChangedI if b_changedtick differs. */
     if (ready && has_textchangedI()
@@ -3859,7 +3863,7 @@ replace_push(
     if (replace_stack_len <= replace_stack_nr)
     {
        replace_stack_len += 50;
-       p = alloc(sizeof(char_u) * replace_stack_len);
+       p = ALLOC_MULT(char_u, replace_stack_len);
        if (p == NULL)      /* out of memory */
        {
            replace_stack_len -= 50;
index 43ad8e97e32fd345d25b8009560fa49de04876f6..4973d3191a511b14742a77738e942fe7b460b5a1 100644 (file)
@@ -558,24 +558,25 @@ EXTERN int        clip_unnamed_saved INIT(= 0);
 EXTERN win_T   *firstwin;              /* first window */
 EXTERN win_T   *lastwin;               /* last window */
 EXTERN win_T   *prevwin INIT(= NULL);  /* previous window */
-# define ONE_WINDOW (firstwin == lastwin)
-# define W_NEXT(wp) ((wp)->w_next)
-# define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next)
-# define FOR_ALL_FRAMES(frp, first_frame) \
+#define ONE_WINDOW (firstwin == lastwin)
+#define W_NEXT(wp) ((wp)->w_next)
+#define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; wp = wp->w_next)
+#define FOR_ALL_FRAMES(frp, first_frame) \
     for (frp = first_frame; frp != NULL; frp = frp->fr_next)
-# define FOR_ALL_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
-# define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \
+#define FOR_ALL_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
+#define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \
     for ((wp) = ((tp) == NULL || (tp) == curtab) \
            ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
 /*
  * When using this macro "break" only breaks out of the inner loop. Use "goto"
  * to break out of the tabpage loop.
  */
-# define FOR_ALL_TAB_WINDOWS(tp, wp) \
+#define FOR_ALL_TAB_WINDOWS(tp, wp) \
     for ((tp) = first_tabpage; (tp) != NULL; (tp) = (tp)->tp_next) \
        for ((wp) = ((tp) == curtab) \
                ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
 
+
 EXTERN win_T   *curwin;        /* currently active window */
 
 EXTERN win_T   *aucmd_win;     /* window used in aucmd_prepbuf() */
@@ -1663,4 +1664,5 @@ EXTERN HINSTANCE g_hinst INIT(= NULL);
 
 #ifdef FEAT_TEXT_PROP
 EXTERN int text_prop_frozen INIT(= 0);
+EXTERN int popup_visible INIT(= FALSE);
 #endif
index 8edc86cd76fe9a97d1423938b4748888434028aa..c4df7d9a57b0729979555b49ea8200aab7d9e410 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -5117,6 +5117,9 @@ gui_update_screen(void)
 
     /* Trigger CursorMoved if the cursor moved. */
     if (!finish_op && (has_cursormoved()
+# ifdef FEAT_TEXT_PROP
+               || popup_visible
+# endif
 # ifdef FEAT_CONCEAL
                || curwin->w_p_cole > 0
 # endif
@@ -5124,6 +5127,10 @@ gui_update_screen(void)
     {
        if (has_cursormoved())
            apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf);
+#ifdef FEAT_TEXT_PROP
+       if (popup_visible)
+           popup_check_cursor_pos();
+#endif
 # ifdef FEAT_CONCEAL
        if (curwin->w_p_cole > 0)
        {
index e1ddbf7e9ae2c4ad363efbf453dc5e6307b7518c..e9165c6bfb7e30e612bfa7b1634ed85c77824f4f 100644 (file)
@@ -1159,6 +1159,9 @@ main_loop(
            /* Trigger CursorMoved if the cursor moved. */
            if (!finish_op && (
                        has_cursormoved()
+#ifdef FEAT_TEXT_PROP
+                       || popup_visible
+#endif
 #ifdef FEAT_CONCEAL
                        || curwin->w_p_cole > 0
 #endif
@@ -1168,14 +1171,18 @@ main_loop(
                if (has_cursormoved())
                    apply_autocmds(EVENT_CURSORMOVED, NULL, NULL,
                                                               FALSE, curbuf);
-# ifdef FEAT_CONCEAL
+#ifdef FEAT_TEXT_PROP
+               if (popup_visible)
+                   popup_check_cursor_pos();
+#endif
+#ifdef FEAT_CONCEAL
                if (curwin->w_p_cole > 0)
                {
                    conceal_old_cursor_line = last_cursormoved.lnum;
                    conceal_new_cursor_line = curwin->w_cursor.lnum;
                    conceal_update_lines = TRUE;
                }
-# endif
+#endif
                last_cursormoved = curwin->w_cursor;
            }
 
index 357b7611d065d9e531fa46b000d2a0f859444240..2d61ab8bf450e454e8f0b21049c838e0fe5130c4 100644 (file)
@@ -285,6 +285,49 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict, int atcursor)
            }
        }
     }
+
+    di = dict_find(dict, (char_u *)"moved", -1);
+    if (di != NULL)
+    {
+       wp->w_popup_curwin = curwin;
+       wp->w_popup_lnum = curwin->w_cursor.lnum;
+       wp->w_popup_mincol = curwin->w_cursor.col;
+       wp->w_popup_maxcol = curwin->w_cursor.col;
+       if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
+       {
+           char_u  *s = di->di_tv.vval.v_string;
+           int     flags = 0;
+
+           if (STRCMP(s, "word") == 0)
+               flags = FIND_IDENT | FIND_STRING;
+           else if (STRCMP(s, "WORD") == 0)
+               flags = FIND_STRING;
+           else if (STRCMP(s, "any") != 0)
+               semsg(_(e_invarg2), s);
+           if (flags != 0)
+           {
+               char_u  *ptr;
+               int     len = find_ident_under_cursor(&ptr, flags);
+
+               if (len > 0)
+               {
+                   wp->w_popup_mincol = (int)(ptr - ml_get_curline());
+                   wp->w_popup_maxcol = wp->w_popup_mincol + len - 1;
+               }
+           }
+       }
+       else if (di->di_tv.v_type == VAR_LIST
+               && di->di_tv.vval.v_list != NULL
+               && di->di_tv.vval.v_list->lv_len == 2)
+       {
+           list_T *l = di->di_tv.vval.v_list;
+
+           wp->w_popup_mincol = tv_get_number(&l->lv_first->li_tv);
+           wp->w_popup_maxcol = tv_get_number(&l->lv_first->li_next->li_tv);
+       }
+       else
+           semsg(_(e_invarg2), tv_get_string(&di->di_tv));
+    }
 }
 
 /*
@@ -707,6 +750,21 @@ invoke_popup_callback(win_T *wp, typval_T *result)
     clear_tv(&rettv);
 }
 
+/*
+ * Close popup "wp" and invoke any close callback for it.
+ */
+    static void
+popup_close_and_callback(win_T *wp, typval_T *arg)
+{
+    int id = wp->w_id;
+
+    if (wp->w_close_cb.cb_name != NULL)
+       // Careful: This may make "wp" invalid.
+       invoke_popup_callback(wp, arg);
+
+    popup_close(id);
+}
+
 /*
  * popup_close({id})
  */
@@ -717,13 +775,7 @@ f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
     win_T      *wp = find_popup_win(id);
 
     if (wp != NULL)
-    {
-       if (wp->w_close_cb.cb_name != NULL)
-           // Careful: This may make "wp" invalid.
-           invoke_popup_callback(wp, &argvars[1]);
-
-       popup_close(id);
-    }
+       popup_close_and_callback(wp, &argvars[1]);
 }
 
 /*
@@ -1066,4 +1118,28 @@ popup_do_filter(int c)
     return res;
 }
 
+/*
+ * Called when the cursor moved: check if any popup needs to be closed if the
+ * cursor moved far enough.
+ */
+    void
+popup_check_cursor_pos()
+{
+    win_T *wp;
+    typval_T tv;
+
+    popup_reset_handled();
+    while ((wp = find_next_popup(TRUE)) != NULL)
+       if (wp->w_popup_curwin != NULL
+               && (curwin != wp->w_popup_curwin
+                   || curwin->w_cursor.lnum != wp->w_popup_lnum
+                   || curwin->w_cursor.col < wp->w_popup_mincol
+                   || curwin->w_cursor.col > wp->w_popup_maxcol))
+       {
+           tv.v_type = VAR_NUMBER;
+           tv.vval.v_number = -1;
+           popup_close_and_callback(wp, &tv);
+       }
+}
+
 #endif // FEAT_TEXT_PROP
index 24a1023950bab3204cb39aeb010147c0f4dfac97..a50e7b7faa5ce7bd5f12351cc473eaf3d1ca33f2 100644 (file)
@@ -17,4 +17,5 @@ int not_in_popup_window(void);
 void popup_reset_handled(void);
 win_T *find_next_popup(int lowest);
 int popup_do_filter(int c);
+void popup_check_cursor_pos(void);
 /* vim: set ft=c : */
index f179618166a478b33debf839e237156abe32b68d..8c97e880e62d540847787ef3efbd91bf9bafe425 100644 (file)
@@ -1050,6 +1050,7 @@ update_popups(void)
     // so that the window with a higher zindex is drawn later, thus goes on
     // top.
     // TODO: don't redraw every popup every time.
+    popup_visible = FALSE;
     popup_reset_handled();
     while ((wp = find_next_popup(TRUE)) != NULL)
     {
@@ -1066,6 +1067,7 @@ update_popups(void)
 
        // Draw the popup text.
        win_update(wp);
+       popup_visible = TRUE;
 
        wp->w_winrow -= top_off;
        wp->w_wincol -= left_off;
index 591c5a2fc2ed0ff8d45a27686980957dfe616ad6..bc1e4878605cf88062731fb95aebe2d6dd408d35 100644 (file)
@@ -2897,6 +2897,12 @@ struct window_S
                                          // computed
     callback_T w_close_cb;         // popup close callback
     callback_T w_filter_cb;        // popup filter callback
+
+    win_T      *w_popup_curwin;    // close popup if curwin differs
+    linenr_T   w_popup_lnum;       // close popup if cursor not on this line
+    colnr_T    w_popup_mincol;     // close popup if cursor before this col
+    colnr_T    w_popup_maxcol;     // close popup if cursor after this col
+
 # if defined(FEAT_TIMERS)
     timer_T    *w_popup_timer;     // timer for closing popup window
 # endif
index ca95977a7673266c908df0ae57d165fa1526d5e0..6d3279b4bb7c369a2172771252d13b11d585545d 100644 (file)
@@ -909,7 +909,7 @@ func Test_popup_position_adjust()
   %bwipe!
 endfunc
 
-function Test_adjust_left_past_screen_width()
+func Test_adjust_left_past_screen_width()
   " width of screen
   let X = join(map(range(&columns), {->'X'}), '')
 
@@ -973,4 +973,65 @@ function Test_adjust_left_past_screen_width()
 
   popupclear
   %bwipe!
-endfunction
+endfunc
+
+func Test_popup_moved()
+  new
+  call test_override('char_avail', 1)
+  call setline(1, ['one word to move around', 'a WORD.and->some thing'])
+
+  exe "normal gg0/word\<CR>"
+  let winid = popup_atcursor('text', {'moved': 'any'})
+  redraw
+  call assert_equal(1, popup_getpos(winid).visible)
+  " trigger the check for last_cursormoved by going into insert mode
+  call feedkeys("li\<Esc>", 'xt')
+  call assert_equal({}, popup_getpos(winid))
+  popupclear
+
+  exe "normal gg0/word\<CR>"
+  let winid = popup_atcursor('text', {'moved': 'word'})
+  redraw
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("hi\<Esc>", 'xt')
+  call assert_equal({}, popup_getpos(winid))
+  popupclear
+
+  exe "normal gg0/word\<CR>"
+  let winid = popup_atcursor('text', {'moved': 'word'})
+  redraw
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("li\<Esc>", 'xt')
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("ei\<Esc>", 'xt')
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("eli\<Esc>", 'xt')
+  call assert_equal({}, popup_getpos(winid))
+  popupclear
+
+  exe "normal gg0/WORD\<CR>"
+  let winid = popup_atcursor('text', {'moved': 'WORD'})
+  redraw
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("eli\<Esc>", 'xt')
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("wi\<Esc>", 'xt')
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("Eli\<Esc>", 'xt')
+  call assert_equal({}, popup_getpos(winid))
+  popupclear
+
+  exe "normal gg0/word\<CR>"
+  let winid = popup_atcursor('text', {'moved': [5, 10]})
+  redraw
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("eli\<Esc>", 'xt')
+  call feedkeys("ei\<Esc>", 'xt')
+  call assert_equal(1, popup_getpos(winid).visible)
+  call feedkeys("eli\<Esc>", 'xt')
+  call assert_equal({}, popup_getpos(winid))
+  popupclear
+
+  bwipe!
+  call test_override('ALL', 0)
+endfunc
index 33eb93c36bacf9f5b44858b61dcc61d207aa1627..2cefa3bac0cf727a7724613c0b31b4d8637422b6 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1453,
 /**/
     1452,
 /**/