diff src/popupwin.c @ 29900:a6721cafbc74 v9.0.0288

patch 9.0.0288: when 'cmdheight' is zero some messages are not displayed Commit: https://github.com/vim/vim/commit/9198de3ae2bd20ac51d580c44f2b43c282c1e773 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 27 21:30:03 2022 +0100 patch 9.0.0288: when 'cmdheight' is zero some messages are not displayed Problem: When 'cmdheight' is zero some messages are not displayed. Solution: Use a popup notification window.
author Bram Moolenaar <Bram@vim.org>
date Sat, 27 Aug 2022 22:45:03 +0200
parents 89e1d67814a9
children c9ff1715f03d
line wrap: on
line diff
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -412,15 +412,20 @@ popup_handle_scrollbar_click(win_T *wp, 
 }
 
 #if defined(FEAT_TIMERS)
+/*
+ * Add a timer to "wp" with "time".
+ * If "close" is true use popup_close(), otherwise popup_hide().
+ */
     static void
-popup_add_timeout(win_T *wp, int time)
+popup_add_timeout(win_T *wp, int time, int close)
 {
     char_u	    cbbuf[50];
     char_u	    *ptr = cbbuf;
     typval_T	    tv;
 
     vim_snprintf((char *)cbbuf, sizeof(cbbuf),
-				       "(_) => popup_close(%d)", wp->w_id);
+		close ? "(_) => popup_close(%d)" : "(_) => popup_hide(%d)",
+		wp->w_id);
     if (get_lambda_tv_and_compile(&ptr, &tv, FALSE, &EVALARG_EVALUATE) == OK)
     {
 	wp->w_popup_timer = create_timer(time, 0);
@@ -669,7 +674,8 @@ popup_highlight_curline(win_T *wp)
 
 	    if (syn_name2id((char_u *)linehl) == 0)
 		linehl = "PmenuSel";
-	    sign_define_by_name(sign_name, NULL, (char_u *)linehl, NULL, NULL, NULL, NULL);
+	    sign_define_by_name(sign_name, NULL, (char_u *)linehl,
+						       NULL, NULL, NULL, NULL);
 	}
 
 	sign_place(&sign_id, (char_u *)"PopUpMenu", sign_name,
@@ -905,7 +911,7 @@ apply_general_options(win_T *wp, dict_T 
     // Add timer to close the popup after some time.
     nr = dict_get_number(dict, "time");
     if (nr > 0)
-	popup_add_timeout(wp, nr);
+	popup_add_timeout(wp, nr, TRUE);
 #endif
 
     di = dict_find(dict, (char_u *)"moved", -1);
@@ -1289,6 +1295,9 @@ popup_adjust_position(win_T *wp)
 	    if (wp->w_winrow >= Rows)
 		wp->w_winrow = Rows - 1;
 	}
+	if (wp->w_popup_pos == POPPOS_BOTTOM)
+	    // assume that each buffer line takes one screen line
+	    wp->w_winrow = MAX(Rows - wp->w_buffer->b_ml.ml_line_count - 1, 0);
 
 	if (!use_wantcol)
 	    center_hor = TRUE;
@@ -1649,6 +1658,7 @@ typedef enum
     TYPE_ATCURSOR,
     TYPE_BEVAL,
     TYPE_NOTIFICATION,
+    TYPE_MESSAGE_WIN,	// similar to TYPE_NOTIFICATION
     TYPE_DIALOG,
     TYPE_MENU,
     TYPE_PREVIEW,	// preview window
@@ -1656,6 +1666,15 @@ typedef enum
 } create_type_T;
 
 /*
+ * Return TRUE if "type" is TYPE_NOTIFICATION or TYPE_MESSAGE_WIN.
+ */
+    static int
+popup_is_notification(create_type_T type)
+{
+    return type == TYPE_NOTIFICATION || type == TYPE_MESSAGE_WIN;
+}
+
+/*
  * Make "buf" empty and set the contents to "text".
  * Used by popup_create() and popup_settext().
  */
