203203--- The range itself is visualized by default with the statuscolumn signs.
204204--- Default: 1.
205205---
206+ --- `autopeek.predicate` defines a condition of whether to show peek window at
207+ --- the current command line state. Takes a table with input data and should
208+ --- return `true` to peek and `false` otherwise.
209+ --- Will be called only if it is possible to parse range from the current command
210+ --- line text and it is for buffer lines (no command or |:command-addr| is `lines`)
211+ --- Default: |MiniCmdline.default_autopeek_predicate()|.
212+ ---
213+ --- Input data fields:
214+ --- - <left> `(number)` - left range edge. Not necessarily smallest.
215+ --- - <right> `(number)` - right range edge. Same as `left` for a single line range.
216+ --- - <cmd> `(string)` - full command name. Can be empty string if no valid
217+ --- command is (yet) entered.
218+ ---
206219--- `autopeek.window` defines behavior of a peek window.
207220--- `autopeek.window.config` is a table defining floating window characteristics
208221--- or a callable returning such table.
212225--- customize |'statuscolumn'| value for the peek window. Takes a table with input
213226--- data and should return a string to display for line |v:lnum|.
214227--- Default: |MiniCmdline.default_autopeek_statuscolumn()|.
215- --- Input data fields:
216- --- - <left> `(number)` - left range edge. Not necessarily smallest.
217- --- - <right> `(number)` - right range edge. Same as `left` for a single line range.
228+ --- Input data fields are the same as for `autopeek.predicate`.
218229---
219230--- Example of showing `<` and `>` signs on range lines: >lua
220231---
@@ -274,6 +285,9 @@ MiniCmdline.config = {
274285 -- Number of lines to show above and below range lines
275286 n_context = 1 ,
276287
288+ -- Custom rule of when to show peek window
289+ predicate = nil ,
290+
277291 -- Window options
278292 window = {
279293 -- Floating window config
@@ -348,6 +362,19 @@ MiniCmdline.default_autocorrect_func = function(data, opts)
348362 return H .get_nearest_abbr (data .word , all , abbr_lens )
349363end
350364
365+ --- Default autopeek predicate
366+ ---
367+ --- @param data table Input autopeek data. As described in | MiniCmdline.config | .
368+ --- @param opts table | nil Options. Reserved for future use.
369+ ---
370+ --- @return boolean If command defines |: command-preview | - ` false ` , otherwise - ` true ` .
371+ --- This makes autopeek easier to use for commands like |:substitute|,
372+ --- especially if |'inccommand'| is set to `split`.
373+ MiniCmdline .default_autopeek_predicate = function (data , opts )
374+ local cmd_preview_map = H .cache .cmd_preview_map or H .get_cmd_preview_map ()
375+ return cmd_preview_map [data .cmd ] ~= true
376+ end
377+
351378--- Default autopeek statuscolumn
352379---
353380--- - Show signs next to lines depending on their relation to peeked range.
@@ -493,6 +520,7 @@ H.setup_config = function(config)
493520 H .check_type (' autopeek' , config .autopeek , ' table' )
494521 H .check_type (' autopeek.enable' , config .autopeek .enable , ' boolean' )
495522 H .check_type (' autopeek.n_context' , config .autopeek .n_context , ' number' )
523+ H .check_type (' autopeek.predicate' , config .autopeek .predicate , ' callable' , true )
496524 H .check_type (' autopeek.window' , config .autopeek .window , ' table' )
497525 local autopeek_win_config = config .autopeek .window .config
498526 if not (type (autopeek_win_config ) == ' table' or vim .is_callable (autopeek_win_config )) then
@@ -588,6 +616,7 @@ H.on_cmdline_enter = function()
588616
589617 H .cache = {
590618 buf_id = vim .api .nvim_get_current_buf (),
619+ cmd_preview_map = H .get_cmd_preview_map (),
591620 cmd_type = vim .fn .getcmdtype (),
592621 config = H .get_config (),
593622 peek = {},
@@ -597,6 +626,7 @@ H.on_cmdline_enter = function()
597626 H .cache .autocomplete_predicate = H .cache .config .autocomplete .predicate or MiniCmdline .default_autocomplete_predicate
598627 H .cache .buf_is_cmdwin = vim .fn .getbufinfo (H .cache .buf_id )[1 ].command == 1
599628
629+ H .cache .autopeek_predicate = H .cache .config .autopeek .predicate or MiniCmdline .default_autopeek_predicate
600630 MiniCmdline ._peek_statuscolumn = H .make_peek_statuscolumn ()
601631 if H .cache .config .autopeek .enable then H .autopeek () end
602632end
@@ -901,26 +931,33 @@ H.autopeek = function(force)
901931 local line = H .cache .state .line
902932 if line :find (' %S' ) == nil then H .peek_hide () end
903933
904- local range = H .parse_cmd_range (line )
934+ local parsed = H .parse_cmd (line )
935+ local range , cmd = parsed .range , parsed .cmd
905936 if range [1 ] == nil and range [2 ] == nil then return H .peek_hide () end
906937
907- -- NOTE: Force peek update if command line height has changed when typing
908- local cmdheight = math.ceil ((vim .fn .strdisplaywidth (line ) + 1 ) / vim .o .columns )
909- cmdheight = math.max (cmdheight , vim .o .cmdheight )
910- force = force or cmdheight ~= H .cache .peek .cmdheight
911- local cur_range = H .cache .peek .range or {}
912- if not force and range [1 ] == cur_range [1 ] and range [2 ] == cur_range [2 ] then return end
913-
914- -- Normalize and show range
938+ -- Normalize range lines
915939 local n_lines = vim .api .nvim_buf_line_count (0 )
916940 local left = H .clamp (range [1 ] or range [2 ], 1 , n_lines )
917941 local right = H .clamp (range [2 ] or range [1 ], 1 , n_lines )
918942 local from = right < left and right or left
919943 local to = right < left and left or right
944+ local data = { left = left , right = right , cmd = parsed .cmd }
945+
946+ -- Do not peek if predicate says so
947+ if not H .cache .autopeek_predicate (data ) then return H .peek_hide () end
948+
949+ -- Force peek update if command line height has changed when typing
950+ local cmdheight = math.ceil ((vim .fn .strdisplaywidth (line ) + 1 ) / vim .o .columns )
951+ cmdheight = math.max (cmdheight , vim .o .cmdheight )
952+ force = force or cmdheight ~= H .cache .peek .cmdheight
953+
954+ -- Skip peek update if command line state is the same (for performance)
955+ local cur_data = H .cache .peek .data or {}
956+ local is_data_same = left == cur_data .left and right == cur_data .right and cmd == cur_data .cmd
957+ if not force and is_data_same then return end
920958
921- H .cache .peek .range = range
922959 H .cache .peek .cmdheight = cmdheight
923- H .cache .peek .statuscolumn_data = { left = left , right = right }
960+ H .cache .peek .data = data
924961 H .cache .peek .win_id = H .peek_show (from , to )
925962end
926963
@@ -1051,7 +1088,7 @@ end
10511088
10521089H .make_peek_statuscolumn = function ()
10531090 local statuscolumn = H .cache .config .autopeek .window .statuscolumn or MiniCmdline .default_autopeek_statuscolumn
1054- return function () return statuscolumn (H .cache .peek .statuscolumn_data ) or ' ' end
1091+ return function () return statuscolumn (H .cache .peek .data ) or ' ' end
10551092end
10561093
10571094-- Utilities ------------------------------------------------------------------
@@ -1079,8 +1116,21 @@ H.fit_to_width = function(text, width)
10791116 return t_width <= width and text or (' …' .. vim .fn .strcharpart (text , t_width - width + 1 , width - 1 ))
10801117end
10811118
1082- H .parse_cmd_range = function (line )
1119+ H .get_cmd_preview_map = function ()
1120+ local res = { substitute = true , smagic = true , snomagic = true }
1121+ -- NOTE: Check `name` type as on Neovim<0.11 output can be `{ [true] = 6 }`
1122+ for name , data in pairs (vim .api .nvim_get_commands ({})) do
1123+ if type (name ) == ' string' and data .preview then res [name ] = true end
1124+ end
1125+ for name , data in pairs (vim .api .nvim_buf_get_commands (0 , {})) do
1126+ if type (name ) == ' string' and data .preview then res [name ] = true end
1127+ end
1128+ return res
1129+ end
1130+
1131+ H .parse_cmd = function (line )
10831132 local ok , parsed = pcall (vim .api .nvim_parse_cmd , line , {})
1133+ local needs_reparse = not ok
10841134
10851135 -- Try extra parsing to have a result for some edge cases
10861136 -- - Line with only range
@@ -1097,7 +1147,9 @@ H.parse_cmd_range = function(line)
10971147 end
10981148
10991149 -- Treat `range` only as a "line range"
1100- return (ok and parsed .addr == ' line' ) and parsed .range or {}
1150+ local range = (ok and parsed .addr == ' line' ) and parsed .range or {}
1151+ local cmd = needs_reparse and ' ' or parsed .cmd
1152+ return { range = range , cmd = cmd }
11011153end
11021154
11031155H .getcmdcomplpat = function () return vim .fn .getcmdcomplpat () end
0 commit comments