diff src/popupwin.c @ 17292:8a095d343c59 v8.1.1645

patch 8.1.1645: cannot use a popup window for a balloon commit https://github.com/vim/vim/commit/b3d17a20d243f65bcfe23de08b7afd948c5132c2 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 7 18:28:14 2019 +0200 patch 8.1.1645: cannot use a popup window for a balloon Problem: Cannot use a popup window for a balloon. Solution: Add popup_beval(). Add the "mousemoved" property. Add the screenpos() function.
author Bram Moolenaar <Bram@vim.org>
date Sun, 07 Jul 2019 18:30:05 +0200
parents 6a7ba68d448e
children 0dff534a0807
line wrap: on
line diff
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -168,6 +168,35 @@ set_moved_columns(win_T *wp, int flags)
 }
 
 /*
+ * Used when popup options contain "mousemoved": set default moved values.
+ */
+    static void
+set_mousemoved_values(win_T *wp)
+{
+    wp->w_popup_mouse_row = mouse_row;
+    wp->w_popup_mouse_mincol = mouse_col;
+    wp->w_popup_mouse_maxcol = mouse_col;
+}
+
+/*
+ * Used when popup options contain "moved" with "word" or "WORD".
+ */
+    static void
+set_mousemoved_columns(win_T *wp, int flags)
+{
+    char_u	*text;
+    int		col;
+
+    if (find_word_under_cursor(mouse_row, mouse_col, TRUE, flags,
+						NULL, NULL, &text, &col) == OK)
+    {
+	wp->w_popup_mouse_mincol = col;
+	wp->w_popup_mouse_maxcol = col + STRLEN(text) - 1;
+	vim_free(text);
+    }
+}
+
+/*
  * Return TRUE if "row"/"col" is on the border of the popup.
  * The values are relative to the top-left corner.
  */
@@ -336,6 +365,53 @@ apply_move_options(win_T *wp, dict_T *d)
 }
 
     static void
+handle_moved_argument(win_T *wp, dictitem_T *di, int mousemoved)
+{
+    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, "expr") == 0)
+	    flags = FIND_IDENT | FIND_STRING | FIND_EVAL;
+	else if (STRCMP(s, "any") != 0)
+	    semsg(_(e_invarg2), s);
+	if (flags != 0)
+	{
+	    if (mousemoved)
+		set_mousemoved_columns(wp, flags);
+	    else
+		set_moved_columns(wp, flags);
+	}
+    }
+    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;
+	int	mincol = tv_get_number(&l->lv_first->li_tv);
+	int	maxcol = tv_get_number(&l->lv_first->li_next->li_tv);
+
+	if (mousemoved)
+	{
+	    wp->w_popup_mouse_mincol = mincol;
+	    wp->w_popup_mouse_maxcol = maxcol;
+	}
+	else
+	{
+	    wp->w_popup_mincol = mincol;
+	    wp->w_popup_maxcol = maxcol;
+	}
+    }
+    else
+	semsg(_(e_invarg2), tv_get_string(&di->di_tv));
+}
+
+    static void
 check_highlight(dict_T *dict, char *name, char_u **pval)
 {
     dictitem_T  *di;
@@ -541,31 +617,14 @@ apply_general_options(win_T *wp, dict_T 
     if (di != NULL)
     {
 	set_moved_values(wp);
-	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;
+	handle_moved_argument(wp, di, FALSE);
+    }
 
-	    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)
-		set_moved_columns(wp, flags);
-	}
-	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));
+    di = dict_find(dict, (char_u *)"mousemoved", -1);
+    if (di != NULL)
+    {
+	set_mousemoved_values(wp);
+	handle_moved_argument(wp, di, TRUE);
     }
 
     di = dict_find(dict, (char_u *)"filter", -1);
