Skip to content

peter-bread/peter.nvim

Repository files navigation

peter.nvim


My modular, relatively minimal* Neovim config for MacOS and Linux.


Requirements

  • Terminal emulator that supports:
    • Truecolor (24-bit colours)
    • Kitty Keyboard Protocol
    • e.g. Ghostty, kitty, WezTerm (with enable_kitty_keyboard = true)
  • A Nerd Font (for icons)
  • git
  • Neovim 0.11+ (and it's dependencies)
  • Fuzzy finding (snacks.picker):
  • Installing dev tools (mason.nvim):
    • For a detailed list, see here.
    • General:
      • git
      • curl or GNU wget
      • unzip
      • tar (or gtar)
      • gzip
    • External language runtimes & package managers:
  • Language Parsers (nvim-treesitter):
    • tar
    • curl
    • tree-sitter CLI (0.26.1+)
    • a C compiler (e.g. cc, gcc, clang)
    • node (23.0.0+)

Install

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"

Structure

General

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

Languages

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 = 4

Allowing both methods provides the most flexibilty. The first approach enables proper centralisation of language configuration. The second approach follows a more traditional structure.

LSP

LSP servers are configured separately. LSP configuration is done in one of two places:

  1. after/lsp/<lsp_server>.lua
  2. .nvim/lsp/<lsp_server>.lua (for project-local config, if exrc is 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.

Missing Functionality

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:

Custom snippets

Plugins:

Markdown

I would like to add a renderer and any other utilities. Are these actually needed though?

Plugins:

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

See Also