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,18 @@ 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+ --- @param data table Input autopeek data. As described in | MiniCmdline.config | .
367+ --- @param opts table | nil Options. Reserved for future use.
368+ ---
369+ --- @return boolean If command itself defines |: command-preview | - ` false ` ,
370+ --- otherwise - `true`. This makes autopeek easier to use for commands
371+ --- like |:substitute|, especially if |'inccommand'| is set to `split`.
372+ MiniCmdline .default_autopeek_predicate = function (data , opts )
373+ local cmd_preview_map = H .cache .cmd_preview_map or H .get_cmd_preview_map ()
374+ return cmd_preview_map [data .cmd ] ~= true
375+ end
376+
351377--- Default autopeek statuscolumn
352378---
353379--- - Show signs next to lines depending on their relation to peeked range.
@@ -493,6 +519,7 @@ H.setup_config = function(config)
493519 H .check_type (' autopeek' , config .autopeek , ' table' )
494520 H .check_type (' autopeek.enable' , config .autopeek .enable , ' boolean' )
495521 H .check_type (' autopeek.n_context' , config .autopeek .n_context , ' number' )
522+ H .check_type (' autopeek.predicate' , config .autopeek .predicate , ' callable' , true )
496523 H .check_type (' autopeek.window' , config .autopeek .window , ' table' )
497524 local autopeek_win_config = config .autopeek .window .config
498525 if not (type (autopeek_win_config ) == ' table' or vim .is_callable (autopeek_win_config )) then
@@ -588,6 +615,7 @@ H.on_cmdline_enter = function()
588615
589616 H .cache = {
590617 buf_id = vim .api .nvim_get_current_buf (),
618+ cmd_preview_map = H .get_cmd_preview_map (),
591619 cmd_type = vim .fn .getcmdtype (),
592620 config = H .get_config (),
593621 peek = {},
@@ -597,6 +625,7 @@ H.on_cmdline_enter = function()
597625 H .cache .autocomplete_predicate = H .cache .config .autocomplete .predicate or MiniCmdline .default_autocomplete_predicate
598626 H .cache .buf_is_cmdwin = vim .fn .getbufinfo (H .cache .buf_id )[1 ].command == 1
599627
628+ H .cache .autopeek_predicate = H .cache .config .autopeek .predicate or MiniCmdline .default_autopeek_predicate
600629 MiniCmdline ._peek_statuscolumn = H .make_peek_statuscolumn ()
601630 if H .cache .config .autopeek .enable then H .autopeek () end
602631end
@@ -901,26 +930,33 @@ H.autopeek = function(force)
901930 local line = H .cache .state .line
902931 if line :find (' %S' ) == nil then H .peek_hide () end
903932
904- local range = H .parse_cmd_range (line )
933+ local parsed = H .parse_cmd (line )
934+ local range , cmd = parsed .range , parsed .cmd
905935 if range [1 ] == nil and range [2 ] == nil then return H .peek_hide () end
906936
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
937+ -- Normalize range lines
915938 local n_lines = vim .api .nvim_buf_line_count (0 )
916939 local left = H .clamp (range [1 ] or range [2 ], 1 , n_lines )
917940 local right = H .clamp (range [2 ] or range [1 ], 1 , n_lines )
918941 local from = right < left and right or left
919942 local to = right < left and left or right
943+ local data = { left = left , right = right , cmd = parsed .cmd }
944+
945+ -- Do not peek if predicate says so
946+ if not H .cache .autopeek_predicate (data ) then return H .peek_hide () end
947+
948+ -- Force peek update if command line height has changed when typing
949+ local cmdheight = math.ceil ((vim .fn .strdisplaywidth (line ) + 1 ) / vim .o .columns )
950+ cmdheight = math.max (cmdheight , vim .o .cmdheight )
951+ force = force or cmdheight ~= H .cache .peek .cmdheight
952+
953+ -- Skip peek update if command line state is the same
954+ local cur_data = H .cache .peek .data or {}
955+ local is_data_same = left == cur_data .left and right == cur_data .right and cmd == cur_data .cmd
956+ if not force and is_data_same then return end
920957
921- H .cache .peek .range = range
922958 H .cache .peek .cmdheight = cmdheight
923- H .cache .peek .statuscolumn_data = { left = left , right = right }
959+ H .cache .peek .data = data
924960 H .cache .peek .win_id = H .peek_show (from , to )
925961end
926962
@@ -1051,7 +1087,7 @@ end
10511087
10521088H .make_peek_statuscolumn = function ()
10531089 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
1090+ return function () return statuscolumn (H .cache .peek .data ) or ' ' end
10551091end
10561092
10571093-- Utilities ------------------------------------------------------------------
@@ -1079,8 +1115,21 @@ H.fit_to_width = function(text, width)
10791115 return t_width <= width and text or (' …' .. vim .fn .strcharpart (text , t_width - width + 1 , width - 1 ))
10801116end
10811117
1082- H .parse_cmd_range = function (line )
1118+ H .get_cmd_preview_map = function ()
1119+ local res = { substitute = true , smagic = true , snomagic = true }
1120+ -- NOTE: Check `name` type as on Neovim<0.11 output can be `{ [true] = 6 }`
1121+ for name , data in pairs (vim .api .nvim_get_commands ({})) do
1122+ if type (name ) == ' string' and data .preview then res [name ] = true end
1123+ end
1124+ for name , data in pairs (vim .api .nvim_buf_get_commands (0 , {})) do
1125+ if type (name ) == ' string' and data .preview then res [name ] = true end
1126+ end
1127+ return res
1128+ end
1129+
1130+ H .parse_cmd = function (line )
10831131 local ok , parsed = pcall (vim .api .nvim_parse_cmd , line , {})
1132+ local needs_reparse = not ok
10841133
10851134 -- Try extra parsing to have a result for some edge cases
10861135 -- - Line with only range
@@ -1097,7 +1146,9 @@ H.parse_cmd_range = function(line)
10971146 end
10981147
10991148 -- Treat `range` only as a "line range"
1100- return (ok and parsed .addr == ' line' ) and parsed .range or {}
1149+ local range = (ok and parsed .addr == ' line' ) and parsed .range or {}
1150+ local cmd = needs_reparse and ' ' or parsed .cmd
1151+ return { range = range , cmd = cmd }
11011152end
11021153
11031154H .getcmdcomplpat = function () return vim .fn .getcmdcomplpat () end
0 commit comments