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? LazyPluginSpec[] Plugins to be installed.
---@field ftplugin? peter.lang.config.ftplugin Buffer-specific options and config.
---@class (exact) peter.lang.config.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, it is useful to use the accompanying
utility functions, found in lua/peter/util/plugins/languages.lua.
These remove some of the boilerplate code for extending the options of commonly
used plugins.
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
local L = require("peter.util.plugins.languages")
---@type peter.lang.config
return {
lsp = { "lua_ls" }, -- enable lua language server
plugins = {
L.treesitter({ "lua", "luadoc" }), -- install parsers
L.mason({ "lua_ls", "stylua" }), -- install LSP and formatter
L.format({ lua = { "stylua" } }), -- register formatter
},
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
local L = require("peter.util.plugins.languages")
---@type peter.lang.config
return {
lsp = { "lua_ls" }, -- enable lua language server
plugins = {
L.treesitter({ "lua", "luadoc" }), -- install parsers
L.mason({ "lua_ls", "stylua" }), -- install LSP and formatter
L.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: