nvim-deck : A plugin for displaying, filtering, and selecting items from customizable lists.
Open project files
CleanShot.2024-12-08.at.11.24.57.mp4
Grep and Replace
CleanShot.2024-12-08.at.11.45.57.mp4
Git integration
CleanShot.2024-12-08.at.12.01.21.mp4
nvim-deck revolves around four core concepts:
- Source:
- A source provides a list of items to display.
- Item:
- An item represents a single entry from the source, containing data and display text.
- Action:
- Actions define what happens when the user interacts with an item.
- Context:
- Context represents the current state, The user can control deck UI via invoke context methods.
- Built-in Git integration.
:Deck git
to open the git launcher.
- Built-in ripgrep integration.
:Deck grep
to start a grep search.
- Built-in file listing.
:Deck files
to show files under the root directory (ripgrep
,PureLua
).
- Highly customizable: sources, actions, previewers, decorators, views, and matchers.
- Use normal-window by default
- IMO, floating-window is fancy but normal window is more handy for edit & preview.
- UX focused
- Use
vim.wait
carefully, it makes a crisp and smooth experience.
- Use
- Configuration over Object control
nvim-deck
does not require huge setup functions- Instead of this, nvim-deck allows you to customize by controlling |deck.Context| object.
- Neovim stable or later
- ripgrep: grep and finding files
- folke/snacks.nvim: previewing images
- echasnovski/mini.icons: file icons
- Nerd Fonts: icons
Here’s an example of how to set up nvim-deck
:
local deck = require('deck')
-- Apply pre-defined easy settings.
-- For manual configuration, refer to the code in `deck/easy.lua`.
require('deck.easy').setup()
-- Set up buffer-specific key mappings for nvim-deck.
vim.api.nvim_create_autocmd('User', {
pattern = 'DeckStart',
callback = function(e)
local ctx = e.data.ctx --[[@as deck.Context]]
ctx.keymap('n', '<Tab>', deck.action_mapping('choose_action'))
ctx.keymap('n', '<C-l>', deck.action_mapping('refresh'))
ctx.keymap('n', 'i', deck.action_mapping('prompt'))
ctx.keymap('n', 'a', deck.action_mapping('prompt'))
ctx.keymap('n', '@', deck.action_mapping('toggle_select'))
ctx.keymap('n', '*', deck.action_mapping('toggle_select_all'))
ctx.keymap('n', 'p', deck.action_mapping('toggle_preview_mode'))
ctx.keymap('n', 'd', deck.action_mapping('delete'))
ctx.keymap('n', '<CR>', deck.action_mapping('default'))
ctx.keymap('n', 'o', deck.action_mapping('open'))
ctx.keymap('n', 'O', deck.action_mapping('open_keep'))
ctx.keymap('n', 's', deck.action_mapping('open_split'))
ctx.keymap('n', 'v', deck.action_mapping('open_vsplit'))
ctx.keymap('n', 'N', deck.action_mapping('create'))
ctx.keymap('n', 'w', deck.action_mapping('write'))
ctx.keymap('n', '<C-u>', deck.action_mapping('scroll_preview_up'))
ctx.keymap('n', '<C-d>', deck.action_mapping('scroll_preview_down'))
-- If you want to start the filter by default, call ctx.prompt() here
ctx.prompt()
end
})
--key-mapping for explorer source (requires `require('deck.easy').setup()`).
vim.api.nvim_create_autocmd('User', {
pattern = 'DeckStart:explorer',
callback = function(e)
local ctx = e.data.ctx --[[@as deck.Context]]
ctx.keymap('n', 'h', deck.action_mapping('explorer.collapse'))
ctx.keymap('n', 'l', deck.action_mapping('explorer.expand'))
ctx.keymap('n', '.', deck.action_mapping('explorer.toggle_dotfiles'))
ctx.keymap('n', 'c', deck.action_mapping('explorer.clipboard.save_copy'))
ctx.keymap('n', 'm', deck.action_mapping('explorer.clipboard.save_move'))
ctx.keymap('n', 'p', deck.action_mapping('explorer.clipboard.paste'))
ctx.keymap('n', 'x', deck.action_mapping('explorer.clipboard.paste'))
ctx.keymap('n', '<Leader>ff', deck.action_mapping('explorer.dirs'))
ctx.keymap('n', 'P', deck.action_mapping('toggle_preview_mode'))
ctx.keymap('n', '~', function()
ctx.do_action('explorer.get_api').set_cwd(vim.fs.normalize('~'))
end)
ctx.keymap('n', '\\', function()
ctx.do_action('explorer.get_api').set_cwd(vim.fs.normalize('/'))
end)
end
})
-- Example key bindings for launching nvim-deck sources. (These mapping required `deck.easy` calls.)
vim.keymap.set('n', '<Leader>ff', '<Cmd>Deck files<CR>', { desc = 'Show recent files, buffers, and more' })
vim.keymap.set('n', '<Leader>gr', '<Cmd>Deck grep<CR>', { desc = 'Start grep search' })
vim.keymap.set('n', '<Leader>gi', '<Cmd>Deck git<CR>', { desc = 'Open git launcher' })
vim.keymap.set('n', '<Leader>he', '<Cmd>Deck helpgrep<CR>', { desc = 'Live grep all help tags' })
-- Show the latest deck context.
vim.keymap.set('n', '<Leader>;', function()
local context = deck.get_history()[vim.v.count == 0 and 1 or vim.v.count]
if context then
context.show()
end
end)
-- Do default action on next item.
vim.keymap.set('n', '<Leader>n', function()
local ctx = require('deck').get_history()[1]
if ctx then
ctx.set_cursor(ctx.get_cursor() + 1)
ctx.do_action('default')
end
end)
If you create nvim-deck source or action, we recommend to follow guidelines.
nvim-deck supports the concept of duck-typing.
So if your custom source has source-specific actions, you should register alias actions for them.
- default
- create
- delete
- rename
- write
- refresh
- open
- open_split
- open_vsplit
The source definition looks like this:
source = {
...
actions = {
deck.alias_action('default', 'source.default'),
{
name = 'source.default',
execute = ...
}
}
...
}
The source.default
action will be shown in action picker. The user can have a
unified experience across many different sources just by writing
ctx.keymap('n', '<CR>', deck.action_mapping('default'))
.
!!! We strongly recommend using lua-language-server
!!!
You can customize your nvim-deck appearance.
- guicursor
require('deck').setup({
guicursor = 'a:ver25',
})
- winhighlight
vim.api.nvim_create_autocmd('User', {
group = misc.group,
pattern = 'DeckShow',
callback = function()
vim.wo.winhighlight = 'CursorLine:Visual'
end
})
The source is typed as |deck.Source|. The source can be executed by
deck.start()
.
The source can specify source-level actions, decorators, and previewers.
require('deck').start({
name = 'my_source',
execute = function(ctx)
ctx.item({
display_text = 'Hello, World!',
})
ctx.done()
end,
actions = {
...
},
decorators = {
...
},
previewers = {
...
},
})
The action is typed as |deck.Action| and can be registered below three different levels.
- Config Action : Provided by a start configuration.
This level can be registered by start_config.actions
field.
require('deck').start(some_of_the_source, {
actions = {
{
name = 'my_open',
execute = function(ctx)
-- some of the process.
end
}
}
})
- Source Action : Provided by a source.
This level of actions can be registered by source.actions
field.
require('deck').start({
name = 'my_source',
...
actions = {
{
name = 'my_open',
execute = function(ctx)
-- some of the process.
end
}
}
})
- Global Action : Registered globally.
This level of actions can be registered by deck.register_action()
.
require('deck').register_action({
name = 'my_open',
resolve = function(ctx)
-- Action is available only if there is exactly one action item with a filename.
return #ctx.get_action_items() == 1 and ctx.get_action_items()[1].data.filename
end,
execute = function(ctx)
-- Open the file.
vim.cmd.edit(ctx.get_action_items()[1].data.filename)
end
})
Note: The same name actions are choosen in the order of 1 -> 2 -> 3.
The start-preset is typed as |deck.StartPreset| and can be registered globally.
A start-preset in nvim-deck
allows you to define shortcut command. In the
below example, you can use :Deck recent
command.
-- After registration, you can start the preset using the `:Deck recent` command.
require('deck').register_start_preset('recent', {
require('deck').start({
require('deck.builtin.source.recent_files')(),
require('deck.builtin.source.buffers')(),
})
})
nvim-deck
has decorator
concept. It's designed to decorate the deck-buffer
via nvim_buf_set_extmark
. The below example shows how to create your own
decorator.
--- This is example decorator.
--- To display the basename of the file and dirname as a comment.
--- This decorator highlight basename and make dirname less noticeable.
require('deck').register_decorator({
name = 'basename_dirname',
resolve = function(_, item)
-- This decorator is available only if the item has a filename.
return item.data.filename
end,
decorate = function(ctx, item, row)
local dirname = vim.fn.fnamemodify(item.data.filename, ':~:h')
local display_text = item.display_text
local s, e = display_text:find(dirname, 1, true)
if s then
return {
-- Hide the directory part (using conceal)
{
row = row,
col = s - 1,
end_row = row,
end_col = e + 1,
conceal = '',
ephemeral = true,
},
-- Display the directory name as a comment at the end of the line
{
row = row,
col = 0,
virt_text = { { dirname, 'Comment' } },
virt_text_pos = 'eol'
}
}
end
return {}
end
})
nvim-deck
has previewer
concept. It's designed to show the item preview.
require('deck').register_previewer({
name = 'bat',
resolve = function(_, item)
return item.data.filename and vim.fn.filereadable(item.data.filename) == 1
end,
preview = function(_, item, env)
vim.api.nvim_win_call(env.win, function()
vim.fn.termopen(('bat --color=always %s'):format(item.data.filename))
end)
end
})
Show buffers.
Name | Type | Default | Description |
---|---|---|---|
ignore_paths | string[]? | [vim.fn.expand('%:p')] | Ignore paths. The default value is intented to hide current buffer. |
nofile | boolean? | false | Ignore nofile buffers. |
deck.start(require('deck.builtin.source.buffers')({
ignore_paths = { vim.fn.expand('%:p'):gsub('/$', '') },
nofile = false,
}))
Show available actions from |deck.Context|
Name | Type | Default | Description |
---|---|---|---|
context | |deck.Context| |
deck.start(require('deck.builtin.source.deck.actions')({
context = context
}))
Show deck.start history.
No options
deck.start(require('deck.builtin.source.deck.history')())
Show deck.notify history.
No options
deck.start(require('deck.builtin.source.deck.notify')())
Show dirs under specified root directory.
Name | Type | Default | Description |
---|---|---|---|
ignore_globs | string[]? | [] | Ignore glob patterns. |
root_dir | string | Target root directory. |
deck.start(require('deck.builtin.source.dirs')({
root_dir = vim.fn.getcwd(),
ignore_globs = { '**/node_modules/', '**/.git/' },
}))
Explorer source.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target directory. | |
mode | 'drawer' | 'filer' | Mode of explorer. | |
min_width | number | Minimum explorer window size. | |
narrow | { enabled?: boolean, ignore_globs?: string[] } | Narrow finder options. | |
reveal | string | Reveal target path. |
To use explorer, you must set `start_preset` or use `require('deck.easy').setup()`.
If you call `require('deck.easy').setup()`, then you can use explorer by `:Deck explorer` command.
Show files under specified root directory.
Name | Type | Default | Description |
---|---|---|---|
ignore_globs | string[]? | [] | Ignore glob patterns. |
root_dir | string | Target root directory. |
deck.start(require('deck.builtin.source.files')({
root_dir = vim.fn.getcwd(),
ignore_globs = { '**/node_modules/', '**/.git/' },
}))
Show git launcher.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. |
deck.start(require('deck.builtin.source.git.changeset')({
cwd = vim.fn.getcwd(),
}))
Show git branches
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. |
deck.start(require('deck.builtin.source.git.branch')({
cwd = vim.fn.getcwd()
}))
Show git changeset for specified revision.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. | |
from_rev | string | From revision. | |
to_rev | string? | To revision. If you omit this option, it will be HEAD. |
deck.start(require('deck.builtin.source.git.changeset')({
cwd = vim.fn.getcwd(),
from_rev = 'HEAD~3',
to_rev = 'HEAD'
}))
Show git log.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. | |
max_count | integer? | Max count for log |
deck.start(require('deck.builtin.source.git.log')({
cwd = vim.fn.getcwd(),
}))
Show git reflog.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. | |
max_count | integer? | Max count for reflog |
deck.start(require('deck.builtin.source.git.reflog')({
cwd = vim.fn.getcwd(),
}))
Show git remotes.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. |
deck.start(require('deck.builtin.source.git.remote')({
cwd = vim.fn.getcwd(),
}))
Show git status.
Name | Type | Default | Description |
---|---|---|---|
cwd | string | Target git root. |
deck.start(require('deck.builtin.source.git.status')({
cwd = vim.fn.getcwd(),
}))
Grep files under specified root directory. (required ripgrep
)
Name | Type | Default | Description |
---|---|---|---|
root_dir | string | Target root directory. | |
ignore_globs | string[]? | [] | Ignore glob patterns. |
deck.start(require('deck.builtin.source.grep')({
root_dir = vim.fn.getcwd(),
pattern = vim.fn.input('grep: '),
ignore_globs = { '**/node_modules/', '**/.git/' },
}))
Live grep all helptags. (required ripgrep
)
No options
deck.start(require('deck.builtin.source.helpgrep')())
Listing any provided items.
Name | Type | Default | Description |
---|---|---|---|
items | string[]|deck.ItemSpecifier[] | Items to list. |
deck.start(require('deck.builtin.source.items')({
items = vim.iter(vim.api.nvim_list_bufs()):map(function(buf)
return ('#%s'):format(buf)
end):totable()
}))
Show buffer lines.
No options
deck.start(require('deck.builtin.source.lines')({
bufnrs = { vim.api.nvim_get_current_buf() },
}))
List recent directories.
Name | Type | Default | Description |
---|---|---|---|
ignore_paths | string[]? | [] | Ignore paths. |
require('deck.builtin.source.recent_dirs'):setup({
path = '~/.deck.recent_dirs'
})
vim.api.nvim_create_autocmd('DirChanged', {
callback = function(e)
require('deck.builtin.source.recent_dirs'):add(e.cwd)
end,
})
deck.start(require('deck.builtin.source.recent_dirs')({
ignore_paths = { '**/node_modules/', '**/.git/' },
}))
List recent files.
Name | Type | Default | Description |
---|---|---|---|
ignore_paths | string[]? | [] | Ignore paths. |
require('deck.builtin.source.recent_files'):setup({
path = '~/.deck.recent_files'
})
vim.api.nvim_create_autocmd('BufEnter', {
callback = function()
local bufname = vim.api.nvim_buf_get_name(0)
if vim.fn.filereadable(bufname) == 1 then
require('deck.builtin.source.recent_files'):add(vim.fs.normalize(bufname))
end
end,
})
deck.start(require('deck.builtin.source.recent_files')({
ignore_paths = { '**/node_modules/', '**/.git/' },
}))
-
choose_action
-
Open action source.
The actions listed are filtered by whether they are valid in the current context.
-
-
delete_buffer
-
Delete
item.data.bufnr
from buffers list.If multiple items are selected, they will be deleted in order.
-
-
delete_file
-
Delete
item.data.filename
from filesystem.If multiple items are selected, they will be deleted in order.
-
-
open
-
Open
item.data.filename
oritem.data.bufnr
.Open at the recently normal window.
-
-
open_keep
-
Open
item.data.filename
oritem.data.bufnr
.But keep the deck window and cursor.
-
-
open_split
-
Open
item.data.filename
oritem.data.bufnr
.Open at the recently normal window with split.
-
-
open_split_keep
-
Open
item.data.filename
oritem.data.bufnr
.Open at the recently normal window with split. But keep the deck window and cursor.
-
-
open_tabnew
-
Open
item.data.filename
oritem.data.bufnr
.Open at the new tabpage.
-
-
open_vsplit
-
Open
item.data.filename
oritem.data.bufnr
.Open at the recently normal window with vsplit.
-
-
open_vsplit_keep
-
Open
item.data.filename
oritem.data.bufnr
.Open at the recently normal window with vsplit. But keep the deck window and cursor.
-
-
print
- Print selected items.
-
prompt
- Open filtering prompt
-
refresh
- Re-execute source. (it can be used to refresh the items)
-
scroll_preview_down
- Scroll preview window down.
-
scroll_preview_up
- Scroll preview window up.
-
substitute
-
Open substitute buffer with selected items (
item.data.filename
anditem.data.lnum
are required).You can modify and save the buffer to reflect the changes to the original files.
-
-
toggle_preview_mode
- Toggle preview mode
-
toggle_select
- Toggle selected state of the cursor item.
-
toggle_select_all
- Toggle selected state of all items.
-
write_buffer
- Write modified
item.data.bufnr
oritem.data.filename
that has buffer.
- Write modified
-
yank
- Yank item.display_text field to default register.
-
DeckHide
- Triggered after deck window hidden.
-
DeckShow
- Triggered after deck window shown.
-
DeckStart
- Triggered when deck starts.
-
DeckStart:{source.name}
- Triggered when deck starts for source.
Create action mapping function for ctx.keymap.
Name | Type | Description |
---|---|---|
action_names | string|string[] | action name or action names to use for mappings. |
Â
Create alias action.
Name | Type | Description |
---|---|---|
alias_name | string | new action name. |
alias_action_name | string | existing action name. |
Â
Get all registered actions.
No arguments Â
Get all registered decorators.
No arguments Â
Get all history (first history is latest).
No arguments Â
Get all registered previewers.
No arguments Â
Get all registered start presets.
No arguments Â
Register action.
Name | Type | Description |
---|---|---|
action | |deck.Action| | action to register. |
Â
Register decorator.
Name | Type | Description |
---|---|---|
decorator | |deck.Decorator| | decorator to register. |
Â
Register previewer.
Name | Type | Description |
---|---|---|
previewer | |deck.Previewer| | previewer to register. |
Â
Register start_preset.
Name | Type | Description |
---|---|---|
name | string | preset name. |
start_fn | fun() | Start function. |
Â
Register start_preset.
Name | Type | Description |
---|---|---|
start_preset | deck.StartPreset | |deck.StartPreset| |
Â
Remove specific action.
Name | Type | Description |
---|---|---|
predicate | fun(action: |deck.Action|): boolean | Predicate function. If return true, remove action. |
Â
Remove specific decorator.
Name | Type | Description |
---|---|---|
predicate | fun(decorator: |deck.Decorator|): boolean | Predicate function. If return true, remove decorator. |
Â
Remove previewer.
Name | Type | Description |
---|---|---|
predicate | fun(previewer: |deck.Previewer|): boolean | Predicate function. If return true, remove previewer. |
Â
Remove specific start_preset.
Name | Type | Description |
---|---|---|
predicate | fun(start_preset: |deck.StartPreset|): boolean | Predicate function. If return true, remove start_preset. |
Â
Setup deck globally.
Name | Type | Description |
---|---|---|
config | deck.ConfigSpecifier | Setup deck configuration. |
Â
Start deck with given sources.
Name | Type | Description |
---|---|---|
source | deck.Source|deck.Source[] | source or sources to start. |
start_config | deck.StartConfigSpecifier | start configuration. |
Â
*deck.Action*
---@class deck.Action
---@field public name string
---@field public desc? string
---@field public hidden? boolean
---@field public resolve? deck.ActionResolveFunction
---@field public execute deck.ActionExecuteFunction
*deck.Config*
---@class deck.Config: deck.ConfigSpecifier
---@field public guicursor? string
---@field public max_history_size integer
---@field public default_start_config? deck.StartConfigSpecifier
*deck.ConfigSpecifier*
---@class deck.ConfigSpecifier
---@field public guicursor? string
---@field public max_history_size? integer
---@field public default_start_config? deck.StartConfigSpecifier
*deck.Context*
---@class deck.Context
---@field id integer
---@field ns integer
---@field buf integer
---@field name string
---@field get_config fun(): deck.StartConfig
---@field execute fun()
---@field is_visible fun(): boolean
---@field show fun()
---@field hide fun()
---@field focus fun()
---@field prompt fun()
---@field scroll_preview fun(delta: integer)
---@field get_status fun(): deck.Context.Status
---@field is_filtering fun(): boolean
---@field is_syncing fun(): boolean
---@field get_cursor fun(): integer
---@field set_cursor fun(cursor: integer)
---@field get_query fun(): string
---@field set_query fun(query: string)
---@field get_matcher_query fun(): string
---@field get_dynamic_query fun(): string
---@field set_selected fun(item: deck.Item, selected: boolean)
---@field get_selected fun(item: deck.Item): boolean
---@field set_select_all fun(select_all: boolean)
---@field get_select_all fun(): boolean
---@field set_preview_mode fun(preview_mode: boolean)
---@field get_preview_mode fun(): boolean
---@field get_items fun(): deck.Item[]
---@field get_cursor_item fun(): deck.Item?
---@field get_action_items fun(): deck.Item[]
---@field get_filtered_items fun(): deck.Item[]
---@field get_rendered_items fun(): deck.Item[]
---@field get_selected_items fun(): deck.Item[]
---@field get_actions fun(): deck.Action[]
---@field get_decorators fun(): deck.Decorator[]
---@field get_previewer fun(): deck.Previewer?
---@field sync fun()
---@field keymap fun(mode: string|string[], lhs: string, rhs: fun(ctx: deck.Context))
---@field do_action fun(name: string): any
---@field dispose fun()
---@field disposed fun(): boolean
---@field on_dispose fun(callback: fun()): fun()
---@field on_redraw fun(callback: fun())
---@field on_show fun(callback: fun())
---@field on_hide fun(callback: fun())
*deck.Decoration*
---@class deck.Decoration
---@field public col? integer
---@field public end_col? integer
---@field public hl_group? string
---@field public hl_eol? boolean
---@field public virt_text? deck.VirtualText[]
---@field public virt_text_pos? 'eol' | 'overlay' | 'right_align' | 'inline'
---@field public virt_text_win_col? integer
---@field public virt_text_hide? boolean
---@field public virt_text_repeat_linebreak? boolean
---@field public virt_lines? deck.VirtualText[][]
---@field public virt_lines_above? boolean
---@field public ephemeral? boolean
---@field public priority? integer
---@field public sign_text? string
---@field public sign_hl_group? string
---@field public number_hl_group? string
---@field public line_hl_group? string
---@field public conceal? string
*deck.Decorator*
---@class deck.Decorator
---@field public name string
---@field public dynamic? boolean
---@field public resolve? deck.DecoratorResolveFunction
---@field public decorate deck.DecoratorDecorateFunction
*deck.ExecuteContext*
---@class deck.ExecuteContext
---@field public item fun(item: deck.ItemSpecifier)
---@field public done fun( )
---@field public queue fun(task: fun())
---@field public get_query fun(): string
---@field public get_config fun(): deck.StartConfig
---@field public aborted fun(): boolean
---@field public on_abort fun(callback: fun())
*deck.Item*
---@class deck.Item: deck.ItemSpecifier
---@field public display_text string
---@field public data table
*deck.ItemSpecifier*
---@class deck.ItemSpecifier
---@field public display_text string|(deck.VirtualText[])
---@field public highlights? deck.Highlight[]
---@field public filter_text? string
---@field public dedup_id? string
---@field public data? table
*deck.PerformanceConfig*
---@class deck.PerformanceConfig
---@field public sync_timeout_ms integer
---@field public gather_budget_ms integer
---@field public gather_batch_size integer
---@field public gather_interrupt_ms integer
---@field public filter_bugdet_ms integer
---@field public filter_batch_size integer
---@field public filter_interrupt_ms integer
---@field public render_bugdet_ms integer
---@field public render_batch_size integer
---@field public render_interrupt_ms integer
---@field public render_delay_ms integer
*deck.Previewer*
---@class deck.Previewer
---@field public name string
---@field public priority? integer
---@field public resolve? deck.PreviewerResolveFunction
---@field public preview deck.PreviewerPreviewFunction
*deck.Source*
---@class deck.Source
---@field public name string
---@field public dynamic? boolean
---@field public events? { Start?: fun(ctx: deck.Context), BufWinEnter?: fun(ctx: deck.Context, env: { first: boolean }) }
---@field public execute deck.SourceExecuteFunction
---@field public actions? deck.Action[]
---@field public decorators? deck.Decorator[]
---@field public previewers? deck.Previewer[]
---@field public parse_query? deck.ParseQuery
*deck.StartConfig*
---@class deck.StartConfig: deck.StartConfigSpecifier
---@field public name string
---@field public view fun(): deck.View
---@field public matcher deck.Matcher
---@field public history boolean
---@field public performance deck.PerformanceConfig
---@field public disable_actions? string[]
---@field public disable_decorators? string[]
---@field public disable_previewers? string[]
---@field public dedup boolean
---@field public query string
*deck.StartConfigSpecifier*
---@class deck.StartConfigSpecifier
---@field public name? string
---@field public view? fun(): deck.View
---@field public matcher? deck.Matcher
---@field public history? boolean
---@field public actions? deck.Action[]
---@field public decorators? deck.Decorator[]
---@field public previewers? deck.Previewer[]
---@field public performance? deck.PerformanceConfig|{}
---@field public disable_actions? string[]
---@field public disable_decorators? string[]
---@field public disable_previewers? string[]
---@field public dedup? boolean
---@field public query? string
---@field public auto_abort? boolean
*deck.StartPreset*
---@class deck.StartPreset
---@field public name string
---@field public args? table<string|integer, { complete?: (fun(prefix: string):string[]), required?: boolean }>
---@field public start fun(args: table<string|integer, string>)
*deck.View*
---@class deck.View
---@field public get_win fun(): integer?
---@field public is_visible fun(ctx: deck.Context): boolean
---@field public show fun(ctx: deck.Context)
---@field public hide fun(ctx: deck.Context)
---@field public redraw fun(ctx: deck.Context)
---@field public prompt fun(ctx: deck.Context)
---@field public scroll_preview fun(ctx: deck.Context, delta: integer)