]> granicus.if.org Git - vim/commitdiff
patch 9.0.0288: when 'cmdheight' is zero some messages are not displayed v9.0.0288
authorBram Moolenaar <Bram@vim.org>
Sat, 27 Aug 2022 20:30:03 +0000 (21:30 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 27 Aug 2022 20:30:03 +0000 (21:30 +0100)
Problem:    When 'cmdheight' is zero some messages are not displayed.
Solution:   Use a popup notification window.

12 files changed:
runtime/doc/options.txt
src/feature.h
src/message.c
src/popupwin.c
src/proto/message.pro
src/proto/popupwin.pro
src/proto/time.pro
src/screen.c
src/structs.h
src/testdir/test_messages.vim
src/time.c
src/version.c

index 116bb2a8758e85a267e214db11f05103dfa95135..1aa5c2cd900fb6603588af033d7b0a1e00efe7cd 100644 (file)
@@ -1789,9 +1789,11 @@ A jump table for the options with a short description can be found at |Q_op|.
        page can have a different value.
 
        When 'cmdheight' is zero, there is no command-line unless it is being
-       used.  Some informative messages will not be displayed, any other
-       messages will cause the |hit-enter| prompt.  Expect some other
-       unexpected behavior too.
+       used.  Informative messages will be displayed in a popup notification
+       window at the bottom if the window, using the MessageWindow highlight
+       group {only if compiled with the +popupwin and +timers features},
+       otherwise they will not be displayed.  Other messages will cause the
+       |hit-enter| prompt.  Expect some other unexpected behavior too.
 
                                                *'cmdwinheight'* *'cwh'*
 'cmdwinheight' 'cwh'   number  (default 7)
index f1a7af8dffcc0919361e7c6f745e0c10651904bf..22b0c50cbcef8223309e43a6f010b754b6624392 100644 (file)
 # define FEAT_PROP_POPUP
 #endif
 
+/*
+ * +message_window     use a popup for messages when 'cmdheight' is zero
+ */
+#if defined(FEAT_PROP_POPUP) && defined(FEAT_TIMERS)
+# define HAS_MESSAGE_WINDOW
+#endif
+
 #if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME)
 // Can limit syntax highlight time to 'redrawtime'.
 # define SYN_TIME_LIMIT 1
index 46cf1e02722ddba40f2f76c62a6690e55fb284de..00ad2c7d307c6b795c53aa633aee30a891f0d919 100644 (file)
@@ -954,8 +954,8 @@ msg_may_trunc(int force, char_u *s)
     int                n;
     int                room;
 
-    // If something unexpected happened "room" may be negative, check for that
-    // just in case.
+    // If 'cmdheight' is zero or something unexpected happened "room" may be
+    // negative.
     room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
     if (room > 0 && (force || (shortmess(SHM_TRUNC) && !exmode_active))
            && (n = (int)STRLEN(s) - room) > 0 && p_ch > 0)
@@ -1420,6 +1420,21 @@ set_keep_msg_from_hist(void)
 }
 #endif
 
+/*
+ * Return TRUE when the message popup window should be used.
+ */
+    int
+use_message_window(void)
+{
+#ifdef HAS_MESSAGE_WINDOW
+    // TRUE if there is no command line showing ('cmdheight' is zero and not
+    // already editing or showing a message) use a popup window for messages.
+    return p_ch == 0 && cmdline_row >= Rows;
+#else
+    return FALSE;
+#endif
+}
+
 /*
  * Prepare for outputting characters in the command line.
  */
@@ -1444,7 +1459,20 @@ msg_start(void)
     }
 #endif
 
-    if (!msg_scroll && full_screen)    // overwrite last message
+    if (use_message_window())
+    {
+       if (popup_message_win_visible() && msg_col > 0)
+       {
+           win_T *wp = popup_get_message_win();
+
+           curbuf = wp->w_buffer;
+           ml_append(wp->w_buffer->b_ml.ml_line_count,
+                                             (char_u *)"", (colnr_T)0, FALSE);
+           curbuf = curwin->w_buffer;
+       }
+       msg_col = 0;
+    }
+    else if (!msg_scroll && full_screen)       // overwrite last message
     {
        msg_row = cmdline_row;
        msg_col =
@@ -2195,6 +2223,46 @@ msg_puts_attr_len(char *str, int maxlen, int attr)
     need_fileinfo = FALSE;
 }
 
