forked from aniani/vim
patch 8.1.1441: popup window filter not yet implemented
Problem: Popup window filter not yet implemented. Solution: Implement the popup filter.
This commit is contained in:
parent
2d247849ce
commit
bf0eff0b72
@ -1,4 +1,4 @@
|
||||
*popup.txt* For Vim version 8.1. Last change: 2019 May 31
|
||||
*popup.txt* For Vim version 8.1. Last change: 2019 Jun 01
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@ -90,11 +90,11 @@ Probably 2. is the best choice.
|
||||
|
||||
IMPLEMENTATION:
|
||||
- Code is in popupwin.c
|
||||
- Implement filter.
|
||||
Check that popup_close() works in the filter.
|
||||
- Invoke filter with character before mapping?
|
||||
- Handle screen resize in screenalloc(). (Ben Jackson, #4467)
|
||||
- Why does 'nrformats' leak from the popup window buffer???
|
||||
- Implement padding
|
||||
- Implement border
|
||||
- Handle screen resize in screenalloc().
|
||||
- Make redrawing more efficient and avoid flicker.
|
||||
Store popup info in a mask, use the mask in screen_line()
|
||||
Keep mask until next update_screen(), find differences and redraw affected
|
||||
@ -102,8 +102,8 @@ IMPLEMENTATION:
|
||||
Fix redrawing problem with completion.
|
||||
Fix redrawing problem when scrolling non-current window
|
||||
Fix redrawing the statusline on top of a popup
|
||||
- Disable commands, feedkeys(), CTRL-W, etc. in a popup window. Or whitelist
|
||||
commands that are allowed?
|
||||
- Disable commands, feedkeys(), CTRL-W, etc. in a popup window.
|
||||
Use NOT_IN_POPUP_WINDOW.
|
||||
- Figure out the size and position better.
|
||||
if wrapping splits a double-wide character
|
||||
if wrapping inserts indent
|
||||
@ -385,7 +385,6 @@ The second argument of |popup_create()| is a dictionary with options:
|
||||
{not implemented yet}
|
||||
filter a callback that can filter typed characters, see
|
||||
|popup-filter|
|
||||
{not implemented yet}
|
||||
callback a callback to be used when the popup closes, e.g. when
|
||||
using |popup_filter_menu()|, see |popup-callback|.
|
||||
{not implemented yet}
|
||||
@ -426,7 +425,6 @@ So we get:
|
||||
|
||||
POPUP FILTER *popup-filter*
|
||||
|
||||
{not implemented yet}
|
||||
A callback that gets any typed keys while a popup is displayed. The filter is
|
||||
not invoked when the popup is hidden.
|
||||
|
||||
@ -437,10 +435,23 @@ filter is also called. The filter of the popup window with the highest zindex
|
||||
is called first.
|
||||
|
||||
The filter function is called with two arguments: the ID of the popup and the
|
||||
key.
|
||||
key, e.g.: >
|
||||
func MyFilter(winid, key)
|
||||
if a:key == "\<F2>"
|
||||
" do something
|
||||
return 1
|
||||
endif
|
||||
if a:key == 'x'
|
||||
call popup_close(a:winid)
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunc
|
||||
|
||||
Currently the key is what results after any mapping. This may change...
|
||||
|
||||
Some common key actions:
|
||||
Esc close the popup
|
||||
x close the popup (see note below)
|
||||
cursor keys select another entry
|
||||
Tab accept current suggestion
|
||||
|
||||
@ -451,6 +462,11 @@ popup is col 1, row 1 (not counting the border).
|
||||
Vim provides standard filters |popup_filter_menu()| and
|
||||
|popup_filter_yesno()|.
|
||||
|
||||
Note that "x" is the normal way to close a popup. You may want to use Esc,
|
||||
but since many keys start with an Esc character, there may be a delay before
|
||||
Vim recognizes the Esc key. If you do use Esc, it is reecommended to set the
|
||||
'ttimeoutlen' option to 100 and set 'timeout' and/or 'ttimeout'.
|
||||
|
||||
|
||||
POPUP CALLBACK *popup-callback*
|
||||
|
||||
|
@ -1801,6 +1801,10 @@ vgetc(void)
|
||||
ui_remove_balloon();
|
||||
}
|
||||
#endif
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
if (popup_do_filter(c))
|
||||
c = K_IGNORE;
|
||||
#endif
|
||||
|
||||
return c;
|
||||
}
|
||||
|
20
src/misc2.c
20
src/misc2.c
@ -2731,17 +2731,31 @@ get_special_key_name(int c, int modifiers)
|
||||
trans_special(
|
||||
char_u **srcp,
|
||||
char_u *dst,
|
||||
int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
|
||||
int in_string) /* TRUE when inside a double quoted string */
|
||||
int keycode, // prefer key code, e.g. K_DEL instead of DEL
|
||||
int in_string) // TRUE when inside a double quoted string
|
||||
{
|
||||
int modifiers = 0;
|
||||
int key;
|
||||
int dlen = 0;
|
||||
|
||||
key = find_special_key(srcp, &modifiers, keycode, FALSE, in_string);
|
||||
if (key == 0)
|
||||
return 0;
|
||||
|
||||
return special_to_buf(key, modifiers, keycode, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the character sequence for "key" with "modifiers" into "dst" and return
|
||||
* the resulting length.
|
||||
* When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL.
|
||||
* The sequence is not NUL terminated.
|
||||
* This is how characters in a string are encoded.
|
||||
*/
|
||||
int
|
||||
special_to_buf(int key, int modifiers, int keycode, char_u *dst)
|
||||
{
|
||||
int dlen = 0;
|
||||
|
||||
/* Put the appropriate modifier in a string */
|
||||
if (modifiers != 0)
|
||||
{
|
||||
|
123
src/popupwin.c
123
src/popupwin.c
@ -149,25 +149,33 @@ apply_options(win_T *wp, buf_T *buf UNUSED, dict_T *dict, int atcursor)
|
||||
if (get_lambda_tv(&ptr, &tv, TRUE) == OK)
|
||||
{
|
||||
wp->w_popup_timer = create_timer(nr, 0);
|
||||
wp->w_popup_timer->tr_callback.cb_name =
|
||||
vim_strsave(partial_name(tv.vval.v_partial));
|
||||
func_ref(wp->w_popup_timer->tr_callback.cb_name);
|
||||
wp->w_popup_timer->tr_callback.cb_partial = tv.vval.v_partial;
|
||||
wp->w_popup_timer->tr_callback = get_callback(&tv);
|
||||
clear_tv(&tv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Option values resulting in setting an option.
|
||||
str = dict_get_string(dict, (char_u *)"highlight", TRUE);
|
||||
str = dict_get_string(dict, (char_u *)"highlight", FALSE);
|
||||
if (str != NULL)
|
||||
set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
|
||||
str, OPT_FREE|OPT_LOCAL, 0);
|
||||
|
||||
di = dict_find(dict, (char_u *)"wrap", -1);
|
||||
if (di != NULL)
|
||||
{
|
||||
nr = dict_get_number(dict, (char_u *)"wrap");
|
||||
wp->w_p_wrap = nr != 0;
|
||||
}
|
||||
|
||||
di = dict_find(dict, (char_u *)"filter", -1);
|
||||
if (di != NULL)
|
||||
{
|
||||
callback_T callback = get_callback(&di->di_tv);
|
||||
|
||||
if (callback.cb_name != NULL)
|
||||
set_callback(&wp->w_filter_cb, &callback);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -759,4 +767,109 @@ not_in_popup_window()
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all the POPF_HANDLED flags in global popup windows and popup windows
|
||||
* in the current tab.
|
||||
*/
|
||||
void
|
||||
popup_reset_handled()
|
||||
{
|
||||
win_T *wp;
|
||||
|
||||
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
wp->w_popup_flags &= ~POPF_HANDLED;
|
||||
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
wp->w_popup_flags &= ~POPF_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the next visible popup where POPF_HANDLED is not set.
|
||||
* Must have called popup_reset_handled() first.
|
||||
* When "lowest" is TRUE find the popup with the lowest zindex, otherwise the
|
||||
* popup with the highest zindex.
|
||||
*/
|
||||
win_T *
|
||||
find_next_popup(int lowest)
|
||||
{
|
||||
win_T *wp;
|
||||
win_T *found_wp;
|
||||
int found_zindex;
|
||||
|
||||
found_zindex = lowest ? INT_MAX : 0;
|
||||
found_wp = NULL;
|
||||
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
if ((wp->w_popup_flags & (POPF_HANDLED|POPF_HIDDEN)) == 0
|
||||
&& (lowest ? wp->w_zindex < found_zindex
|
||||
: wp->w_zindex > found_zindex))
|
||||
{
|
||||
found_zindex = wp->w_zindex;
|
||||
found_wp = wp;
|
||||
}
|
||||
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
if ((wp->w_popup_flags & (POPF_HANDLED|POPF_HIDDEN)) == 0
|
||||
&& (lowest ? wp->w_zindex < found_zindex
|
||||
: wp->w_zindex > found_zindex))
|
||||
{
|
||||
found_zindex = wp->w_zindex;
|
||||
found_wp = wp;
|
||||
}
|
||||
|
||||
if (found_wp != NULL)
|
||||
found_wp->w_popup_flags |= POPF_HANDLED;
|
||||
return found_wp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoke the filter callback for window "wp" with typed character "c".
|
||||
* Uses the global "mod_mask" for modifiers.
|
||||
* Returns the return value of the filter.
|
||||
* Careful: The filter may make "wp" invalid!
|
||||
*/
|
||||
static int
|
||||
invoke_popup_filter(win_T *wp, int c)
|
||||
{
|
||||
int res;
|
||||
typval_T rettv;
|
||||
int dummy;
|
||||
typval_T argv[3];
|
||||
char_u buf[NUMBUFLEN];
|
||||
|
||||
argv[0].v_type = VAR_NUMBER;
|
||||
argv[0].vval.v_number = (varnumber_T)wp->w_id;
|
||||
|
||||
// Convert the number to a string, so that the function can use:
|
||||
// if a:c == "\<F2>"
|
||||
buf[special_to_buf(c, mod_mask, TRUE, buf)] = NUL;
|
||||
argv[1].v_type = VAR_STRING;
|
||||
argv[1].vval.v_string = vim_strsave(buf);
|
||||
|
||||
argv[2].v_type = VAR_UNKNOWN;
|
||||
|
||||
call_callback(&wp->w_filter_cb, -1,
|
||||
&rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
|
||||
res = tv_get_number(&rettv);
|
||||
vim_free(argv[1].vval.v_string);
|
||||
clear_tv(&rettv);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when "c" was typed: invoke popup filter callbacks.
|
||||
* Returns TRUE when the character was consumed,
|
||||
*/
|
||||
int
|
||||
popup_do_filter(int c)
|
||||
{
|
||||
int res = FALSE;
|
||||
win_T *wp;
|
||||
|
||||
popup_reset_handled();
|
||||
|
||||
while (!res && (wp = find_next_popup(FALSE)) != NULL)
|
||||
if (wp->w_filter_cb.cb_name != NULL)
|
||||
res = invoke_popup_filter(wp, c);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // FEAT_TEXT_PROP
|
||||
|
@ -69,6 +69,7 @@ int simplify_key(int key, int *modifiers);
|
||||
int handle_x_keys(int key);
|
||||
char_u *get_special_key_name(int c, int modifiers);
|
||||
int trans_special(char_u **srcp, char_u *dst, int keycode, int in_string);
|
||||
int special_to_buf(int key, int modifiers, int keycode, char_u *dst);
|
||||
int find_special_key(char_u **srcp, int *modp, int keycode, int keep_x_key, int in_string);
|
||||
int extract_modifiers(int key, int *modp);
|
||||
int find_special_key_in_table(int c);
|
||||
|
@ -14,4 +14,7 @@ void f_popup_move(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_getpos(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_getoptions(typval_T *argvars, typval_T *rettv);
|
||||
int not_in_popup_window(void);
|
||||
void popup_reset_handled(void);
|
||||
win_T *find_next_popup(int lowest);
|
||||
int popup_do_filter(int c);
|
||||
/* vim: set ft=c : */
|
||||
|
45
src/screen.c
45
src/screen.c
@ -996,48 +996,19 @@ update_debug_sign(buf_T *buf, linenr_T lnum)
|
||||
update_popups(void)
|
||||
{
|
||||
win_T *wp;
|
||||
win_T *lowest_wp;
|
||||
int lowest_zindex;
|
||||
|
||||
// Reset all the VALID_POPUP flags.
|
||||
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
wp->w_popup_flags &= ~POPF_REDRAWN;
|
||||
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
wp->w_popup_flags &= ~POPF_REDRAWN;
|
||||
|
||||
// Find the window with the lowest zindex that hasn't been updated yet,
|
||||
// so that the window with a higher zindex is drawn later, thus goes on
|
||||
// top.
|
||||
// TODO: don't redraw every popup every time.
|
||||
for (;;)
|
||||
popup_reset_handled();
|
||||
while ((wp = find_next_popup(TRUE)) != NULL)
|
||||
{
|
||||
// Find the window with the lowest zindex that hasn't been updated yet,
|
||||
// so that the window with a higher zindex is drawn later, thus goes on
|
||||
// top.
|
||||
lowest_zindex = INT_MAX;
|
||||
lowest_wp = NULL;
|
||||
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
if ((wp->w_popup_flags & (POPF_REDRAWN|POPF_HIDDEN)) == 0
|
||||
&& wp->w_zindex < lowest_zindex)
|
||||
{
|
||||
lowest_zindex = wp->w_zindex;
|
||||
lowest_wp = wp;
|
||||
}
|
||||
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
|
||||
if ((wp->w_popup_flags & (POPF_REDRAWN|POPF_HIDDEN)) == 0
|
||||
&& wp->w_zindex < lowest_zindex)
|
||||
{
|
||||
lowest_zindex = wp->w_zindex;
|
||||
lowest_wp = wp;
|
||||
}
|
||||
|
||||
if (lowest_wp == NULL)
|
||||
break;
|
||||
|
||||
// Recompute the position if the text changed.
|
||||
if (lowest_wp->w_popup_last_changedtick
|
||||
!= CHANGEDTICK(lowest_wp->w_buffer))
|
||||
popup_adjust_position(lowest_wp);
|
||||
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
|
||||
popup_adjust_position(wp);
|
||||
|
||||
win_update(lowest_wp);
|
||||
lowest_wp->w_popup_flags |= POPF_REDRAWN;
|
||||
win_update(wp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -2890,6 +2890,7 @@ struct window_S
|
||||
int w_wantcol; // "col" for popup window
|
||||
varnumber_T w_popup_last_changedtick; // b:changedtick when position was
|
||||
// computed
|
||||
callback_T w_filter_cb; // popup filter callback
|
||||
# if defined(FEAT_TIMERS)
|
||||
timer_T *w_popup_timer; // timer for closing popup window
|
||||
# endif
|
||||
|
@ -473,3 +473,46 @@ func Test_popup_atcursor()
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_popup_filter()
|
||||
new
|
||||
call setline(1, 'some text')
|
||||
|
||||
func MyPopupFilter(winid, c)
|
||||
if a:c == 'e'
|
||||
let g:eaten = 'e'
|
||||
return 1
|
||||
endif
|
||||
if a:c == '0'
|
||||
let g:ignored = '0'
|
||||
return 0
|
||||
endif
|
||||
if a:c == 'x'
|
||||
call popup_close(a:winid)
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunc
|
||||
|
||||
let winid = popup_create('something', {'filter': 'MyPopupFilter'})
|
||||
redraw
|
||||
|
||||
" e is consumed by the filter
|
||||
call feedkeys('e', 'xt')
|
||||
call assert_equal('e', g:eaten)
|
||||
|
||||
" 0 is ignored by the filter
|
||||
normal $
|
||||
call assert_equal(9, getcurpos()[2])
|
||||
call feedkeys('0', 'xt')
|
||||
call assert_equal('0', g:ignored)
|
||||
call assert_equal(1, getcurpos()[2])
|
||||
|
||||
" x closes the popup
|
||||
call feedkeys('x', 'xt')
|
||||
call assert_equal('e', g:eaten)
|
||||
call assert_equal(-1, winbufnr(winid))
|
||||
|
||||
delfunc MyPopupFilter
|
||||
popupclear
|
||||
endfunc
|
||||
|
@ -767,6 +767,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1441,
|
||||
/**/
|
||||
1440,
|
||||
/**/
|
||||
|
@ -615,7 +615,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
|
||||
|
||||
// Values for w_popup_flags.
|
||||
#define POPF_HIDDEN 1 // popup is not displayed
|
||||
#define POPF_REDRAWN 2 // popup was just redrawn
|
||||
#define POPF_HANDLED 2 // popup was just redrawn or filtered
|
||||
|
||||
/*
|
||||
* Terminal highlighting attribute bits.
|
||||
|
@ -4844,6 +4844,9 @@ win_free(
|
||||
#ifdef FEAT_MENU
|
||||
remove_winbar(wp);
|
||||
#endif
|
||||
#ifdef FEAT_TEXT_PROP
|
||||
free_callback(&wp->w_filter_cb);
|
||||
#endif
|
||||
|
||||
#ifdef FEAT_SYN_HL
|
||||
vim_free(wp->w_p_cc_cols);
|
||||
|
Loading…
x
Reference in New Issue
Block a user