1
0
forked from aniani/vim

patch 8.1.1453: popup window "moved" property not implemented yet

Problem:    Popup window "moved" property not implemented yet.
Solution:   Implement it.
This commit is contained in:
Bram Moolenaar
2019-06-02 18:40:06 +02:00
parent b0ebbda06c
commit 3397f74ac2
11 changed files with 202 additions and 31 deletions

View File

@@ -90,7 +90,6 @@ Probably 2. is the best choice.
IMPLEMENTATION: IMPLEMENTATION:
- Code is in popupwin.c - Code is in popupwin.c
- Fix positioning with border and padding.
- Why does 'nrformats' leak from the popup window buffer??? - Why does 'nrformats' leak from the popup window buffer???
- Make redrawing more efficient and avoid flicker. - Make redrawing more efficient and avoid flicker.
First draw popups, creating a mask, use the mask in screen_line() when 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. zindex Priority for the popup, default 50.
time Time in milliseconds after which the popup will close. time Time in milliseconds after which the popup will close.
When omitted |popup_close()| must be used. When omitted |popup_close()| must be used.
moved "cell": close the popup if the cursor moved at least moved Specifies to close the popup if the cursor moved:
one screen cell. - "any": if the cursor moved at all
"word" allows for moving the cursor within |<cword>| - "word": if the cursor moved outside |<cword>|
"WORD" allows for moving the cursor within |<cWORD>| - "WORD": if the cursor moved outside |<cWORD>|
a list with two numbers specifies the start and end - [{start}, {end}]: if the cursor moved before column
column outside of which the popup will close {start} or after {end}
{not implemented yet} The popup also closes if the cursor moves to another
line or to another window.
filter A callback that can filter typed characters, see filter A callback that can filter typed characters, see
|popup-filter|. |popup-filter|.
callback A callback that is called when the popup closes, e.g. 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 result, which could be an index in the popup lines, or whatever was passed as
the second argument of `popup_close()`. 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* 3. Examples *popup-examples*

View File