+// values for "where"
+#define PUT_APPEND 0           // append to "lnum"
+#define PUT_TRUNC 1            // replace "lnum"
+#define PUT_BELOW 2            // add below "lnum"
+                               //
+#ifdef HAS_MESSAGE_WINDOW
+
+/*
+ * Put text "t_s" until "s" in the message window.
+ * "where" specifies where to put the text.
+ */
+    static void
+put_msg_win(win_T *wp, int where, char_u *t_s, char_u *end, linenr_T lnum)
+{
+    int            c = *end;
+
+    *end = NUL;
+    if (where == PUT_BELOW)
+       ml_append_buf(wp->w_buffer, lnum, t_s, (colnr_T)0, FALSE);
+    else
+    {
+       char_u *newp;
+
+       curbuf = wp->w_buffer;
+       if (where == PUT_APPEND)
+           newp = concat_str(ml_get(lnum), t_s);
+       else
+           newp = vim_strnsave(t_s, end - t_s);
+       ml_replace(lnum, newp, FALSE);
+       curbuf = curwin->w_buffer;
+    }
+    redraw_win_later(wp, UPD_NOT_VALID);
+
+    // set msg_col so that a newline is written if needed
+    msg_col = STRLEN(t_s);
+
+    *end = c;
+}
+#endif
+
 /*
  * The display part of msg_puts_attr_len().
  * May be called recursively to display scroll-back text.
@@ -2215,6 +2283,43 @@ msg_puts_display(
     int                sb_col = msg_col;
     int                wrap;
     int                did_last_char;
+    int                where = PUT_APPEND;
+#ifdef HAS_MESSAGE_WINDOW
+    win_T      *msg_win = NULL;
+    linenr_T    lnum = 1;
+
+    if (use_message_window())
+    {
+       msg_win = popup_get_message_win();
+
+       if (msg_win != NULL)
+       {
+           if (!popup_message_win_visible())
+           {
+               if (*str == NL)
+               {
+                   // When not showing the message window and the output
+                   // starts with a NL show the message normally.
+                   msg_win = NULL;
+               }
+               else
+               {
+                   // currently hidden, make it empty
+                   curbuf = msg_win->w_buffer;
+                   while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
+                       ml_delete(1);
+                   curbuf = curwin->w_buffer;
+               }
+           }
+           else
+           {
+               lnum = msg_win->w_buffer->b_ml.ml_line_count;
+               if (msg_col == 0)
+                   where = PUT_TRUNC;
+           }
+       }
+    }
+#endif
 
     did_wait_return = FALSE;
     while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL)
@@ -2244,15 +2349,29 @@ msg_puts_display(
             * ourselves).
             */
            if (t_col > 0)
+           {
                // output postponed text
-               t_puts(&t_col, t_s, s, attr);
+#ifdef HAS_MESSAGE_WINDOW
+               if (msg_win != NULL)
+               {
+                   put_msg_win(msg_win, where, t_s, s, lnum);
+                   t_col = 0;
+                   where = PUT_BELOW;
+               }
+               else
+#endif
+                   t_puts(&t_col, t_s, s, attr);
+           }
 
            // When no more prompt and no more room, truncate here
            if (msg_no_more && lines_left == 0)
                break;
 
-           // Scroll the screen up one line.
-           msg_scroll_up();
+#ifdef HAS_MESSAGE_WINDOW
+           if (msg_win == NULL)
+#endif
+               // Scroll the screen up one line.
+               msg_scroll_up();
 
            msg_row = Rows - 2;
            if (msg_col >= Columns)     // can happen after screen resize
