Extras
Extras are how Blak says “yes” to language support, optional tools, and personal preference — without bloating core for everyone.
All extras live under lua/blak/extras/, registered in lua/blak/extras/init.lua.
The contract
An extra is a single Lua module that can contribute any of:
- Treesitter parsers (
ensure_installed) - Mason tools (
mason.ensure_installed) - LSP servers via
vim.lsp.config() - Formatters and linters by filetype
- Snacks module options
- Keymaps (auto-shown in
:BlakKeys) - Plugin specs for lazy.nvim
When you disable an extra and restart, Blak stops registering that extra’s plugin specs, keymaps, tools, parsers, and config contributions. Run :BlakExtras sync afterward to let lazy.nvim clean up removed plugins.
Managing extras
:BlakExtras " open the extras UI:BlakExtras list " same UI, explicit:BlackExtras list " same command, typo-friendly:BlakExtras enable lang.rust:BlakExtras disable git.lazygit:BlakExtras sync " run :Lazy sync after changesThe UI groups enabled extras and available extras, shows the tools and plugins
each one contributes, and lets you toggle the row under the cursor with x or
<CR>. Press s to sync lazy.nvim, r to refresh, and q to close. Extras
from lua/blak/user.lua are marked [config]; remove them there when you want
the UI to stop treating them as enabled.
State persists outside the repo in stdpath('state')/blak/extras.json. That means:
- A fresh clone with the same
NVIM_APPNAMEreuses the same enabled extras. - A fresh install under a new
NVIM_APPNAMEstarts from your config defaults. - Multiple checkouts (
blak,blak-dev) can have different enabled sets. user.luaandextras.jsoncompose: anything inextras.enabledinuser.luais added on top of the state file.
If an extra was renamed or removed, :BlakDoctor reports it as unknown. Run :BlakExtras disable <id> to remove that stale state entry.
After enabling an extra:
- Blak applies its config to the current session.
- Run
:BlakExtras syncor:Lazy syncif plugins were added. - Run
:BlakToolsInstallto install any new Mason tools required. - Run
:BlakDoctorto confirm everything resolved.
After disabling an extra, the state file updates immediately. Restart Blak when you want already-loaded plugins, keymaps, and runtime hooks to disappear from the current session, then run :BlakExtras sync if plugin specs were removed.
Dedicated pages
Each supported extra has a dedicated page with its user.lua enable snippet,
configuration examples, install notes, and verification path.
Languages
lang.lua
Lua development — what Blak itself is written in.
| Adds | Value |
|---|---|
| Treesitter | lua, luadoc |
| Mason | stylua |
| LSP | lua_ls |
| Format | stylua for .lua |
lang.typescript
TypeScript and JavaScript with ESLint + Prettier.
| Adds | Value |
|---|---|
| Treesitter | javascript, typescript, tsx, jsdoc, json |
| Mason | prettier, prettierd, eslint_d |
| LSP | ts_ls, eslint |
| Format | prettierd (fallback prettier) for js/ts/jsx/tsx/json |
| Lint | eslint_d for js/ts/jsx/tsx |
lang.typescript-tsgo
TypeScript and JavaScript with the experimental native tsgo LSP, ESLint, and Prettier.
Enable this instead of lang.typescript when you want to try TypeScript’s Go-based language server. If both are enabled and this extra applies after lang.typescript, it removes ts_ls from the merged config for future setup. Restart after switching if ts_ls already attached in the current session.
| Adds | Value |
|---|---|
| Treesitter | javascript, typescript, tsx, jsdoc, json |
| Mason | prettier, prettierd, eslint_d |
| LSP | tsgo, eslint |
| Format | prettierd (fallback prettier) for js/ts/jsx/tsx/json |
| Lint | eslint_d for js/ts/jsx/tsx |
lang.python
Python with Pyright + Ruff + Black + isort.
| Adds | Value |
|---|---|
| Treesitter | python |
| Mason | black, isort, ruff |
| LSP | pyright, ruff |
| Format | isort, then black |
| Lint | ruff |
lang.python-pro
Python with BasedPyright, Ruff-first formatting, venv selection, and debugpy.
Enable this instead of lang.python when you want the richer Python stack.
| Adds | Value |
|---|---|
| Treesitter | python, requirements |
| Mason | ruff, debugpy |
| LSP | basedpyright, ruff |
| Format | ruff_organize_imports, then ruff_format |
| Plugins | venv-selector.nvim |
| Keys | <leader>cv for :VenvSelect |
lang.rust
Rust with rust-analyzer and TOML support.
| Adds | Value |
|---|---|
| Treesitter | rust, toml |
| Mason | codelldb |
| LSP | rust_analyzer (with cargo.allFeatures + Clippy), taplo |
| Format | rustfmt (LSP fallback), taplo (LSP fallback) |
| Plugins | saecki/crates.nvim |
lang.go
Go with gopls and golangci-lint.
| Adds | Value |
|---|---|
| Treesitter | go, gomod, gosum, gowork |
| Mason | goimports, gofumpt, golangci-lint |
| LSP | gopls |
| Format | goimports, gofumpt |
| Lint | golangcilint |
lang.markdown
Markdown with Marksman LSP and Prettier.
| Adds | Value |
|---|---|
| Treesitter | markdown, markdown_inline |
| Mason | prettier, prettierd, markdownlint |
| LSP | marksman |
| Format | prettierd (fallback prettier) for markdown |
| Lint | markdownlint |
lang.c
C and C++ with clangd and clang-format.
| Adds | Value |
|---|---|
| Treesitter | c, cpp |
| Mason | clang-format |
| LSP | clangd |
| Format | clang_format for c, cpp, objc, objcpp, cuda |
lang.bash
Shell scripting with the bash language server and shellcheck. Shell formatting
with shfmt already ships in Blak core.
| Adds | Value |
|---|---|
| Treesitter | bash |
| Mason | shellcheck |
| LSP | bashls |
| Lint | shellcheck for sh, bash |
lang.web
Frontend HTML, CSS, Tailwind, and Emmet with Prettier.
| Adds | Value |
|---|---|
| Treesitter | html, css, scss |
| Mason | prettier, prettierd |
| LSP | html, cssls, tailwindcss, emmet_language_server |
| Format | prettierd (fallback prettier) for html, css, scss, less |
lang.docker
Dockerfile and Docker Compose with hadolint linting.
| Adds | Value |
|---|---|
| Treesitter | dockerfile |
| Mason | hadolint |
| LSP | dockerls, docker_compose_language_service |
| Lint | hadolint for dockerfile |
| Filetype | registers yaml.docker-compose for Compose files |
lang.yaml
YAML with yaml-language-server, SchemaStore schemas, and Prettier.
| Adds | Value |
|---|---|
| Treesitter | yaml |
| Mason | prettier, prettierd |
| LSP | yamlls with SchemaStore schemas |
| Format | prettierd (fallback prettier) for yaml |
| Plugin | b0o/SchemaStore.nvim |
lang.json
JSON with jsonls, SchemaStore schemas, and Prettier.
| Adds | Value |
|---|---|
| Treesitter | json, jsonc |
| Mason | prettier, prettierd |
| LSP | jsonls with SchemaStore schemas |
| Format | prettierd (fallback prettier) for json, jsonc |
| Plugin | b0o/SchemaStore.nvim |
lang.terraform
Terraform and HCL with terraform-ls, terraform fmt, and tflint.
| Adds | Value |
|---|---|
| Treesitter | terraform, hcl |
| Mason | tflint |
| LSP | terraformls |
| Format | terraform_fmt for terraform, terraform-vars (needs the terraform CLI) |
| Lint | tflint for terraform |
lang.nix
Nix with the nil language server and nixfmt.
| Adds | Value |
|---|---|
| Treesitter | nix |
| Mason | nixfmt |
| LSP | nil_ls |
| Format | nixfmt for nix |
lang.zig
Zig with the zls language server (formatting via built-in zig fmt).
| Adds | Value |
|---|---|
| Treesitter | zig |
| LSP | zls |
UI
ui.animations
Smooth scroll and cursor animations via Snacks.
| Adds | Value |
|---|---|
| Snacks | animate.enabled = true, scroll.enabled = true |
ui.base46
AvengeMedia/base46, the NvChad Base46 colorscheme collection as regular Neovim colorschemes.
| Adds | Value |
|---|---|
| Plugin | AvengeMedia/base46 |
Enable the extra, sync plugins, then set ui.colorscheme to a Base46 scheme such as base46-gruvchad.
ui.comfy-line-numbers
mluders/comfy-line-numbers.nvim shows relative line labels using left-hand digits and maps those labels back to vertical motions.
| Adds | Value |
|---|---|
| Plugin | mluders/comfy-line-numbers.nvim |
| Keymap | label + j or k motions |
| Keymap | label + <Down> or <Up> motions |
Enable the extra, sync plugins, then use the displayed labels with j, k, <Down>, or <Up>. For example, 11j and 11<Down> both move to the line whose comfy label is 11.
ui.dim
Snacks dim highlights the active scope by dimming the surrounding lines.
| Adds | Value |
|---|---|
| Snacks | dim.enabled = true |
Snacks already ships in core, so this extra enables the dim module without adding a plugin spec.
ui.image-preview
Image previews in pickers and floats — works in Kitty, WezTerm, and Ghostty.
| Adds | Value |
|---|---|
| Snacks | image.enabled = true |
ui.indent
Indent guides with animated active-scope highlighting via Snacks. Core ships the module disabled; this extra flips it on.
| Adds | Value |
|---|---|
| Snacks | indent.enabled = true |
| Keymap | <leader>ug → toggle indent guides |
ui.lualine
lualine.nvim as an opt-in statusline.
| Adds | Value |
|---|---|
| Plugin | nvim-lualine/lualine.nvim |
| Deps | mini.icons |
| Config | global statusline, Blak theme auto-detection, ASCII separators |
This extra turns off native showmode while lualine is enabled because the statusline already displays the current mode. Disable the extra, restart Blak, then run :BlakExtras sync to remove the plugin spec.
ui.zen
Distraction-free editing mode.
| Adds | Value |
|---|---|
| Snacks | zen.enabled = true |
| Keymap | <leader>uz → toggle zen |
Debug
debug.dap
nvim-dap and nvim-dap-ui for Debug Adapter Protocol workflows.
| Adds | Value |
|---|---|
| Plugins | mfussenegger/nvim-dap, rcarriga/nvim-dap-ui |
| Deps | nvim-nio |
| Keymaps | <leader>d* debug actions |
Language adapters and launch configurations stay explicit in user.lua.
Test
test.neotest
neotest as a base test runner framework.
| Adds | Value |
|---|---|
| Plugin | nvim-neotest/neotest |
| Deps | nvim-nio, plenary.nvim, FixCursorHold.nvim, nvim-treesitter |
| Keymaps | <leader>T* test actions |
Language-specific adapters stay explicit in plugins.specs.
Git
git.lazygit
LazyGit floating window via Snacks.
| Adds | Value |
|---|---|
| Snacks | lazygit.enabled = true |
| Keymap | <leader>gg → LazyGit float |
Requires lazygit in $PATH.
git.diffview
sindrets/diffview.nvim for richer diffs and file history.
| Adds | Value |
|---|---|
| Plugin | sindrets/diffview.nvim |
| Keymap | <leader>gD → :DiffviewOpen |
| Keymap | <leader>gH → file history |
git.gitbrowse
Open the current file, line, or repository on its Git remote (GitHub, GitLab, Bitbucket, sourcehut) using Snacks gitbrowse. No new plugin.
| Adds | Value |
|---|---|
| Keymap | <leader>gB → open on remote (normal and visual) |
git.neogit
NeogitOrg/neogit, a Magit-style
interactive Git interface. Pairs with git.diffview and uses the core Snacks
picker.
| Adds | Value |
|---|---|
| Plugin | NeogitOrg/neogit |
| Deps | plenary.nvim |
| Treesitter | git_config, git_rebase, gitcommit, diff |
| Keymap | <leader>gn → open Neogit |
AI
ai.claudecode
claudecode.nvim integration for Claude Code CLI sessions and native diff review.
| Adds | Value |
|---|---|
| Plugin | coder/claudecode.nvim |
| Deps | folke/snacks.nvim |
| Commands | :ClaudeCode* command family |
| Keymap | <leader>ac -> toggle Claude Code |
| Keymap | <leader>aF -> focus Claude Code |
| Keymap | <leader>ar -> resume Claude Code |
| Keymap | <leader>aC -> continue Claude Code |
| Keymap | <leader>am -> select model |
| Keymap | <leader>ab -> add current buffer |
| Keymap | <leader>as -> send visual selection |
| Keymap | <leader>aA -> accept diff |
| Keymap | <leader>aD -> deny diff |
Claude Code options are passed through ai.claudecode. Blak sets
terminal.provider = "snacks" because Snacks is already part of core:
return { extras = { enabled = { "ai.claudecode" } }, ai = { claudecode = { log_level = "info", terminal = { provider = "snacks", }, }, },}Never enabled by default. Opt in with
:BlakExtras enable ai.claudecode.
ai.copilot
GitHub Copilot integration via zbirenbaum/copilot.lua.
| Adds | Value |
|---|---|
| Plugin | zbirenbaum/copilot.lua |
Never enabled by default. Opt in with
:BlakExtras enable ai.copilot.
ai.sidekick
sidekick.nvim AI CLI terminals and optional Copilot Next Edit Suggestions.
| Adds | Value |
|---|---|
| Plugin | folke/sidekick.nvim |
| Snacks | picker.actions.sidekick_send |
| Keymap | <C-.> → focus the Sidekick CLI |
| Keymap | <leader>aa → toggle the CLI |
| Keymap | <leader>as → select an AI CLI |
| Keymap | <leader>ad → detach the current CLI session |
| Keymap | <leader>af → send the current file |
| Keymap | <leader>at → send {this} context |
| Keymap | <leader>av → send the visual selection |
| Keymap | <leader>ap → pick a prompt |
Enable it, sync plugins, then install at least one AI CLI supported by Sidekick, such as Codex, Claude, Gemini, or OpenCode:
:BlakExtras enable ai.sidekick:BlakExtras sync:checkhealth sidekickBlak keeps ai.sidekick.nes.enabled = false by default so the extra remains a terminal-based AI workflow unless you opt into Copilot Next Edit Suggestions:
return { extras = { enabled = { "ai.sidekick" } }, ai = { sidekick = { nes = { enabled = true }, cli = { mux = { enabled = true, backend = "tmux" }, }, }, },}The extra registers a Snacks picker action named sidekick_send. If you want a picker-local key for sending file/search selections to Sidekick, add it yourself so it remains part of your visible config:
return { extras = { enabled = { "ai.sidekick" } }, snacks = { picker = { win = { input = { keys = { ["<a-a>"] = { "sidekick_send", mode = { "n", "i" } }, }, }, }, }, },}Never enabled by default. Disable it, restart Blak, then run
:BlakExtras syncto remove the plugin spec.
ai.supermaven
supermaven-nvim inline AI completion.
| Adds | Value |
|---|---|
| Plugin | supermaven-inc/supermaven-nvim |
| Commands | :Supermaven* command family |
| Keymap | <leader>aS -> toggle Supermaven |
| Keymap | <M-l> -> accept the inline suggestion |
| Keymap | <M-w> -> accept one word |
| Keymap | <M-]> -> clear the inline suggestion |
Blak disables Supermaven’s built-in plugin keymaps and registers the mappings
above through :BlakKeys instead. That keeps the extra discoverable and avoids
quietly taking over <Tab>.
Supermaven options are passed through ai.supermaven:
return { extras = { enabled = { "ai.supermaven" } }, ai = { supermaven = { log_level = "info", ignore_filetypes = { markdown = true, }, }, },}Never enabled by default. Disable it, restart Blak, then run
:BlakExtras syncto remove the plugin spec.
Editor
editor.aerial
aerial.nvim for an opt-in code outline window.
| Adds | Value |
|---|---|
| Plugin | stevearc/aerial.nvim |
| Deps | mini.icons |
| Keymap | <leader>co → toggle outline |
editor.flash
flash.nvim for label-based jump motions
and Treesitter selection. Deliberately shadows native s/S; opt-in and
visible in :BlakKeys.
| Adds | Value |
|---|---|
| Plugin | folke/flash.nvim |
| Keymaps | s jump, S Treesitter, r/R remote/search, <C-s> toggle in search |
editor.grug-far
grug-far.nvim for buffer-based, ripgrep-powered project-wide find and replace.
| Adds | Value |
|---|---|
| Plugin | MagicDuck/grug-far.nvim |
| Keymap | <leader>sr → search and replace (normal and visual) |
editor.scratch
Snacks scratch buffers: persistent, context-aware throwaway notepads. No new plugin.
| Adds | Value |
|---|---|
| Keymap | <leader>. → toggle scratch buffer |
| Keymap | <leader>S → select scratch buffer |
editor.harpoon
Harpoon v2 for project-local file marks and a small editable quick menu.
| Adds | Value |
|---|---|
| Plugin | ThePrimeagen/harpoon on branch harpoon2 |
| Deps | plenary.nvim |
| Config | calls require("harpoon"):setup({}) |
| Keymaps | <leader>h* Harpoon file actions |
editor.mini
nvim-mini modules as opt-in editor pieces.
| Adds | Value |
|---|---|
| Plugins | one nvim-mini/mini.<module> spec for each configured non-core, non-conflicting mini.modules entry |
| Config | calls require("mini.<module>").setup(mini.opts.<module> or {}) |
This extra does not enable any optional Mini module by default. mini.icons and
pair handling ship in core; put the other Mini modules you want in
mini.modules, enable editor.mini, then run :BlakExtras sync.
editor.overseer
overseer.nvim for project task running and job management.
| Adds | Value |
|---|---|
| Plugin | stevearc/overseer.nvim |
| Keymaps | <leader>oo, <leader>or, <leader>oq |
editor.refactoring
refactoring.nvim for Treesitter-powered extract, inline, and print-debug refactors.
| Adds | Value |
|---|---|
| Plugin | ThePrimeagen/refactoring.nvim |
| Deps | plenary.nvim, nvim-treesitter |
| Keymaps | <leader>r* refactor actions |
editor.render-markdown
render-markdown.nvim for richer in-buffer Markdown rendering.
| Adds | Value |
|---|---|
| Plugin | MeanderingProgrammer/render-markdown.nvim |
| Deps | nvim-treesitter, mini.icons |
| Treesitter | markdown, markdown_inline |
| Keymap | <leader>um → toggle Markdown rendering |
editor.todo-comments
todo-comments.nvim for highlighted and searchable TODO-style comments.
| Adds | Value |
|---|---|
| Plugin | folke/todo-comments.nvim |
| Deps | plenary.nvim |
| Keymaps | ]t, [t, <leader>xT |
editor.trouble
trouble.nvim for richer diagnostics, references, symbols, quickfix, and location list views.
| Adds | Value |
|---|---|
| Plugin | folke/trouble.nvim |
| Deps | mini.icons |
| Keymaps | <leader>xX, <leader>xQ, <leader>xL, <leader>cO, <leader>cR |
editor.window-navigation
Native window movement on Ctrl-h/j/k/l.
| Adds | Value |
|---|---|
| Keymaps | <C-h> left, <C-j> down, <C-k> up, <C-l> right |
This is an extra instead of a core default because <C-l> redraws the screen in
stock Neovim. Opting in keeps the shortcut explicit and reversible.
editor.neotree
nvim-neo-tree/neo-tree.nvim as an alternative file explorer alongside Oil.
| Adds | Value |
|---|---|
| Plugin | nvim-neo-tree/neo-tree.nvim (v3.x) |
| Deps | plenary.nvim, mini.icons, nui.nvim |
| Keymap | <leader>E → toggle Neo-tree |
editor.snacks-explorer
Snacks explorer as the configured file explorer.
| Adds | Value |
|---|---|
| Config | sets explorer.provider = "snacks" |
| Snacks | explorer.enabled = true; explorer picker auto_close = true |
| Binary | fd on $PATH for fast file discovery |
| Keymap | <leader>e → toggle Snacks explorer |
Snacks already ships in core for dashboard/input/notifier/picker support, so this extra enables the explorer module instead of adding a new plugin. Blak also toggles an already-open Snacks explorer instead of opening a second one.
editor.snacks-terminal
Snacks terminal as the configured terminal provider.
| Adds | Value |
|---|---|
| Config | sets terminal.provider = "snacks" |
| Snacks | terminal.enabled = true |
| Command | :BlakTerminal [cmd] uses Snacks.terminal.toggle() |
| Keymap | terminal.toggle_key toggles Snacks terminal |
Snacks already ships in core, so this extra enables the terminal module and keeps the existing Blak command and keymap surface.
editor.telescope
nvim-telescope/telescope.nvim as the picker backend.
| Adds | Value |
|---|---|
| Plugin | nvim-telescope/telescope.nvim |
| Deps | plenary.nvim, mini.icons |
| Config | sets picker.provider = "telescope" |
Enabling this swaps :BlakPick and all <leader>f* mappings to Telescope.
editor.fzf-lua
ibhagwan/fzf-lua as the picker backend.
| Adds | Value |
|---|---|
| Plugin | ibhagwan/fzf-lua |
| Deps | mini.icons |
| Config | sets picker.provider = "fzf_lua" |
Anatomy of an extra
-- lua/blak/extras/lang/rust.luareturn { id = "lang.rust", label = "Rust", description = "rust-analyzer + treesitter", treesitter = { "rust", "toml" }, mason = { "codelldb" }, lsp = { servers = { rust_analyzer = { settings = { ["rust-analyzer"] = { check = { command = "clippy" } }, }, }, }, }, format = { formatters_by_ft = { rust = { lsp_format = "fallback" } }, }, keys = { { lhs = "<leader>cc", rhs = ":!cargo check<CR>", desc = "cargo check" }, }, plugins = { -- optional, lazy.nvim spec list { "owner/plugin.nvim", opts = {} }, }, apply = function(config) -- optional, runs after merge config.snacks.dim = { enabled = true } end,}That’s the entire surface. See Writing an extra for the full guide.