Skip to content
cb-gPublic

Latest commit

 

History

28 Commits

Folders and files

Repository files navigation

Neovim configuration for Linux

Targets the latest stable Neovim (0.12) on Debian/Ubuntu, x86_64 or aarch64. Everything that can live in ~/.local is installed there by a script, no root needed except for a handful of apt packages.

features

  • plugin manager: lazy.nvim, locked versions in lazy-lock.json
  • colors: kanagawa by default; tokyonight, catppuccin, rose-pine and gruvbox are a keypress away (t on the dashboard, previewed live, remembered across restarts). statusline: lualine
  • syntax: nvim-treesitter (main branch, parsers built with the tree-sitter cli)
  • language servers: native vim.lsp with nvim-lspconfig, installed by mason; per-server settings in lsp/
  • completion: blink.cmp with lsp, path, snippet and buffer sources
  • fuzzy finding: telescope with the native fzf sorter
  • files: oil.nvim (edit directories like buffers, replaces netrw)
  • formatting on demand: conform.nvim
  • markdown rendered in place with plain glyphs: render-markdown.nvim; no browser, no terminal image protocol, works over ssh
  • quarto: completion, hover and diagnostics inside code chunks with quarto-nvim and otter.nvim
  • debugging: nvim-dap with a ui, adapters for python, rust, c/c++, go, javascript/typescript, haskell
  • pinned files: harpoon, todo highlighting: todo-comments
  • zen mode (snacks), built-in undo tree and difftool
  • git: gitsigns, fugitive, lazygit through snacks
  • sessions per directory: auto-session
  • dashboard with a cow and a random quote (like vim-startify, no cowsay needed), notifications, indent guides: snacks.nvim
  • keymap hints: which-key
  • plain text throughout, no nerd-font icons, so any monospace font works
  • tmux: shared pane navigation, matching dotfiles/.tmux.conf
  • languages: Lua, LaTeX, Python, R, Quarto, Julia, OCaml, Haskell, Rust, Go, Zig, C/C++, Fortran, Bash, TypeScript/JavaScript, Markdown, TOML, YAML, JSON, SQL, CSV

install

git clone https://github.com/cb-g/nvim ~/nvim
~/nvim/scripts/install.sh

The script downloads the latest release of neovim, the tree-sitter cli, ripgrep, fd, stylua, lazygit and yq into ~/.local/opt and ~/.local/bin, symlinks ~/.config/nvim and ~/.tmux.conf to this repository and clones the tmux plugin manager. Any terminal with true color works; the config uses no icons, so any monospace font does too. Rerun it to update those tools. Make sure ~/.local/bin is on your PATH.

Nothing else is required: a stock Ubuntu already has the compiler, curl, git and unzip that parsers and servers need. The following are optional, each unlocks one thing:

apt package unlocks
tmux the tmux integration and dotfiles/.tmux.conf
wl-clipboard (wayland) or xclip (x11) the "+ register in a local session; over ssh neovim uses OSC 52 through the terminal instead
nodejs npm the bash, typescript, eslint, html, json, yaml, docker and sql servers and the javascript debug adapter
golang-go gopls and the go debug adapter
gfortran a compiler for fortls to check against
clangd C and C++ on aarch64, where mason has no build
python3-venv python3-pip lets mason install basedpyright and black; not needed if you use uv tool install basedpyright black
zathura biber chktex texlive-extra-utils LaTeX: pdf viewer with synctex, bibliography, texlab's chktex diagnostics, latexindent formatting

Everything at once:

sudo apt install tmux wl-clipboard xclip nodejs npm clangd python3-venv python3-pip zathura biber chktex texlive-extra-utils

Then start nvim. lazy.nvim installs the plugins, treesitter compiles the parsers and mason installs the servers whose runtime it can find (see language servers). :checkhealth tells you what is missing.

Shell aliases that go well with this:

alias vim=nvim
alias vimc='cd ~/nvim'
alias cleantex=~/nvim/scripts/rm_latex_aux.sh

layout

init.lua                  leader keys, loads lua/config
lua/config/options.lua    editor options
lua/config/keymaps.lua    global keymaps
lua/config/autocmds.lua   autocommands
lua/config/lazy.lua       lazy.nvim bootstrap and settings
lua/config/tools.lua      helper: is an executable available
lua/config/theme.lua      colorscheme picker and the remembered choice
lua/config/fortune.lua    the cow and its quotes for the dashboard
lua/plugins/ui.lua        kanagawa, lualine, which-key, snacks
lua/plugins/editor.lua    oil, telescope, harpoon, todo-comments, autopairs, surround, auto-session
lua/plugins/treesitter.lua
lua/plugins/completion.lua blink.cmp
lua/plugins/lsp.lua       lspconfig, mason, mason-lspconfig, lazydev, mason-tool-installer
lua/plugins/dap.lua       nvim-dap, dap-ui, adapters
lua/plugins/format.lua    conform
lua/plugins/git.lua       gitsigns, fugitive
lua/plugins/tmux.lua      nvim-tmux-navigation
lua/plugins/lang.lua      vimtex, R.nvim, quarto, julia-vim, vim-ocaml, haskell-tools, render-markdown, rainbow_csv
lsp/<server>.lua          per-server settings, picked up by vim.lsp.config
after/ftplugin/<ft>.lua   buffer-local keymaps and options (tex, ocaml, markdown, quarto)
dotfiles/                 .tmux.conf
scripts/install.sh        linux bootstrap
scripts/rm_latex_aux.sh   delete latex auxiliary files in the cwd