@@ -2285,18 +2404,25 @@ msg_puts_display(
                // store text for scrolling back
                store_sb_text(&sb_str, s, attr, &sb_col, TRUE);
 
-           inc_msg_scrolled();
-           need_wait_return = TRUE; // may need wait_return in main()
-           redraw_cmdline = TRUE;
-           if (cmdline_row > 0 && !exmode_active)
-               --cmdline_row;
-
-           /*
-            * If screen is completely filled and 'more' is set then wait
-            * for a character.
-            */
-           if (lines_left > 0)
-               --lines_left;
+#ifdef HAS_MESSAGE_WINDOW
+           if (msg_win == NULL)
+           {
+#endif
+               inc_msg_scrolled();
+               need_wait_return = TRUE; // may need wait_return in main()
+               redraw_cmdline = TRUE;
+               if (cmdline_row > 0 && !exmode_active)
+                   --cmdline_row;
+
+               /*
+                * If screen is completely filled and 'more' is set then wait
+                * for a character.
+                */
+               if (lines_left > 0)
+                   --lines_left;
+#ifdef HAS_MESSAGE_WINDOW
+           }
+#endif
            if (p_more && lines_left == 0 && State != MODE_HITRETURN
                                            && !msg_no_more && !exmode_active)
            {
@@ -2322,8 +2448,19 @@ msg_puts_display(
                                            && msg_col + t_col >= Columns - 1);
        if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
                                                 || *s == '\t' || *s == BELL))
+       {
            // output any postponed text
-           t_puts(&t_col, t_s, s, attr);
+#ifdef HAS_MESSAGE_WINDOW
+           if (msg_win != NULL)
+           {
+               put_msg_win(msg_win, where, t_s, s, lnum);
+               t_col = 0;
+               where = PUT_BELOW;
+           }
+           else
+#endif
+               t_puts(&t_col, t_s, s, attr);
+       }
 
        if (wrap && p_more && !recurse)
            // store text for scrolling back
@@ -2331,7 +2468,20 @@ msg_puts_display(
 
        if (*s == '\n')             // go to next line
        {
-           msg_didout = FALSE;     // remember that line is empty
+#ifdef HAS_MESSAGE_WINDOW
+           if (msg_win != NULL)
+           {
+               // Ignore a NL when the buffer is empty, it is used to scroll
+               // up the text.
+               if ((msg_win->w_buffer->b_ml.ml_flags & ML_EMPTY) == 0)
+               {
+                   put_msg_win(msg_win, PUT_BELOW, t_s, t_s, lnum);
+                   ++lnum;
+               }
+           }
+           else
+#endif
+               msg_didout = FALSE;         // remember that line is empty
 #ifdef FEAT_RIGHTLEFT
            if (cmdmsg_rl)
                msg_col = Columns - 1;
@@ -2344,6 +2494,7 @@ msg_puts_display(
        else if (*s == '\r')        // go to column 0
        {
            msg_col = 0;
+           where = PUT_TRUNC;
        }
        else if (*s == '\b')        // go to previous char
        {
@@ -2352,9 +2503,14 @@ msg_puts_display(
        }
        else if (*s == TAB)         // translate Tab into spaces
        {
-           do
-               msg_screen_putchar(' ', attr);
-           while (msg_col & 7);
+#ifdef HAS_MESSAGE_WINDOW
+           if (msg_win != NULL)
+               msg_col = (msg_col + 7) % 8;
+           else
+#endif
+               do
+                   msg_screen_putchar(' ', attr);
+               while (msg_col & 7);
        }
        else if (*s == BELL)            // beep (from ":sh")
            vim_beep(BO_SH);
@@ -2403,7 +2559,19 @@ msg_puts_display(
 
     // output any postponed text
     if (t_col > 0)
-       t_puts(&t_col, t_s, s, attr);
+    {
+#ifdef HAS_MESSAGE_WINDOW
+       if (msg_win != NULL)
+           put_msg_win(msg_win, where, t_s, s, lnum);
+       else
+#endif
+           t_puts(&t_col, t_s, s, attr);
+    }
+
+#ifdef HAS_MESSAGE_WINDOW
+    if (msg_win != NULL)
+       popup_show_message_win();
+#endif
     if (p_more && !recurse)
        store_sb_text(&sb_str, s, attr, &sb_col, FALSE);
 
@@ -2431,6 +2599,10 @@ message_filtered(char_u *msg)
     static void
 msg_scroll_up(void)
 {
+#ifdef HAS_MESSAGE_WINDOW
+    if (use_message_window())
+       return;
+#endif
 #ifdef FEAT_GUI
     // Remove the cursor before scrolling, ScreenLines[] is going
     // to become invalid.
index 4752dbffd0e2fd11d5ef92434cf95868c7f7acba..68ec64a2dfd01b20a87a4ebf41210bfdf7af2577 100644 (file)
@@ -412,15 +412,20 @@ popup_handle_scrollbar_click(win_T *wp, int row, int col)
 }
 
 #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 *dict)
     // 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,12 +1658,22 @@ typedef enum
     TYPE_ATCURSOR,
     TYPE_BEVAL,
     TYPE_NOTIFICATION,
+    TYPE_MESSAGE_WIN,  // similar to TYPE_NOTIFICATION
     TYPE_DIALOG,
     TYPE_MENU,
     TYPE_PREVIEW,      // preview window
     TYPE_INFO          // popup menu info
 } 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().
@@ -1913,6 +1932,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})
@@ -1928,7 +1962,6 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
     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 *rettv, create_type_T type)
     {
        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 *rettv, create_type_T type)
     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 *rettv, create_type_T type)
        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 *rettv, create_type_T type)
        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.
