🍿 A collection of QoL plugins for Neovim
Find a file
github-actions[bot] daa3ddd8a1
chore(main): release 2.24.0 (#2186)
🤖 I have created a release *beep* *boop*
---


##
[2.24.0](https://github.com/folke/snacks.nvim/compare/v2.23.0...v2.24.0)
(2025-10-23)


### Features

* **bigfile:** disable mini-hipatterns
([#2170](https://github.com/folke/snacks.nvim/issues/2170))
([3d4dd13](3d4dd13d2e))
* **dashboard:** optional `filter` for projects. Closes
[#798](https://github.com/folke/snacks.nvim/issues/798)
([fe88a07](fe88a07d53))
* **debug:** allow debug evaluation of block selections
([#1331](https://github.com/folke/snacks.nvim/issues/1331))
([231ffae](231ffae08d))
* **git:** allow configuring extra git args and git cmd args for all git
sources. See [#2178](https://github.com/folke/snacks.nvim/issues/2178)
([5782b5c](5782b5cda0))
* **image:** add icns support
([#2120](https://github.com/folke/snacks.nvim/issues/2120))
([9df47bc](9df47bce6a))
* **image:** added clear fun. Closes
[#1394](https://github.com/folke/snacks.nvim/issues/1394)
([30687d1](30687d195b))
* **image:** added support for base64 encoded images in url. Closes
[#2304](https://github.com/folke/snacks.nvim/issues/2304)
([2c56e10](2c56e10b1d))
* **image:** allow specifying a page number for inlined pdfs
([#1806](https://github.com/folke/snacks.nvim/issues/1806))
([3f0fe34](3f0fe34308))
* **indent:** pass win to filter func. Closes
[#2307](https://github.com/folke/snacks.nvim/issues/2307)
([8116e0b](8116e0b380))
* **input:** added support for a custom highlight functions. Closes
[#2216](https://github.com/folke/snacks.nvim/issues/2216)
([9b80137](9b80137ace))
* **layout:** height=0.7 for preview in vscode layout
([c3d6c01](c3d6c01916))
* **layout:** static (non-flex) layouts now shrink the root box to fit
the contents. See
[#2035](https://github.com/folke/snacks.nvim/issues/2035)
([ba7845b](ba7845bb85))
* **picker.finder:** added assertions that finder is still running when
receiving results
([a45503b](a45503b957))
* **picker.git_diff:** add `base` option to show diff against a merge
base. Useful to see changes on a branch/PR
([7964f04](7964f040bf))
* **picker.git:** allow passing extra args to git log command for file
renames ([#1964](https://github.com/folke/snacks.nvim/issues/1964))
([2aee35d](2aee35d059))
* **picker.git:** use default previewer args in git_show
([#1736](https://github.com/folke/snacks.nvim/issues/1736))
([f324f96](f324f96bea))
* **picker.layout:** added `config` hook for resolved layouts. See
[#2035](https://github.com/folke/snacks.nvim/issues/2035)
([722f9ea](722f9eac7c))
* **picker.lsp_config:** added more info to lsp picker
([636be5c](636be5c3d1))
* **picker.lsp:** added lsp_incoming_calls and lsp_outgoing_calls.
Closes [#1843](https://github.com/folke/snacks.nvim/issues/1843)
([55d6670](55d6670a7e))
* **picker.lsp:** added option `keep_parents` to `lsp_symbols` (default
`false`). See [#2083](https://github.com/folke/snacks.nvim/issues/2083).
closes [#2266](https://github.com/folke/snacks.nvim/issues/2266)
([2b9d522](2b9d52258d))
* **picker.projects:** make max_depth customizable
([#2253](https://github.com/folke/snacks.nvim/issues/2253))
([3e9e2e2](3e9e2e2d71))
* **picker.scratch:** add scratch picker with grep, new and delete
keybinds ([#1019](https://github.com/folke/snacks.nvim/issues/1019))
([ca0f8b2](ca0f8b2c09))
* **picker.select:** select now fits the list to the items independent
of the layout. Closes
[#2035](https://github.com/folke/snacks.nvim/issues/2035)
([5c63614](5c63614880))
* **picker:** add author field to git log
([#2295](https://github.com/folke/snacks.nvim/issues/2295))
([2cf864a](2cf864aaa1))
* **picker:** add exact match position highlighting for grep results
([3b54c8d](3b54c8d3d1))
* **picker:** add git_restore action for git_status picker
([2b22fe7](2b22fe7861))
* **picker:** add toggle_regex for grep
([#1594](https://github.com/folke/snacks.nvim/issues/1594))
([bd6ee23](bd6ee23546))
* **picker:** added `Snacks.picker.tags()` a picker for ctags. Closes
[#1728](https://github.com/folke/snacks.nvim/issues/1728)
([4290287](42902871f5))
* **picker:** added custom options to `vim.ui.select` that snacks can
use for a better select
([264cab1](264cab1380))
* **picker:** added live support to `git_log`, which uses `-S` (pickaxe)
to search. Closes
[#1544](https://github.com/folke/snacks.nvim/issues/1544)
([c9fa6f7](c9fa6f7b07))
* **picker:** allow configuring pathspec for git grep
([#2311](https://github.com/folke/snacks.nvim/issues/2311))
([57fbda7](57fbda70d6))
* **picker:** also ignore dot bare git files
([#2058](https://github.com/folke/snacks.nvim/issues/2058))
([4bb0dae](4bb0dae95d))
* **picker:** enhanced resume with multi-state support and flexible API
([bc6c446](bc6c446c11))
* **picker:** flexible filename format
([#2294](https://github.com/folke/snacks.nvim/issues/2294))
([9ad5d53](9ad5d5374a))
* **picker:** mapped `<c-g>` to `print_cwd` in list. See
[#2244](https://github.com/folke/snacks.nvim/issues/2244)
([faa6aba](faa6abacb4))
* **picker:** Support rmagatti/autosession session manager
([#1825](https://github.com/folke/snacks.nvim/issues/1825))
([fc06234](fc06234ce1))
* **picker:** updated Snacks.picker.lsp_config to work with
`vim.lsp.config`
([292d46f](292d46f773))
* **picker:** when resuming a source that has nothing to resume, start a
picker with the source instead
([db3c13c](db3c13c28e))
* **terminal:** minor improvements for user experience
([#2276](https://github.com/folke/snacks.nvim/issues/2276))
([39b14c4](39b14c4006))
* **toggle:** allow notification customization via function
([#2247](https://github.com/folke/snacks.nvim/issues/2247))
([3ccab97](3ccab9736b))
* **win:** added support for `vim.o.winborder`. Set win.border = true to
use it
([b30523c](b30523c89f))
* **win:** all existing snacks windows for all plugins now honor
`vim.o.winborder`. Defaults to `rounded` if not set.
([c1737d8](c1737d866e))
* **win:** generalize footer options for keys
([#363](https://github.com/folke/snacks.nvim/issues/363))
([b8d1719](b8d17192b6))
* **win:** make split window "stacking" configurable
([e46a094](e46a09427c))


### Bug Fixes

* **bigfile:** bigfile doesn't work on windows.
([#1969](https://github.com/folke/snacks.nvim/issues/1969))
([b4944ff](b4944ff320)),
closes [#1722](https://github.com/folke/snacks.nvim/issues/1722)
* **bufdelete:** try alternate buffer first and otherwise last used
buffer
([914c900](914c9004be))
* **dashboard:** fix path filtering for `recent_files` with `cwd` option
([#2201](https://github.com/folke/snacks.nvim/issues/2201))
([057d4ab](057d4ab80e))
* **dashboard:** oldfiles filter should return a boolean instead of the
result of find. Fixes
[#2283](https://github.com/folke/snacks.nvim/issues/2283)
([fcd309f](fcd309f9ea))
* **dashboard:** pcall chansend for dashoard terminal widgets
([dc65ffd](dc65ffd4f5))
* **dashboard:** recent cwd filter matching
([5c4365e](5c4365e993))
* **dashboard:** recent_files section not displaying files without cwd
parameter ([#2284](https://github.com/folke/snacks.nvim/issues/2284))
([1ed737e](1ed737e465))
* **dashboard:** replace deprecated AutoSession command
([#2288](https://github.com/folke/snacks.nvim/issues/2288))
([e9228d6](e9228d6b2f))
* **dashboard:** restore showtabline/laststatus when entering another
non-float window. Closes
[#1774](https://github.com/folke/snacks.nvim/issues/1774)
([cc69a93](cc69a9304b))
* **dashboard:** set `border = "none"` on `terminal` sections
([#1643](https://github.com/folke/snacks.nvim/issues/1643))
([83f364f](83f364f833))
* **dashboard:** update cursor on loading the dashboard. Closes
[#2004](https://github.com/folke/snacks.nvim/issues/2004)
([29682a0](29682a0a72))
* **dashboard:** use fqn for icon. Closes
[#1496](https://github.com/folke/snacks.nvim/issues/1496)
([24e92e0](24e92e0c94))
* **dim:** fixed the issue of dim's scope variable being nil and
outputting… ([#1938](https://github.com/folke/snacks.nvim/issues/1938))
([943a3c7](943a3c7d4a))
* **explorer.git:** don't propagate deletes to parent dirs that don't
exist
([835c4cb](835c4cbfc6))
* **explorer.watch:** handle systems where fs_event doesn't return file
names. Closes [#2190](https://github.com/folke/snacks.nvim/issues/2190).
Closes [#2032](https://github.com/folke/snacks.nvim/issues/2032)
([d6e34b1](d6e34b158d))
* **explorer:** mounted directories being detected as non-directories in
Tree:expand ([#2053](https://github.com/folke/snacks.nvim/issues/2053))
([7a5eb10](7a5eb1036a))
* **explorer:** reset main when entering another window. Closes
[#1587](https://github.com/folke/snacks.nvim/issues/1587)
([a5d45d5](a5d45d543e))
* **git:** always check parents for git root to fix an issue with git
submodules. Closes
[#2143](https://github.com/folke/snacks.nvim/issues/2143)
([14dd362](14dd362d5d))
* **gitbrowse:** fixed urls for gitlab
([#2073](https://github.com/folke/snacks.nvim/issues/2073))
([9ebf052](9ebf052fef))
* **gitbrowse:** send commit as a opt when calling gitbrowse
([#2289](https://github.com/folke/snacks.nvim/issues/2289))
([a466429](a4664298ba))
* **git:** set `diff.noprefix=false` for `git diff` to ensure correct
format ([#2174](https://github.com/folke/snacks.nvim/issues/2174))
([93f43ca](93f43ca10f))
* **image.terminal:** do only terminal detection for now. Closes
[#2323](https://github.com/folke/snacks.nvim/issues/2323)
([6c7ddae](6c7ddae887))
* **image:** correct off by one issue in render fallback
([#1560](https://github.com/folke/snacks.nvim/issues/1560))
([441bdcd](441bdcd210))
* **image:** correct render fallback to handle "editor" relative
position ([#2296](https://github.com/folke/snacks.nvim/issues/2296))
([c552cea](c552cea131))
* **image:** correct render fallback to handle "editor" relative
position ([#2297](https://github.com/folke/snacks.nvim/issues/2297))
([1c3f15c](1c3f15cb54))
* **image:** detect kitty image protocol through terminal capability
request. Closes
[#1695](https://github.com/folke/snacks.nvim/issues/1695)
([43261ba](43261baf87))
* **image:** do not save remote image if fetch fails
([#1915](https://github.com/folke/snacks.nvim/issues/1915))
([cb6bf05](cb6bf052da))
* **image:** ENOENT on preview
([#2301](https://github.com/folke/snacks.nvim/issues/2301))
([5173e96](5173e96f33))
* **image:** hover close in insert mode
([#2215](https://github.com/folke/snacks.nvim/issues/2215))
([ef59af0](ef59af0ffc))
* **image:** markdown inline link query for shortened urls
([#1481](https://github.com/folke/snacks.nvim/issues/1481))
([2daa1b2](2daa1b28b2))
* **image:** set winblend=0 for floatwin when use unicode placeholders
([#1615](https://github.com/folke/snacks.nvim/issues/1615))
([758e64c](758e64c18f))
* **image:** skip `\usepackage` in comments and body
([#2325](https://github.com/folke/snacks.nvim/issues/2325))
([90227af](90227af497))
* **image:** work-around for sha256 not allowed to be a Blob
([92a08ce](92a08cece7))
* **indent:** check that win is valid in step. Closes
[#1943](https://github.com/folke/snacks.nvim/issues/1943)
([e409f31](e409f31cc9))
* **indent:** nil check before setting extmark
([#1635](https://github.com/folke/snacks.nvim/issues/1635))
([02bf7d2](02bf7d2205))
* **input:** schedule stopinsert. Fixes
[#1841](https://github.com/folke/snacks.nvim/issues/1841)
([ad6cbc8](ad6cbc8d5d))
* **input:** zindex
([67d690d](67d690d362))
* **input:** zindex. Closes
[#2302](https://github.com/folke/snacks.nvim/issues/2302)
([d491236](d491236941))
* **layout:** allocate at least 1 cell for a widget and enlarge/shrink
the root box when needed. Closes
[#2261](https://github.com/folke/snacks.nvim/issues/2261)
([71d6d3c](71d6d3cad4))
* **layout:** allow width/height to be a function. Closes
[#2184](https://github.com/folke/snacks.nvim/issues/2184)
([c757d4d](c757d4dc28))
* **lazygit:** allow extensible user args
([#789](https://github.com/folke/snacks.nvim/issues/789))
([da655a3](da655a3538))
* **lazygit:** check if default config file exists before adding to
LG_CONFIG_FILE
([#2256](https://github.com/folke/snacks.nvim/issues/2256))
([3731644](3731644e38))
* **main:** get correct winid for prev window
([db399b1](db399b1332))
* **notifier:** include icon in padding in minimal style
([#2239](https://github.com/folke/snacks.nvim/issues/2239))
([6daef52](6daef528c1))
* **notifier:** keep filtered notifications in history
([#2209](https://github.com/folke/snacks.nvim/issues/2209))
([ac61546](ac6154688b))
* **picker.actions:** `<c-g>` in list view now prints file path instead
of cwd. Fallback to cwd
([0b0a58a](0b0a58ae4a))
* **picker.actions:** ensure the current window is updated after tabdrop
([#2326](https://github.com/folke/snacks.nvim/issues/2326))
([b30121b](b30121bfce))
* **picker.actions:** multi-action descriptions. Fixes
[#1501](https://github.com/folke/snacks.nvim/issues/1501)
([4edf207](4edf207bfe))
* **picker.actions:** take into account if source is `recent` explicitly
([#1920](https://github.com/folke/snacks.nvim/issues/1920))
([b9bd8ae](b9bd8ae982))
* **picker.core:** respect camelCase for scoring when ignorecase is true
([#1601](https://github.com/folke/snacks.nvim/issues/1601))
([a32735b](a32735b9e8))
* **picker.format:** added min_width for truncated paths
([b7f8116](b7f811613a))
* **picker.format:** apply hidden file hl group last. Fixes
[#2127](https://github.com/folke/snacks.nvim/issues/2127)
([0bf8fe4](0bf8fe4ece))
* **picker.format:** correcter max_width for truncpath
([a5d2964](a5d29646e5))
* **picker.format:** simplified resolvable formatters and more correct
([d5b6d30](d5b6d30b5e))
* **picker.git_diff:** use absolute path when adding buffer to avoid
duplicates ([#1819](https://github.com/folke/snacks.nvim/issues/1819))
([a012f39](a012f394c9))
* **picker.git:** add `ignorecase` for `git_grep`
([#1629](https://github.com/folke/snacks.nvim/issues/1629))
([7502e77](7502e77803))
* **picker.git:** use unmerged icon for unmerged. Fixes
[#1531](https://github.com/folke/snacks.nvim/issues/1531)
([abee3c9](abee3c9eff))
* **picker.grep:** better line/col parsing. Closes
[#2126](https://github.com/folke/snacks.nvim/issues/2126). Fixes
[#2123](https://github.com/folke/snacks.nvim/issues/2123)
([1fee799](1fee799ad6))
* **picker.grep:** faulty rg cmd. Closes
[#2280](https://github.com/folke/snacks.nvim/issues/2280)
([65a5c8b](65a5c8b3d0))
* **picker.list:** resize when needed. Closes
[#2290](https://github.com/folke/snacks.nvim/issues/2290)
([df018ed](df018edfdb))
* **picker.lsp_config:** cmd can be a function
([ba745ba](ba745ba281))
* **picker.lsp:** don't process lsp request results when aborted. Closes
[#2327](https://github.com/folke/snacks.nvim/issues/2327)
([4e10708](4e1070867a))
* **picker.lsp:** move get_clients inside vim.schedule to prevent issues
on Neovim 0.11. Closes
[#2320](https://github.com/folke/snacks.nvim/issues/2320)
([79f3a8d](79f3a8d8b3))
* **picker.lsp:** trigger docs workflow
([6f1158f](6f1158fe9b))
* **picker.man:** make tab/split/vsplit work. Closes
[#2171](https://github.com/folke/snacks.nvim/issues/2171)
([f39d114](f39d1144e7))
* **picker.marks:** fix buffer checking
([#2287](https://github.com/folke/snacks.nvim/issues/2287))
([ca0858a](ca0858a30a))
* **picker.preview:** better hack to deal with buffer local option
weirdness
([c968d4d](c968d4def4))
* **picker.preview:** directory preview should use cwd. Closes
[#2212](https://github.com/folke/snacks.nvim/issues/2212). Fixes
[#2093](https://github.com/folke/snacks.nvim/issues/2093)
([d050712](d05071255c))
* **picker.preview:** don't record previeww searches in history and
prevent scrolling from the top. Closes
[#2305](https://github.com/folke/snacks.nvim/issues/2305)
([080320b](080320bb82))
* **picker.preview:** dont do win-local hack for floating windows
([12b2f0d](12b2f0d2bd))
* **picker.qflist:** error with qflist picker when the list contains
invalid items
([#2293](https://github.com/folke/snacks.nvim/issues/2293))
([6af1e76](6af1e76758))
* **picker.recent:** include closed / unlisted buffers in recent. Closes
[#1745](https://github.com/folke/snacks.nvim/issues/1745)
([5959631](595963140e))
* **picker:** add type field to qflist item
([#1538](https://github.com/folke/snacks.nvim/issues/1538))
([#1539](https://github.com/folke/snacks.nvim/issues/1539))
([125978b](125978b57a))
* **picker:** added show_delay to config max ms to wait to show if no
results found yet. Closes
[#2206](https://github.com/folke/snacks.nvim/issues/2206)
([64583a0](64583a0386))
* **picker:** allow some sources to use the current window as main.
Closes [#2012](https://github.com/folke/snacks.nvim/issues/2012). See
[#1941](https://github.com/folke/snacks.nvim/issues/1941)
([5cda953](5cda9532ca))
* **picker:** correct z-index for preview="main" layout
([e796aef](e796aef0fa))
* **picker:** do not record consecutive duplicate history
([#2040](https://github.com/folke/snacks.nvim/issues/2040))
([d0a5310](d0a5310417))
* **picker:** fixup for pickers that dont display files
([1b4205e](1b4205eb1a))
* **picker:** load correct actions in list of action names. Closes
[#1501](https://github.com/folke/snacks.nvim/issues/1501)
([b064be2](b064be2882))
* **picker:** lsp_config now includes any configfured LSP and excludes
deprecated servers
([a0d6eba](a0d6eba1a2))
* **picker:** prevent WinEnter handling during startup
([756a791](756a791131))
* **picker:** show_delay config value
([67bb3a7](67bb3a7ba0))
* **picker:** show_delay is in ms. Also increase it to allow
auto_confirm to work properly
([924a930](924a9304e9))
* **picker:** use nvim_paste instead of nvim_put. Closes
[#1941](https://github.com/folke/snacks.nvim/issues/1941)
([021e04f](021e04fa6f))
* **projects:** normalize item.text for correct Windows support
([#2275](https://github.com/folke/snacks.nvim/issues/2275))
([457596b](457596be6d))
* **rename:** made rename more robust and make sure target directory
exists. Closes [#2252](https://github.com/folke/snacks.nvim/issues/2252)
([c494447](c494447737))
* **scope:** allow user to disable keys
([#1918](https://github.com/folke/snacks.nvim/issues/1918))
([bebf0bd](bebf0bd38e))
* **scratch:** branch fallback for detached head
([#1519](https://github.com/folke/snacks.nvim/issues/1519))
([98345c7](98345c7012))
* **scratch:** hide buffer after formatting when close
([#1523](https://github.com/folke/snacks.nvim/issues/1523))
([4379085](4379085616))
* **scratch:** use icon[1] when icon is a table to avoid table.concat
error ([#2242](https://github.com/folke/snacks.nvim/issues/2242))
([ba90011](ba90011a14))
* **scroll:** don't animate 1 line scrolls (jk). Closes
[#1620](https://github.com/folke/snacks.nvim/issues/1620)
([d293b21](d293b21fe1))
* **scroll:** stop anim and reset state when win has new buf, or buf was
changed. Closes
[#1820](https://github.com/folke/snacks.nvim/issues/1820). Closes
[#2221](https://github.com/folke/snacks.nvim/issues/2221)
([766f7b8](766f7b87aa))
* **statuscolumn:** show open folds in consecutive levels
([#1534](https://github.com/folke/snacks.nvim/issues/1534))
([7bcd3ba](7bcd3baaf8))
* **terminal:** check win valid before creating a new terminal
([#1927](https://github.com/folke/snacks.nvim/issues/1927))
([ba7bbcd](ba7bbcd0df))
* **terminal:** make sure terminals opend with `open()` can be found
with `list()`. Closes
[#2172](https://github.com/folke/snacks.nvim/issues/2172). Closes
[#2173](https://github.com/folke/snacks.nvim/issues/2173)
([13f3006](13f3006dbf))
* **terminal:** set buffer when opening terminal with position='current'
([#2162](https://github.com/folke/snacks.nvim/issues/2162))
([2aacf55](2aacf55082)),
closes [#2148](https://github.com/folke/snacks.nvim/issues/2148)
* **terminal:** stack only terminal splits by default. Closes
[#2137](https://github.com/folke/snacks.nvim/issues/2137)
([8c50196](8c501965be))
* **util:** fix invalid window error
([#1996](https://github.com/folke/snacks.nvim/issues/1996))
([32e5bf1](32e5bf1730))
* **util:** only use mini.icons if it has been setup. Closes
[#2199](https://github.com/folke/snacks.nvim/issues/2199)
([774bf9d](774bf9d8c8))
* **win:** check parent win is valid before getting size
([#2315](https://github.com/folke/snacks.nvim/issues/2315))
([471eb03](471eb036c4))
* **zen:** make zoom and minimizing work in terminal mode
([#1912](https://github.com/folke/snacks.nvim/issues/1912))
([fb54927](fb54927ab0))


### Performance Improvements

* **dashboard:** add basic OSC11 and CSI6n support to terminal sections
(gh 10 seconds faster)
([fb016d2](fb016d20c2))
* **git:** invoke `git status` with `--no-optional-locks`
([#2175](https://github.com/folke/snacks.nvim/issues/2175))
([e441c64](e441c641eb))
* **grep:** move match parsing to resolve and fix an issue with `.*`
results. Closes
[#2308](https://github.com/folke/snacks.nvim/issues/2308)
([1417701](1417701af6))
* **picker:** set `limit_live=10000` by default. Makes no sense to load
millions of matches when doing live searches.
([04990d0](04990d042c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-23 11:43:00 +02:00
.github chore(main): release 2.24.0 (#2186) 2025-10-23 11:43:00 +02:00
doc chore(build): auto-generate docs 2025-10-23 09:39:50 +00:00
docs chore(build): auto-generate docs 2025-10-23 09:39:50 +00:00
lua fix(image): skip \usepackage in comments and body (#2325) 2025-10-23 11:14:32 +02:00
plugin feat: ensure Snacks global is available when not using setup 2024-11-04 16:39:24 +01:00
queries fix(image): markdown inline link query for shortened urls (#1481) 2025-10-20 14:56:50 +02:00
scripts ci: docs 2025-10-22 09:56:43 +02:00
tests feat(image): added support for base64 encoded images in url. Closes #2304 2025-10-21 22:59:36 +02:00
.editorconfig ci: integrated with ci scripts 2024-11-03 09:04:33 +01:00
.gitignore chore(update): update repository (#800) 2025-10-22 16:58:00 +02:00
CHANGELOG.md chore(main): release 2.24.0 (#2186) 2025-10-23 11:43:00 +02:00
LICENSE ci: integrated with ci scripts 2024-11-03 09:04:33 +01:00
README.md chore(build): auto-generate docs 2025-10-22 08:13:30 +00:00
selene.toml feat: initial commit 2024-11-02 23:24:33 +01:00
stylua.toml feat: initial commit 2024-11-02 23:24:33 +01:00
vim.yml ci: update test scripts 2025-10-08 21:26:25 +02:00

🍿 snacks.nvim

A collection of small QoL plugins for Neovim.

Features

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) ‼️
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 ‼️
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

Requirements

📦 Installation

Install the plugin with your package manager:

lazy.nvim

Important

A couple of plugins require snacks.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,
  ---@type snacks.Config
  opts = {
    -- your configuration comes here
    -- or leave it empty to use the default settings
    -- refer to the configuration section below
    bigfile = { 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.

⚙️ Configuration

Please refer to the readme of each plugin for their specific configuration.

Default Options
---@class snacks.Config
---@field animate? snacks.animate.Config
---@field bigfile? snacks.bigfile.Config
---@field dashboard? snacks.dashboard.Config
---@field dim? snacks.dim.Config
---@field explorer? snacks.explorer.Config
---@field gitbrowse? snacks.gitbrowse.Config
---@field image? snacks.image.Config
---@field indent? snacks.indent.Config
---@field input? snacks.input.Config
---@field layout? snacks.layout.Config
---@field lazygit? snacks.lazygit.Config
---@field notifier? snacks.notifier.Config
---@field picker? snacks.picker.Config
---@field profiler? snacks.profiler.Config
---@field quickfile? snacks.quickfile.Config
---@field scope? snacks.scope.Config
---@field scratch? snacks.scratch.Config
---@field scroll? snacks.scroll.Config
---@field statuscolumn? snacks.statuscolumn.Config
---@field terminal? snacks.terminal.Config
---@field toggle? snacks.toggle.Config
---@field win? snacks.win.Config
---@field words? snacks.words.Config
---@field zen? snacks.zen.Config
---@field styles? table<string, snacks.win.Config>
---@field image? snacks.image.Config|{}
{
  image = {
    -- define these here, so that we don't need to load the image module
    formats = {
      "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
  },
}

🚀 Usage

See the example below for how to configure snacks.nvim.

{
  "folke/snacks.nvim",
  priority = 1000,
  lazy = false,
  ---@type snacks.Config
  opts = {
    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" },
    -- 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 `:=` command
        if vim.fn.has("nvim-0.11") == 1 then
          vim._print = function(_, ...)
            dd(...)
          end
        else
          vim.print = _G.dd 
        end

        -- Create some toggle mappings
        Snacks.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 > 0 and vim.o.conceallevel or 2 }):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,
}

🌈 Highlight Groups

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"})