@@ -1914,6 +1933,21 @@ popup_terminal_exists(void)
 #endif
 
 /*
+ * Set the color for a notification window.
+ */
+    static void
+popup_update_color(win_T *wp, create_type_T type)
+{
+    char    *hiname = type == TYPE_MESSAGE_WIN
+				       ? "MessageWindow" : "PopupNotification";
+    int		nr = syn_name2id((char_u *)hiname);
+
+    set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
+		(char_u *)(nr == 0 ? "WarningMsg" : hiname),
+		OPT_FREE|OPT_LOCAL, 0);
+}
+
+/*
  * popup_create({text}, {options})
  * popup_atcursor({text}, {options})
  * etc.
@@ -1928,7 +1962,6 @@ popup_create(typval_T *argvars, typval_T
     int		new_buffer;
     buf_T	*buf = NULL;
     dict_T	*d = NULL;
-    int		nr;
     int		i;
 
     if (argvars != NULL)
@@ -1975,7 +2008,7 @@ popup_create(typval_T *argvars, typval_T
     {
 	if (dict_has_key(d, "tabpage"))
 	    tabnr = (int)dict_get_number(d, "tabpage");
-	else if (type == TYPE_NOTIFICATION)
+	else if (popup_is_notification(type))
 	    tabnr = -1;  // notifications are global by default
 	else
 	    tabnr = 0;
@@ -2101,7 +2134,7 @@ popup_create(typval_T *argvars, typval_T
     wp->w_zindex = POPUPWIN_DEFAULT_ZINDEX;
     wp->w_popup_close = POPCLOSE_NONE;
 
-    if (type == TYPE_NOTIFICATION)
+    if (popup_is_notification(type))
     {
 	win_T  *twp, *nextwin;
 	int	height = buf->b_ml.ml_line_count + 3;
@@ -2140,10 +2173,7 @@ popup_create(typval_T *argvars, typval_T
 	wp->w_popup_padding[1] = 1;
 	wp->w_popup_padding[3] = 1;
 
-	nr = syn_name2id((char_u *)"PopupNotification");
-	set_string_option_direct_in_win(wp, (char_u *)"wincolor", -1,
-		(char_u *)(nr == 0 ? "WarningMsg" : "PopupNotification"),
-		OPT_FREE|OPT_LOCAL, 0);
+	popup_update_color(wp, type);
     }
 
     if (type == TYPE_DIALOG || type == TYPE_MENU)
@@ -2203,8 +2233,8 @@ popup_create(typval_T *argvars, typval_T
 	apply_options(wp, d, TRUE);
 
 #ifdef FEAT_TIMERS
-    if (type == TYPE_NOTIFICATION && wp->w_popup_timer == NULL)
-	popup_add_timeout(wp, 3000);
+    if (popup_is_notification(type) && wp->w_popup_timer == NULL)
+	popup_add_timeout(wp, 3000, type == TYPE_NOTIFICATION);
 #endif
 
     popup_adjust_position(wp);
@@ -4408,6 +4438,86 @@ popup_close_info(void)
 }
 #endif
 
+#if defined(HAS_MESSAGE_WINDOW) || defined(PROTO)
+
+// Window used for messages when 'winheight' is zero.
+static win_T *message_win = NULL;
+
+/*
+ * Get the message window.
+ * Returns NULL if something failed.
+ */
+    win_T *
+popup_get_message_win(void)
+{
+    if (message_win == NULL)
+    {
+	int i;
+
+	message_win = popup_create(NULL, NULL, TYPE_MESSAGE_WIN);
+
+	if (message_win == NULL)
+	    return NULL;
+
+	// use the full screen width
+	message_win->w_width = Columns;
+
+	// position at bottom of screen
+	message_win->w_popup_pos = POPPOS_BOTTOM;
+	message_win->w_wantcol = 1;
+	message_win->w_minwidth = 9999;
+
+	// no padding, border at the top
+	for (i = 0; i < 4; ++i)
+	    message_win->w_popup_padding[i] = 0;
+	for (i = 1; i < 4; ++i)
+	    message_win->w_popup_border[i] = 0;
+
+	if (message_win->w_popup_timer != NULL)
+	    message_win->w_popup_timer->tr_keep = TRUE;
+    }
+    return message_win;
+}
+
+/*
+ * If the message window is not visible: show it
+ * If the message window is visible: reset the timeout
+ */
+    void
+popup_show_message_win(void)
+{
+    if (message_win != NULL)
+    {
+	if ((message_win->w_popup_flags & POPF_HIDDEN) != 0)
+	{
+	    // the highlight may have changed.
+	    popup_update_color(message_win, TYPE_MESSAGE_WIN);
+	    popup_show(message_win);
+	}
+	else if (message_win->w_popup_timer != NULL)
+	    timer_start(message_win->w_popup_timer);
+    }
+}
+
+    int
+popup_message_win_visible(void)
+{
+    return message_win != NULL
+	&& (message_win->w_popup_flags & POPF_HIDDEN) == 0;
+}
+
+/*
+ * If the message window is visible: hide it.
+ */
+    void
+popup_hide_message_win(void)
+{
+    if (message_win != NULL)
+	popup_hide(message_win);
+}
+
+#endif
+
 /*
  * Close any popup for a text property associated with "win".
  * Return TRUE if a popup was closed.