index 3f8a8fe2e39eeaab93a9fa9b62fa2cf0439229b8..bea30160dc7c234dd4ccd52a3670820d288a298c 100644 (file)
@@ -23,6 +23,7 @@ void msg_end_prompt(void);
 void wait_return(int redraw);
 void set_keep_msg(char_u *s, int attr);
 void set_keep_msg_from_hist(void);
+int use_message_window(void);
 void msg_start(void);
 void msg_starthere(void);
 void msg_putchar(int c);
index 2bdf4f529eaffaa27a7a593d589903905660b43d..ef769413c4f97b4277fbc7f17d23bf2498e8c8d8 100644 (file)
@@ -62,6 +62,10 @@ int popup_create_preview_window(int info);
 void popup_close_preview(void);
 void popup_hide_info(void);
 void popup_close_info(void);
+win_T *popup_get_message_win(void);
+void popup_show_message_win(void);
+int popup_message_win_visible(void);
+void popup_hide_message_win(void);
 int popup_win_closed(win_T *win);
 void popup_set_title(win_T *wp);
 void popup_update_preview_title(void);
index 54ed4ba7bfc5a505caaae357511349d46d2183d6..affdb7a6d55938e2c8bef772966ac3ea5adf9c58 100644 (file)
@@ -9,6 +9,7 @@ void f_strftime(typval_T *argvars, typval_T *rettv);
 void f_strptime(typval_T *argvars, typval_T *rettv);
 long proftime_time_left(proftime_T *due, proftime_T *now);
 timer_T *create_timer(long msec, int repeat);
+void timer_start(timer_T *timer);
 long check_due_timer(void);
 void stop_timer(timer_T *timer);
 int set_ref_in_timer(int copyID);
index 866e3e481a3eee75cac6f77400d2cdd9faa8578b..a1741ca5f203b164efbeb8b66355fce4d8a10115 100644 (file)
@@ -4211,10 +4211,10 @@ showmode(void)
     int                nwr_save;
     int                sub_attr;
 