a typical session

  1. nvim in a project directory. The dashboard shows the cow, pinned actions and recent files; s restores the last session for that directory, t picks a theme.
  2. <leader>fs to jump to a file, <leader>fg to grep for a symbol, - to browse and reorganise the directory in oil.
  3. Language servers attach on their own once the file type is known: K for docs, gd to the definition, grr for references, grn to rename, gra for code actions, <leader>e to read a diagnostic, <leader>cf to format.
  4. <leader>a pins the files you keep coming back to, <leader>1 to <leader>4 jump between them, <C-e> shows the list.
  5. <leader>gs for staging and committing in fugitive, <leader>gg for lazygit, ]h and <leader>hp to walk through changes.
  6. <leader>dt sets a breakpoint, <F5> starts the debugger with the ui, <F10> steps.
  7. In LaTeX <leader>ll compiles on every save and <leader>lv opens the pdf; in markdown and quarto <leader>cp toggles the rendered view; <leader>z for writing without distractions.
  8. Sessions save on exit, so the next nvim in that directory picks up where you left off.

<leader>fk lists every keymap with its description, and pressing <leader> and waiting shows the groups. Everything below is also visible there.

keymaps

Leader is space, local leader is backslash. j and k are swapped: j moves up, k moves down, in normal, visual and select mode. The same orientation is used for pane navigation and resizing in tmux and for moving through telescope results.

general