@@ -1456,8 +1456,7 @@ ins_need_undo_get(void)
* inserting sequences of characters (e.g., for CTRL-R). * inserting sequences of characters (e.g., for CTRL-R).
*/ */
void void
ins_redraw( ins_redraw(int ready) // not busy with something
int ready UNUSED) /* not busy with something */
{ {
#ifdef FEAT_CONCEAL #ifdef FEAT_CONCEAL
linenr_T conceal_old_cursor_line = 0; linenr_T conceal_old_cursor_line = 0;
@@ -1468,10 +1467,12 @@ ins_redraw(
if (char_avail()) if (char_avail())
return; return;
#if defined(FEAT_CONCEAL)
/* Trigger CursorMoved if the cursor moved. Not when the popup menu is /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
* visible, the command might delete it. */ * visible, the command might delete it. */
if (ready && (has_cursormovedI() if (ready && (has_cursormovedI()
# ifdef FEAT_TEXT_PROP
|| popup_visible
# endif
# if defined(FEAT_CONCEAL) # if defined(FEAT_CONCEAL)
|| curwin->w_p_cole > 0 || curwin->w_p_cole > 0
# endif # endif
@@ -1497,6 +1498,10 @@ ins_redraw(
update_curswant(); update_curswant();
ins_apply_autocmds(EVENT_CURSORMOVEDI); ins_apply_autocmds(EVENT_CURSORMOVEDI);
} }
#ifdef FEAT_TEXT_PROP
if (popup_visible)
popup_check_cursor_pos();
#endif
# ifdef FEAT_CONCEAL # ifdef FEAT_CONCEAL
if (curwin->w_p_cole > 0) if (curwin->w_p_cole > 0)
{ {
@@ -1507,7 +1512,6 @@ ins_redraw(
# endif # endif
last_cursormoved = curwin->w_cursor; last_cursormoved = curwin->w_cursor;
} }
#endif
/* Trigger TextChangedI if b_changedtick differs. */ /* Trigger TextChangedI if b_changedtick differs. */
if (ready && has_textchangedI() if (ready && has_textchangedI()
@@ -3859,7 +3863,7 @@ replace_push(
if (replace_stack_len <= replace_stack_nr) if (replace_stack_len <= replace_stack_nr)
{ {
replace_stack_len += 50; 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 */ if (p == NULL) /* out of memory */
{ {
replace_stack_len -= 50; replace_stack_len -= 50;

View File

@@ -558,24 +558,25 @@ EXTERN int clip_unnamed_saved INIT(= 0);
EXTERN win_T *firstwin; /* first window */ EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */ EXTERN win_T *lastwin; /* last window */
EXTERN win_T *prevwin INIT(= NULL); /* previous window */ EXTERN win_T *prevwin INIT(= NULL); /* previous window */
# define ONE_WINDOW (firstwin == lastwin) #define ONE_WINDOW (firstwin == lastwin)
# define W_NEXT(wp) ((wp)->w_next) #define W_NEXT(wp) ((wp)->w_next)
# define FOR_ALL_WINDOWS(wp) for (wp = firstwin; wp != NULL; 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 FOR_ALL_FRAMES(frp, first_frame) \
for (frp = first_frame; frp != NULL; frp = frp->fr_next) 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_TABPAGES(tp) for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
# define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \ #define FOR_ALL_WINDOWS_IN_TAB(tp, wp) \
for ((wp) = ((tp) == NULL || (tp) == curtab) \ for ((wp) = ((tp) == NULL || (tp) == curtab) \
? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
/* /*
* When using this macro "break" only breaks out of the inner loop. Use "goto" * When using this macro "break" only breaks out of the inner loop. Use "goto"
* to break out of the tabpage loop. * 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 ((tp) = first_tabpage; (tp) != NULL; (tp) = (tp)->tp_next) \
for ((wp) = ((tp) == curtab) \ for ((wp) = ((tp) == curtab) \
? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next) ? firstwin : (tp)->tp_firstwin; (wp); (wp) = (wp)->w_next)
EXTERN win_T *curwin; /* currently active window */ EXTERN win_T *curwin; /* currently active window */
EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */ EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */
@@ -1663,4 +1664,5 @@ EXTERN HINSTANCE g_hinst INIT(= NULL);
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
EXTERN int text_prop_frozen INIT(= 0); EXTERN int text_prop_frozen INIT(= 0);
EXTERN int popup_visible INIT(= FALSE);
#endif #endif

View File

@@ -5117,6 +5117,9 @@ gui_update_screen(void)
/* Trigger CursorMoved if the cursor moved. */ /* Trigger CursorMoved if the cursor moved. */
if (!finish_op && (has_cursormoved() if (!finish_op && (has_cursormoved()
# ifdef FEAT_TEXT_PROP
|| popup_visible
# endif
# ifdef FEAT_CONCEAL # ifdef FEAT_CONCEAL
|| curwin->w_p_cole > 0 || curwin->w_p_cole > 0
# endif # endif
@@ -5124,6 +5127,10 @@ gui_update_screen(void)
{ {
if (has_cursormoved()) if (has_cursormoved())
apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf); apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf);
#ifdef FEAT_TEXT_PROP
if (popup_visible)
popup_check_cursor_pos();
#endif
# ifdef FEAT_CONCEAL # ifdef FEAT_CONCEAL
if (curwin->w_p_cole > 0) if (curwin->w_p_cole > 0)
{ {

View File

@@ -1159,6 +1159,9 @@ main_loop(
/* Trigger CursorMoved if the cursor moved. */ /* Trigger CursorMoved if the cursor moved. */
if (!finish_op && ( if (!finish_op && (
has_cursormoved() has_cursormoved()
#ifdef FEAT_TEXT_PROP
|| popup_visible
#endif
#ifdef FEAT_CONCEAL #ifdef FEAT_CONCEAL
|| curwin->w_p_cole > 0 || curwin->w_p_cole > 0
#endif #endif
@@ -1168,14 +1171,18 @@ main_loop(
if (has_cursormoved()) if (has_cursormoved())
apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, apply_autocmds(EVENT_CURSORMOVED, NULL, NULL,
FALSE, curbuf); 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) if (curwin->w_p_cole > 0)
{ {
conceal_old_cursor_line = last_cursormoved.lnum; conceal_old_cursor_line = last_cursormoved.lnum;
conceal_new_cursor_line = curwin->w_cursor.lnum; conceal_new_cursor_line = curwin->w_cursor.lnum;
conceal_update_lines = TRUE; conceal_update_lines = TRUE;
} }
# endif #endif
last_cursormoved = curwin->w_cursor; last_cursormoved = curwin->w_cursor;
} }

View 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); 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}) * popup_close({id})
*/ */
@@ -717,13 +775,7 @@ f_popup_close(typval_T *argvars, typval_T *rettv UNUSED)
win_T *wp = find_popup_win(id); win_T *wp = find_popup_win(id);
if (wp != NULL) if (wp != NULL)
{ popup_close_and_callback(wp, &argvars[1]);
if (wp->w_close_cb.cb_name != NULL)
// Careful: This may make "wp" invalid.
invoke_popup_callback(wp, &argvars[1]);
popup_close(id);
}
} }
/* /*
@@ -1066,4 +1118,28 @@ popup_do_filter(int c)
return res; 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 #endif // FEAT_TEXT_PROP

View File

@@ -17,4 +17,5 @@ int not_in_popup_window(void);
void popup_reset_handled(void); void popup_reset_handled(void);
win_T *find_next_popup(int lowest); win_T *find_next_popup(int lowest);
int popup_do_filter(int c); int popup_do_filter(int c);
void popup_check_cursor_pos(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -1050,6 +1050,7 @@ update_popups(void)
// so that the window with a higher zindex is drawn later, thus goes on // so that the window with a higher zindex is drawn later, thus goes on
// top. // top.
// TODO: don't redraw every popup every time. // TODO: don't redraw every popup every time.
popup_visible = FALSE;
popup_reset_handled(); popup_reset_handled();
while ((wp = find_next_popup(TRUE)) != NULL) while ((wp = find_next_popup(TRUE)) != NULL)
{ {
@@ -1066,6 +1067,7 @@ update_popups(void)
// Draw the popup text. // Draw the popup text.
win_update(wp); win_update(wp);
popup_visible = TRUE;
wp->w_winrow -= top_off; wp->w_winrow -= top_off;
wp->w_wincol -= left_off; wp->w_wincol -= left_off;

View File

@@ -2897,6 +2897,12 @@ struct window_S
// computed // computed
callback_T w_close_cb; // popup close callback callback_T w_close_cb; // popup close callback
callback_T w_filter_cb; // popup filter 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) # if defined(FEAT_TIMERS)
timer_T *w_popup_timer; // timer for closing popup window timer_T *w_popup_timer; // timer for closing popup window
# endif # endif

View File

@@ -909,7 +909,7 @@ func Test_popup_position_adjust()
%bwipe! %bwipe!
endfunc endfunc
function Test_adjust_left_past_screen_width() func Test_adjust_left_past_screen_width()
" width of screen " width of screen
let X = join(map(range(&columns), {->'X'}), '') let X = join(map(range(&columns), {->'X'}), '')
@@ -973,4 +973,65 @@ function Test_adjust_left_past_screen_width()
popupclear popupclear
%bwipe! %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

View File

@@ -767,6 +767,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1453,
/**/ /**/
1452, 1452,
/**/ /**/