Essay

ACH-NEOVIM: My Neovim Configuration for macOS

October 12, 2026112 min read

How I set up Neovim on my Mac: installing it, every key, every plugin with its code, and every language, written from the configuration's own source.

01.Getting Started

ACH-NEOVIM is my Neovim configuration for macOS. Neovim is a text editor that runs inside a terminal and is driven from the keyboard, and a configuration is the set of files that tells it which plugins to load, what each key does and how each language is handled. I wrote this one from scratch on lazy.nvim, the plugin manager, and it lives at github.com/anirbanchakraborty-dev/ACH-NEOVIM under the MIT licence.

Why I built it. I wanted one editor that already knows every language I work in: C and C++, Python, Rust, SystemVerilog and Verilog, VHDL, LaTeX and Markdown, with the rest of about ninety languages there when I need them. I did not want it to fill my disk with tools for languages I never open, so nothing for a language installs until I open a file in it. I wanted it to start fast, too. It starts within 10% of stock LazyVim's time, and its own test suite fails any change that makes it take more than one and a half times as long to start as it did when I first timed it. LazyVim showed me what a well-made Neovim setup looks like. I took its ideas and built my own, small enough that I can read every line of it and keep it working, and the few files that adapt a LazyVim function say so in their first lines and name LazyVim's Apache-2.0 licence.

Who it is for. It is for someone on a Mac who writes code and technical documents in many languages, works from the keyboard, and would rather set things up properly once than tinker forever.

My favourite part. I never install a language's tools by hand. I open a file in a language I have not touched in months, and while I read the first screen, its highlighting, completion and formatter install in the background and switch on. A close second is having Claude Code right inside the editor, on Space a c, looking at the same file I am.

02.Installation

Installing takes one Homebrew session, one clone and one first start. Every command below is typed in a terminal, in the order given.

Install Homebrew. Homebrew is the Mac's package manager, and everything else comes from it. If brew --version prints nothing, follow the one command on brew.sh.

Install the programs. Neovim itself, git, ripgrep and fd for searching, lazygit for git, the tree-sitter command-line program, ImageMagick for pictures, Ghostty, and the font:

Bash
brew install neovim git ripgrep fd lazygit tree-sitter-cli imagemagick
brew install --cask ghostty font-jetbrains-mono-nerd-font
xcode-select --install

ACH-NEOVIM needs Neovim 0.12.4 or later, and nvim --version prints the version on its first line. The tree-sitter program builds each language's parser, the part that reads its syntax, with the compiler from Apple's Command Line Tools, which is what the last line installs.

Back up what you have. The clone goes exactly where a Neovim configuration lives, so move yours aside first, with the folders Neovim keeps its data, its state and its cache in:

Bash
mv ~/.config/nvim ~/.config/nvim.bak
mv ~/.local/share/nvim ~/.local/share/nvim.bak
mv ~/.local/state/nvim ~/.local/state/nvim.bak
mv ~/.cache/nvim ~/.cache/nvim.bak

A line whose folder does not exist only prints an error, so run all four.

Clone the configuration.

Bash
git clone https://github.com/anirbanchakraborty-dev/ACH-NEOVIM ~/.config/nvim

Link Ghostty's settings. The repository carries Ghostty's settings in ghostty/config.ghostty: the font at 15 points, the navy background, the left Option key working as Alt, and the sixteen colours Neovim's own terminal uses. Link the file to where Ghostty reads it:

Bash
mkdir -p ~/.config/ghostty
ln -s ~/.config/nvim/ghostty/config.ghostty ~/.config/ghostty/config.ghostty

Start Neovim.

Bash
nvim

The first start installs every plugin at the commit pinned in lazy-lock.json, so you get the versions I test. Let it finish before you open anything.

Check what is missing. Inside Neovim, type this and press Enter:

Plain Text
:checkhealth ach

Read what it says. It lists each program the configuration uses, installed or not, and gives each missing one the single command that installs it.

Open a file. The first time you open a file in a language, its parser, its language server, its formatter and its linter install by themselves in the background, without asking, and switch on when they are ready. A language that needs a compiler or runtime only Homebrew provides, such as Haskell's GHC or Julia, asks first, once, in one line that names it and its rough size. Say yes, and Homebrew installs it in the background while you keep editing. Say no, and it does not ask again until you next start Neovim.

Add the programs some keys use. A key whose program is missing prints the line that installs it instead of running, and :checkhealth ach lists the same programs:

ProgramWhat it is forInstall
lazygitLazygit on Space g g and Space g Gbrew install lazygit
ghGitHub issues and pull requests on Space g i and Space g pbrew install gh, then gh auth login
claudethe Claude Code panel on Space abrew install --cask claude-code
latexmkbuilding LaTeX documents on Space c bbrew install --cask mactex
displaylineshowing LaTeX PDFs in Skim and jumping between them and the sourcebrew install --cask skim
magickturning pictures and formulas into images the terminal can showbrew install imagemagick
pdflatextypesetting the formulas in Markdown filesbrew install --cask mactex
gsletting ImageMagick read the PDF a formula is typeset intobrew install ghostscript
pdftotextreading Intel's manual to find each instruction's pagebrew install poppler
newsboatthe feed reader on Space Nbrew install newsboat

03.What's New

Here is what ACH-NEOVIM does beyond editing text, area by area. Each area's keys are in the Keymaps section below.

