mini.pick documentation
Generated from the main
branch of ‘mini.nvim’
mini.pick Pick anything
MIT License Copyright (c) 2023 Evgeni Chasnovski
Module
Features:
Single window general purpose interface for picking element from any array.
On demand toggleable preview and info views.
Interactive query matching (filter+sort) with fast non-blocking default which does fuzzy matching and allows other modes (MiniPick.default_match()).
Built-in pickers (see MiniPick.builtin):
Files.
Pattern match (for fixed pattern or with live feedback; both allow file filtering via glob patterns).
Buffers.
Help tags.
CLI output.
Resume latest picker.
:Pick command to work with extensible MiniPick.registry.
vim.ui.select() implementation. To adjust, use MiniPick.ui_select() or save-restore
vim.ui.select
manually after calling MiniPick.setup().Rich and customizable built-in MiniPick-actions when picker is active:
Manually change currently focused item.
Scroll vertically and horizontally.
Toggle preview or info view.
Mark/unmark items to choose later.
Refine current matches (make them part of a new picker).
And many more.
Minimal yet flexible MiniPick-source specification with:
Items (array, callable, or manually set later).
Source name.
Working directory.
Matching algorithm.
Way matches are shown in main window.
Item preview.
“On choice” action for current and marked items.
Custom actions/keys can be configured globally, per buffer, or per picker.
Out of the box support for ‘ignorecase’ and ‘smartcase’.
Match caching to increase responsiveness on repeated prompts.
Notes:
Works on all supported versions but Neovim>=0.10 will give more visual feedback in floating window footer.
For more pickers see MiniExtra.pickers.
Sources with more details:
Dependencies
Suggested dependencies (provide extra functionality, will work without them):
Enabled mini.icons module to show icons near the items for actual paths. Falls back to ‘nvim-tree/nvim-web-devicons’ plugin or no icons will be used.
MiniPick-cli-tools CLI tool(s) to power MiniPick.builtin.files(), MiniPick.builtin.grep(), and MiniPick.builtin.grep_live() built-in pickers:
rg
(github.com/BurntSushi/ripgrep; enough for all three; recommended).fd
(github.com/sharkdp/fd; forfiles
only).git
(github.com/git/git; enough for all three).
Note: CLI tools are called only with basic arguments needed to get items. To customize the output, use their respective configuration approaches. Here are some examples of where to start:
github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#configuration-file
github.com/sharkdp/fd#excluding-specific-files-or-directories
git-scm.com/docs/gitignore
Setup
This module needs a setup with require('mini.pick').setup({})
(replace {}
with your config
table). It will create global Lua table MiniPick
which you can use for scripting or manually (with :lua MiniPick.*
).
See MiniPick.config for available config settings.
You can override runtime config settings locally to buffer inside vim.b.minipick_config
which should have same structure as MiniPick.config
. See mini.nvim-buffer-local-config for more details.
Comparisons
nvim-telescope/telescope.nvim:
The main inspiration for this module, so there is significant overlap.
Has three (or two) window UI (prompt, matches, preview), while this module combines everything in one window. It allows more straightforward customization for unusual scenarios.
Default match algorithm is somewhat slow, while this module should match relatively lag-free for at least 100K+ items.
Has many built-in pickers, while this module has handful at its core relying on other ‘mini.nvim’ modules to provide more (see mini.extra).
-
Mostly same comparison as with ‘nvim-telescope/telescope.nvim’.
Requires junegunn/fzf installed to power fuzzy matching, while this module provides built-in Lua matching.
Highlight groups
MiniPickBorder
- window border.MiniPickBorderBusy
- window border while picker is busy processing.MiniPickBorderText
- non-prompt on border.MiniPickCursor
- cursor during active picker (hidden by default).MiniPickIconDirectory
- default icon for directory.MiniPickIconFile
- default icon for file.MiniPickHeader
- headers in info buffer and previews.MiniPickMatchCurrent
- current matched item.MiniPickMatchMarked
- marked matched items.MiniPickMatchRanges
- ranges matching query elements.MiniPickNormal
- basic foreground/background highlighting.MiniPickPreviewLine
- target line in preview.MiniPickPreviewRegion
- target region in preview.MiniPickPrompt
- prompt.MiniPickPromptCaret
- caret in prompt.MiniPickPromptPrefix
- prefix of the prompt.
To change any highlight group, set it directly with nvim_set_hl().
Events
To allow user customization and integration of external tools, certain User autocommand events are triggered under common circumstances:
MiniPickMatch
- just after updating query matches or setting items.MiniPickStart
- just after picker has started.MiniPickStop
- just before picker is stopped.
Overview
General idea is to take array of objects, display them with interactive filter/sort/navigate/preview, and allow to choose one or more items.
How to start a picker
Use MiniPick.start() with
opts.source
defining MiniPick-source. Example:MiniPick.start({ source = { items = vim.fn.readdir('.') } })
Use any of MiniPick.builtin pickers directly. Example:
MiniPick.builtin.files({ tool = 'git' })
Use :Pick command which uses customizable pickers from MiniPick.registry. Example:
:Pick files tool='git'
User interface
UI consists from a single window capable of displaying three different views:
“Main” - where current query matches are shown.
“Preview” - preview of current item (toggle with
<Tab>
).“Info” - general info about picker and its state (toggle with
<S-Tab>
).
Current prompt is displayed at the top left of the window border with vertical line indicating caret (current input position).
Bottom part of window border displays (in Neovim>=0.10) extra visual feedback:
Left part is a picker name.
Right part contains information in the format
<current index in matches> | <match count> | <marked count> / <total count>
When picker is busy (like if there are no items yet set or matching is active) window border changes color to be MiniPickBorderBusy
after config.delay.busy
milliseconds of idle time.
Life cycle
Type characters to filter and sort matches. It uses MiniPick.default_match() with
query
being an array of pressed characters. Overview of how it matches:If query starts with
'
, the match is exact.If query starts with
^
, the match is exact at start.If query ends with
$
, the match is exact at end.If query starts with
*
, the match is forced to be fuzzy.Otherwise match is fuzzy.
Sorting is done to first minimize match width and then match start. Nothing more: no favoring certain places in string, etc.
Type special keys to perform MiniPick-actions. Here are some basic ones:
<C-n>
/<Down>
moves down;<C-p>
/<Up>
moves up.<Left>
/<Right>
moves prompt caret left / right.<S-Tab>
toggles information window with all available mappings.<Tab>
toggles preview.<C-x>
/<C-a>
toggles current / all item(s) as (un)marked.<C-Space>
/<M-Space>
makes all matches or marked items as new picker.<CR>
/<M-CR>
chooses current/marked item(s).<Esc>
/<C-c>
stops picker.
Implementation details
Processing key typing is done via a dedicated key query process for more control over their side effects. As a result, regular mappings don’t work here and picker’s window needs to be current as long as it is shown. Changing window focus leads to automatic picker stop (after small delay).
Any picker is non-blocking but waits to return the chosen item. Example:
file = MiniPick.builtin.files()
allows other actions to be executed when picker is shown while still assigningfile
with value of the chosen item.
Source
Source is defined as a source
field inside one of (in increasing priority):
MiniPick.config - has global effect.
vim.b.minipick_config
- has buffer-local effect.opts.source
in picker call - has effect for that particular call.
Example of source to choose from arglist:
{ items = vim.fn.argv, name = 'Arglist' }
Note: this is mostly useful for writing pickers. Can safely skip if you want to just use provided pickers.
Items
source.items
defines items to choose from. It should be one of the following:
Array of objects which can have different types. Any type is allowed.
nil
. Picker waits for explicit MiniPick.set_picker_items() call.Callable returning any of the previous types. Will be called once on start with source’s
cwd
set as current-directory.
MiniPick-source.items-stritems Matching is done for items array based on the string representation of its elements (here called “stritems”). For single item it is computed as follows:
Callable is called once with output used in next steps.
String item is used as is.
String <text> field of table item is used (if present).
Use output of vim.inspect().
Example:
items = { 'aaa.txt', { text = 'bbb' }, function() return 'ccc' end }
-- corresponding stritems are { 'aaa.txt', 'bbb', 'ccc' }
Default value is nil
, assuming it always be supplied by the caller.
MiniPick-source.items-common There are some recommendations for common item types in order for them to work out of the box with MiniPick.default_show(), MiniPick.default_preview(), MiniPick.default_choose(), MiniPick.default_choose_marked():
Path (file or directory). Use string or
path
field of a table. Path can be either absolute, relative to thesource.cwd
, or have a general URI format (only if supplied as table field). Examples:'aaa.txt'
,{ path = 'aaa.txt' }
Buffer. Use buffer id as number, string, or
bufnr
/buf_id
/buf
field of a table (any name is allowed). Examples:1
,'1'
,{ bufnr = 1 }
,{ buf_id = 1 }
,{ buf = 1 }
Line in file or buffer. Use table representation with
lnum
field with line number (starting from 1) or string in “<path>\0<line>” format (\0
is an actual null character; don’t escape the slash; may need to be\000
). Examples:{ path = 'aaa.txt', lnum = 2 }, 'aaa.txt\0002', { bufnr = 1, lnum = 3 }
Position in file or buffer. Use table representation with
lnum
andcol
fields with line and column numbers (starting from 1) or string in “<path>\0<line>\0<col>” format (\0
is an actual null character, don’t escape the slash; may need to be\000
). Examples:{ path = 'aaa.txt', lnum = 2, col = 3 }, 'aaa.txt\0' .. '2\0003', { bufnr = 1, lnum = 3, col = 4 }
Region in file or buffer. Use table representation with
lnum
,col
,end_lnum
,end_col
fields for start and end line/column. All numbers start from 1, end line is inclusive, end column is exclusive. This naming is similar to getqflist() and diagnostic-structure. Examples:{ path = 'aaa.txt', lnum = 2, col = 3, end_lnum = 4, end_col = 5 }, { bufnr = 1, lnum = 3, col = 4, end_lnum = 5, end_col = 6 }
Note: all table items will benefit from having text
field for better matching.
Name
source.name
defines the name of the picker to be used for visual feedback.
Default value is “
Current working directory
source.cwd
is a string defining the current working directory in which picker operates. It should point to a valid actually present directory path. This is a part of source to allow persistent way to use relative paths, i.e. not depend on current directory being constant after picker start. It also makes the MiniPick.builtin.resume() picker more robust.
It will be set as local current-directory (:lcd) of picker’s main window to allow simpler code for “in window” functions (choose/preview/custom/etc.).
Default value is current-directory.
Match
source.match
is a callable defining how stritems (see MiniPick-source.items-stritems) are matched (filtered and sorted) based on the query.
It will be called with the following arguments:
stritems
- all available stritems for current picker.inds
- array ofstritems
indexes usually pointing at current matches. It does point to current matches in the case of interactively appending character at the end of the query. It assumes that matches for such bigger query is a subset of previous matches (implementation can ignore it). This can be utilized to increase performance by checking fewer stritems.query
- array of strings. Usually (like is common case of user interactively typing query) each string represents one character. However, any strings are allowed, as query can be set with MiniPick.set_picker_query().
It should either return array of match indexes for stritems elements matching the query (synchronous) or explicitly use MiniPick.set_picker_match_inds() to set them (may be asynchronous).
Notes:
The result can be any array of
stritems
indexes, i.e. not necessarily a subset of inputinds
.Both
stritems
andquery
depend on values of ‘ignorecase’ and ‘smartcase’. If query shows “ignore case” properties (only ‘ignorecase’ is set or both ‘ignorecase’ / ‘smartcase’ are set and query has only lowercase characters), thenstritems
andquery
will have only lowercase characters. This allows automatic support for case insensitive matching while being faster and having simpler match function implementation.Writing custom
source.match
usually means also changing MiniPick-source.show because it is used to highlight stritems parts actually matching the query.
Example of simple “exact” match()
preserving initial order:
local match_exact = function(stritems, inds, query)
local prompt_pattern = vim.pesc(table.concat(query))
local f = function(i) return stritems[i]:find(prompt_pattern) ~= nil end
return vim.tbl_filter(f, inds)
end
-- For non-blocking version see `:h MiniPick.poke_is_picker_active()`
Default value is MiniPick.default_match().
Show
source.show
is a callable defining how matched items are shown in the window.
It will be called with the following arguments:
buf_id
- identifier of the target buffer.items_to_show
- array of actual items to be shown inbuf_id
. This is a subset of currently matched items computed to fit in current window view.query
- array of strings. Same as insource.match
.
It should update buffer buf_id
to visually represent items_to_show
one item per line starting from line one (it shouldn’t depend on options.content_from_bottom
). This also includes possible visualization of which parts of stritem actually matched query.
Example (assuming string items; without highlighting):
local show_prepend = function(buf_id, items_arr, query)
local lines = vim.tbl_map(function(x) return 'Item: ' .. x end, items_arr)
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
end
Default value is MiniPick.default_show().
Preview
source.preview
is a callable defining how item preview is done.
It will be called with the following arguments:
buf_id
- identifier of the target buffer. Note: for every separate instance of item previewing new scratch buffer is be created.item
- item to preview.
It should update buffer buf_id
to visually represent item
.
Example:
local preview_inspect = function(buf_id, item)
local lines = vim.split(vim.inspect(item), '\n')
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
end
Default value is MiniPick.default_preview().
Choose an item
source.choose
is a callable defining what to do when an item is chosen.
It will be called with the following arguments:
item
- chosen item. Always non-nil
.
It should perform any intended “choose” action for an item and return a value indicating whether picker should continue (i.e. not stop): nil
and false
will stop picker, other values will continue.
Notes:
- It is called when picker window is still current. Use
windows.target
value from MiniPick.get_picker_state() output to do something with target window.
Example:
local choose_file_continue = function(item)
if vim.fn.filereadable(item) == 0 then return end
vim.api.nvim_win_call(
MiniPick.get_picker_state().windows.main,
function() vim.cmd('edit ' .. item) end
)
return true
end
Default value is MiniPick.default_choose().
Choose marked items
source.choose_marked
is a callable defining what to do when marked items (see MiniPick-actions-mark) are chosen. Serves as a companion to source.choose
which can choose several items.
It will be called with the following arguments:
items_marked
- array of marked items. Can be empty.
It should perform any intended “choose” action for several items and return a value indicating whether picker should continue (i.e. not stop): nil
and false
will stop picker, other values will continue.
Notes:
- It is called when picker window is still current. Use
windows.target
value from MiniPick.get_picker_state() output to do something with target window.
Example:
local choose_marked_print = function(items) print(vim.inspect(items)) end
Default value is MiniPick.default_choose_marked().
Actions
When picker is active, mappings
table defines a set of special keys which when pressed will execute certain actions. Those can be of two types:
Built-in: actions present in default
config.mappings
. Can be only overridden with a different key.Custom: user defined actions. Should be a table with
char
andfunc
fields.
Built-in
Caret
User can add character not only at query end, but more generally at caret.
mappings.caret_left
- move caret to left.mappings.caret_right
- move caret to right.
Choose
Choose is a fundamental action that actually implements the intent of calling a picker, i.e. pick an item.
mappings.choose
- choose as is, i.e. applysource.choose
for current item.mappings.choose_in_split
- make horizontal split at target window, update target window to the new split, and choose.mappings.choose_in_tabpage
- same aschoose_in_split
, but create tabpage.mappings.choose_in_vsplit
- same aschoose_in_split
, but split vertically.mappings.choose_marked
- choose marked items as is, i.e. applysource.choose_marked
at current marked items.
Delete
Delete actions are for deleting elements from query.
Mark
Marking is an action of adding certain items to a separate list which then can be chosen with mappings.choose_marked
(for example, sent to quickfix list). This is a companion to a regular choosing which can pick only one item.
mappings.mark
- toggle marked/unmarked state of current item.mappings.mark_all
- toggle marked/unmarked state (mark all if not all marked; unmark all otherwise) of all currently matched items.
Notes:
- Marks persist across queries and matches. For example, user can make a query with marking all matches several times and marked items from all queries will be preserved.
Move
Move is a fundamental action of changing which item is current.
mappings.move_down
- change focus to the item below.mappings.move_start
change focus to the first currently matched itemmappings.move_up
- change focus to the item above.
Notes:
Up and down wrap around edges:
move_down
on last item moves to first,move_up
on first moves to last.Moving when preview or info view is shown updates the view with new item.
These also work with non-overridable alternatives:
<Down>
moves down.<Home>
moves to first matched.<Up>
moves up.
Paste
Paste is an action to paste content of registers at caret.
mappings.paste
- paste from register defined by the next key press.
Notes:
Does not support expression register
=
.Supports special cases of register: <C-f> (as c_CTRL-R_CTRL-F), <C-w> (as c_CTRL-R_CTRL-W), <C-a> (as c_CTRL-R_CTRL-A), <C-l> (as c_CTRL-R_CTRL-L).
Refine
Refine is an action that primarily executes the following:
Takes certain items and makes them be all items (in order they are present).
Resets query.
Updates
source.match
to be the one from config.mappings.refine
- refine currently matched items.mappings.refine_marked
- refine currently marked items.
This action is useful in at least two cases:
Perform consecutive “narrowing” queries. Example: to get items that contain both “hello” and “world” exact matches (in no particular order) with default matching, type “’hello” (notice “’” at the start) followed by
<C-Space>
and another “’world”.Reset
match
to default. Particularly useful in MiniPick.builtin.grep_live().
Scroll
Scroll is an action to either move current item focus further than to the neighbor item or adjust window view to see more information.
mappings.scroll_down
- when matches are shown, go down by the amount of visible matches. In preview and info view - scroll down as with CTRL-F.mappings.scroll_left
- scroll left as with zH.mappings.scroll_right
- scroll right as with zL.mappings.scroll_up
- when matches are shown, go up by the amount of visible matches. In preview and info view - scroll up as with CTRL-B.
Stop
mappings.stop
stops the picker. <C-c> also always stops the picker.
Toggle
Toggle action is a way to change view: show if target is not shown, reset to main view otherwise.
mappings.toggle_info
- toggle info view.mappings.toggle_preview
- toggle preview.
Note:
Updating query in any way resets window view to show matches.
Moving current item focus keeps preview or info view with updated item.
Custom
Along with built-in actions, users can define custom actions. This can be done by supplying custom elements to mappings
table. The field defines action name (used to infer an action description in info view). The value is a table with the following fields:
<char>
(string)
- single character acting as action trigger.<func>
(function)
- callable to be executed without arguments after user presses <char>. Its return value is treated as “should stop picker after execution”, i.e. returning nothing,nil
, orfalse
continues picker while everything else (prefertrue
) stops it.
Example of execute
custom mapping:
execute = {
char = '<C-e>',
func = function() vim.cmd(vim.fn.input('Execute: ')) end,
}
Examples
Disable icons
Disable icons in MiniPick.builtin pickers related to paths:
local pick = require('mini.pick')
pick.setup({ source = { show = pick.default_show } })
Switch toggle and move keys
require('mini.pick').setup({
mappings = {
toggle_info = '<C-k>',
toggle_preview = '<C-p>',
move_down = '<Tab>',
move_up = '<S-Tab>',
}
})
Different window styles:
-- Different border
{ window = { config = { border = 'double' } } }
-- "Cursor tooltip"
{
window = {
config = {
relative = 'cursor', anchor = 'NW',
row = 0, col = 0, width = 40, height = 20,
},
},
}
-- Centered on screen
local win_config = function()
local height = math.floor(0.618 * vim.o.lines)
local width = math.floor(0.618 * vim.o.columns)
return {
anchor = 'NW', height = height, width = width,
row = math.floor(0.5 * (vim.o.lines - height)),
col = math.floor(0.5 * (vim.o.columns - width)),
}
end
{ window = { config = win_config } }
setup()
MiniPick.setup
({config})
Module setup
:Pick
Calling this function creates a :Pick
user command. It takes picker name from MiniPick.registry as mandatory first argument and executes it with following (expanded, expandcmd()) <f-args> combined in a single table. To add custom pickers, update MiniPick.registry.
Example:
:Pick files tool='git'
:Pick grep pattern='<cword>'
It also sets custom vim.ui.select() implementation to use the module. See MiniPick.ui_select().
Parameters
{config} (table|nil)
Module config table. See MiniPick.config.
Usage
require('mini.pick').setup() -- use default config
-- OR
require('mini.pick').setup({}) -- replace {} with your config table
config
MiniPick.config
Defaults
MiniPick.config = {
-- Delays (in ms; should be at least 1)
delay = {
-- Delay between forcing asynchronous behavior
async = 10,
-- Delay between computation start and visual feedback about it
busy = 50,
},
-- Keys for performing actions. See `:h MiniPick-actions`.
mappings = {
caret_left = '<Left>',
caret_right = '<Right>',
choose = '<CR>',
choose_in_split = '<C-s>',
choose_in_tabpage = '<C-t>',
choose_in_vsplit = '<C-v>',
choose_marked = '<M-CR>',
delete_char = '<BS>',
delete_char_right = '<Del>',
delete_left = '<C-u>',
delete_word = '<C-w>',
mark = '<C-x>',
mark_all = '<C-a>',
move_down = '<C-n>',
move_start = '<C-g>',
move_up = '<C-p>',
paste = '<C-r>',
refine = '<C-Space>',
refine_marked = '<M-Space>',
scroll_down = '<C-f>',
scroll_left = '<C-h>',
scroll_right = '<C-l>',
scroll_up = '<C-b>',
stop = '<Esc>',
toggle_info = '<S-Tab>',
toggle_preview = '<Tab>',
},
-- General options
options = {
-- Whether to show content from bottom to top
content_from_bottom = false,
-- Whether to cache matches (more speed and memory on repeated prompts)
use_cache = false,
},
-- Source definition. See `:h MiniPick-source`.
source = {
items = nil,
name = nil,
cwd = nil,
match = nil,
show = nil,
preview = nil,
choose = nil,
choose_marked = nil,
},
-- Window related options
window = {
-- Float window config (table or callable returning it)
config = nil,
-- String to use as caret in prompt
prompt_caret = '▏',
-- String to use as prefix in prompt
prompt_prefix = '> ',
},
}
Delays
config.delay
defines plugin delays (in ms). All should be strictly positive.
delay.async
is a delay between forcing asynchronous behavior. This usually means making screen redraws and utilizing MiniPick.poke_is_picker_active() (for example, to stop current matching if query has updated). Smaller values give smoother user experience at the cost of more computations.
delay.busy
is a delay between when some computation starts and showing visual feedback about it by making window border to have MiniPickBorderBusy
highlight group. Smaller values will give feedback faster at the cost of feeling like flicker.
Mappings
config.mappings
defines keys for special actions to be triggered after certain keys. See MiniPick-actions for more information.
Options
config.options
contains some general purpose options.
options.content_from_bottom
is a boolean indicating whether content should be shown from bottom to top. That means that best matches will be shown at the bottom. Note: for better experience use Neovim>=0.10, which has floating window footer capability. Default: false
.
options.use_cache
is a boolean indicating whether match results should be cached per prompt (i.e. concatenated query). This results into faster response on repeated prompts (like when deleting query entries) at the cost of using more memory. Default: false
.
Source
config.source
defines fallbacks for source specification. For example, this can be used to change default match
to use different implementation or show
to not show icons for some MiniPick.builtin pickers (see MiniPick-examples). See MiniPick-source for more information.
Window
config.window
contains window specific configurations.
window.config
defines a (parts of) default floating window config for the main picker window. This can be either a table overriding some parts or a callable returning such table. See MiniPick-examples for some examples.
window.prompt_caret
defines how caret is displayed in window’s prompt. Default: ‘▏’.
window.prompt_prefix
defines what prefix is used in window’s prompt. Default: ‘>’.
start()
MiniPick.start
({opts})
Start picker
Notes:
If there is currently an active picker, it is properly stopped and new one is started “soon” in the main event-loop (see vim.schedule()).
Current window at the moment of this function call is treated as “target”. It will be set back as current after MiniPick.stop(). See MiniPick.get_picker_state() and MiniPick.set_picker_target_window().
Parameters
{opts} (table|nil)
Options. Should have same structure as MiniPick.config. Default values are inferred from there. Usually should have proper MiniPick-source.items defined.
Return
(any)
Item which was current when picker is stopped; nil
if aborted.
stop()
MiniPick.stop
()
Stop active picker
refresh()
MiniPick.refresh
()
Refresh active picker
default_match()
MiniPick.default_match
({stritems}, {inds}, {query}, {opts})
Default match
Filter target stritems to contain query and sort from best to worst matches.
Implements default value for MiniPick-source.match.
By default (if no special modes apply) it does the following fuzzy matching:
Stritem contains query if it contains all its elements verbatim in the same order (possibly with gaps, i.e. not strictly one after another). Note: empty query and empty string element is contained in any string.
Sorting is done with the following ordering (same as in mini.fuzzy):
The smaller the match width (end column minus start column) the better.
Among same match width, the smaller start column the better.
Among same match width and start column, preserve original order.
Notes:
- Most common interactive usage results into
query
containing one typed character per element.
Special modes
Forced modes:
Query starts with “*“: match the rest fuzzy (without other modes).
Query starts with “’”: match the rest exactly (without gaps).
Place modes:
Query starts with ‘^’: match the rest exactly at start.
Query ends with ‘$’: match the rest exactly at end.
Both modes can be used simultaneously.
Grouped: query contains at least one whitespace element. Output is computed as if query is split at whitespace indexes with concatenation between them.
Precedence of modes: “forced exact” = “forced fuzzy” > “place start/end” > “grouped” > “default”
Examples
Assuming stritems
are { '_abc', 'a_bc', 'ab_c', 'abc_' }
, here are some example matches based on prompt (concatenated query):
| Prompt | Matches |
|--------|------------------------|
| abc | All |
| *abc | All |
| | |
| 'abc | abc_, _abc |
| *'abc | None (no "'" in items) |
| | |
| ^abc | abc_ |
| *^abc | None (no "^" in items) |
| | |
| abc$ | _abc |
| *abc$ | None (no "$" in items) |
| | |
| ab c | abc_, _abc, ab_c |
| *ab c | None (no " " in items) |
Having query { 'ab', 'c' }
is the same as “ab c” prompt.
You can have a feel of how this works with this command:
MiniPick.start({ source = { items = { '_abc', 'a_bc', 'ab_c', 'abc_' } } })
Parameters
{stritems} (table)
Array of all stritems.
{inds} (table)
Array of stritems
indexes to match. All of them should point at string elements of stritems
. No check is done for performance reasons.
{query} (table)
Array of strings.
{opts} (table|nil)
Options. Possible fields:
<sync>
(boolean)
- Whether to match synchronously. Default:false
.<preserve_order>
(boolean)
- Whether to skip sort step. Default:false
.
Return
(table|nil)
Depending on whether computation is synchronous (either opts.sync
is true
or there is an active picker):
If yes, array of
stritems
indexes matching thequery
(from best to worst).If no,
nil
is returned with MiniPick.set_picker_match_inds() used later.
default_show()
MiniPick.default_show
({buf_id}, {items}, {query}, {opts})
Default show
Show items in a buffer and highlight parts that actually match query (assuming match is done with MiniPick.default_match()). Lines are computed based on the MiniPick-source.items-stritems.
Implements default value for MiniPick-source.show.
Uses the following highlight groups (see mini.pick for their description):
MiniPickIconDirectory
MiniPickIconFile
MiniPickMatchCurrent
MiniPickMatchMarked
MiniPickMatchRanges
Parameters
{buf_id} (number)
Identifier of target buffer.
{items} (table)
Array of items to show.
{query} (table)
Array of strings representing query.
{opts} (table|nil)
Options. Possible fields:
<show_icons>
(boolean)
- whether to show icons for entries recognized as valid actually present paths on disk (see MiniPick-source.items-common), empty space otherwise. Tries to usetext
field as fallback for path. Default:false
. Note: MiniPick.builtin pickers showing file/directory paths usetrue
by default.<icons>
(table)
- table with fallback icons used if icon provider does not itself supply default icons for category. Can have fields:<directory>
(string)
- icon for directory. Default: “”.<file>
(string)
- icon for file. Default: “”.<none>
(string)
- icon for non-valid path. Default: ” “.
default_preview()
MiniPick.default_preview
({buf_id}, {item}, {opts})
Default preview
Preview item. Logic follows the rules in MiniPick-source.items-common:
File and buffer are shown at the start.
Directory has its content listed.
Line/position/region in file or buffer is shown at start.
Others are shown directly with vim.inspect().
Implements default value for MiniPick-source.preview.
Uses the following highlight groups (see mini.pick for their description):
MiniPickPreviewLine
MiniPickPreviewRegion
Parameters
{buf_id} (number)
Identifier of target buffer.
{item} (any)
Item to preview.
{opts} (table|nil)
Options. Possible values:
<n_context_lines>
(number)
- number of lines to load past target position when reading from disk. Useful to explore context. Default: ‘lines’ twice.<line_position>
(string)
- where in the window to show item position. One of “top”, “center”, “bottom”. Default: “top”.
default_choose()
MiniPick.default_choose
({item})
Default choose
Choose item. Logic follows the rules in MiniPick-source.items-common:
File uses bufadd() and sets cursor at the start of line/position/region.
Buffer is set as current in target window and sets cursor similarly.
Directory is called with :edit in the target window.
Others have the output of vim.inspect() printed in Command line.
Implements default value for MiniPick-source.choose.
Parameters
{item} (any)
Item to choose.
default_choose_marked()
MiniPick.default_choose_marked
({items}, {opts})
Default choose marked items
Choose marked items. Logic follows the rules in MiniPick-source.items-common:
If among items there is at least one file or buffer, quickfix list is opened with all file or buffer lines/positions/regions.
Otherwise, picker’s
source.choose
is called on the first item.
Implements default value for MiniPick-source.choose_marked.
Parameters
{items} (table)
Array of items to choose.
{opts} (table|nil)
Options. Possible fields:
- <list_type>
(string)
- which type of list to open. One of “quickfix” or “location”. Default: “quickfix”.
ui_select()
MiniPick.ui_select
({items}, {opts}, {on_choice}, {start_opts})
Select rewrite
Function which can be used to directly override vim.ui.select() to use ‘mini.pick’ for any “select” type of tasks. Set automatically in MiniPick.setup().
Implements required by vim.ui.select()
signature, with some differencies:
Allows
opts.preview_item
that returns an array of lines for item preview.Allows fourth
start_opts
argument to customize MiniPick.start() call.
Notes:
on_choice
is called when target window is current.
Usage
-- Customize with fourth argument inside a function wrapper
vim.ui.select = function(items, opts, on_choice)
local start_opts = { window = { config = { width = vim.o.columns } } }
return MiniPick.ui_select(items, opts, on_choice, start_opts)
end
To preserve original vim.ui.select()
:
local ui_select_orig = vim.ui.select
require('mini.pick').setup()
vim.ui.select = ui_select_orig
builtin
MiniPick.builtin
Table with built-in pickers
builtin.files()
MiniPick.builtin.files
({local_opts}, {opts})
Pick from files
Lists all files recursively in all subdirectories. Tries to use one of the CLI tools to create items (see MiniPick-cli-tools): rg
, fd
, git
. If none is present, uses fallback which utilizes vim.fs.dir().
To customize CLI tool search, either use tool’s global configuration approach or directly MiniPick.builtin.cli() with specific command.
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
- <tool>
(string)
- which tool to use. One of “rg”, “fd”, “git”, “fallback”. Default: whichever tool is present, trying in that same order.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.grep()
MiniPick.builtin.grep
({local_opts}, {opts})
Pick from pattern matches
Lists all pattern matches recursively in all subdirectories. Tries to use one of the CLI tools to create items (see MiniPick-cli-tools): rg
, git
. If none is present, uses fallback which utilizes vim.fs.dir() and Lua pattern matches (NOT recommended in large directories).
To customize CLI tool search, either use tool’s global configuration approach or directly MiniPick.builtin.cli() with specific command.
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
<tool>
(string)
- which tool to use. One of “rg”, “git”, “fallback”. Default: whichever tool is present, trying in that same order.<pattern>
(string)
- string pattern to search. If not given, asks user interactively with input().<globs>
(table)
- array of string glob patterns to restrict search to matching files. Supported only by “rg” and “git” tools, respects their specific glob syntax and effects. Default:{}
(no restriction). Example:{ '*.lua', 'lua/**' }
for Lua files and files in “lua” directory.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.grep_live()
MiniPick.builtin.grep_live
({local_opts}, {opts})
Pick from pattern matches with live feedback
Perform pattern matching treating prompt as pattern. Gives live feedback on which matches are found. Use MiniPick-actions-refine to revert to regular matching. Use <C-o>
to restrict search to files matching glob patterns. Tries to use one of the CLI tools to create items (see MiniPick-cli-tools): rg
, git
. If none is present, error is thrown (for performance reasons).
To customize search, use tool’s global configuration approach.
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
<tool>
(string)
- which tool to use. One of “rg”, “git”. Default: whichever tool is present, trying in that same order.<globs>
(table)
- array of string glob patterns to restrict search to matching files. Supported only by “rg” and “git” tools, respects their specific glob syntax and effects. Default:{}
(no restriction). Example:{ '*.lua', 'lua/**' }
for Lua files and files in “lua” directory. Use<C-o>
custom mapping to add glob to the array.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.help()
MiniPick.builtin.help
({local_opts}, {opts})
Pick from help tags
Notes:
- On choose directly executes :help command with appropriate modifier (none, :vertical, :tab). This is done through custom mappings named
show_help_in_{split,vsplit,tab}
. Notchoose_in_{split,vsplit,tab}
because there is no split guarantee (like if there is already help window opened).
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
- <default_split>
(string)
- direction of a split forchoose
action. One of “horizontal”, “vertical”, “tab”. Default: “horizontal”.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.buffers()
MiniPick.builtin.buffers
({local_opts}, {opts})
Pick from buffers
Notes:
There are not built-in mappings for buffer manipulation. Here is an example of how to call this function with mapping to wipeout the current item:
local wipeout_cur = function() vim.api.nvim_buf_delete(MiniPick.get_picker_matches().current.bufnr, {}) end local buffer_mappings = { wipeout = { char = '<C-d>', func = wipeout_cur } } MiniPick.builtin.buffers(local_opts, { mappings = buffer_mappings })
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
<include_current>
(boolean)
- whether to include current buffer in the output. Default:true
.<include_unlisted>
(boolean)
- whether to include unlisted-buffers in the output. Default:false
.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.cli()
MiniPick.builtin.cli
({local_opts}, {opts})
Pick from CLI output
Executes command line tool and constructs items based on its output. Uses MiniPick.set_picker_items_from_cli().
Example: MiniPick.builtin.cli({ command = { 'echo', 'a\nb\nc' } })
Parameters
{local_opts} (table|nil)
Options defining behavior of this particular picker. Possible fields:
<command>
(table)
- forwarded toset_picker_items_from_cli()
.<postprocess>
(function)
- forwarded toset_picker_items_from_cli()
.<spawn_opts>
(table)
- forwarded toset_picker_items_from_cli()
. Note: ifcwd
field is absent, it is inferred from MiniPick-source.cwd.
{opts} (table|nil)
Options forwarded to MiniPick.start().
builtin.resume()
MiniPick.builtin.resume
()
Resume latest picker
registry
MiniPick.registry
Picker registry
Place for users and extensions to manage pickers with their commonly used local options. By default contains all MiniPick.builtin pickers. All entries should accept only a single local_opts
table argument.
Serves as a source for :Pick command.
Customization examples:
-- Adding custom picker to pick `register` entries
MiniPick.registry.registry = function()
local items = vim.tbl_keys(MiniPick.registry)
table.sort(items)
local source = {items = items, name = 'Registry', choose = function() end}
local chosen_picker_name = MiniPick.start({ source = source })
if chosen_picker_name == nil then return end
return MiniPick.registry[chosen_picker_name]()
end
-- Make `:Pick files` accept `cwd`
MiniPick.registry.files = function(local_opts)
local opts = { source = { cwd = local_opts.cwd } }
local_opts.cwd = nil
return MiniPick.builtin.files(local_opts, opts)
end
get_picker_items()
MiniPick.get_picker_items
()
Get items of active picker
Return
(table|nil)
Picker items or nil
if no active picker.
See also
MiniPick.set_picker_items() and MiniPick.set_picker_items_from_cli()
get_picker_stritems()
MiniPick.get_picker_stritems
()
Get stritems of active picker
Return
(table|nil)
Picker stritems (MiniPick-source.items-stritems) or nil
if no active picker.
See also
MiniPick.set_picker_items() and MiniPick.set_picker_items_from_cli()
get_picker_matches()
MiniPick.get_picker_matches
()
Get matches of active picker
Return
(table|nil)
Picker matches or nil
if no active picker. Matches is a table with the following fields:
<all>
(table|nil)
- all currently matched items.<all_inds>
(table|nil)
- indexes of all currently matched items.<current>
(any)
- current matched item.<current_ind>
(number|nil)
- index of current matched item.<marked>
(table|nil)
- marked items.<marked_inds>
(table|nil)
- indexes of marked items.<shown>
(table|nil)
- shown items (from top to bottom).<shown_inds>
(table|nil)
- indexes of shown items (from top to bottom).
See also
MiniPick.set_picker_match_inds()
get_picker_opts()
MiniPick.get_picker_opts
()
Get config of active picker
Return
(table|nil)
Picker config (start()
’s input opts
table) or nil
if no active picker.
See also
get_picker_state()
MiniPick.get_picker_state
()
Get state data of active picker
Return
(table|nil)
Table with picker state data or nil
if no active picker. State data is a table with the following fields:
<buffers>
(table)
- table withmain
,preview
,info
fields representing buffer identifier (ornil
) for corresponding view.<windows>
(table)
- table withmain
andtarget
fields representing window identifiers for main and target windows.<caret>
(number)
- caret column.<is_busy>
(boolean)
- whether picker is busy with computations.
See also
MiniPick.set_picker_target_window()
get_picker_query()
MiniPick.get_picker_query
()
Get query of active picker
Return
(table|nil)
Array of picker query or nil
if no active picker.
See also
set_picker_items()
MiniPick.set_picker_items
({items}, {opts})
Set items for active picker
Note: sets items asynchronously in non-blocking fashion.
Parameters
{items} (table)
Array of items.
{opts} (table|nil)
Options. Possible fields:
<do_match>
(boolean)
- whether to perform match after setting items. Default:true
.<querytick>
(number|nil)
- value of querytick (MiniPick.get_querytick()) to periodically check against when setting items. If checked querytick differs from supplied, no items are set.
See also
MiniPick.get_picker_items() and MiniPick.get_picker_stritems()
set_picker_items_from_cli()
MiniPick.set_picker_items_from_cli
({command}, {opts})
Set items for active picker based on CLI output
Asynchronously executes command
and sets items to its postprocessed output.
Example:
local items = vim.schedule_wrap(function()
MiniPick.set_picker_items_from_cli({ 'echo', 'a\nb\nc' })
end)
MiniPick.start({ source = { items = items, name = 'Echo abc' } })
Parameters
{command} (table)
Array with (at least one) string command parts.
{opts} (table|nil)
Options. Possible fields:
<postprocess>
(function)
- callable performing postprocessing of output. Will be called with array of lines as input, should return array of items. Default: removes trailing empty lines and uses rest as string items.<spawn_opts>
(table)
-options
for uv.spawn(), exceptargs
andstdio
. Note: relativecwd
path is resolved against active picker’scwd
.<set_items_opts>
(table)
- table forwarded to MiniPick.set_picker_items().
See also
MiniPick.get_picker_items() and MiniPick.get_picker_stritems()
set_picker_match_inds()
MiniPick.set_picker_match_inds
({match_inds}, {match_type})
Set match indexes for active picker
There are two intended use cases:
Inside custom asynchronous MiniPick-source.match function to set which of picker’s stritems match the query. See MiniPick.poke_is_picker_active().
To programmatically set current match and marked items. See MiniPick.get_picker_matches().
Parameters
{match_inds} (table)
Array of numbers with picker’s items indexes.
{match_type} (string|nil)
Type of match indexes to set. One of:
"all"
(default) - indexes of items that match query."current"
- index of current match. Only first element is used and should also be present among query matches."marked"
- indexes of marked items. Values can be not among query matches. Will make only input indexes be marked, i.e. current marks are reset. Note: no"shown"
match type as those indexes are computed automatically.
See also
set_picker_opts()
MiniPick.set_picker_opts
({opts})
Set config for active picker
Parameters
{opts} (table)
Table overriding initial opts
input of MiniPick.start().
See also
set_picker_target_window()
MiniPick.set_picker_target_window
({win_id})
Set target window for active picker
Parameters
{win_id} (number)
Valid window identifier to be used as the new target window.
See also
set_picker_query()
MiniPick.set_picker_query
({query})
Set query for active picker
Parameters
{query} (table)
Array of strings to be set as the new picker query.
See also
get_querytick()
MiniPick.get_querytick
()
Get query tick
Query tick is a unique query identifier. Intended to be used to detect user activity during and between MiniPick.start() calls for efficient non-blocking functionality. Updates after any query change, picker start and stop.
See MiniPick.poke_is_picker_active() for usage example.
Return
(number)
Query tick.
is_picker_active()
MiniPick.is_picker_active
()
Check if there is an active picker
Return
(boolean)
Whether there is currently an active picker.
See also
MiniPick.poke_is_picker_active()
poke_is_picker_active()
MiniPick.poke_is_picker_active
()
Poke if picker is active
Intended to be used for non-blocking implementation of source methods. Returns an output of MiniPick.is_picker_active(), but depending on whether there is a coroutine running:
If no, return it immediately.
If yes, return it after
coroutine.yield()
withcoroutine.resume()
called “soon” by the main event-loop (see vim.schedule()).
Example of non-blocking exact match
(as demo; can be optimized further):
local match_nonblock = function(match_inds, stritems, query)
local prompt, querytick = table.concat(query), MiniPick.get_querytick()
local f = function()
local res = {}
for _, ind in ipairs(match_inds) do
local should_stop = not MiniPick.poke_is_picker_active() or
MiniPick.get_querytick() ~= querytick
if should_stop then return end
if stritems[ind]:find(prompt) ~= nil then table.insert(res, ind) end
end
MiniPick.set_picker_match_inds(res)
end
coroutine.resume(coroutine.create(f))
end
Return
(boolean)
Whether there is an active picker.