Customize
Blak has one config file and one optional-module command:
:BlakConfig:BlakExtras:BlakConfig opens lua/blak/user.lua. If it does not exist yet, Blak creates
it from a small example. From a shell, the same setup is:
cp ~/.config/blak/lua/blak/user.example.lua ~/.config/blak/lua/blak/user.luaThe easy path
Section titled “The easy path”Most customization should be this boring:
---@type blak.UserConfigreturn { picker = { provider = "fff" }, completion = { super_tab = true }, terminal = { toggle_key = "<C-/>" }, extras = { enabled = { "lang.typescript", "git.lazygit" } },}That table is deep-merged into Blak’s defaults. You only keep the keys you want
to change, and the ---@type blak.UserConfig annotation gives lua_ls
completion for Blak config keys.
user.lua is gitignored by default so your local setup stays local. Blak also
ships picker ignore metadata so file tools can still find the file.
Common changes
Section titled “Common changes”Switch picker:
return { picker = { provider = "snacks" }, -- fff | snacks | telescope | fzf_lua}Switch explorer:
:BlakExtras enable editor.snacks-explorerOr set the provider directly if you are already managing Snacks options:
return { explorer = { provider = "snacks" }, snacks = { explorer = { enabled = true } },}Add or override keymaps:
return { keymaps = { { key = "<leader>sg", action = "<cmd>BlakPick grep<cr>", description = "Grep" }, { mode = { "n", "x" }, key = "<leader>y", action = '"+y', description = "Yank to clipboard", }, { key = "<leader>rn", action = function() vim.lsp.buf.rename() end, description = "Rename symbol", }, { key = "<leader>/", disable = true }, },}Every active mapping needs description so it appears in :BlakKeys. Use
mode for one mode or a list of modes, and use a command string or Lua function
for action. Use disable = true to remove one of Blak’s default mappings
before adding your replacement.
Add Mason tools or Treesitter parsers:
return { mason = { ensure_installed = { "stylua", "shfmt", "tree-sitter-cli", "buf" }, }, treesitter = { ensure_installed = { "bash", "lua", "markdown", "proto" }, },}Tune LSP diagnostics:
return { lsp = { diagnostics = { virtual_text = false, virtual_lines = true, }, },}Personal plugins
Section titled “Personal plugins”Use plugins.specs for personal lazy.nvim specs that do not belong in Blak
core or a reusable extra:
return { plugins = { specs = { { "tpope/vim-sleuth", event = "BufReadPost" }, }, },}Blak appends these specs after core and enabled extras, so you can also use them to tune or disable a default plugin through normal lazy.nvim spec rules.
If the plugin is a broadly useful, reversible feature, consider writing an
extra instead. Extras are the shareable path;
plugins.specs is the personal path.
Lua hooks
Section titled “Lua hooks”Use hooks when a setting is clearer as code than as config:
return { hooks = { after = function(config) vim.opt.cursorline = false end, },}hooks.before runs after Blak merges defaults, globals, user.lua, and
setup(opts), but before validation and extras apply. Use it to adjust the
merged config before Blak consumes it.
hooks.after runs after Blak finishes setup and after each successful
user.lua reload. If you create autocmds there, use your own augroup with
clear = true so reloads stay clean.
Full control form
Section titled “Full control form”When a table starts fighting you, return a function instead. Blak passes the config table it is building directly:
---@param config blak.Config---@param blak blak.UserContextreturn function(config, blak) config.picker.provider = "snacks" table.insert(config.extras.enabled, "lang.typescript") table.insert(config.plugins.specs, { "tpope/vim-sleuth", event = "BufReadPost" })
config.hooks.after = function() vim.opt.cursorline = false endendThis is still plain Lua. There is no Blak-specific DSL: config starts with
Blak defaults plus vim.g.blak_config, then Blak applies any setup(opts),
validates, and applies extras. blak.util is available on the second argument
for path, file, notification, and safe-require helpers.
Merge semantics
Section titled “Merge semantics”Blak deep-merges config tables via vim.tbl_deep_extend("force", defaults, user).
- Scalars in your table replace defaults.
- Tables are merged key by key.
- Lists are replaced by index, so prefer extras or the function form when you want to append to defaults.
See the config schema for valid keys and the defaults reference for what you are overriding.
When to fork
Section titled “When to fork”Fork when you want to change Blak’s public contract for everyone: a different
default picker, completion engine, explorer strategy, splash, or upgrade path.
Use user.lua, plugins.specs, hooks, or an extra when you want to change your
own setup.
Language extras fill in missing LSP settings and Snacks options; explicit values
in user.lua take precedence. Provider-switching extras intentionally select
their provider. Avoid enabling two competing provider extras together.