Git. Change bars in the margin show what changed since the last commit, and ] h and [ h move between the changes. Lazygit opens on Space g g. Neogit, git's status page inside Neovim, opens on Space g n, and diffview shows every uncommitted change side by side on Space g D. GitHub's issues and pull requests are on Space g i and Space g p, through gh. A git key pressed on a file outside every repository says so and opens nothing, and a link copied to the current line never carries a user name or a token from the remote's address.

Claude Code. Space a c opens Claude Code in a panel on the right, 40 percent of the screen wide. It sees the file and the selection I am on, and a change it proposes opens side by side, to accept with Space a a or reject with Space a d. Its server listens only on this Mac, refuses a connection without the token in its lock file, and never starts when Neovim has no window.

LaTeX. VimTeX builds the document on Space c b, with latexmk or with a command the project sets, and shows the PDF in Skim, and I can jump from a line of the source to its place in the PDF and back. The build's own files are kept outside the repository.

Markdown. Headings, lists and tables are drawn in place while I write, formulas and pictures are drawn as images inside the editor, and Space c p opens a preview in the browser that keeps up with the file as it changes. The preview's server listens only on this Mac and serves nothing outside the folder it was started for.

Intel's manual. Space c x opens Intel's x86 manual in Skim at the page for the instruction under the cursor, and on any other word lists every instruction to pick one. The manual is Intel's to publish, so it is not in the repository.

News. Space N opens newsboat, a feed reader, in a window floating over the editor.

Ghostty. The repository carries Ghostty's settings: JetBrains Mono at 15 points, the same navy background as the editor, the left Option key working as Alt, and the sixteen colours Neovim's own terminal uses.

Startup. It starts within 10% of stock LazyVim's time, the two timed side by side over thirty starts each, and the test suite fails any change that makes it take more than one and a half times as long to start as it did when first timed.

Updates. scripts/update updates every plugin and Mason package, runs the full test suite, and commits both lock files when it passes, or puts everything back when it does not.

Upgrade check. The first time a new Neovim release starts on a screen, the fast test suite runs in the background, and the release is recorded once it passes.

Key card. docs/key-card.md is one page of keys to keep beside the keyboard, and a test fails whenever it disagrees with the keys the configuration sets.

This page. scripts/docs writes this page from the configuration's own source, so a plugin, a key or a language added to the configuration shows here the next time it runs.

04.Keymaps

Every key this configuration sets, with the description the menus show for it and the modes it works in, grouped the way the key card in docs/key-card.md groups them. A key is written the way it is pressed: Space f f is Space, then f, then f, and Ctrl-h is h pressed while Ctrl is held.

The Mode column uses Neovim's one-letter names. n is normal mode, where keys move and edit. x is visual mode, after selecting text with v. s is select mode, which snippets use for the parts to fill in. o is operator-pending mode, after an operator such as d and before the motion that says what it acts on. i is insert mode, for typing. c is the command line, after :. t is a terminal window.

Inside Neovim each key also shows an icon. This page leaves the icons out, because they come from the JetBrains Mono Nerd Font and this website does not load that font, so each would draw as an empty box. Keys a plugin sets only inside its own window, and text objects such as i ( in d i (, are not listed here. Inside Neovim, Space s k searches every key, those included.

Files and buffers

KeyDescriptionMode
Space SpaceFind Files (Root Dir)n
Space f rRecentn
Space f nNew Filen
Space eFile Tree (project)n
Space f oOpen Folder as Text (oil)n
Space ,Buffersn
Shift-hPrev Buffern
Shift-lNext Buffern
Space b dDelete Buffern
Ctrl-sSave Filen, x, s, i
Ctrl-sToggle Flash in Searchc
Space q sRestore Session for This Foldern
Space q qQuit Alln
Space EFile Tree (working folder)n
Space b DDelete Buffer and Windown
Space b bSwitch to Other Buffern
Space b oDelete Other Buffersn
Space f EFile Tree (working folder)n
Space f FFind Files (cwd)n
Space f RRecent (cwd)n
Space f TTerminal (cwd)n
Space f bBuffersn
Space f cFind Config Filen
Space f eFile Tree (project)n
Space f fFind Files (Root Dir)n
Space f gFind Files (git-files)n
Space f pProjectsn
Space f tTerminal (Root Dir)n
Space f yCopy File Pathn
Space q SPick a Sessionn
Space q dDon't Save This Sessionn
Space q lRestore Last Sessionn

Search and moving

KeyDescriptionMode
Space /Grep (Root Dir)n
Space s bBuffer Linesn
Space s rSearch and Replacen, x
Space s hHelp Pagesn
Space s kKeymapsn
Space s RResumen
sFlash Jumpn, x, o
SFlash Select by Syntaxn, x, o
Space :Command Historyn
Space s "Registersn
Space s /Search Historyn
Space s BGrep Open Buffersn
Space s CCommandsn
Space s DBuffer Diagnosticsn
Space s GGrep (cwd)n
Space s HHighlightsn
Space s MMan Pagesn
Space s SLSP Workspace Symbolsn
Space s TTODO and FIX Commentsn
Space s WSelection or Word (cwd)n, x
Space s aAutocmdsn
Space s cCommand Historyn
Space s dDiagnosticsn
Space s gGrep (Root Dir)n
Space s iIconsn
Space s jJumpsn
Space s lLocation Listn
Space s mMarksn
Space s pSearch for Plugin Specn
Space s qQuickfix Listn
Space s sLSP Symbolsn
Space s tTODO Commentsn
Space s uUndo Historyn
Space s wSelection or Word (Root Dir)n, x
[ HFirst Hunkn
[ bPrev Buffern
[ tPrevious TODO Commentn
] HLast Hunkn
] bNext Buffern
] tNext TODO Commentn

Code

KeyDescriptionMode
g dGoto Definitionn
g r rReferencesn
KHovern
Space c aCode Actionn, x
Space c rRenamen
Space c fFormatn, x
Space c dLine Diagnosticsn
] dNext Diagnosticn
Space x xProblems (Trouble)n
Space c mMasonn
Space c xx86 Manualn
Space c bBuild Documentn
Space c pMarkdown Previewn
Space c ASource Actionn
Space c CToggle Codelensn
Space c FFormat Injected Langsn, x
Space c RRename Filen
Space c SDefinitions and References (Trouble)n
Space c cRun Codelensn, x
Space c lLsp Infon
Space c oOrganize Importsn
Space c sSymbols (Trouble)n
Space x LLocation List (Trouble)n
Space x QQuickfix List (Trouble)n
Space x TTODO and FIX Comments (Trouble)n
Space x XProblems in This Buffer (Trouble)n
Space x lLocation Listn
Space x qQuickfix Listn
Space x tTODO Comments (Trouble)n
[ [Prev Referencen
[ dPrev Diagnosticn
[ ePrev Errorn
[ qPrevious Problem or Quickfix Entryn
[ wPrev Warningn
] ]Next Referencen
] eNext Errorn
] qNext Problem or Quickfix Entryn
] wNext Warningn
g DGoto Declarationn
g a iIncoming Callsn
g a oOutgoing Callsn
g r iGoto Implementationn
g r tGoto Type Definitionn

Git

KeyDescriptionMode
Space g gLazygit (Root Dir)n
Space g nNeogit (Root Dir)n
] hNext Hunkn
Space g h pPreview Hunk Inlinen
Space g h sStage or Unstage Hunkn, x
Space g h rReset Hunkn, x
Space g DDiff View (Root Dir)n
Space u bToggle Git Blame Linen
Space g BGit Browse (open)n, x
Space g pGitHub Pull Requestsn
Space g FFile History (Diff View)n
Space g GLazygit (cwd)n
Space g LGit Log (cwd)n
Space g SGit Stashn
Space g YGit Browse (copy link)n, x
Space g bGit Line Historyn
Space g cGit Branchesn
Space g dGit Diff (hunks)n
Space g fGit File Historyn
Space g h BBlame Buffern
Space g h DDiff This ~n
Space g h RReset Buffern
Space g h SStage Buffern
Space g h bBlame Linen
Space g h dDiff Thisn
Space g iGitHub Issuesn
Space g lGit Log (Root Dir)n
Space g sGit Statusn
[ hPrev Hunkn

Claude Code

KeyDescriptionMode
Space a cToggle Clauden
Space a bAdd Buffer to Clauden
Space a sAdd File to Clauden
Space a sSend to Claudex
Space a aAccept Diffn
Space a dDeny Diffn
Space a rResume Clauden
Space a CContinue Clauden
Space a fFocus Clauden
Space a mSelect Claude Modeln

Debugging

KeyDescriptionMode
Space d bToggle Breakpointn
Space d cStart or Continuen
Space d OStep Overn
Space d iStep Inton
Space d oStep Outn
Space d tStop Debuggingn
Space d uDebug Interfacen
Space d BConditional Breakpointn
Space d CRun to Cursorn
Space d LLog Pointn
Space d MDebug Test Classn
Space d PPause Debuggingn
Space d RRestart Debuggingn
Space d aStart with Argumentsn
Space d eEvaluate Expressionn, x
Space d gJump to Line Without Runningn
Space d jFrame Downn
Space d kFrame Upn
Space d lRerun Last Debugn
Space d mDebug Nearest Testn
Space d rDebug Consolen
Space d sDebug Sessionsn
Space d wInspect Valuen

Windows and toggles

KeyDescriptionMode
Ctrl-hGo to Left Windown
Space -Split Window Belown
Space |Split Window Rightn
Space w dDelete Windown
Space u fToggle Format on Save (all buffers)n
Space u FToggle Format on Save (this buffer)n
Space u wToggle Wrapn
Space u sToggle Spellingn
Space u zToggle Zen Moden
Space u uUndo Treen
Ctrl-kGo to Upper Windown
Ctrl-lGo to Right Windown
Space Tab TabNew Tabn
Space Tab [Previous Tabn
Space Tab ]Next Tabn
Space Tab dClose Tabn
Space Tab fFirst Tabn
Space Tab lLast Tabn
Space Tab oClose Other Tabsn
Space u DToggle Dimmingn
Space u EPick a Docked Panen
Space u GToggle Git Signsn
Space u IInspect Treen
Space u LToggle Relative Numbern
Space u TToggle Treesitter Highlightn
Space u ZToggle Zoom Moden
Space u cToggle Concealn
Space u dToggle Diagnosticsn
Space u eToggle Docked Panesn
Space u gToggle Indent Guidesn
Space u hToggle Inlay Hintsn
Space u iInspect Posn
Space u lToggle Line Numbersn
Space u rRedraw / Clear hlsearchn
Space w mToggle Zoom Moden

Outside the menus

KeyDescriptionMode
EscEscape and Clear hlsearchn, s, i
Ctrl-/Terminal (Root Dir)n, t
Alt-jMove Downn, x, s, i
Ctrl-SpaceGrow Selection by Syntaxn, x, o
Alt-DownAdd Cursor Belown, x
Space nNotification Historyn
Space NNewsn
Space lLazyn
Space ?Buffer Keymaps (which-key)n
Ctrl-DownDecrease Window Heightn
Ctrl-LeftDecrease Window Widthn
Ctrl-RightIncrease Window Widthn
Ctrl-UpIncrease Window Heightn
Ctrl-w SpaceWindow Hydra Mode (which-key)n
DownDownn, x
Alt-UpAdd Cursor Aboven, x
Alt-kMove Upn, x, s, i
NLGo to Lower Windown
Space `Switch to Other Buffern
Space m AAdd Cursors at Every Matchn, x
Space m NAdd Cursor at Previous Matchn, x
Space m SSkip to Previous Matchn, x
Space m aAlign Cursorsn
Space m nAdd Cursor at Next Matchn, x
Space m sSkip to Next Matchn, x
Space m xAdd or Remove a Cursor Heren, x
UpUpn, x
<Indent Leftx
>Indent Rightx
NPrev Search Resultn, x, o
RFlash Search by Syntaxx, o
g KSignature Helpn
g c OAdd Comment Aboven
g c oAdd Comment Belown
i hSelect Hunkx, o
jDownn, x
kUpn, x
nNext Search Resultn, x, o
rFlash Remoteo

05.Configuration

Everything that makes ACH-NEOVIM what it is lives in plain Lua files in the repository. These are the places I change most, and how I change them.

The layout

Plain Text
~/.config/nvim
├── init.lua checks the Neovim version, then loads lua/ach
├── lazy-lock.json the commit of every plugin
├── mason-lock.json the version of every Mason package
├── lua/ach/ options, keys, autocommands, the language table, and the logic behind each feature
│ └── plugins/ the plugin specs, one file per area
├── snippets/ my own snippets
├── ghostty/ Ghostty's settings
├── docs/ the key card, the list of languages, and the hand-written parts of this page
├── scripts/ check, update and docs
└── tests/ the test suite

Options, keymaps and autocommands

Editor options live in lua/ach/options.lua, keys that belong to no plugin in lua/ach/keymaps.lua, and autocommands, the small actions Neovim runs when something happens, such as opening a file or saving one, in lua/ach/autocmds.lua. Keys that belong to a plugin live in that plugin's spec, under keys.

Adding a plugin

A plugin is a file in lua/ach/plugins/ that returns its spec, because lazy.nvim imports every file in that folder. The Full Spec tabs in the Plugins section below are real specs to copy from. Then:

  • Give every key a desc, and give that description a line in M.keys in lua/ach/icons.lua. The test suite fails a key without one, since that line is what draws its icon in the menus.
  • Give the plugin an entry in lua/ach/docs.lua, with its category and one sentence saying what it does. The test suite fails a plugin in lazy-lock.json without one.
  • Start Neovim once, so lazy.nvim installs the plugin and records its commit in lazy-lock.json.
  • If the plugin adds keys, run scripts/check --keymaps. Then run scripts/check, and commit the new file, lazy-lock.json, lua/ach/icons.lua, lua/ach/docs.lua and docs/site/keymaps.json together.

Adding a language

Every language is one entry in M.languages in lua/ach/languages.lua, under its name. The entry lists the file types it covers in ft, the Tree-sitter parsers in ts, the language servers in lsp, the formatters in fmt, the linters in lint, any other Mason packages it needs in mason, and harper = true when Harper should check its grammar. The Entry tab of each language in the Languages section below is that language's real entry, and CMake's uses every one of these fields. Settings for a server go in M.settings in lua/ach/servers.lua, under the server's name, and show in the language's Options tab.

Then run scripts/check, and scripts/check --full, which installs the new language's tools, tests them, adds their versions to mason-lock.json and rewrites the list of languages in docs/languages.md. Commit all of it together.

Settings for one project

Neovim reads a file called .nvim.lua in the folder it starts in, because ACH-NEOVIM turns on Neovim's exrc option. Neovim asks before it runs such a file the first time, and again whenever the file changes, so a repository you clone cannot run code on you just by shipping one. A LaTeX project can use it to give Space c b its own build command:

Lua
require("ach.latex").build_with(function(main)
return { "make", "pdf" }, vim.fs.dirname(main)
end)

The function receives the main file's path and returns the command and the folder to run it in. Returning nothing falls back to latexmk.

Updates and the lock files

lazy-lock.json holds the commit of every plugin and mason-lock.json the version of every Mason package, so two Macs on the same commit of this repository run the same code.

  • scripts/update --list shows what an update would move: the new commits of each plugin and the newer release of each Mason package. It changes nothing.
  • scripts/update updates every plugin and Mason package, runs scripts/check --full, and commits both lock files when it passes. When it fails, it puts the lock files back and makes what is installed match them again.
  • scripts/update --restore does only that second part. Run it on a second Mac after a git pull brings new lock files.
  • Inside Neovim, :AchMasonUpdate updates every installed Mason package and moves its pin, and :AchMasonLock pins a package installed by hand from the :Mason window.

06.Plugins

Every plugin in lazy-lock.json, grouped by what it does, each with a link to its repository. The Options tab shows opts, the settings lazy.nvim hands to the plugin, and the Full Spec tab shows the whole spec: where the plugin comes from, when it loads, its keys and its options. Either one can be copied into a file in lua/ach/plugins/.

Some plugins are set up in pieces, one in each file that needs a part of them, and each piece is shown with the file it lives in. A plugin that only comes in for another plugin's sake shows the line that brings it in.

Coding

The completion menu, offering words from the language server, snippets, file paths and the open buffer.

Repository: saghen/blink.cmp

From lua/ach/plugins/coding.lua:

Lua
opts = { keymap = { preset = "enter" }, -- The kind icons are the icon database's, bare, since blink adds its own spacing. appearance = { nerd_font_variant = "mono", kind_icons = require("ach.icons").kinds }, completion = { accept = { auto_brackets = { enabled = true } }, documentation = { auto_show = true, auto_show_delay_ms = 200 }, ghost_text = { enabled = true }, menu = { draw = { treesitter = { "lsp" } } }, }, signature = { enabled = true }, sources = { default = { "lsp", "path", "snippets", "buffer" }, providers = { -- The repository's own folder, so the snippets are found through the link and under nvim -u alike. snippets = { opts = { search_paths = { vim.g.ach_root .. "/snippets" } } }, }, }, fuzzy = { implementation = "prefer_rust_with_warning" }, cmdline = { enabled = true }, }

From lua/ach/plugins/lsp.lua:

Lua
opts = {
sources = {
default = { "lazydev" },
providers = {
lazydev = { name = "LazyDev", module = "lazydev.integrations.blink", score_offset = 100 },
},
},
}

friendly-snippets

A collection of snippets for many languages.

Repository: rafamadriz/friendly-snippets

lazy.nvim installs it as a dependency of blink.cmp, in lua/ach/plugins/coding.lua:

Lua
dependencies = { "rafamadriz/friendly-snippets" }

lazydev.nvim

Tells the Lua language server about Neovim's own Lua functions and the installed plugins, for completion and checking in these configuration files.

Repository: folke/lazydev.nvim

From lua/ach/plugins/lsp.lua:

Lua
opts = {
library = {
{ path = "${3rd}/luv/library", words = { "vim%.uv" } },
{ path = "snacks.nvim", words = { "Snacks" } },
"lazy.nvim",
},
}

mini.ai

Extends the a and i text objects, so d i ( and its kind reach further, such as into the next pair.

Repository: nvim-mini/mini.ai

From lua/ach/plugins/coding.lua:

Lua
opts = function() local ai = require("mini.ai") return { -- Look this far for an object, so a long function still counts as one. n_lines = 500, custom_textobjects = { o = ai.gen_spec.treesitter({ a = { "@block.outer", "@conditional.outer", "@loop.outer" }, i = { "@block.inner", "@conditional.inner", "@loop.inner" }, }), f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }), c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }), u = ai.gen_spec.function_call(), }, } end

mini.pairs

Types the closing bracket or quote when the opening one is typed.

Repository: nvim-mini/mini.pairs

From lua/ach/plugins/coding.lua:

Lua
opts = { modes = { insert = true, command = true, terminal = false } }

ts-comments.nvim

Makes g c use the right comment marker in a file that mixes languages.

Repository: folke/ts-comments.nvim

From lua/ach/plugins/coding.lua:

Lua
opts = {}

Colorscheme

tokyonight.nvim

Tokyo Night, in its night style, with the navy background.

Repository: folke/tokyonight.nvim

From lua/ach/plugins/colorscheme.lua:

Lua
opts = function() local p = require("ach.palette") return { style = "night", on_colors = function(c) c.bg = p.bg c.bg_dark = p.bg_dark c.bg_float = p.bg_dark c.bg_popup = p.bg_dark c.bg_sidebar = p.bg_dark c.bg_statusline = p.bg_dark c.bg_highlight = p.bg_highlight c.bg_search = p.bg_search c.bg_visual = p.bg_visual c.border = p.border c.fg = p.fg c.fg_dark = p.fg_dark c.fg_float = p.fg c.fg_gutter = p.fg_gutter c.fg_sidebar = p.fg_dark c.comment = p.comment c.dark3 = p.dark3 end, on_highlights = function(hl) hl.AchBanner = { fg = p.banner } hl.AchBannerShadow = { fg = p.border } hl.AchBannerCaption = { fg = p.fg_dark } -- Math drawn by snacks.image takes the text colour, so a formula -- reads as part of the page. hl.SnacksImageMath = { fg = p.fg } end, } end

Editor

flash.nvim

Jumps anywhere on the screen: s, then the first letters of the place, then the label shown there.

Repository: folke/flash.nvim

From lua/ach/plugins/editor.lua:

Lua
opts = {}

grug-far.nvim

Search and replace across files, with a preview (Space s r).

Repository: MagicDuck/grug-far.nvim

From lua/ach/plugins/editor.lua:

Lua
opts = { headerMaxWidth = 80 }

multicursor.nvim

Several cursors that edit together. Alt-Down adds one on the line below.

Repository: jake-stewart/multicursor.nvim

From lua/ach/plugins/editor.lua:

Lua
-- Several cursors that edit together. { "jake-stewart/multicursor.nvim", branch = "1.0", config = function() local m = mc() m.setup() -- These keys exist only while there is more than one cursor. m.addKeymapLayer(function(set) set({ "n", "x" }, "<left>", m.prevCursor, { desc = "Previous Cursor" }) set({ "n", "x" }, "<right>", m.nextCursor, { desc = "Next Cursor" }) set({ "n", "x" }, "<leader>md", m.deleteCursor, { desc = "Delete This Cursor" }) set("n", "<esc>", function() if not m.cursorsEnabled() then m.enableCursors() else m.clearCursors() end end, { desc = "Clear Cursors" }) end) end, keys = { { "<leader>mn", function() mc().matchAddCursor(1) end, mode = { "n", "x" }, desc = "Add Cursor at Next Match" }, { "<leader>mN", function() mc().matchAddCursor(-1) end, mode = { "n", "x" }, desc = "Add Cursor at Previous Match", }, { "<leader>ms", function() mc().matchSkipCursor(1) end, mode = { "n", "x" }, desc = "Skip to Next Match" }, { "<leader>mS", function() mc().matchSkipCursor(-1) end, mode = { "n", "x" }, desc = "Skip to Previous Match" }, { "<leader>mA", function() mc().matchAllAddCursors() end, mode = { "n", "x" }, desc = "Add Cursors at Every Match", }, { "<leader>mx", function() mc().toggleCursor() end, mode = { "n", "x" }, desc = "Add or Remove a Cursor Here" }, { "<leader>ma", function() mc().alignCursors() end, desc = "Align Cursors" }, -- Ctrl with the arrows resizes windows (keymaps.lua), so Option adds cursors. { "<A-Up>", function() mc().lineAddCursor(-1) end, mode = { "n", "x" }, desc = "Add Cursor Above" }, { "<A-Down>", function() mc().lineAddCursor(1) end, mode = { "n", "x" }, desc = "Add Cursor Below" }, }, }

oil.nvim

Shows a folder as a text buffer, where renaming a line renames the file (Space f o).

Repository: stevearc/oil.nvim

From lua/ach/plugins/editor.lua:

Lua
opts = { default_file_explorer = false, view_options = { show_hidden = true } }

todo-comments.nvim

Highlights TODO, FIX, HACK and NOTE comments, and finds them all in a picker.

Repository: folke/todo-comments.nvim

From lua/ach/plugins/editor.lua:

Lua
-- Only the icons change; the colours and alternate names stay todo-comments' own.
opts = { keywords = I.todo_keywords() }

trouble.nvim

Lists of problems, references and symbols to move through (Space x x).

Repository: folke/trouble.nvim

From lua/ach/plugins/editor.lua:

Lua
opts = {
modes = { lsp = { win = { position = "right" } } },
icons = { kinds = I.spaced(I.kinds) },
}

which-key.nvim

Shows the keys that can follow the ones already pressed, each with a description and an icon.

Repository: folke/which-key.nvim

From lua/ach/plugins/keys.lua:

Lua
opts = { preset = "helix", spec = { { mode = { "n", "x" }, { "<leader><tab>", group = "tabs", icon = I.group("tabs") }, { "<leader>a", group = "claude", icon = I.group("claude") }, { "<leader>b", group = "buffer", icon = I.group("buffer"), expand = function() return require("which-key.extras").expand.buf() end, }, { "<leader>c", group = "code", icon = I.group("code") }, { "<leader>d", group = "debug", icon = I.group("debug") }, { "<leader>f", group = "file/find", icon = I.group("file/find") }, { "<leader>g", group = "git", icon = I.group("git") }, { "<leader>gh", group = "hunks", icon = I.group("hunks") }, { "<leader>m", group = "multicursor", icon = I.group("multicursor") }, { "<leader>q", group = "quit/session", icon = I.group("quit/session") }, { "<leader>s", group = "search", icon = I.group("search") }, { "<leader>u", group = "toggles", icon = I.group("toggles") }, { "<leader>w", group = "windows", icon = I.group("windows"), proxy = "<c-w>", expand = function() return require("which-key.extras").expand.win() end, }, { "<leader>x", group = "diagnostics/quickfix", icon = I.group("diagnostics/quickfix") }, { "[", group = "prev", icon = I.group("prev") }, { "]", group = "next", icon = I.group("next") }, { "g", group = "goto", icon = I.group("goto") }, { "z", group = "fold", icon = I.group("fold") }, }, }, }

Formatting

conform.nvim

Runs each language's formatters on save and on Space c f.

Repository: stevearc/conform.nvim

From lua/ach/plugins/format.lua:

Lua
opts = function() return require("ach.format").opts() end

Linting

nvim-lint

Runs each language's linters and shows what they find.

Repository: mfussenegger/nvim-lint

From lua/ach/plugins/lint.lua:

Lua
{
"mfussenegger/nvim-lint",
-- Loaded when a file opens, so the first file is linted and the status
-- bar can name its linters from the start.
event = { "BufReadPost", "BufNewFile", "BufWritePost" },
config = function() require("ach.lint").setup() end,
}

LSP

mason.nvim

Downloads language servers, formatters, linters and debuggers into Neovim's own folder, at the versions mason-lock.json names (Space c m).

Repository: mason-org/mason.nvim

From lua/ach/plugins/mason.lua:

Lua
opts = {
ui = {
icons = {
package_installed = I.mason.installed,
package_pending = I.mason.pending,
package_uninstalled = I.mason.uninstalled,
},
},
}

nvim-lspconfig

Starting settings for each language server, added to from lua/ach/servers.lua.

Repository: neovim/nvim-lspconfig

From lua/ach/plugins/lsp.lua:

Lua
{
"neovim/nvim-lspconfig",
-- Loaded as the first file is read, so the diagnostics' look and the
-- servers' settings are in place before anything reports on it, and with
-- no file after the first screen. Its lsp/ folder must be on the runtime
-- path before the first server is enabled, so lua/ach/lsp.lua loads it
-- then too, for a file type set on a buffer with no file.
event = { "BufReadPre", "BufNewFile", "VeryLazy" },
config = function() require("ach.lsp").setup() end,
}

SchemaStore.nvim

The schemas that tell the JSON and YAML servers what a file such as package.json may hold.

Repository: b0o/SchemaStore.nvim

From lua/ach/plugins/lsp.lua:

Lua
{ "b0o/SchemaStore.nvim", lazy = true, version = false }

TreeSitter

nvim-treesitter

Installs the Tree-sitter parsers, which read each language's syntax for highlighting, indenting and selecting.

Repository: nvim-treesitter/nvim-treesitter

From lua/ach/plugins/treesitter.lua:

Lua
{ "nvim-treesitter/nvim-treesitter", branch = "main", -- The main branch says it does not support lazy loading, meaning its -- commands and parser folder must be there before a file needs them. -- LazyVim loads it lazily all the same, and so does this: at the start -- when a file is named, otherwise after the first screen, or sooner when -- lua/ach/treesitter.lua starts it on a buffer or one of its commands runs. lazy = vim.fn.argc(-1) == 0, event = "VeryLazy", cmd = { "TSUpdate", "TSInstall", "TSInstallFromGrammar", "TSUninstall", "TSLog" }, build = ":TSUpdate", init = function() -- nvim-treesitter rereads its parser list on this event, so the table's -- own parsers are added back each time. vim.api.nvim_create_autocmd("User", { pattern = "TSUpdate", callback = function() require("ach.treesitter").register_custom() end, }) end, config = function() require("nvim-treesitter").setup({}) end, }

nvim-treesitter-textobjects

Text objects and moves by syntax: functions, classes and parameters.

Repository: nvim-treesitter/nvim-treesitter-textobjects

From lua/ach/plugins/treesitter.lua:

Lua
{ "nvim-treesitter/nvim-treesitter-textobjects", branch = "main", event = "VeryLazy", config = function() require("nvim-treesitter-textobjects").setup({ move = { set_jumps = true } }) -- Buffers opened before VeryLazy were attached before these queries -- were on the runtime path, so they get their moves now. for _, buf in ipairs(vim.api.nvim_list_bufs()) do if vim.api.nvim_buf_is_loaded(buf) then require("ach.treesitter").attach(buf) end end end, }

UI

edgy.nvim

Keeps the side panels, such as the file tree, the problem list and the Claude Code panel, at fixed places and sizes.

Repository: folke/edgy.nvim

From lua/ach/plugins/ui.lua:

Lua
opts = function() local opts = { bottom = { { ft = "qf", title = "QuickFix" }, { ft = "help", size = { height = 20 }, -- A help file opened for editing is an ordinary file, not a docked page. filter = function(buf) return vim.bo[buf].buftype == "help" end, }, }, right = { -- The Claude Code panel's view comes first, so it claims the panel -- before the generic terminal view the loop below appends, which -- names no width and would leave the panel 30 columns wide. require("ach.claude").view(), { title = "Grug Far", ft = "grug-far", size = { width = 0.4 } }, }, -- Inside a docked pane, Ctrl and the arrows resize the pane. keys = { ["<c-Right>"] = function(win) win:resize("width", 2) end, ["<c-Left>"] = function(win) win:resize("width", -2) end, ["<c-Up>"] = function(win) win:resize("height", 2) end, ["<c-Down>"] = function(win) win:resize("height", -2) end, }, } for _, pos in ipairs({ "top", "bottom", "left", "right" }) do opts[pos] = opts[pos] or {} table.insert(opts[pos], { ft = "trouble", filter = function(_, win) local w = vim.w[win].trouble return w and w.position == pos and w.type == "split" and w.relative == "editor" and not vim.w[win].trouble_preview end, }) table.insert(opts[pos], { ft = "snacks_terminal", size = { height = 0.4 }, title = "%{b:snacks_terminal.id}: %{b:term_title}", filter = function(_, win) local w = vim.w[win].snacks_win return w and w.position == pos and w.relative == "editor" and not vim.w[win].trouble_preview end, }) end return opts end

lualine.nvim

The status bar along the bottom of the screen.

Repository: nvim-lualine/lualine.nvim

From lua/ach/plugins/statusline.lua:

Lua
opts = function() return require("ach.statusline").options() end

mini.hipatterns

Shows a colour code such as #1a1b26 in the colour it names.

Repository: nvim-mini/mini.hipatterns

From lua/ach/plugins/ui.lua:

Lua
opts = function() return { highlighters = { hex_color = require("mini.hipatterns").gen_highlighter.hex_color() } } end

mini.icons

An icon for each file type, folder and plugin.

Repository: nvim-mini/mini.icons

From lua/ach/plugins/statusline.lua:

Lua
-- The icon database's overrides: the hardware languages get chips, gates and
-- waveforms, and file types mini.icons does not know get an icon of their own.
opts = function() return require("ach.icons").mini() end

rainbow-delimiters.nvim

Colours each level of nested brackets differently.

Repository: HiPhish/rainbow-delimiters.nvim

From lua/ach/plugins/ui.lua:

Lua
-- Each nesting level of brackets in its own colour, from tokyonight's rainbow groups.
-- It reads no options, so lazy.nvim only has to put it on the runtime path.
{ "HiPhish/rainbow-delimiters.nvim", event = { "BufReadPre", "BufNewFile" } }

Util

lazy.nvim

The plugin manager. It installs each plugin at the commit lazy-lock.json names, and loads each one when it is first needed.

Repository: folke/lazy.nvim

From lua/ach/plugins/core.lua:

Lua
{ "folke/lazy.nvim", version = false }

persistence.nvim

Saves which files were open in each folder, so Space q s brings them back.

Repository: folke/persistence.nvim

From lua/ach/plugins/editor.lua:

Lua
opts = {}

plenary.nvim

A library of Lua functions other plugins build on, among them octo.nvim.

Repository: nvim-lua/plenary.nvim

lazy.nvim installs it as a dependency of octo.nvim, in lua/ach/plugins/git.lua:

Lua
dependencies = { "nvim-lua/plenary.nvim" }

snacks.nvim

Many small tools in one plugin. Here it gives the file picker, the dashboard, notifications, toggles, the terminal, the file tree, indent guides, the git keys and the image previews.

Repository: folke/snacks.nvim

From lua/ach/plugins/dashboard.lua:

Lua
opts = {
notifier = { enabled = true, timeout = 3000 },
dashboard = {
enabled = true,
sections = {
function(self) return require("ach.dashboard").sections(self) end,
},
},
}

From lua/ach/plugins/editor.lua:

Lua
opts = {
explorer = { enabled = true },
bigfile = { enabled = true },
quickfile = { enabled = true },
}

From lua/ach/plugins/git.lua:

Lua
{ "folke/snacks.nvim", keys = { { "<leader>gg", git("lazygit"), desc = "Lazygit (Root Dir)" }, { "<leader>gG", git("lazygit", "cwd"), desc = "Lazygit (cwd)" }, { "<leader>gs", git("pick", "git_status"), desc = "Git Status" }, { "<leader>gS", git("pick", "git_stash"), desc = "Git Stash" }, { "<leader>gd", git("pick", "git_diff"), desc = "Git Diff (hunks)" }, { "<leader>gl", git("pick", "git_log"), desc = "Git Log (Root Dir)" }, { "<leader>gL", git("pick", "git_log", "cwd"), desc = "Git Log (cwd)" }, { "<leader>gf", git("pick", "git_log_file"), desc = "Git File History" }, { "<leader>gb", git("pick", "git_log_line"), desc = "Git Line History" }, { "<leader>gc", git("pick", "git_branches"), desc = "Git Branches" }, { "<leader>gB", git("browse"), mode = { "n", "x" }, desc = "Git Browse (open)" }, { "<leader>gY", git("copy_link"), mode = { "n", "x" }, desc = "Git Browse (copy link)" }, }, }

From lua/ach/plugins/keys.lua:

Lua
opts = {
picker = {
enabled = true,
icons = { kinds = I.spaced(I.kinds), diagnostics = I.spaced(I.diagnostics) },
},
}

From lua/ach/plugins/markdown.lua:

Lua
opts = { image = { enabled = true } }

From lua/ach/plugins/tools.lua:

Lua
{ "folke/snacks.nvim", keys = { { "<leader>cx", function() require("ach.x86").lookup() end, desc = "x86 Manual", }, { "<leader>N", function() require("ach.news").open() end, desc = "News", }, }, }

From lua/ach/plugins/ui.lua:

Lua
opts = {
indent = { enabled = true },
scope = { enabled = true },
words = { enabled = true },
statuscolumn = { enabled = true },
input = { enabled = true },
}

Debugging (Plugins)

mason-nvim-dap.nvim

Reads which debug packages Mason has installed and sets up an adapter and launch choices for each.

Repository: jay-babu/mason-nvim-dap.nvim

From lua/ach/plugins/dap.lua:

Lua
{ "jay-babu/mason-nvim-dap.nvim", version = "^2", dependencies = { "mason-org/mason.nvim" } }

nvim-dap

The debugger client: breakpoints, stepping and inspecting.

Repository: mfussenegger/nvim-dap

From lua/ach/plugins/dap.lua:

Lua
{ "mfussenegger/nvim-dap", commit = "cfa2d58f4537aca6ca83e2de1a0d9f1491121264", dependencies = { { "rcarriga/nvim-dap-ui", commit = "cc9dd33aade7f20bae414d0cba163bc60d4d4b43" }, { "nvim-neotest/nvim-nio", commit = "edcc181a875301dd21840189aa2f2f9ad69fc172" }, { "theHamsta/nvim-dap-virtual-text", commit = "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, { "jay-babu/mason-nvim-dap.nvim", version = "^2", dependencies = { "mason-org/mason.nvim" } }, { "mfussenegger/nvim-dap-python", commit = "1808458eba2b18f178f990e01376941a42c7f93b" }, }, cmd = { "DapContinue", "DapToggleBreakpoint", "DapClearBreakpoints", "DapToggleRepl", "DapStepOver", "DapStepInto", "DapStepOut", "DapPause", "DapTerminate", "DapDisconnect", "DapRestartFrame", "DapNew", "DapEval", "DapSetLogLevel", "DapShowLog", }, keys = function() local keys = {} for _, k in ipairs(require("ach.dap").keys) do keys[#keys + 1] = { k[1], k[2], desc = k[3], mode = k[4] } end return keys end, config = function() require("ach.dap").setup() end, }

nvim-dap-python

Debugs Python through debugpy.

Repository: mfussenegger/nvim-dap-python

From lua/ach/plugins/dap.lua:

Lua
{ "mfussenegger/nvim-dap-python", commit = "1808458eba2b18f178f990e01376941a42c7f93b" }

nvim-dap-ui

The debugger's panels (Space d u).

Repository: rcarriga/nvim-dap-ui

From lua/ach/plugins/dap.lua:

Lua
{ "rcarriga/nvim-dap-ui", commit = "cc9dd33aade7f20bae414d0cba163bc60d4d4b43" }

nvim-dap-virtual-text

Shows each variable's value beside the code while the program is paused.

Repository: theHamsta/nvim-dap-virtual-text

From lua/ach/plugins/dap.lua:

Lua
{ "theHamsta/nvim-dap-virtual-text", commit = "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }

nvim-nio

A library for running Lua side by side, which nvim-dap-ui needs.

Repository: nvim-neotest/nvim-nio

From lua/ach/plugins/dap.lua:

Lua
{ "nvim-neotest/nvim-nio", commit = "edcc181a875301dd21840189aa2f2f9ad69fc172" }

Language Plugins

haskell-tools.nvim

Starts the Haskell language server, evaluates a module's examples, and debugs through hdb.

Repository: mrcjkb/haskell-tools.nvim

From lua/ach/plugins/managed.lua:

Lua
{ "mrcjkb/haskell-tools.nvim", version = "^11", lazy = false }

lean.nvim

Starts the Lean server and shows the proof state beside the file.

Repository: Julian/lean.nvim

From lua/ach/plugins/managed.lua:

Lua
-- Lean, loaded as a .lean file is read or created, before its file type is
-- set, so its own ftplugin and commands are there when the type is.
{
"Julian/lean.nvim",
commit = "42186878a385ab021296e8f8024521d11a661754",
event = { "BufReadPre *.lean", "BufNewFile *.lean" },
}

nvim-jdtls

Starts jdtls for Java, imports the project, and runs the debugger and the tests.

Repository: mfussenegger/nvim-jdtls

From lua/ach/plugins/managed.lua:

Lua
-- Java and Scala, loaded when ach.managed first requires them.
{ "mfussenegger/nvim-jdtls", commit = "6e9d953f0b82bccdb834cfde0e893f3119c22592" }

nvim-metals

Starts Metals for Scala, with its own debug server.

Repository: scalameta/nvim-metals

From lua/ach/plugins/managed.lua:

Lua
{ "scalameta/nvim-metals", commit = "a4b20656bf1014404dd63bf9fd5f22fcc50fee52" }

rustaceanvim

Starts rust-analyzer for Rust, adds Cargo's commands, and debugs through codelldb.

Repository: mrcjkb/rustaceanvim

From lua/ach/plugins/managed.lua:

Lua
-- Rust and Haskell. Neither may be lazy-loaded: each does its work from an
-- ftplugin, which must be on the runtime path before the first file of its
-- type opens, and each loads the rest of itself only when first used.
{ "mrcjkb/rustaceanvim", version = "^9", lazy = false }

Git (Plugins)

diffview.nvim

Every uncommitted change side by side, and a file's history (Space g D).

Repository: sindrets/diffview.nvim

From lua/ach/plugins/git.lua:

Lua
opts = {
enhanced_diff_hl = true,
-- A merge conflict shows the two sides above and the result below.
view = { merge_tool = { layout = "diff3_mixed" } },
}

gitsigns.nvim

Change bars in the margin, and keys to move between changes and stage them. ] h moves to the next.

Repository: lewis6991/gitsigns.nvim

From lua/ach/plugins/git.lua:

Lua
opts = function() return require("ach.git").gitsigns_opts() end

neogit

git's status page inside Neovim, where changes are staged and committed (Space g n).

Repository: NeogitOrg/neogit

From lua/ach/plugins/git.lua:

Lua
opts = {
kind = "tab",
graph_style = "unicode",
integrations = { diffview = true, snacks = true },
}

octo.nvim

GitHub's issues and pull requests, through gh, on Space g i and Space g p.

Repository: pwntester/octo.nvim

From lua/ach/plugins/git.lua:

Lua
opts = { picker = "snacks", enable_builtin = true }

Claude Code (Plugins)

claudecode.nvim

Claude Code in a panel beside the code. It sees the open file and the selection, and shows each change it proposes side by side (Space a c).

Repository: coder/claudecode.nvim

From lua/ach/plugins/claude.lua:

Lua
opts = function() return require("ach.claude").opts() end

LaTeX

vimtex

Builds the PDF on Space c b, shows it in Skim, and jumps from the source to the PDF and back.

Repository: lervag/vimtex

From lua/ach/plugins/latex.lua:

Lua
{ "lervag/vimtex", -- Loaded at start rather than on a LaTeX file, because the Neovim that -- Skim starts for an inverse search opens no LaTeX file and still needs -- the VimtexInverseSearch command. lazy = false, -- VimTeX reads its settings when it loads, so they are set first. init = function() for name, value in pairs(require("ach.latex").globals()) do vim.g[name] = value end end, config = function() vim.api.nvim_create_autocmd("User", { group = vim.api.nvim_create_augroup("ach_latex", { clear = true }), pattern = "VimtexEventInitPost", callback = function() require("ach.latex").attach(vim.api.nvim_get_current_buf()) end, }) end, }

Markdown

live-preview.nvim

A preview in the browser that keeps up with the file as it changes (Space c p).

Repository: brianhuster/live-preview.nvim

From lua/ach/plugins/markdown.lua:

Lua
opts = P.opts()

render-markdown.nvim

Draws headings, lists, tables and code blocks in place while a Markdown file is open.

Repository: MeanderingProgrammer/render-markdown.nvim

From lua/ach/plugins/markdown.lua:

Lua
opts = {
file_types = P.file_types,
debounce = debounce,
completions = { blink = { enabled = true } },
-- snacks draws formulas as pictures, and two drawings would overlap.
latex = { enabled = false },
code = { sign = false, width = "block", right_pad = 1 },
heading = { sign = false },

07.Languages

One subsection for each entry in lua/ach/languages.lua. Nothing here is installed until a file of that language is opened. Then its Tree-sitter parser, its language servers, its formatters and its linters install in the background, without asking, and switch on when they are ready. A compiler or runtime that only Homebrew provides is asked about first, once, in one line that names it and its rough size.

Each table names the parts: the file types the entry covers, the parsers that read its syntax, the language servers that check the code as it is typed, the formatters that tidy it on save, the linters that report problems, the debugger, and whether Harper, a grammar checker, reads it. The Entry tab is the language's entry in lua/ach/languages.lua. The Options tab, where there is one, holds its servers' settings from lua/ach/servers.lua.

angular

PartNames
File typeshtmlangular
Parsersangular
Serversangularls, tailwindcss
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
angular = {
ft = { "htmlangular" },
ts = { "angular" },
lsp = { "angularls", "tailwindcss" },
fmt = { "prettier" },
mason = { "prettier" },
}

ansible

PartNames
File typesyaml.ansible
Parsersyaml
Serversansiblels
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
ansible = { ft = { "yaml.ansible" }, ts = { "yaml" }, lsp = { "ansiblels" }, mason = { "ansible-lint" } }

asm

PartNames
File typesasm, nasm
Parsersasm, nasm
Serversasm_lsp
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
asm = { ft = { "asm", "nasm" }, ts = { "asm", "nasm" }, lsp = { "asm_lsp" } }

astro

PartNames
File typesastro
Parsersastro
Serversastro, tailwindcss
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
astro = { ft = { "astro" }, ts = { "astro" }, lsp = { "astro", "tailwindcss" } }

awk

PartNames
File typesawk
Parsersawk
Serversawk_ls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
awk = { ft = { "awk" }, ts = { "awk" }, lsp = { "awk_ls" } }

bsv

PartNames
File typesbsv
Parsersbsv
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
bsv = { ft = { "bsv" }, ts = { "bsv" } }

c

PartNames
File typesc, cpp, objc, objcpp, cuda
Parsersc, cpp, cuda, objc
Serversclangd
Formattersclang_format
Lintersnone
Debuggerlldb-dap
GrammarHarper, in c, cpp
Lua
c = {
ft = { "c", "cpp", "objc", "objcpp", "cuda" },
ts = { "c", "cpp", "cuda", "objc" },
lsp = { "clangd" },
fmt = { "clang_format" },
mason = { "clang-format" },
harper = { "c", "cpp" },
}

clojure

PartNames
File typesclojure, edn
Parsersclojure
Serversclojure_lsp
Formattersnone
Lintersnone
Debuggernone
GrammarHarper, in clojure
Lua
clojure = { ft = { "clojure", "edn" }, ts = { "clojure" }, lsp = { "clojure_lsp" }, harper = { "clojure" } }

cmake

PartNames
File typescmake
Parserscmake
Serversneocmake
Formattersgersemi
Linterscmakelint
Debuggernone
GrammarHarper
Lua
cmake = {
ft = { "cmake" },
ts = { "cmake" },
lsp = { "neocmake" },
-- cmake-format, from cmakelang, no longer runs on current Python.
fmt = { "gersemi" },
lint = { "cmakelint" },
mason = { "gersemi", "cmakelint" },
harper = true,
}

css

PartNames
File typescss, scss, less
Parserscss, scss
Serverscssls, tailwindcss
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
css = {
ft = { "css", "scss", "less" },
ts = { "css", "scss" },
lsp = { "cssls", "tailwindcss" },
fmt = { "prettier" },
mason = { "prettier" },
}

csv

PartNames
File typescsv, tsv
Parserscsv, tsv
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
csv = { ft = { "csv", "tsv" }, ts = { "csv", "tsv" } }

dart

PartNames
File typesdart
Parsersdart
Serversdartls
Formattersdart_format
Lintersnone
Debuggernone
GrammarHarper
Lua
dart = {
ft = { "dart" },
ts = { "dart" },
lsp = { "dartls" },
fmt = { "dart_format" },
harper = true,
system = { dart = { name = "the Dart SDK", brew = { "dart-sdk" }, size = "about 600 MB" } },
}

devicetree

PartNames
File typesdts
Parsersdevicetree
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
devicetree = { ft = { "dts" }, ts = { "devicetree" } }

docker

PartNames
File typesdockerfile, yaml.docker-compose
Parsersdockerfile, yaml
Serversdockerls, docker_compose_language_service
Formattersnone
Lintershadolint for dockerfile
Debuggernone
Grammarnone
Lua
docker = {
ft = { "dockerfile", "yaml.docker-compose" },
ts = { "dockerfile", "yaml" },
lsp = { "dockerls", "docker_compose_language_service" },
lint = { dockerfile = { "hadolint" } },
mason = { "hadolint" },
}

dot

PartNames
File typesdot
Parsersdot
Serversdotls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
dot = { ft = { "dot" }, ts = { "dot" }, lsp = { "dotls" } }

dotnet

PartNames
File typescs, fsharp
Parsersc_sharp, fsharp
Serverscsharp_ls, fsautocomplete
Formatterscsharpier for cs and fantomas for fsharp
Lintersnone
Debuggernetcoredbg
GrammarHarper, in cs
Lua
dotnet = { ft = { "cs", "fsharp" }, ts = { "c_sharp", "fsharp" }, lsp = { "csharp_ls", "fsautocomplete" }, fmt = { cs = { "csharpier" }, fsharp = { "fantomas" } }, mason = { "csharpier", "fantomas", "netcoredbg" }, harper = { "cs" }, runtime = { name = ".NET SDK", check = { "dotnet", "--version" }, brew = { "dotnet" }, size = "about 800 MB" }, }

elixir

PartNames
File typeselixir, eelixir, heex
Parserselixir, heex, eex
Serverselixirls
Formattersnone
Lintersnone
Debuggerelixir-ls's debugger
GrammarHarper, in elixir
Lua
elixir = {
ft = { "elixir", "eelixir", "heex" },
ts = { "elixir", "heex", "eex" },
lsp = { "elixirls" },
harper = { "elixir" },
runtime = { name = "Elixir", check = { "elixir", "--version" }, brew = { "elixir" }, size = "about 400 MB" },

elm

PartNames
File typeselm
Parserselm
Serverselmls
Formatterselm_format
Lintersnone
Debuggernone
Grammarnone
Lua
elm = { ft = { "elm" }, ts = { "elm" }, lsp = { "elmls" }, fmt = { "elm_format" }, mason = { "elm-format" } }

ember

PartNames
File typeshandlebars, javascript.glimmer, typescript.glimmer
Parsersglimmer, glimmer_javascript, glimmer_typescript
Serversember
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
ember = {
ft = { "handlebars", "javascript.glimmer", "typescript.glimmer" },
ts = { "glimmer", "glimmer_javascript", "glimmer_typescript" },
lsp = { "ember" },
fmt = { "prettier" },
mason = { "prettier" },
}

erlang

PartNames
File typeserlang
Parserserlang
Serverselp
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
erlang = {
ft = { "erlang" },
ts = { "erlang" },
lsp = { "elp" },
runtime = { name = "Erlang", check = { "erl", "-version" }, brew = { "erlang" }, size = "about 350 MB" },
}

firrtl

PartNames
File typesfirrtl
Parsersfirrtl
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
firrtl = { ft = { "firrtl" }, ts = { "firrtl" } }

fish

PartNames
File typesfish
Parsersfish
Serversfish_lsp
Formattersfish_indent
Lintersnone
Debuggernone
Grammarnone
Lua
fish = {
ft = { "fish" },
ts = { "fish" },
lsp = { "fish_lsp" },
fmt = { "fish_indent" },
-- fish_indent ships with the shell, and fish-lsp runs it.
runtime = { name = "fish", check = { "fish", "--version" }, brew = { "fish" }, size = "about 20 MB" },
}

fortran

PartNames
File typesfortran
Parsersfortran
Serversfortls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
fortran = { ft = { "fortran" }, ts = { "fortran" }, lsp = { "fortls" } }

git (Languages)

PartNames
File typesgitcommit, gitconfig, gitrebase, gitignore, gitattributes
Parsersgit_config, gitcommit, git_rebase, gitignore, gitattributes
Serversnone
Formattersnone
Lintersnone
Debuggernone
GrammarHarper, in gitcommit
Lua
git = {
ft = { "gitcommit", "gitconfig", "gitrebase", "gitignore", "gitattributes" },
ts = { "git_config", "gitcommit", "git_rebase", "gitignore", "gitattributes" },
harper = { "gitcommit" },
}

gleam

PartNames
File typesgleam
Parsersgleam
Serversgleam
Formattersgleam
Lintersnone
Debuggernone
GrammarHarper
Lua
gleam = {
ft = { "gleam" },
ts = { "gleam" },
lsp = { "gleam" },
fmt = { "gleam" },
harper = true,
system = { gleam = { name = "Gleam", brew = { "gleam" }, size = "about 400 MB" } },
}

glsl

PartNames
File typesglsl
Parsersglsl
Serversglsl_analyzer
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
glsl = { ft = { "glsl" }, ts = { "glsl" }, lsp = { "glsl_analyzer" } }

go

PartNames
File typesgo, gomod, gowork, gotmpl
Parsersgo, gomod, gowork, gosum, gotmpl
Serversgopls
Formattersgoimports, gofumpt for go
Lintersgolangcilint for go
Debuggerdelve
GrammarHarper, in go
Lua
go = { ft = { "go", "gomod", "gowork", "gotmpl" }, ts = { "go", "gomod", "gowork", "gosum", "gotmpl" }, lsp = { "gopls" }, fmt = { go = { "goimports", "gofumpt" } }, lint = { go = { "golangcilint" } }, mason = { "goimports", "gofumpt", "gomodifytags", "impl", "golangci-lint", "delve" }, harper = { "go" }, runtime = { name = "Go", check = { "go", "version" }, brew = { "go" }, size = "about 250 MB" }, }

graphql

PartNames
File typesgraphql
Parsersgraphql
Serversgraphql
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
graphql = {
ft = { "graphql" },
ts = { "graphql" },
lsp = { "graphql" },
fmt = { "prettier" },
mason = { "prettier" },
}

groovy

PartNames
File typesgroovy
Parsersgroovy
Serversgroovyls
Formattersnone
Lintersnone
Debuggernone
GrammarHarper
Lua
groovy = { ft = { "groovy" }, ts = { "groovy" }, lsp = { "groovyls" }, harper = true, runtime = java }

haskell

PartNames
File typeshaskell, lhaskell, cabal
Parsershaskell
Serversstarted by haskell-tools.nvim
Formatterscabal_fmt for cabal and fourmolu for haskell
Lintershlint for haskell
Debuggerhdb
GrammarHarper, in haskell, lhaskell
Lua
haskell = { ft = { "haskell", "lhaskell", "cabal" }, ts = { "haskell" }, managed = "haskell-tools.nvim", fmt = { haskell = { "fourmolu" }, cabal = { "cabal_fmt" } }, lint = { haskell = { "hlint" } }, mason = { "haskell-language-server", "fourmolu", "hlint" }, harper = { "haskell", "lhaskell" }, runtime = { name = "GHC", check = { "ghc", "--version" }, brew = { "ghcup" }, after = { { "ghcup", "install", "ghc", "--set", "recommended" } }, size = "about 3 GB", }, }

helm

PartNames
File typeshelm
Parsershelm
Servershelm_ls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
helm = { ft = { "helm" }, ts = { "helm" }, lsp = { "helm_ls" } }

hlsl

PartNames
File typeshlsl
Parsershlsl
Serversslangd
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
hlsl = { ft = { "hlsl" }, ts = { "hlsl" }, lsp = { "slangd" } }

html

PartNames
File typeshtml
Parsershtml
Servershtml, emmet_language_server, tailwindcss
Formattersprettier
Lintersnone
Debuggernone
GrammarHarper
Lua
html = {
ft = { "html" },
ts = { "html" },
lsp = { "html", "emmet_language_server", "tailwindcss" },
fmt = { "prettier" },
mason = { "prettier" },
harper = true,
}

ini

PartNames
File typesdosini, editorconfig
Parsersini, editorconfig
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
ini = { ft = { "dosini", "editorconfig" }, ts = { "ini", "editorconfig" } }

java

PartNames
File typesjava
Parsersjava
Serversstarted by nvim-jdtls
Formattersnone
Lintersnone
Debuggerjava-debug and java-test
GrammarHarper
Lua
java = {
ft = { "java" },
ts = { "java" },
managed = "nvim-jdtls",
mason = { "jdtls", "java-debug-adapter", "java-test" },
harper = true,
runtime = java,
}

jq

PartNames
File typesjq
Parsersjq
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
jq = { ft = { "jq" }, ts = { "jq" } }

json

PartNames
File typesjson, jsonc, json5
Parsersjson, json5
Serversjsonls
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
json = {
ft = { "json", "jsonc", "json5" },
ts = { "json", "json5" },
lsp = { "jsonls" },
fmt = { "prettier" },
mason = { "prettier" },
}

julia

PartNames
File typesjulia
Parsersjulia
Serversjulials
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
julia = {
ft = { "julia" },
ts = { "julia" },
lsp = { "julials" },
runtime = { name = "Julia", check = { "julia", "--version" }, brew = { "julia" }, size = "about 1.5 GB" },
}

just

PartNames
File typesjust
Parsersjust
Serversjust
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
just = { ft = { "just" }, ts = { "just" }, lsp = { "just" } }

kconfig

PartNames
File typeskconfig
Parserskconfig
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
kconfig = { ft = { "kconfig" }, ts = { "kconfig" } }

kotlin

PartNames
File typeskotlin
Parserskotlin
Serverskotlin_language_server
Formattersktlint
Lintersktlint
Debuggerkotlin-debug-adapter
GrammarHarper
Lua
kotlin = {
ft = { "kotlin" },
ts = { "kotlin" },
lsp = { "kotlin_language_server" },
fmt = { "ktlint" },
lint = { "ktlint" },
mason = { "ktlint", "kotlin-debug-adapter" },
harper = true,
runtime = java,
}

lean

PartNames
File typeslean
Parsersnone
Serversstarted by lean.nvim
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
lean = { ft = { "lean" }, managed = "lean.nvim", runtime = { name = "elan", check = { "elan", "--version" }, brew = { "elan-init" }, after = { { "elan", "default", "stable" } }, size = "about 1.5 GB", }, }

linker

PartNames
File typesld
Parserslinkerscript
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
linker = { ft = { "ld" }, ts = { "linkerscript" } }

llvm

PartNames
File typesllvm
Parsersllvm
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
llvm = { ft = { "llvm" }, ts = { "llvm" } }

lua

PartNames
File typeslua
Parserslua, luadoc, luap
Serverslua_ls
Formattersstylua
Lintersnone
Debuggernone
GrammarHarper
Lua
lua = {
ft = { "lua" },
ts = { "lua", "luadoc", "luap" },
lsp = { "lua_ls" },
fmt = { "stylua" },
mason = { "stylua" },
harper = true,
}

make

PartNames
File typesmake, automake
Parsersmake
Serversautotools_ls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
make = { ft = { "make", "automake" }, ts = { "make" }, lsp = { "autotools_ls" } }

markdown (Languages)

PartNames
File typesmarkdown, markdown.mdx
Parsersmarkdown, markdown_inline
Serversmarksman
Formattersprettier, markdownlint-cli2 (never on save, only on Space c f)
Lintersmarkdownlint-cli2
Debuggernone
GrammarHarper, in markdown
Lua
markdown = { ft = { "markdown", "markdown.mdx" }, ts = { "markdown", "markdown_inline" }, lsp = { "marksman" }, fmt = { "prettier", "markdownlint-cli2" }, lint = { "markdownlint-cli2" }, mason = { "prettier", "markdownlint-cli2" }, harper = { "markdown" }, manual = true, }

meson

PartNames
File typesmeson
Parsersmeson
Serversmesonlsp
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
meson = { ft = { "meson" }, ts = { "meson" }, lsp = { "mesonlsp" } }

mlir

PartNames
File typesmlir
Parsersmlir
Serversmlir_lsp_server
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
mlir = { ft = { "mlir" }, ts = { "mlir" }, lsp = { "mlir_lsp_server" }, system = { ["mlir-lsp-server"] = llvm } }

ninja

PartNames
File typesninja
Parsersninja
Serversnone
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
ninja = { ft = { "ninja" }, ts = { "ninja" } }

nix

PartNames
File typesnix
Parsersnix
Serversnil_ls
Formattersnixfmt
Lintersstatix
Debuggernone
GrammarHarper
Lua
nix = { ft = { "nix" }, ts = { "nix" }, lsp = { "nil_ls" }, fmt = { "nixfmt" }, lint = { "statix" }, mason = { "statix" }, -- nil asks Nix for its builtins as it builds, and Homebrew does not carry Nix. runtime = { name = "Nix", check = { "nix", "--version" }, command = "curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh", }, -- Mason's nixfmt is built for Linux only. system = { nixfmt = { name = "nixfmt", brew = { "nixfmt" }, size = "about 30 MB" } }, harper = true, }

nushell

PartNames
File typesnu
Parsersnu
Serversnushell
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
nushell = {
ft = { "nu" },
ts = { "nu" },
lsp = { "nushell" },
system = { nu = { name = "nushell", brew = { "nushell" }, size = "about 60 MB" } },
}

ocaml

PartNames
File typesocaml, ocamlinterface
Parsersocaml, ocaml_interface
Serversocamllsp
Formattersocamlformat
Lintersnone
Debuggernone
Grammarnone
Lua
ocaml = { ft = { "ocaml", "ocamlinterface" }, ts = { "ocaml", "ocaml_interface" }, lsp = { "ocamllsp" }, fmt = { "ocamlformat" }, mason = { "ocamlformat" }, runtime = { name = "OCaml", check = { "ocaml", "-version" }, brew = { "opam" }, after = { { "opam", "init", "-n", "-y" } }, size = "about 600 MB", }, }

perl

PartNames
File typesperl
Parsersperl
Serversperlnavigator
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
perl = { ft = { "perl" }, ts = { "perl" }, lsp = { "perlnavigator" } }

php

PartNames
File typesphp
Parsersphp, phpdoc
Serversintelephense
Formattersphp_cs_fixer
Lintersphpcs
Debuggerphp-debug-adapter
GrammarHarper
Lua
php = {
ft = { "php" },
ts = { "php", "phpdoc" },
lsp = { "intelephense" },
fmt = { "php_cs_fixer" },
lint = { "phpcs" },
mason = { "php-cs-fixer", "phpcs", "php-debug-adapter" },
harper = true,
runtime = { name = "PHP", check = { "php", "--version" }, brew = { "php" }, size = "about 500 MB" },

powershell

PartNames
File typesps1
Parserspowershell
Serverspowershell_es
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
powershell = {
ft = { "ps1" },
ts = { "powershell" },
lsp = { "powershell_es" },
runtime = { name = "PowerShell", check = { "pwsh", "-Version" }, brew = { "powershell" }, size = "about 900 MB" },
}

prisma

PartNames
File typesprisma
Parsersprisma
Serversprismals
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
prisma = { ft = { "prisma" }, ts = { "prisma" }, lsp = { "prismals" } }

proto

PartNames
File typesproto
Parsersproto
Serversbuf_ls
Formattersbuf
Lintersnone
Debuggernone
Grammarnone
Lua
proto = { ft = { "proto" }, ts = { "proto" }, lsp = { "buf_ls" }, fmt = { "buf" } }

python

PartNames
File typespython
Parserspython, rst, requirements
Serversbasedpyright, ruff
Formattersruff_format
Lintersnone
Debuggerdebugpy
GrammarHarper
Lua
python = {
ft = { "python" },
ts = { "python", "rst", "requirements" },
lsp = { "basedpyright", "ruff" },
fmt = { "ruff_format" },
mason = { "debugpy" },
harper = true,
}

r

PartNames
File typesr, rmd, quarto, rnoweb
Parsersr, rnoweb, markdown
Serversr_language_server
Formattersnone
Lintersnone
Debuggernone
GrammarHarper, in quarto
Lua
r = { ft = { "r", "rmd", "quarto", "rnoweb" }, ts = { "r", "rnoweb", "markdown" }, lsp = { "r_language_server" }, harper = { "quarto" }, -- The server is an R package, which R builds from source on install. runtime = { name = "R", check = { "Rscript", "-e", "library(languageserver)" }, brew = { "r" }, after = { { "Rscript", "-e", "install.packages('languageserver', repos = 'https://cloud.r-project.org')" } }, size = "about 1.5 GB", }, }

rego

PartNames
File typesrego
Parsersrego
Serversregols, regal
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
rego = { ft = { "rego" }, ts = { "rego" }, lsp = { "regols", "regal" } }

ruby

PartNames
File typesruby, eruby
Parsersruby, embedded_template
Serversruby_lsp, rubocop
Formatterserb_format for eruby and rubocop for ruby
Lintersnone
Debuggernone
GrammarHarper, in ruby
Lua
ruby = { ft = { "ruby", "eruby" }, ts = { "ruby", "embedded_template" }, lsp = { "ruby_lsp", "rubocop" }, fmt = { ruby = { "rubocop" }, eruby = { "erb_format" } }, mason = { "erb-formatter" }, harper = { "ruby" }, runtime = { name = "Ruby 3", check = { "ruby", "-e", "exit(RUBY_VERSION >= '3.0' ? 0 : 1)" }, brew = { "ruby" }, size = "about 100 MB", }, }

rust

PartNames
File typesrust
Parsersrust, ron
Serversstarted by rustaceanvim
Formattersnone
Lintersnone
Debuggercodelldb
GrammarHarper
Lua
rust = { ft = { "rust" }, ts = { "rust", "ron" }, managed = "rustaceanvim", mason = { "rust-analyzer", "codelldb" }, harper = true, runtime = { name = "Rust", check = { "cargo", "--version" }, brew = { "rustup" }, after = { { "rustup", "default", "stable" } }, size = "about 1.5 GB", }, }

scala

PartNames
File typesscala, sbt
Parsersscala
Serversstarted by nvim-metals
Formattersnone
Lintersnone
DebuggerMetals' own debug server
GrammarHarper, in scala
Lua
scala = { ft = { "scala", "sbt" }, ts = { "scala" }, managed = "nvim-metals", harper = { "scala" }, runtime = { name = "Coursier", check = { "coursier", "list" }, brew = { "coursier", "openjdk@21" }, size = "about 700 MB", }, }

sh

PartNames
File typessh, bash, zsh
Parsersbash, zsh
Serversbashls
Formattersshfmt for bash and shfmt for sh
Lintersnone
Debuggernone
GrammarHarper, in sh
Lua
sh = {
ft = { "sh", "bash", "zsh" },
ts = { "bash", "zsh" },
lsp = { "bashls" },
fmt = { sh = { "shfmt" }, bash = { "shfmt" } },
mason = { "shfmt", "shellcheck" },
harper = { "sh" },

solidity

PartNames
File typessolidity
Parserssolidity
Serverssolidity_ls
Formattersnone
Lintersnone
Debuggernone
GrammarHarper
Lua
solidity = { ft = { "solidity" }, ts = { "solidity" }, lsp = { "solidity_ls" }, harper = true }

sql

PartNames
File typessql, mysql, plsql
Parserssql
Serversnone
Formatterssqlfluff
Linterssqlfluff
Debuggernone
Grammarnone
Lua
sql = {
ft = { "sql", "mysql", "plsql" },
ts = { "sql" },
fmt = { "sqlfluff" },
lint = { "sqlfluff" },
mason = { "sqlfluff" },
}

starlark

PartNames
File typesbzl, starlark
Parsersstarlark
Serversstarpls
Formattersbuildifier
Lintersnone
Debuggernone
Grammarnone
Lua
starlark = {
ft = { "bzl", "starlark" },
ts = { "starlark" },
lsp = { "starpls" },
fmt = { "buildifier" },
mason = { "buildifier" },
}

svelte

PartNames
File typessvelte
Parserssvelte
Serverssvelte, tailwindcss
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
svelte = { ft = { "svelte" }, ts = { "svelte" }, lsp = { "svelte", "tailwindcss" } }

swift

PartNames
File typesswift
Parsersswift
Serverssourcekit
Formattersnone
Lintersnone
Debuggerlldb-dap
GrammarHarper
Lua
swift = {
ft = { "swift" },
ts = { "swift" },
lsp = { "sourcekit" },
harper = true,
system = { ["sourcekit-lsp"] = xcode },
}

systemverilog

PartNames
File typesverilog, systemverilog
Parserssystemverilog
Serversverible
Formattersverible
Lintersnone
Debuggernone
Grammarnone
Lua
systemverilog = {
ft = { "verilog", "systemverilog" },
ts = { "systemverilog" },
lsp = { "verible" },
fmt = { "verible" },
mason = { "verible" },
}

tablegen

PartNames
File typestablegen
Parserstablegen
Serverstblgen_lsp_server
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
tablegen = {
ft = { "tablegen" },
ts = { "tablegen" },
lsp = { "tblgen_lsp_server" },
system = { ["tblgen-lsp-server"] = llvm },
}

tcl

PartNames
File typestcl, sdc, xdc
Parserstcl
Serverstclsp
Formattersnone
Linterstclint
Debuggernone
Grammarnone
Lua
tcl = { ft = { "tcl", "sdc", "xdc" }, ts = { "tcl" }, lsp = { "tclsp" }, lint = { "tclint" } }

terraform

PartNames
File typesterraform, terraform-vars, hcl
Parsersterraform, hcl
Serversterraformls
Formattersnone
Linterstflint for terraform
Debuggernone
Grammarnone
Lua
terraform = {
ft = { "terraform", "terraform-vars", "hcl" },
ts = { "terraform", "hcl" },
lsp = { "terraformls" },
lint = { terraform = { "tflint" } },
mason = { "tflint" },
}

tex

PartNames
File typestex, plaintex, bib
Parserslatex, bibtex
Serverstexlab
Formattersnone
Lintersnone
Debuggernone
GrammarHarper, in tex, plaintex
Lua
tex = {
ft = { "tex", "plaintex", "bib" },
ts = { "latex", "bibtex" },
lsp = { "texlab" },
harper = { "tex", "plaintex" },
manual = true,
}

text

PartNames
File typestext
Parsersnone
Serversnone
Formattersnone
Lintersnone
Debuggernone
GrammarHarper
Lua
text = { ft = { "text" }, harper = true, manual = true }

thrift

PartNames
File typesthrift
Parsersthrift
Serversthriftls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
thrift = { ft = { "thrift" }, ts = { "thrift" }, lsp = { "thriftls" } }

toml

PartNames
File typestoml
Parserstoml
Serverstaplo
Formatterstaplo
Lintersnone
Debuggernone
GrammarHarper
Lua
toml = { ft = { "toml" }, ts = { "toml" }, lsp = { "taplo" }, fmt = { "taplo" }, harper = true }

twig

PartNames
File typestwig
Parserstwig
Serverstwiggy_language_server
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
twig = { ft = { "twig" }, ts = { "twig" }, lsp = { "twiggy_language_server" } }

typescript

PartNames
File typesjavascript, javascriptreact, javascript.jsx, typescript, typescriptreact, typescript.tsx
Parsersjavascript, jsdoc, typescript, tsx
Serversvtsls, eslint, tailwindcss
Formattersprettier
Lintersnone
Debuggerjs-debug
GrammarHarper, in javascript, javascriptreact, typescript, typescriptreact
Lua
typescript = {
ft = { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" },
ts = { "javascript", "jsdoc", "typescript", "tsx" },
lsp = { "vtsls", "eslint", "tailwindcss" },
fmt = { "prettier" },
mason = { "prettier", "js-debug-adapter" },
harper = { "javascript", "javascriptreact", "typescript", "typescriptreact" },

typst

PartNames
File typestypst
Parserstypst
Serverstinymist
Formatterstypstyle (never on save, only on Space c f)
Lintersnone
Debuggernone
GrammarHarper
Lua
typst = {
ft = { "typst" },
ts = { "typst" },
lsp = { "tinymist" },
fmt = { "typstyle" },
mason = { "typstyle" },
harper = true,
manual = true,
}

veryl

PartNames
File typesveryl
Parsersveryl
Serversveryl_ls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
veryl = { ft = { "veryl" }, ts = { "veryl" }, lsp = { "veryl_ls" } }

vhdl

PartNames
File typesvhdl
Parsersvhdl
Serversvhdl_ls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
vhdl = { ft = { "vhdl" }, ts = { "vhdl" }, lsp = { "vhdl_ls" } }

vim

PartNames
File typesvim
Parsersvim, vimdoc
Serversvimls
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
vim = { ft = { "vim" }, ts = { "vim", "vimdoc" }, lsp = { "vimls" } }

vue

PartNames
File typesvue
Parsersvue
Serversvue_ls, vtsls, tailwindcss
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
vue = {
ft = { "vue" },
ts = { "vue" },
lsp = { "vue_ls", "vtsls", "tailwindcss" },
fmt = { "prettier" },
mason = { "prettier" },
}

wgsl

PartNames
File typeswgsl
Parserswgsl
Serverswgsl_analyzer
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
wgsl = { ft = { "wgsl" }, ts = { "wgsl" }, lsp = { "wgsl_analyzer" } }

xml

PartNames
File typesxml, xsd, xslt, svg
Parsersxml
Serverslemminx
Formattersnone
Lintersnone
Debuggernone
Grammarnone
Lua
xml = { ft = { "xml", "xsd", "xslt", "svg" }, ts = { "xml" }, lsp = { "lemminx" } }

yaml

PartNames
File typesyaml
Parsersyaml
Serversyamlls
Formattersprettier
Lintersnone
Debuggernone
Grammarnone
Lua
yaml = { ft = { "yaml" }, ts = { "yaml" }, lsp = { "yamlls" }, fmt = { "prettier" }, mason = { "prettier" } }

zig

PartNames
File typeszig
Parserszig
Serverszls
Formattersnone
Lintersnone
Debuggerlldb-dap
GrammarHarper
Lua
zig = {
ft = { "zig" },
ts = { "zig" },
lsp = { "zls" },
harper = true,
runtime = { name = "Zig", check = { "zig", "version" }, brew = { "zig" }, size = "about 2 GB" },
}

— Anirban

Hardware–software at the seam where compilers meet microcode.

FeedbackBook mode
neovimluaeditormacos