# HG changeset patch # User Bram Moolenaar # Date 1671111005 -3600 # Node ID bb797331e21b833b1d5674a14224a27702abf4fa # Parent 38d3b3da981b990cab34e76a2092139964689af2 patch 9.0.1061: cannot display 'showcmd' somewhere else Commit: https://github.com/vim/vim/commit/ba936f6f4e85cc1408bc3967f9fd7665d948909b Author: Luuk van Baal Date: Thu Dec 15 13:15:39 2022 +0000 patch 9.0.1061: cannot display 'showcmd' somewhere else Problem: Cannot display 'showcmd' somewhere else. Solution: Add the 'showcmdloc' option. (Luuk van Baal, closes https://github.com/vim/vim/issues/11684) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -7220,9 +7220,25 @@ A jump table for the options with a shor - When selecting more than one line, the number of lines. - When selecting a block, the size in screen characters: {lines}x{columns}. + This information can be displayed in an alternative location using the + 'showcmdloc' option. NOTE: This option is set to the Vi default value when 'compatible' is set and to the Vim default value when 'compatible' is reset. + *'showcmdloc'* *'sloc'* +'showcmdloc' 'sloc' string (default "last") + This option can be used to display the (partially) entered command in + another location. Possible values are: + last Last line of the screen (default). + statusline Status line of the current window. + tabline First line of the screen if 'showtabine' is enabled. + Setting this option to "statusline" or "tabline" means that these will + be redrawn whenever the command changes, which can be on every key + pressed. + The %S 'statusline' item can be used in 'statusline' or 'tabline' to + place the text. Without a custom 'statusline' or 'tabline' it will be + displayed in a convenient location. + *'showfulltag'* *'sft'* *'noshowfulltag'* *'nosft'* 'showfulltag' 'sft' boolean (default off) global @@ -7720,6 +7736,7 @@ A jump table for the options with a shor P S Percentage through file of displayed window. This is like the percentage described for 'ruler'. Always 3 in length, unless translated. + S S 'showcmd' content, see 'showcmdloc'. a S Argument list status as in default title. ({current} of {max}) Empty if the argument file count is zero or one. { NF Evaluate expression between '%{' and '}' and substitute result. diff --git a/src/buffer.c b/src/buffer.c --- a/src/buffer.c +++ b/src/buffer.c @@ -4775,6 +4775,11 @@ build_stl_str_hl( get_rel_pos(wp, str, TMPLEN); break; + case STL_SHOWCMD: + if (p_sc && STRCMP(opt_name, p_sloc) == 0) + str = showcmd_buf; + break; + case STL_ARGLISTSTAT: fillable = FALSE; buf_tmp[0] = 0; diff --git a/src/drawscreen.c b/src/drawscreen.c --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -73,8 +73,6 @@ static void redraw_custom_statusline(win static int did_update_one_window; #endif -static void win_redr_status(win_T *wp, int ignore_pum); - /* * Based on the current value of curwin->w_topline, transfer a screenfull * of stuff from Filemem to ScreenLines[], and update curwin->w_botline. @@ -423,7 +421,7 @@ statusline_row(win_T *wp) * If "ignore_pum" is TRUE, also redraw statusline when the popup menu is * displayed. */ - static void + void win_redr_status(win_T *wp, int ignore_pum UNUSED) { int row; @@ -548,6 +546,16 @@ win_redr_status(win_T *wp, int ignore_pu - 1 + wp->w_wincol), attr); win_redr_ruler(wp, TRUE, ignore_pum); + + // Draw the 'showcmd' information if 'showcmdloc' == "statusline". + if (p_sc && *p_sloc == 's') + { + int width = MIN(10, this_ru_col - len - 2); + + if (width > 0) + screen_puts_len(showcmd_buf, width, row, + wp->w_wincol + this_ru_col - width - 1, attr); + } } /* diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -2038,3 +2038,7 @@ EXTERN int skip_win_fix_cursor INIT(= FA EXTERN int skip_win_fix_scroll INIT(= FALSE); // Skip update_topline() call while executing win_fix_scroll(). EXTERN int skip_update_topline INIT(= FALSE); + +// 'showcmd' buffer shared between normal.c and statusline.c +#define SHOWCMD_BUFLEN (SHOWCMD_COLS + 1 + 30) +EXTERN char_u showcmd_buf[SHOWCMD_BUFLEN]; diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -1574,8 +1574,6 @@ may_clear_cmdline(void) * Routines for displaying a partly typed command */ -#define SHOWCMD_BUFLEN (SHOWCMD_COLS + 1 + 30) -static char_u showcmd_buf[SHOWCMD_BUFLEN]; static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() static int showcmd_is_clear = TRUE; static int showcmd_visual = FALSE; @@ -1798,22 +1796,25 @@ pop_showcmd(void) static void display_showcmd(void) { - int len; - + int len = (int)STRLEN(showcmd_buf); + + showcmd_is_clear = (len == 0); cursor_off(); - len = (int)STRLEN(showcmd_buf); - if (len == 0) - showcmd_is_clear = TRUE; - else - { - screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0); - showcmd_is_clear = FALSE; - } - - // clear the rest of an old message by outputting up to SHOWCMD_COLS - // spaces - screen_puts((char_u *)" " + len, (int)Rows - 1, sc_col + len, 0); + if (*p_sloc == 's') + win_redr_status(curwin, FALSE); + else if (*p_sloc == 't') + draw_tabline(); + else // 'showcmdloc' is "last" or empty + { + if (!showcmd_is_clear) + screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0); + + // clear the rest of an old message by outputting up to SHOWCMD_COLS + // spaces + screen_puts((char_u *)" " + len, + (int)Rows - 1, sc_col + len, 0); + } setcursor(); // put cursor back where it belongs } diff --git a/src/option.h b/src/option.h --- a/src/option.h +++ b/src/option.h @@ -343,6 +343,7 @@ typedef enum { #define STL_ALTPERCENT 'P' // percentage as TOP BOT ALL or NN% #define STL_ARGLISTSTAT 'a' // argument list status as (x of y) #define STL_PAGENUM 'N' // page number (when printing) +#define STL_SHOWCMD 'S' // 'showcmd' buffer #define STL_VIM_EXPR '{' // start of expression to substitute #define STL_MIDDLEMARK '=' // separation between left and right #define STL_TRUNCMARK '<' // truncation mark if line is too long @@ -350,7 +351,7 @@ typedef enum { #define STL_HIGHLIGHT '#' // highlight name #define STL_TABPAGENR 'T' // tab page label nr #define STL_TABCLOSENR 'X' // tab page close nr -#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaN{#") +#define STL_ALL ((char_u *) "fFtcvVlLknoObBrRhHmYyWwMqpPaNS{#") // flags used for parsed 'wildmode' #define WIM_FULL 0x01 @@ -892,6 +893,7 @@ EXTERN int p_sn; // 'shortname' EXTERN char_u *p_sbr; // 'showbreak' #endif EXTERN int p_sc; // 'showcmd' +EXTERN char_u *p_sloc; // 'showcmdloc' EXTERN int p_sft; // 'showfulltag' EXTERN int p_sm; // 'showmatch' EXTERN int p_smd; // 'showmode' diff --git a/src/optiondefs.h b/src/optiondefs.h --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -2240,6 +2240,9 @@ static struct vimoption options[] = (char_u *)TRUE #endif } SCTX_INIT}, + {"showcmdloc", "sloc", P_STRING|P_RSTAT, + (char_u *)&p_sloc, PV_NONE, + {(char_u *)"last", (char_u *)"last"} SCTX_INIT}, {"showfulltag", "sft", P_BOOL|P_VI_DEF, (char_u *)&p_sft, PV_NONE, {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, diff --git a/src/optionstr.c b/src/optionstr.c --- a/src/optionstr.c +++ b/src/optionstr.c @@ -93,6 +93,7 @@ static char *(p_scl_values[]) = {"yes", #if defined(MSWIN) && defined(FEAT_TERMINAL) static char *(p_twt_values[]) = {"winpty", "conpty", "", NULL}; #endif +static char *(p_sloc_values[]) = {"last", "statusline", "tabline", NULL}; static int check_opt_strings(char_u *val, char **values, int list); static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, int list); @@ -1894,6 +1895,12 @@ did_set_string_option( } #endif + // 'showcmdloc' + else if (varp == &p_sloc) + { + if (check_opt_strings(p_sloc, p_sloc_values, FALSE) != OK) + errmsg = e_invalid_argument; + } #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN) // 'toolbar' diff --git a/src/proto/drawscreen.pro b/src/proto/drawscreen.pro --- a/src/proto/drawscreen.pro +++ b/src/proto/drawscreen.pro @@ -1,6 +1,7 @@ /* drawscreen.c */ int update_screen(int type_arg); int statusline_row(win_T *wp); +void win_redr_status(win_T *wp, int ignore_pum); void showruler(int always); void win_redr_ruler(win_T *wp, int always, int ignore_pum); void after_updating_screen(int may_resize_shell); diff --git a/src/screen.c b/src/screen.c --- a/src/screen.c +++ b/src/screen.c @@ -4389,8 +4389,18 @@ draw_tabline(void) c = ' '; screen_fill(0, 1, col, (int)Columns, c, c, attr_fill); + // Draw the 'showcmd' information if 'showcmdloc' == "tabline". + if (p_sc && *p_sloc == 't') + { + int width = MIN(10, (int)Columns - col - (tabcount > 1) * 3); + + if (width > 0) + screen_puts_len(showcmd_buf, width, 0, (int)Columns + - width - (tabcount > 1) * 2, attr_nosel); + } + // Put an "X" for closing the current tab if there are several. - if (first_tabpage->tp_next != NULL) + if (tabcount > 1) { screen_putchar('X', 0, (int)Columns - 1, attr_nosel); TabPageIdxs[Columns - 1] = -999; diff --git a/src/testdir/dumps/Test_statusline_showcmd_1.dump b/src/testdir/dumps/Test_statusline_showcmd_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_statusline_showcmd_1.dump @@ -0,0 +1,6 @@ +|a+0&#e0e0e08| +0&#ffffff0@73 +|b+0&#e0e0e08| +0&#ffffff0@73 +|c+0&#e0e0e08> +0&#ffffff0@73 +|~+0#4040ff13&| @73 +|3+3#0000000&|x|2| @71 +|-+2&&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@56 diff --git a/src/testdir/dumps/Test_statusline_showcmd_2.dump b/src/testdir/dumps/Test_statusline_showcmd_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_statusline_showcmd_2.dump @@ -0,0 +1,6 @@ +|a+0&#ffffff0| @73 +|b| @73 +>c| @73 +|~+0#4040ff13&| @73 +|1+3#0000000&|2|3|4| @70 +| +0&&@74 diff --git a/src/testdir/dumps/Test_statusline_showcmd_3.dump b/src/testdir/dumps/Test_statusline_showcmd_3.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_statusline_showcmd_3.dump @@ -0,0 +1,6 @@ +|a+0&#ffffff0| @73 +|b| @73 +>c| @73 +|~+0#4040ff13&| @73 +|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]| @32|1|2|3|4| @6|3|,|1| @11|A|l@1 +|:+0&&| @73 diff --git a/src/testdir/dumps/Test_tabline_showcmd_1.dump b/src/testdir/dumps/Test_tabline_showcmd_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_tabline_showcmd_1.dump @@ -0,0 +1,6 @@ +| +2&#ffffff0|+| |[|N|o| |N|a|m|e|]| | +1&&@51|3+8#0000001#e0e0e08|x|2| +1#0000000#ffffff0@6 +|a+0&#e0e0e08| +0&#ffffff0@73 +|b+0&#e0e0e08| +0&#ffffff0@73 +|c+0&#e0e0e08> +0&#ffffff0@73 +|~+0#4040ff13&| @73 +|-+2#0000000&@1| |V|I|S|U|A|L| |B|L|O|C|K| |-@1| +0&&@38|3|,|2| @10|A|l@1| diff --git a/src/testdir/dumps/Test_tabline_showcmd_2.dump b/src/testdir/dumps/Test_tabline_showcmd_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_tabline_showcmd_2.dump @@ -0,0 +1,6 @@ +| +2&#ffffff0|+| |[|N|o| |N|a|m|e|]| | +1&&@51|1+8#0000001#e0e0e08|2|3|4| +1#0000000#ffffff0@5 +|a+0&&| @73 +|b| @73 +>c| @73 +|~+0#4040ff13&| @73 +| +0#0000000&@56|3|,|1| @10|A|l@1| diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim --- a/src/testdir/gen_opt_test.vim +++ b/src/testdir/gen_opt_test.vim @@ -132,6 +132,7 @@ let test_values = { \ 'selection': [['old', 'inclusive'], ['', 'xxx']], \ 'selectmode': [['', 'mouse', 'key,cmd'], ['xxx']], \ 'sessionoptions': [['', 'blank', 'help,options,slash'], ['xxx']], + \ 'showcmdloc': [['last', 'statusline', 'tabline'], ['xxx']], \ 'signcolumn': [['', 'auto', 'no'], ['xxx', 'no,yes']], \ 'spellfile': [['', 'file.en.add', '/tmp/dir\ with\ space/en.utf-8.add'], ['xxx', '/tmp/file']], \ 'spelllang': [['', 'xxx', 'sr@latin'], ['not&lang', "that\\\rthere"]], diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim --- a/src/testdir/test_statusline.vim +++ b/src/testdir/test_statusline.vim @@ -558,4 +558,26 @@ func Test_statusline_highlight_truncate( call StopVimInTerminal(buf) endfunc +func Test_statusline_showcmd() + CheckScreendump + + let lines =<< trim END + set laststatus=2 + set statusline=%S + set showcmdloc=statusline + call setline(1, ['a', 'b', 'c']) + END + call writefile(lines, 'XTest_statusline', 'D') + + let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 6}) + call feedkeys("\Gl", "xt") + call VerifyScreenDump(buf, 'Test_statusline_showcmd_1', {}) + + call feedkeys("\1234", "xt") + call VerifyScreenDump(buf, 'Test_statusline_showcmd_2', {}) + + call feedkeys("\:set statusline=\:\1234", "xt") + call VerifyScreenDump(buf, 'Test_statusline_showcmd_3', {}) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_tabline.vim b/src/testdir/test_tabline.vim --- a/src/testdir/test_tabline.vim +++ b/src/testdir/test_tabline.vim @@ -1,6 +1,9 @@ " Test for tabline source shared.vim +source view_util.vim +source check.vim +source screendump.vim func TablineWithCaughtError() let s:func_in_tabline_called = 1 @@ -158,5 +161,23 @@ func Test_mouse_click_in_tab() call RunVim([], [], "-e -s -S Xclickscript -c qa") endfunc +func Test_tabline_showcmd() + CheckScreendump + + let lines =<< trim END + set showtabline=2 + set showcmdloc=tabline + call setline(1, ['a', 'b', 'c']) + END + call writefile(lines, 'XTest_tabline', 'D') + + let buf = RunVimInTerminal('-S XTest_tabline', {'rows': 6}) + + call feedkeys("\Gl", "xt") + call VerifyScreenDump(buf, 'Test_tabline_showcmd_1', {}) + + call feedkeys("\1234", "xt") + call VerifyScreenDump(buf, 'Test_tabline_showcmd_2', {}) +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1061, +/**/ 1060, /**/ 1059,