@@ -956,6 +1015,7 @@ typedef enum
 {
     TYPE_NORMAL,
     TYPE_ATCURSOR,
+    TYPE_BEVAL,
     TYPE_NOTIFICATION,
     TYPE_DIALOG,
     TYPE_MENU
@@ -1137,17 +1197,33 @@ popup_create(typval_T *argvars, typval_T
     {
 	wp->w_popup_pos = POPPOS_BOTLEFT;
 	setcursor_mayforce(TRUE);
-	wp->w_wantline = screen_screenrow();
+	wp->w_wantline = curwin->w_winrow + curwin->w_wrow;
 	if (wp->w_wantline == 0)  // cursor in first line
 	{
 	    wp->w_wantline = 2;
 	    wp->w_popup_pos = POPPOS_TOPLEFT;
 	}
-	wp->w_wantcol = screen_screencol() + 1;
+	wp->w_wantcol = curwin->w_wincol + curwin->w_wcol + 1;
 	set_moved_values(wp);
 	set_moved_columns(wp, FIND_STRING);
     }
 
+    if (type == TYPE_BEVAL)
+    {
+	wp->w_popup_pos = POPPOS_BOTLEFT;
+
+	// by default use the mouse position
+	wp->w_wantline = mouse_row;
+	if (wp->w_wantline <= 0)  // mouse on first line
+	{
+	    wp->w_wantline = 2;
+	    wp->w_popup_pos = POPPOS_TOPLEFT;
+	}
+	wp->w_wantcol = mouse_col + 1;
+	set_mousemoved_values(wp);
+	set_mousemoved_columns(wp, FIND_IDENT + FIND_STRING + FIND_EVAL);
+    }
+
     // set default values
     wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
     wp->w_popup_close = POPCLOSE_NONE;
@@ -1276,6 +1352,15 @@ f_popup_atcursor(typval_T *argvars, typv
 }
 
 /*
+ * popup_beval({text}, {options})
+ */
+    void
+f_popup_beval(typval_T *argvars, typval_T *rettv)
+{
+    popup_create(argvars, rettv, TYPE_BEVAL);
+}
+
+/*
  * Invoke the close callback for window "wp" with value "result".
  * Careful: The callback may make "wp" invalid!
  */
@@ -1334,6 +1419,48 @@ popup_close_for_mouse_click(win_T *wp)
     popup_close_and_callback(wp, &res);
 }
 
+    static void
+check_mouse_moved(win_T *wp, win_T *mouse_wp)
+{
+    // Close the popup when all if these are true:
+    // - the mouse is not on this popup
+    // - "mousemoved" was used
+    // - the mouse is no longer on the same screen row or the mouse column is
+    //   outside of the relevant text
+    if (wp != mouse_wp
+	    && wp->w_popup_mouse_row != 0
+	    && (wp->w_popup_mouse_row != mouse_row
+		|| mouse_col < wp->w_popup_mouse_mincol
+		|| mouse_col > wp->w_popup_mouse_maxcol))
+    {
+	typval_T res;
+
+	res.v_type = VAR_NUMBER;
+	res.vval.v_number = -2;
+	popup_close_and_callback(wp, &res);
+    }
+}
+
+/*
+ * Called when the mouse moved: may close a popup with "mousemoved".
+ */
+    void
+popup_handle_mouse_moved(void)
+{
+    win_T   *wp;
+    win_T   *mouse_wp;
+    int	    row = mouse_row;
+    int	    col = mouse_col;
+
+    // find the window where the mouse is in
+    mouse_wp = mouse_find_win(&row, &col, FIND_POPUP);
+
+    for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+	check_mouse_moved(wp, mouse_wp);
+    for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
+	check_mouse_moved(wp, mouse_wp);
+}
+
 /*
  * In a filter: check if the typed key is a mouse event that is used for
  * dragging the popup.
@@ -1821,7 +1948,7 @@ get_borderchars(dict_T *dict, win_T *wp)
 }
 
 /*
- * For popup_getoptions(): add a "moved" entry to "dict".
+ * For popup_getoptions(): add a "moved" and "mousemoved" entry to "dict".
  */
     static void
 get_moved_list(dict_T *dict, win_T *wp)
@@ -1832,9 +1959,18 @@ get_moved_list(dict_T *dict, win_T *wp)
     if (list != NULL)
     {
 	dict_add_list(dict, "moved", list);
+	list_append_number(list, wp->w_popup_lnum);
 	list_append_number(list, wp->w_popup_mincol);
 	list_append_number(list, wp->w_popup_maxcol);
     }
+    list = list_alloc();
+    if (list != NULL)
+    {
+	dict_add_list(dict, "mousemoved", list);
+	list_append_number(list, wp->w_popup_mouse_row);
+	list_append_number(list, wp->w_popup_mouse_mincol);
+	list_append_number(list, wp->w_popup_mouse_maxcol);
+    }
 }
 
 /*