My modular, relatively minimal* Neovim config for MacOS and Linux.
- Terminal emulator that supports:
- A Nerd Font (for icons)
git- Neovim 0.11+ (and it's dependencies)
- Fuzzy finding (
snacks.picker): - Installing dev tools (
mason.nvim): - Language Parsers (
nvim-treesitter):tarcurltree-sitterCLI (0.26.1+)- a C compiler (e.g.
cc,gcc,clang) node(23.0.0+)
Clone the repository and run the headless install
script. Then set NVIM_APPNAME to peter.nvim.
Putting this config under its own NVIM_APPNAME ensures that it doesn't
conflict with any existing Neovim configs and makes it easier to switch between
multiple configs if desired.
For more info, see
here, or run :h NVIM_APPNAME inside Neovim.
git clone https://github.com/peter-bread/peter.nvim.git \
"${XDG_CONFIG_HOME:-$HOME/.config}/peter.nvim" &&
cd "${XDG_CONFIG_HOME:-$HOME/.config}/peter.nvim" &&
./scripts/install &&
export NVIM_APPNAME="peter.nvim"The entry point is the top-level init.lua.
The majority of configuration can be found in lua/peter/.
lua/peter/
├── config/ # Main configuration module
│ ├── autocmds.lua - General autocmds
│ ├── diagnostic.lua - Diagnostic settings and icons
│ ├── filetypes.lua - Add custom filetypes
│ ├── ftplugin.lua - Set up filetype-specific behaviour (from language config)
│ ├── globals.lua - Global functions (for debugging only)
│ ├── init.lua - Entry point for config module
│ ├── keymaps.lua - Set keymaps
│ ├── lazy.lua - Bootstrap and configure lazy.nvim plugin manager
│ ├── lsp.lua - Set up LSP (from language config)
│ └── options.lua - Set global variables and options
├── languages/ # Language configs
│ ├── init.lua - Builds table that maps languages to configs
│ └── lua.lua - Lua config (example)
├── plugins/ # Plugins
│ ├── core/ - General plugins
│ ├── lsp/ - LSP related plugins
│ ├── mini/ - Plugins from mini.nvim
│ └── snacks/ - Modules from snacks.nvim
└── util/ # Utility functions
There is additional configuration in after/.
after/
├── ftplugin/ # Filetype-specific behaviour (NOT from language config)
└── lsp/ # LSP server configurations
Programming languages are managed in
lua/peter/languages/<language>.lua. Each of these
files should return a table of type peter.lang.config. The type is defined in
lua/peter/languages/init.lua and shown
below:
---@class (exact) peter.lang.Config
---@field lsp? string[] List of LSP servers to be enabled.
---@field plugins? peter.lang.plugins | LazyPluginSpec[] Plugins to be installed.
---@field ftplugin? peter.lang.ftplugin Buffer-specific options and config.
---@class (exact) peter.lang.plugins
---@field treesitter? string[] List of treesitter parser names.
---@field mason? thirdparty.mti.PkgEntry[] List of mason packages.
---@field format? peter.lang.formatters_by_ft Mapping of filetypes to formatters.
---@field lint? table<string, string[]> Mapping of filetypes to linters.
---@class (exact) peter.lang.ftplugin
---@field ft string|string[] Filetype(s) to run `callback` on.
---@field callback fun(args: vim.api.keyset.create_autocmd.callback_args)There is also still the option to use
after/ftplugin/<filetype>.lua to set buffer-specific
options. However, it can be easier to use the table approach above as
ftplugin.ft can be a list, so you can apply the same options to multiple
filetypes while only writing the code once, for example Haskell and Cabal
files.
When populating the plugins field, there are common plugins you need to
configure for most languages. Helper functions are defined in
lua/peter/util/plugins/languages.lua.
Instead of calling these directly in in the plugins field, you can include
table fields with the same name (see example below).
Language configs are processed in
lua/peter/languages/init.lua. This builds
and exposes a table which maps language names to configurations. This table can
be accessed with:
-- Whole table.
local languages = require("peter.languages")
-- Just Lua config.
local lua_config = require("peter.languages").lua
local lua_config = require("peter.languages")["lua"]To make working with this table easier, utility functions are provided in
lua/peter/util/languages.lua.
Example config to set up the Lua programming language:
-- lua/peter/languages/lua.lua
-- [NOT REQUIRED]
-- Access helper functions.
--
-- local L = require("peter.util.plugins.languages")
---@type peter.lang.Config
return {
lsp = { "lua_ls" }, -- Enable Lua Language Server.
plugins = {
treesitter = { "lua", "luadoc" }, -- Install parsers.
mason = { "lua_ls", "stylua" }, -- Install LSP and formatter.
format = { lua = { "stylua" } }, -- Register formatter.
-- [NOT REQUIRED]
-- You *can* use these functions directly, but it is better to use a table.
--
-- L.treesitter({ "lua", "luadoc" }) -- Install parsers.
-- Include some other plugin in the spec.
{
"some/plugin",
opts = {},
},
},
ftplugin = {
ft = "lua", -- Run on Lua files.
callback = function() -- Function to be executed for each Lua file.
vim.bo.shiftwidth = 4
end,
},
}If you prefer to use after/ftplugin, you can split this config into two files:
-- lua/peter/languages/lua.lua
---@type peter.lang.Config
return {
lsp = { "lua_ls" }, -- Enable Lua Language Server.
plugins = {
treesitter = { "lua", "luadoc" }, -- Install parsers.
mason = { "lua_ls", "stylua" }, -- Install LSP and formatter.
format = { lua = { "stylua" } }, -- Register formatter.
},
}-- after/ftplugin/lua.lua
vim.bo.shiftwidth = 4Allowing both methods provides the most flexibilty. The first approach enables proper centralisation of language configuration. The second approach follows a more traditional structure.
LSP servers are configured separately. LSP configuration is done in one of two places:
after/lsp/<lsp_server>.lua.nvim/lsp/<lsp_server>.lua(for project-local config, ifexrcis enabled)
In the second case, make sure vim.o.exrc = true and that you also create
.nvim.lua with the following code:
-- .nvim.lua
vim.cmd([[set runtimepath+=.nvim]])These files should each return a table of type vim.lsp.Config.
The nvim-lspconfig plugin is used
to provide sane default configurations for all language servers. As a user, you
can overwrite or extend these configurations in after/lsp/<lsp_server>.lua.
Warning
See here for LSP servers
that are not (yet) compatible with vim.lsp.{enable,config}. These servers need
to be set up with require("lspconfig")[server_name].setup(server_cfg).
Currently, this is not supported in this Neovim config. This will only
be supported if I ever need to use one of these LSP servers, which is
unlikely.
This config is a bit more minimal than my previous config. Below is a list of features that are not currently implemented in this config. Some of these were in my previous config, others were not.
Git Integration (UNFINISHED)
I need to decide how much git integration is needed inside Neovim. How much do I need to do in Neovim vs what can I do from a terminal.
Plugins:
UPDATE:
Started using Neogit. It probably still needs some configuration. If I end up using a statusline, I will need some other plugin to provide diff info.
Statusline
This config is aiming to be relatively minimal. Do I actually need a statusline plugin or is it just aesthetically nice? I do like having diagnostic/git info so I may add this.
Plugins:
Markdown
I would like to add a renderer and any other utilities. Are these actually needed though?
Plugins:
- Renderer:
- Utilties
Debugging
If I am to add this back in, I would like to use both nvim-dap and overseer.nvim. Might not implement for a while as it will probably need quite a lot of setup to get it working nicely. Note: overseer.nvim integrates with nvim-dap, but that is only a small feature of it.
Plugins:
Org-mode
*It's not that minimal.