A collection of small QoL plugins for Neovim.
| Snack | Description | Setup |
|---|---|---|
| animate | Efficient animations including over 45 easing functions (library) | |
| bigfile | Deal with big files | |
| bufdelete | Delete buffers without disrupting window layout | |
| dashboard | Beautiful declarative dashboards | |
| debug | Pretty inspect & backtraces for debugging | |
| dim | Focus on the active scope by dimming the rest | |
| explorer | A file explorer (picker in disguise) | |
| gh | GitHub CLI integration | |
| git | Git utilities | |
| gitbrowse | Open the current file, branch, commit, or repo in a browser (e.g. GitHub, GitLab, Bitbucket) | |
| image | Image viewer using Kitty Graphics Protocol, supported by kitty, wezterm and ghostty | |
| indent | Indent guides and scopes | |
| input | Better vim.ui.input | |
| keymap | Better vim.keymap with support for filetypes and LSP clients | |
| layout | Window layouts | |
| lazygit | Open LazyGit in a float, auto-configure colorscheme and integration with Neovim | |
| notifier | Pretty vim.notify | |
| notify | Utility functions to work with Neovim's vim.notify | |
| picker | Picker for selecting items | |
| profiler | Neovim lua profiler | |
| quickfile | When doing nvim somefile.txt, it will render the file as quickly as possible, before loading your plugins. | |
| rename | LSP-integrated file renaming with support for plugins like neo-tree.nvim and mini.files. | |
| scope | Scope detection, text objects and jumping based on treesitter or indent | |
| scratch | Scratch buffers with a persistent file | |
| scroll | Smooth scrolling | |
| statuscolumn | Pretty status column | |
| terminal | Create and toggle floating/split terminals | |
| toggle | Toggle keymaps integrated with which-key icons / colors | |
| util | Utility functions for Snacks (library) | |
| win | Create and manage floating windows or splits | |
| words | Auto-show LSP references and quickly navigate between them | |
| zen | Zen mode • distraction-free coding |
- Neovim >= 0.9.4
- for proper icons support:
- mini.icons(optional)
- nvim-web-devicons(optional)
- a Nerd Font(optional)
Install the plugin with your package manager:
Important
A couple of plugins requiresnacks.nvim to be set-up early.
Setup creates some autocmds and does not load any plugins.
Check the code to see what it does.
Caution
You need to explicitly pass options for a plugin or set enabled = true to enable it.
Tip
It's a good idea to run :checkhealth snacks to see if everything is set up correctly.
{
"folke/snacks.nvim",
priority=1000,
lazy=false,
---@typesnacks.Configopts= {
-- your configuration comes here-- or leave it empty to use the default settings-- refer to the configuration section belowbigfile= { enabled=true },
dashboard= { enabled=true },
explorer= { enabled=true },
indent= { enabled=true },
input= { enabled=true },
picker= { enabled=true },
notifier= { enabled=true },
quickfile= { enabled=true },
scope= { enabled=true },
scroll= { enabled=true },
statuscolumn= { enabled=true },
words= { enabled=true },
},
}For an in-depth setup of snacks.nvim with lazy.nvim, check the example below.
Please refer to the readme of each plugin for their specific configuration.
Default Options
---@classsnacks.Config---@fieldanimate? snacks.animate.Config---@fieldbigfile? snacks.bigfile.Config---@fielddashboard? snacks.dashboard.Config---@fielddim? snacks.dim.Config---@fieldexplorer? snacks.explorer.Config---@fieldgh? snacks.gh.Config---@fieldgitbrowse? snacks.gitbrowse.Config---@fieldimage? snacks.image.Config---@fieldindent? snacks.indent.Config---@fieldinput? snacks.input.Config---@fieldlayout? snacks.layout.Config---@fieldlazygit? snacks.lazygit.Config---@fieldnotifier? snacks.notifier.Config---@fieldpicker? snacks.picker.Config---@fieldprofiler? snacks.profiler.Config---@fieldquickfile? snacks.quickfile.Config---@fieldscope? snacks.scope.Config---@fieldscratch? snacks.scratch.Config---@fieldscroll? snacks.scroll.Config---@fieldstatuscolumn? snacks.statuscolumn.Config---@fieldterminal? snacks.terminal.Config---@fieldtoggle? snacks.toggle.Config---@fieldwin? snacks.win.Config---@fieldwords? snacks.words.Config---@fieldzen? snacks.zen.Config---@fieldstyles? table<string, snacks.win.Config>---@fieldimage? snacks.image.Config|{}
{
image= {
-- define these here, so that we don't need to load the image moduleformats= {
"png",
"jpg",
"jpeg",
"gif",
"bmp",
"webp",
"tiff",
"heic",
"avif",
"mp4",
"mov",
"avi",
"mkv",
"webm",
"pdf",
"icns",
},
},
}Some plugins have examples in their documentation. You can include them in your config like this:
{
dashboard= { example="github" }
}If you want to customize options for a plugin after they have been resolved, you
can use the config function:
{
gitbrowse= {
config=function(opts, defaults)
table.insert(opts.remote_patterns, { "my", "custom pattern" })
end
},
}See the example below for how to configure snacks.nvim.
{
"folke/snacks.nvim",
priority=1000,
lazy=false,
---@typesnacks.Configopts= {
bigfile= { enabled=true },
dashboard= { enabled=true },
explorer= { enabled=true },
indent= { enabled=true },
input= { enabled=true },
notifier= {
enabled=true,
timeout=3000,
},
picker= { enabled=true },
quickfile= { enabled=true },
scope= { enabled=true },
scroll= { enabled=true },
statuscolumn= { enabled=true },
words= { enabled=true },
styles= {
notification= {
-- wo = { wrap = true } -- Wrap notifications
}
}
},
keys= {
-- Top Pickers & Explorer
{ "<leader><space>", function() Snacks.picker.smart() end, desc="Smart Find Files" },
{ "<leader>,", function() Snacks.picker.buffers() end, desc="Buffers" },
{ "<leader>/", function() Snacks.picker.grep() end, desc="Grep" },
{ "<leader>:", function() Snacks.picker.command_history() end, desc="Command History" },
{ "<leader>n", function() Snacks.picker.notifications() end, desc="Notification History" },
{ "<leader>e", function() Snacks.explorer() end, desc="File Explorer" },
-- find
{ "<leader>fb", function() Snacks.picker.buffers() end, desc="Buffers" },
{ "<leader>fc", function() Snacks.picker.files({ cwd=vim.fn.stdpath("config") }) end, desc="Find Config File" },
{ "<leader>ff", function() Snacks.picker.files() end, desc="Find Files" },
{ "<leader>fg", function() Snacks.picker.git_files() end, desc="Find Git Files" },
{ "<leader>fp", function() Snacks.picker.projects() end, desc="Projects" },
{ "<leader>fr", function() Snacks.picker.recent() end, desc="Recent" },
-- git
{ "<leader>gb", function() Snacks.picker.git_branches() end, desc="Git Branches" },
{ "<leader>gl", function() Snacks.picker.git_log() end, desc="Git Log" },
{ "<leader>gL", function() Snacks.picker.git_log_line() end, desc="Git Log Line" },
{ "<leader>gs", function() Snacks.picker.git_status() end, desc="Git Status" },
{ "<leader>gS", function() Snacks.picker.git_stash() end, desc="Git Stash" },
{ "<leader>gd", function() Snacks.picker.git_diff() end, desc="Git Diff (Hunks)" },
{ "<leader>gf", function() Snacks.picker.git_log_file() end, desc="Git Log File" },
-- gh
{ "<leader>gi", function() Snacks.picker.gh_issue() end, desc="GitHub Issues (open)" },
{ "<leader>gI", function() Snacks.picker.gh_issue({ state="all" }) end, desc="GitHub Issues (all)" },
{ "<leader>gp", function() Snacks.picker.gh_pr() end, desc="GitHub Pull Requests (open)" },
{ "<leader>gP", function() Snacks.picker.gh_pr({ state="all" }) end, desc="GitHub Pull Requests (all)" },
-- Grep
{ "<leader>sb", function() Snacks.picker.lines() end, desc="Buffer Lines" },
{ "<leader>sB", function() Snacks.picker.grep_buffers() end, desc="Grep Open Buffers" },
{ "<leader>sg", function() Snacks.picker.grep() end, desc="Grep" },
{ "<leader>sw", function() Snacks.picker.grep_word() end, desc="Visual selection or word", mode= { "n", "x" } },
-- search
{ '<leader>s"', function() Snacks.picker.registers() end, desc="Registers" },
{ '<leader>s/', function() Snacks.picker.search_history() end, desc="Search History" },
{ "<leader>sa", function() Snacks.picker.autocmds() end, desc="Autocmds" },
{ "<leader>sb", function() Snacks.picker.lines() end, desc="Buffer Lines" },
{ "<leader>sc", function() Snacks.picker.command_history() end, desc="Command History" },
{ "<leader>sC", function() Snacks.picker.commands() end, desc="Commands" },
{ "<leader>sd", function() Snacks.picker.diagnostics() end, desc="Diagnostics" },
{ "<leader>sD", function() Snacks.picker.diagnostics_buffer() end, desc="Buffer Diagnostics" },
{ "<leader>sh", function() Snacks.picker.help() end, desc="Help Pages" },
{ "<leader>sH", function() Snacks.picker.highlights() end, desc="Highlights" },
{ "<leader>si", function() Snacks.picker.icons() end, desc="Icons" },
{ "<leader>sj", function() Snacks.picker.jumps() end, desc="Jumps" },
{ "<leader>sk", function() Snacks.picker.keymaps() end, desc="Keymaps" },
{ "<leader>sl", function() Snacks.picker.loclist() end, desc="Location List" },
{ "<leader>sm", function() Snacks.picker.marks() end, desc="Marks" },
{ "<leader>sM", function() Snacks.picker.man() end, desc="Man Pages" },
{ "<leader>sp", function() Snacks.picker.lazy() end, desc="Search for Plugin Spec" },
{ "<leader>sq", function() Snacks.picker.qflist() end, desc="Quickfix List" },
{ "<leader>sR", function() Snacks.picker.resume() end, desc="Resume" },
{ "<leader>su", function() Snacks.picker.undo() end, desc="Undo History" },
{ "<leader>uC", function() Snacks.picker.colorschemes() end, desc="Colorschemes" },
-- LSP
{ "gd", function() Snacks.picker.lsp_definitions() end, desc="Goto Definition" },
{ "gD", function() Snacks.picker.lsp_declarations() end, desc="Goto Declaration" },
{ "gr", function() Snacks.picker.lsp_references() end, nowait=true, desc="References" },
{ "gI", function() Snacks.picker.lsp_implementations() end, desc="Goto Implementation" },
{ "gy", function() Snacks.picker.lsp_type_definitions() end, desc="Goto T[y]pe Definition" },
{ "gai", function() Snacks.picker.lsp_incoming_calls() end, desc="C[a]lls Incoming" },
{ "gao", function() Snacks.picker.lsp_outgoing_calls() end, desc="C[a]lls Outgoing" },
{ "<leader>ss", function() Snacks.picker.lsp_symbols() end, desc="LSP Symbols" },
{ "<leader>sS", function() Snacks.picker.lsp_workspace_symbols() end, desc="LSP Workspace Symbols" },
-- Other
{ "<leader>z", function() Snacks.zen() end, desc="Toggle Zen Mode" },
{ "<leader>Z", function() Snacks.zen.zoom() end, desc="Toggle Zoom" },
{ "<leader>.", function() Snacks.scratch() end, desc="Toggle Scratch Buffer" },
{ "<leader>S", function() Snacks.scratch.select() end, desc="Select Scratch Buffer" },
{ "<leader>n", function() Snacks.notifier.show_history() end, desc="Notification History" },
{ "<leader>bd", function() Snacks.bufdelete() end, desc="Delete Buffer" },
{ "<leader>cR", function() Snacks.rename.rename_file() end, desc="Rename File" },
{ "<leader>gB", function() Snacks.gitbrowse() end, desc="Git Browse", mode= { "n", "v" } },
{ "<leader>gg", function() Snacks.lazygit() end, desc="Lazygit" },
{ "<leader>un", function() Snacks.notifier.hide() end, desc="Dismiss All Notifications" },
{ "<c-/>", function() Snacks.terminal() end, desc="Toggle Terminal" },
{ "<c-_>", function() Snacks.terminal() end, desc="which_key_ignore" },
{ "]]", function() Snacks.words.jump(vim.v.count1) end, desc="Next Reference", mode= { "n", "t" } },
{ "[[", function() Snacks.words.jump(-vim.v.count1) end, desc="Prev Reference", mode= { "n", "t" } },
{
"<leader>N",
desc="Neovim News",
function()
Snacks.win({
file=vim.api.nvim_get_runtime_file("doc/news.txt", false)[1],
width=0.6,
height=0.6,
wo= {
spell=false,
wrap=false,
signcolumn="yes",
statuscolumn="",
conceallevel=3,
},
})
end,
}
},
init=function()
vim.api.nvim_create_autocmd("User", {
pattern="VeryLazy",
callback=function()
-- Setup some globals for debugging (lazy-loaded)_G.dd=function(...)
Snacks.debug.inspect(...)
end_G.bt=function()
Snacks.debug.backtrace()
end-- Override print to use snacks for `:=` commandifvim.fn.has("nvim-0.11") ==1thenvim._print=function(_, ...)
dd(...)
endelsevim.print=_G.ddend-- Create some toggle mappingsSnacks.toggle.option("spell", { name="Spelling" }):map("<leader>us")
Snacks.toggle.option("wrap", { name="Wrap" }):map("<leader>uw")
Snacks.toggle.option("relativenumber", { name="Relative Number" }):map("<leader>uL")
Snacks.toggle.diagnostics():map("<leader>ud")
Snacks.toggle.line_number():map("<leader>ul")
Snacks.toggle.option("conceallevel", { off=0, on=vim.o.conceallevel>0andvim.o.conceallevelor2 }):map("<leader>uc")
Snacks.toggle.treesitter():map("<leader>uT")
Snacks.toggle.option("background", { off="light", on="dark", name="Dark Background" }):map("<leader>ub")
Snacks.toggle.inlay_hints():map("<leader>uh")
Snacks.toggle.indent():map("<leader>ug")
Snacks.toggle.dim():map("<leader>uD")
end,
})
end,
}Snacks defines a lot of highlight groups and it's impossible to document them all.
Instead, you can use the picker to see all the highlight groups.
Snacks.picker.highlights({pattern="hl_group:^Snacks"})