-    do_mode = ((p_smd && msg_silent == 0)
+    do_mode = p_smd && msg_silent == 0 && p_ch > 0
            && ((State & MODE_INSERT)
                || restart_edit != NUL
-               || VIsual_active));
+               || VIsual_active);
     if (do_mode || reg_recording != 0)
     {
        if (skip_showmode())
index fc44d23a64a94bdc9ff12103238e4679e34b9b68..091b886b2f6c2e4ba9e98f9f81d790614261ca3c 100644 (file)
@@ -2569,6 +2569,7 @@ struct timer_S
     proftime_T tr_due;             // when the callback is to be invoked
     char       tr_firing;          // when TRUE callback is being called
     char       tr_paused;          // when TRUE callback is not invoked
+    char       tr_keep;            // when TRUE keep timer after it fired
     int                tr_repeat;          // number of times to repeat, -1 forever
     long       tr_interval;        // msec
     callback_T tr_callback;
@@ -2605,6 +2606,7 @@ typedef enum {
     POPPOS_BOTRIGHT,
     POPPOS_TOPRIGHT,
     POPPOS_CENTER,
+    POPPOS_BOTTOM,     // bottom of popup at bottom of screen
     POPPOS_NONE
 } poppos_T;
 
index 3c3712ea0c05f0d09e33f7ae5fa931e576afc491..9c731ca23d78610e7d224fc38935079a92f34604 100644 (file)
@@ -392,18 +392,31 @@ func Test_cmdheight_zero()
   set cmdheight=0
   set showcmd
   redraw!
+  let using_popupwin = has('timers') && has('popupwin')
 
   echo 'test echo'
-  call assert_equal(116, screenchar(&lines, 1))
+  if using_popupwin
+    redraw
+    call assert_equal('test echo', Screenline(&lines))
+  else
+    call assert_equal(116, screenchar(&lines, 1))
+  endif
   redraw!
 
   echomsg 'test echomsg'
-  call assert_equal(116, screenchar(&lines, 1))
+  if using_popupwin
+    redraw
+    call assert_equal('test echomsg', Screenline(&lines))
+  else
+    call assert_equal(116, screenchar(&lines, 1))
+  endif
   redraw!
 
-  call feedkeys(":ls\<CR>", "xt")
-  call assert_equal(':ls', Screenline(&lines - 1))
-  redraw!
+  if !using_popupwin
+    call feedkeys(":ls\<CR>", "xt")
+    call assert_equal(':ls', Screenline(&lines))
+    redraw!
+  endif
 
   let char = getchar(0)
   call assert_match(char, 0)
@@ -420,6 +433,9 @@ func Test_cmdheight_zero()
   call assert_equal('otherstring', getline(1))
 
   call feedkeys("g\<C-g>", "xt")
+  if using_popupwin
+    redraw
+  endif
   call assert_match(
         \ 'Col 1 of 11; Line 1 of 1; Word 1 of 1',
         \ Screenline(&lines))
index dc8594a2cd185e48375654586419549f0329523d..c28e7a97b7d66a1de9a7a9895605eeb20cf4deb3 100644 (file)
@@ -464,10 +464,20 @@ create_timer(long msec, int repeat)
        timer->tr_repeat = repeat - 1;
     timer->tr_interval = msec;
 
-    profile_setlimit(msec, &timer->tr_due);
+    timer_start(timer);
     return timer;
 }
 
+/*
+ * (Re)start a timer.
+ */
+    void
+timer_start(timer_T *timer)
+{
+    profile_setlimit(timer->tr_interval, &timer->tr_due);
+    timer->tr_paused = FALSE;
+}
+
 /*
  * Invoke the callback of "timer".
  */
@@ -603,8 +613,13 @@ check_due_timer(void)
            else
            {
                this_due = -1;
-               remove_timer(timer);
-               free_timer(timer);
+               if (timer->tr_keep)
+                   timer->tr_paused = TRUE;
+               else
+               {
+                   remove_timer(timer);
+                   free_timer(timer);
+               }
            }
        }
        if (this_due > 0 && (next_due == -1 || next_due > this_due))
@@ -826,6 +841,7 @@ f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
     else
     {
        int     paused = (int)tv_get_bool(&argvars[1]);
+
        timer = find_timer((int)tv_get_number(&argvars[0]));
        if (timer != NULL)
            timer->tr_paused = paused;
index bfa29efda0559e42cc70b517844a6c3cb2528ee9..b517fe7476a5b3dada27a2fe4de22dfa2909ac6f 100644 (file)
@@ -707,6 +707,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    288,
 /**/
     287,
 /**/