key action
<C-h/j/k/l> move between splits and tmux panes (j up, k down)
<C-\>, <C-Space> last / next pane
<leader>|, <leader>- split right / below
<leader>m, <leader>n next / previous buffer
<leader>x close buffer
<leader>w, - file explorer (oil) in the current file's directory; edit the listing like text and :w to rename, move or delete, <C-r> refreshes, q closes
<leader>y, <leader>Y yank to the system clipboard
<leader>p (visual) paste over selection without losing the register
<leader>/ toggle comment
<C-d>, <C-u>, n, N as usual, with the cursor kept centered
<Esc> clear search highlight
<leader>u undo tree
<leader>z, <leader>Z zen mode, zoom the current window
<leader>a, <C-e> harpoon: pin the current file, open the pinned list
<leader>1 … <leader>4 harpoon: jump to pinned file 1 to 4
]t, [t, <leader>ft next / previous todo comment, list them
<leader>nh, <leader>nd notification history, dismiss notifications
<leader>L lazy
<leader>tt pick a colorscheme (also t on the dashboard)
q close help, quickfix, man and fugitive windows

find (telescope)

key action
<leader>fs files
<leader>fv git files
<leader>fg live grep
<leader>fw grep word under cursor
<leader>fo recent files
<leader>fb buffers
<leader>fh help tags
<leader>fd diagnostics
<leader>fk keymaps
<leader>fr resume last picker
<leader>fS sessions

Inside a picker <C-j> moves up and <C-k> moves down.

code (lsp, formatting)

Neovim's built-in lsp keymaps apply: K hover, grn rename, gra code action, grr references, gri implementation, grt type definition, gO document symbols, [d ]d diagnostics, <C-s> signature help in insert mode. On top of that:

key action
gd, gD definition, declaration
<leader>cr rename
<leader>ca code action
<leader>cf format buffer or selection (conform, lsp fallback)
<leader>cd, <leader>cR definitions, references (telescope)
<leader>cs, <leader>cS document, workspace symbols (telescope)
<leader>e line diagnostics
<leader>q diagnostics to the location list
<leader>th toggle inlay hints
<leader>td toggle diagnostics

completion (blink.cmp)

key action
<CR> accept
<C-n>, <C-p>, arrows next / previous item
<C-Space> open menu, toggle documentation
<C-e> close menu
<Tab>, <S-Tab> jump through snippet fields
<C-b>, <C-f> scroll documentation
<C-k> toggle signature help

git

key action
<leader>gg lazygit
<leader>gl, <leader>gf git log, git log for the current file
<leader>gs :Git (fugitive status)
<leader>gb :Git blame
<leader>gd diff against the index
<leader>gD :DiffTool for two files or directories, type the paths and press enter
]h, [h next / previous hunk
<leader>hs, <leader>hr stage / reset hunk (also in visual mode)
<leader>hS, <leader>hR stage / reset buffer
<leader>hp preview hunk
<leader>hb blame line
<leader>hd diff the current file against the index (gitsigns)
<leader>tb toggle current line blame
ih hunk text object

debug

key action
<F5>, <leader>dd start or continue
<F10>, <leader>do step over
<F11>, <leader>di step into
<F12>, <leader>dO step out
<leader>dt toggle breakpoint
<leader>dB conditional breakpoint
<leader>de evaluate expression under the cursor or selection
<leader>du toggle the debugger ui
<leader>dR repl
<leader>dl run the last configuration
<leader>dq terminate

Adapters: codelldb for Rust, C and C++ (asks for the executable to launch), debugpy for Python (<leader>dd on a file runs it with the project's interpreter), delve for Go, js-debug-adapter for JavaScript and TypeScript, haskell-tools for Haskell.

latex (tex buffers)

key action
<leader>ll compile continuously (latexmk, output in build/)
<leader>ss compile once
<leader>lv view pdf (zathura if installed, otherwise xdg-open)
<leader>lc clean the build directory
<leader>le errors
<leader>lt table of contents
<leader>cl delete auxiliary files in the cwd (scripts/rm_latex_aux.sh)

markdown

key action
<leader>cp toggle in-place rendering (headings, lists, code blocks, tables, links)

quarto (qmd buffers)

key action
<leader>cp, <leader>cP quarto preview, close it (needs the quarto cli)

Code chunks get completion, hover and diagnostics from the language servers of R, Python, Julia and Bash. R.nvim's console keys work in R chunks.

ocaml (ml buffers)

key action
<leader>db dune build
<leader>dr dune exec ./bin/main.exe

r

R.nvim's defaults, all with the local leader (backslash): \rf starts R, \d sends the line, \l sends the line and moves down, \aa sends the file, :RMapsDesc lists everything.

language servers

Mason installs these on first start when the language's runtime is present, so nothing fails on a machine that lacks it:

server language needs
lua_ls Lua nothing
texlab LaTeX nothing (compiling needs texlive and latexmk)
markdown_oxide Markdown nothing
rust_analyzer Rust a toolchain from rustup; rustup component add rust-analyzer rust-src is used when present
taplo TOML nothing
zls Zig nothing
clangd C, C++ mason on x86_64, apt install clangd on aarch64
basedpyright Python uv tool install basedpyright (no sudo), or python3-venv and python3-pip for mason
bashls Bash nodejs, npm; shellcheck and shfmt come from mason
vtsls, eslint TypeScript, JavaScript nodejs, npm
html, jsonls, yamlls, dockerls, sqlls nodejs, npm
gopls Go go
fortls Fortran python3-venv, python3-pip
julials Julia julia
elixirls, elp Elixir, Erlang elixir, erl

Servers that are already on the path (ocamllsp, clangd, basedpyright, rust-analyzer) are enabled directly and not installed again by mason. Handled outside mason:

  • OCaml: opam install ocaml-lsp-server ocamlformat ocp-indent. The server from the active switch is used, ocp-indent's vim plugin is picked up from opam var share.
  • Haskell: install haskell-language-server with ghcup, haskell-tools.nvim starts it.
  • R: R.nvim ships its own language server, install.packages("languageserver") is not needed.
  • Rust: rust-analyzer only works with a toolchain, so install rustup first. rustfmt comes with it and is what <leader>cf uses.
  • Python: uv tool install basedpyright black puts both on the path. The interpreter is taken from $VIRTUAL_ENV, then .venv/ in the project root, then ~/.config/venvs_py/.default, then python3.

Formatters used by <leader>cf: stylua (Lua), black (Python), ocamlformat, rustfmt, fourmolu or ormolu (Haskell), shfmt; anything else falls back to the language server. stylua comes from the install script, the others from their toolchains.

toolchains

# latex
sudo apt install texlive-full latexmk zathura biber chktex texlive-extra-utils
# python
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install basedpyright black
# rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rust-analyzer rust-src
# r
sudo apt install r-base
# go
sudo apt install golang-go
# fortran
sudo apt install gfortran
# quarto
# https://quarto.org/docs/get-started/
# julia
curl -fsSL https://install.julialang.org | sh
# haskell
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
# ocaml
bash -c "sh <(curl -fsSL https://raw.githubusercontent.com/ocaml/opam/master/shell/install.sh)"
opam init && opam install ocaml-lsp-server odoc ocamlformat ocp-indent utop

dotfiles

tmux

dotfiles/.tmux.conf, symlinked to ~/.tmux.conf by the install script. Prefix is ctrl-s.

key action
prefix |, prefix - split right / below in the current path
ctrl-h/j/k/l move between panes, also from inside nvim (j up, k down)
prefix h/j/k/l resize the pane
prefix r reload the config
prefix I install plugins
v, y in copy mode select, copy to the system clipboard

The window-name plugin needs mikefarah's yq, which the install script provides (the yq in apt is a different program).

maintenance

# update plugins (writes lazy-lock.json)
nvim "+Lazy sync"
# update parsers and servers
nvim "+TSUpdate" "+MasonUpdate"
# format the lua files
stylua .

Reset everything the config generated:

rm -rf ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim

references

Contributors

Languages