summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-02 18:40:06 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-02 18:40:06 +0200
commit3397f74ac2ac27f1eef48e950c3c8eeb0338fe55 (patch)
tree7ca95e2cfc692c2d90830948c4a4a6c1b620cd22
parentb0ebbda06cf1a4a7c40cb274529c4c53de534e32 (diff)
downloadvim-git-3397f74ac2ac27f1eef48e950c3c8eeb0338fe55.tar.gz
patch 8.1.1453: popup window "moved" property not implemented yetv8.1.1453
Problem: Popup window "moved" property not implemented yet. Solution: Implement it.
-rw-r--r--runtime/doc/popup.txt19
-rw-r--r--src/edit.c14
-rw-r--r--src/globals.h16
-rw-r--r--src/gui.c7
-rw-r--r--src/main.c11
-rw-r--r--src/popupwin.c90
-rw-r--r--src/proto/popupwin.pro1
-rw-r--r--src/screen.c2
-rw-r--r--src/structs.h6
-rw-r--r--src/testdir/test_popupwin.vim65
-rw-r--r--src/version.c2
11 files changed, 202 insertions, 31 deletions
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 86476d0d8..7fa172c88 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -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*
diff --git a/src/edit.c b/src/edit.c
index 6e4b4743c..ad25252e7 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -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;
diff --git a/src/globals.h b/src/globals.h
index 43ad8e97e..4973d3191 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -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
diff --git a/src/gui.c b/src/gui.c
index 8edc86cd7..c4df7d9a5 100644
--- 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)
{
diff --git a/src/main.c b/src/main.c
index e1ddbf7e9..e9165c6bf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
}
diff --git a/src/popupwin.c b/src/popupwin.c
index 357b7611d..2d61ab8bf 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -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));
+ }
}
/*
@@ -708,6 +751,21 @@ invoke_popup_callback(win_T *wp, typval_T *result)
}
/*
+ * 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})
*/
void
@@ -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
diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro
index 24a102395..a50e7b7fa 100644
--- a/src/proto/popupwin.pro
+++ b/src/proto/popupwin.pro
@@ -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 : */
diff --git a/src/screen.c b/src/screen.c
index f17961816..8c97e880e 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -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;
diff --git a/src/structs.h b/src/structs.h
index 591c5a2fc..bc1e48786 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index ca95977a7..6d3279b4b 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 33eb93c36..2cefa3bac 100644
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1453,
+/**/
1452,
/**/
1451,