# HG changeset patch # User Bram Moolenaar # Date 1665150306 -7200 # Node ID d914a3812d5b09bd4507215d380ca951d9e6ffe0 # Parent e423621787340baf33598b4126e63097012033e9 patch 9.0.0683: cannot specify a time for :echowindow Commit: https://github.com/vim/vim/commit/bdc09a18fca32715687d9911a431da69186528cc Author: Bram Moolenaar Date: Fri Oct 7 14:31:45 2022 +0100 patch 9.0.0683: cannot specify a time for :echowindow Problem: Cannot specify a time for :echowindow. Solution: A count can be used to specify the display time. Add popup_findecho(). diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -396,6 +396,7 @@ popup_create({what}, {options}) Number c popup_dialog({what}, {options}) Number create a popup window used as a dialog popup_filter_menu({id}, {key}) Number filter for a menu popup window popup_filter_yesno({id}, {key}) Number filter for a dialog popup window +popup_findecho() Number get window ID of popup for `:echowin` popup_findinfo() Number get window ID of info popup window popup_findpreview() Number get window ID of preview popup window popup_getoptions({id}) Dict get options of popup window {id} diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -3392,7 +3392,7 @@ text... when the screen is redrawn. *:echow* *:echowin* *:echowindow* -:echow[indow] {expr1} .. +:[N]echow[indow] {expr1} .. Like |:echomsg| but when the messages popup window is available the message is displayed there. This means it will show for three seconds and avoid a @@ -3400,6 +3400,9 @@ text... that, press Esc in Normal mode (when it would otherwise beep). If it disappears too soon you can use `:messages` to see the text. + When [N] is given then the window will show up for + this number of seconds. The last `:echowindow` with a + count matters, it is used once only. The message window is available when Vim was compiled with the +timer and the +popupwin features. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -347,6 +347,12 @@ popup_filter_yesno({id}, {key}) *popu See the example here: |popup_dialog-example| +popup_findecho() *popup_findecho()* + Get the |window-ID| for the popup that shows messages for the + `:echowindow` command. Return zero if there is none. + Mainly useful to hide the popup. + + popup_findinfo() *popup_findinfo()* Get the |window-ID| for the popup info window, as it used by the popup menu. See |complete-popup|. The info popup is diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1289,6 +1289,7 @@ Popup window: *popup-window-function popup_filter_yesno() block until 'y' or 'n' is pressed popup_getoptions() get current options for a popup popup_getpos() get actual position and size of a popup + popup_findecho() get window ID for popup used for `:echowindow` popup_findinfo() get window ID for popup info window popup_findpreview() get window ID for popup preview window popup_list() get list of all popup window IDs diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -6916,7 +6916,7 @@ ex_execute(exarg_T *eap) else if (eap->cmdidx == CMD_echowindow) { #ifdef HAS_MESSAGE_WINDOW - start_echowindow(); + start_echowindow(eap->addr_count > 0 ? eap->line2 : 0); #endif msg_attr(ga.ga_data, echo_attr); #ifdef HAS_MESSAGE_WINDOW diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2273,6 +2273,8 @@ static funcentry_T global_functions[] = ret_bool, PROP_FUNC(f_popup_filter_menu)}, {"popup_filter_yesno", 2, 2, 0, arg2_number_string, ret_bool, PROP_FUNC(f_popup_filter_yesno)}, + {"popup_findecho", 0, 0, 0, NULL, + ret_number, PROP_FUNC(f_popup_findecho)}, {"popup_findinfo", 0, 0, 0, NULL, ret_number, PROP_FUNC(f_popup_findinfo)}, {"popup_findpreview", 0, 0, 0, NULL, diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -552,8 +552,8 @@ EXCMD(CMD_echon, "echon", ex_echo, EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_echowindow, "echowindow", ex_execute, - EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, - ADDR_NONE), + EX_RANGE|EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, + ADDR_OTHER), EXCMD(CMD_else, "else", ex_else, EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE, ADDR_NONE), diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -32,6 +32,9 @@ static poppos_entry_T poppos_entries[] = // Window used for ":echowindow" static win_T *message_win = NULL; +// Time used for the next ":echowindow" message in msec. +static int message_win_time = 3000; + // Flag set when a message is added to the message window, timer is started // when the message window is drawn. This might be after pressing Enter at the // hit-enter prompt. @@ -4379,6 +4382,16 @@ popup_find_info_window(void) #endif void +f_popup_findecho(typval_T *argvars UNUSED, typval_T *rettv) +{ +#ifdef HAS_MESSAGE_WINDOW + rettv->vval.v_number = message_win == NULL ? 0 : message_win->w_id; +#else + rettv->vval.v_number = 0; +#endif +} + + void f_popup_findinfo(typval_T *argvars UNUSED, typval_T *rettv) { #ifdef FEAT_QUICKFIX @@ -4537,7 +4550,11 @@ may_start_message_win_timer(win_T *wp) if (wp == message_win && start_message_win_timer) { if (message_win->w_popup_timer != NULL) + { + message_win->w_popup_timer->tr_interval = message_win_time; timer_start(message_win->w_popup_timer); + message_win_time = 3000; + } start_message_win_timer = FALSE; } } @@ -4568,15 +4585,18 @@ static int ew_msg_col = 0; /* * Invoked before outputting a message for ":echowindow". + * "time_sec" is the display time, zero means using the default 3 sec. */ void -start_echowindow(void) +start_echowindow(int time_sec) { in_echowindow = TRUE; save_msg_didout = msg_didout; save_msg_col = msg_col; msg_didout = ew_msg_didout; msg_col = ew_msg_col; + if (time_sec != 0) + message_win_time = time_sec * 1000; } /* diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -57,6 +57,7 @@ int set_ref_in_popups(int copyID); int popup_is_popup(win_T *wp); win_T *popup_find_preview_window(void); win_T *popup_find_info_window(void); +void f_popup_findecho(typval_T *argvars, typval_T *rettv); void f_popup_findinfo(typval_T *argvars, typval_T *rettv); void f_popup_findpreview(typval_T *argvars, typval_T *rettv); int popup_create_preview_window(int info); @@ -67,7 +68,7 @@ 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); -void start_echowindow(void); +void start_echowindow(int time_sec); void end_echowindow(void); int popup_win_closed(win_T *win); void popup_set_title(win_T *wp); diff --git a/src/proto/vim9cmds.pro b/src/proto/vim9cmds.pro --- a/src/proto/vim9cmds.pro +++ b/src/proto/vim9cmds.pro @@ -25,7 +25,7 @@ char_u *compile_throw(char_u *arg, cctx_ char_u *compile_eval(char_u *arg, cctx_T *cctx); int get_defer_var_idx(cctx_T *cctx); char_u *compile_defer(char_u *arg_start, cctx_T *cctx); -char_u *compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx); +char_u *compile_mult_expr(char_u *arg, int cmdidx, long cmd_count, cctx_T *cctx); char_u *compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx); char_u *compile_exec(char_u *line_arg, exarg_T *eap, cctx_T *cctx); char_u *compile_script(char_u *line, cctx_T *cctx); diff --git a/src/proto/vim9instr.pro b/src/proto/vim9instr.pro --- a/src/proto/vim9instr.pro +++ b/src/proto/vim9instr.pro @@ -60,6 +60,7 @@ int generate_DEFER(cctx_T *cctx, int var int generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len); int generate_ECHO(cctx_T *cctx, int with_white, int count); int generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count); +int generate_ECHOWINDOW(cctx_T *cctx, int count, long time); int generate_SOURCE(cctx_T *cctx, int sid); int generate_PUT(cctx_T *cctx, int regname, linenr_T lnum); int generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line); diff --git a/src/testdir/dumps/Test_echowindow_8.dump b/src/testdir/dumps/Test_echowindow_8.dump --- a/src/testdir/dumps/Test_echowindow_8.dump +++ b/src/testdir/dumps/Test_echowindow_8.dump @@ -4,5 +4,5 @@ |═+0#e000002&@74 |l|a|t|e|r| |m|e|s@1|a|g|e| @61 |m|o|r|e| @70 -|:+0#0000000&|e|c|h|o|w|i|n| |'|m|o|r|e|'| @59 +|:+0#0000000&|7|e|c|h|o|w|i|n| |'|m|o|r|e|'| @58 @57|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_echowindow_9.dump b/src/testdir/dumps/Test_echowindow_9.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_echowindow_9.dump @@ -0,0 +1,8 @@ +| +8#0000001#e0e0e08|+| |[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@49|X+8#0000001#e0e0e08 +> +0#0000000#ffffff0@74 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @73 +|:+0#0000000&|c|a|l@1| |H|i|d|e|W|i|n|(|)| @59 +@57|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -511,6 +511,10 @@ func Test_echowindow() echo 'two' echo 'three' enddef + + def HideWin() + popup_hide(popup_findecho()) + enddef END call writefile(lines, 'XtestEchowindow', 'D') let buf = RunVimInTerminal('-S XtestEchowindow', #{rows: 8}) @@ -536,9 +540,12 @@ func Test_echowindow() call VerifyScreenDump(buf, 'Test_echowindow_7', {}) call term_sendkeys(buf, ":tabnew\") - call term_sendkeys(buf, ":echowin 'more'\") + call term_sendkeys(buf, ":7echowin 'more'\") call VerifyScreenDump(buf, 'Test_echowindow_8', {}) + call term_sendkeys(buf, ":call HideWin()\") + call VerifyScreenDump(buf, 'Test_echowindow_9', {}) + " clean up call StopVimInTerminal(buf) endfunc diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -2367,6 +2367,7 @@ def s:Echomsg() echoerr 'went' .. 'wrong' var local = 'window' echowin 'in' local + :5echowin 'five' enddef def Test_disassemble_echomsg() @@ -2389,6 +2390,9 @@ def Test_disassemble_echomsg() '\d\+ PUSHS "in"\_s*' .. '\d\+ LOAD $0\_s*' .. '\d\+ ECHOWINDOW 2\_s*' .. + ":5echowin 'five'\\_s*" .. + '\d\+ PUSHS "five"\_s*' .. + '\d\+ ECHOWINDOW 1 (5 sec)\_s*' .. '\d\+ RETURN void', res) enddef diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 683, +/**/ 682, /**/ 681, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -457,6 +457,12 @@ typedef struct { int defer_argcount; // number of arguments } deferins_T; +// arguments to ISN_ECHOWINDOW +typedef struct { + int ewin_count; // number of arguments + long ewin_time; // time argument (msec) +} echowin_T; + /* * Instruction */ @@ -507,6 +513,7 @@ struct isn_S { getitem_T getitem; debug_T debug; deferins_T defer; + echowin_T echowin; } isn_arg; }; diff --git a/src/vim9cmds.c b/src/vim9cmds.c --- a/src/vim9cmds.c +++ b/src/vim9cmds.c @@ -1971,10 +1971,11 @@ compile_defer(char_u *arg_start, cctx_T * compile "echomsg expr" * compile "echoerr expr" * compile "echoconsole expr" + * compile "echowindow expr" - may have cmd_count set * compile "execute expr" */ char_u * -compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) +compile_mult_expr(char_u *arg, int cmdidx, long cmd_count, cctx_T *cctx) { char_u *p = arg; char_u *prev = arg; @@ -1982,6 +1983,7 @@ compile_mult_expr(char_u *arg, int cmdid int count = 0; int start_ctx_lnum = cctx->ctx_lnum; type_T *type; + int r = OK; for (;;) { @@ -2015,23 +2017,23 @@ compile_mult_expr(char_u *arg, int cmdid cctx->ctx_lnum = start_ctx_lnum; if (cmdidx == CMD_echo || cmdidx == CMD_echon) - generate_ECHO(cctx, cmdidx == CMD_echo, count); + r = generate_ECHO(cctx, cmdidx == CMD_echo, count); else if (cmdidx == CMD_execute) - generate_MULT_EXPR(cctx, ISN_EXECUTE, count); + r = generate_MULT_EXPR(cctx, ISN_EXECUTE, count); else if (cmdidx == CMD_echomsg) - generate_MULT_EXPR(cctx, ISN_ECHOMSG, count); + r = generate_MULT_EXPR(cctx, ISN_ECHOMSG, count); #ifdef HAS_MESSAGE_WINDOW else if (cmdidx == CMD_echowindow) - generate_MULT_EXPR(cctx, ISN_ECHOWINDOW, count); + r = generate_ECHOWINDOW(cctx, count, cmd_count); #endif else if (cmdidx == CMD_echoconsole) - generate_MULT_EXPR(cctx, ISN_ECHOCONSOLE, count); + r = generate_MULT_EXPR(cctx, ISN_ECHOCONSOLE, count); else - generate_MULT_EXPR(cctx, ISN_ECHOERR, count); + r = generate_MULT_EXPR(cctx, ISN_ECHOERR, count); cctx->ctx_lnum = save_lnum; } - return p; + return r == OK ? p : NULL; } /* diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2683,6 +2683,32 @@ check_args_shadowing(ufunc_T *ufunc, cct } /* + * Get a count before a command. Can only be a number. + * Returns zero if there is no count. + * Returns -1 if there is something wrong. + */ + static long +get_cmd_count(char_u *line, exarg_T *eap) +{ + char_u *p; + + // skip over colons and white space + for (p = line; *p == ':' || VIM_ISWHITE(*p); ++p) + ; + if (!isdigit(*p)) + { + // the command must be following + if (p < eap->cmd) + { + emsg(_(e_invalid_range)); + return -1; + } + return 0; + } + return atol((char *)p); +} + +/* * Get the compilation type that should be used for "ufunc". * Keep in sync with INSTRUCTIONS(). */ @@ -3309,16 +3335,23 @@ compile_def_function( line = compile_defer(p, &cctx); break; +#ifdef HAS_MESSAGE_WINDOW + case CMD_echowindow: + { + long cmd_count = get_cmd_count(line, &ea); + if (cmd_count >= 0) + line = compile_mult_expr(p, ea.cmdidx, + cmd_count, &cctx); + } + break; +#endif case CMD_echo: case CMD_echon: case CMD_echoconsole: case CMD_echoerr: case CMD_echomsg: -#ifdef HAS_MESSAGE_WINDOW - case CMD_echowindow: -#endif case CMD_execute: - line = compile_mult_expr(p, ea.cmdidx, &cctx); + line = compile_mult_expr(p, ea.cmdidx, 0, &cctx); break; case CMD_put: diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -3269,7 +3269,7 @@ exec_instructions(ectx_T *ectx) case ISN_ECHOCONSOLE: case ISN_ECHOERR: { - int count = iptr->isn_arg.number; + int count; garray_T ga; char_u buf[NUMBUFLEN]; char_u *p; @@ -3277,6 +3277,10 @@ exec_instructions(ectx_T *ectx) int failed = FALSE; int idx; + if (iptr->isn_type == ISN_ECHOWINDOW) + count = iptr->isn_arg.echowin.ewin_count; + else + count = iptr->isn_arg.number; ga_init2(&ga, 1, 80); for (idx = 0; idx < count; ++idx) { @@ -3339,7 +3343,8 @@ exec_instructions(ectx_T *ectx) #ifdef HAS_MESSAGE_WINDOW else if (iptr->isn_type == ISN_ECHOWINDOW) { - start_echowindow(); + start_echowindow( + iptr->isn_arg.echowin.ewin_time); msg_attr(ga.ga_data, echo_attr); end_echowindow(); } @@ -6094,8 +6099,13 @@ list_instructions(char *pfx, isn_T *inst (varnumber_T)(iptr->isn_arg.number)); break; case ISN_ECHOWINDOW: - smsg("%s%4d ECHOWINDOW %lld", pfx, current, - (varnumber_T)(iptr->isn_arg.number)); + if (iptr->isn_arg.echowin.ewin_time > 0) + smsg("%s%4d ECHOWINDOW %d (%ld sec)", pfx, current, + iptr->isn_arg.echowin.ewin_count, + iptr->isn_arg.echowin.ewin_time); + else + smsg("%s%4d ECHOWINDOW %d", pfx, current, + iptr->isn_arg.echowin.ewin_count); break; case ISN_ECHOCONSOLE: smsg("%s%4d ECHOCONSOLE %lld", pfx, current, diff --git a/src/vim9instr.c b/src/vim9instr.c --- a/src/vim9instr.c +++ b/src/vim9instr.c @@ -1879,7 +1879,21 @@ generate_MULT_EXPR(cctx_T *cctx, isntype if ((isn = generate_instr_drop(cctx, isn_type, count)) == NULL) return FAIL; isn->isn_arg.number = count; + return OK; +} +/* + * Generate an ISN_ECHOWINDOW instruction + */ + int +generate_ECHOWINDOW(cctx_T *cctx, int count, long time) +{ + isn_T *isn; + + if ((isn = generate_instr_drop(cctx, ISN_ECHOWINDOW, count)) == NULL) + return FAIL; + isn->isn_arg.echowin.ewin_count = count; + isn->isn_arg.echowin.ewin_time = time; return OK; }