diff src/popupwin.c @ 16880:998603a243d7 v8.1.1441

patch 8.1.1441: popup window filter not yet implemented commit https://github.com/vim/vim/commit/bf0eff0b724ebf4951f7ca82e6c648451f9f0c01 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jun 1 17:13:36 2019 +0200 patch 8.1.1441: popup window filter not yet implemented Problem: Popup window filter not yet implemented. Solution: Implement the popup filter.
author Bram Moolenaar <Bram@vim.org>
date Sat, 01 Jun 2019 17:15:06 +0200
parents da5f5836e90c
children 59e4148c0c73
line wrap: on
line diff
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -149,25 +149,33 @@ apply_options(win_T *wp, buf_T *buf UNUS
 	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