ACH-NEOVIM: A Step-by-Step Tutorial to a Supercharged Neovim

A walkthrough of ACH-NEOVIM — my personal Neovim configuration that bootstraps a 45+ language IDE with one command. Native LSP, on-demand tooling, deep ocean palette, and zero manual setup.

April 8, 202613 min read

I've been a Neovim user for years. Every time I rebuild my config from scratch I learn something new — but I also lose a weekend wrangling lazy.nvim, mason, LSP servers, formatters, linters, and a dozen plugins that all need to be wired together just right.

So I finally stopped rebuilding and started shipping. ACH-NEOVIM is the result — a single-command install that drops a polished, 45+ language Neovim IDE onto a fresh Mac with zero manual setup.

This post is a guided tour. By the end, you should be able to clone the repo, run one script, and start coding — or fork it and make it your own.

ACH-NEOVIMMIT

Quick Start

Bash
git clone https://github.com/anirbanchakraborty-dev/ACH-NEOVIM.git
cd ACH-NEOVIM
./install.sh

That's it. Launch nvim, the dashboard appears, plugins download themselves, and the first time you open a Python file the LSP, formatter, and linter install in the background.

What You Get

A short list of what makes this config different from a stock lazy.nvim starter:

  • One-command install. install.sh provisions Homebrew, the latest stable Neovim, and the Claude Code CLI. Re-run it any time — every step is idempotent.
  • On-demand everything. No ensure_installed lists anywhere. Open a Python file and pyright + ruff install themselves. Open a Go file and gopls + gofumpt arrive. Treesitter parsers, formatters, and linters all follow the same pattern.
  • Native LSP client. Uses Neovim 0.11+'s vim.lsp.config / vim.lsp.enable flow with nvim-lspconfig providing per-server defaults. blink.cmp capabilities are merged into every server automatically.
  • 45+ languages supported out of the box, all installed lazily on first use.
  • Deep ocean palette. A custom tokyonight override (#011628 background, #011423 floats, #0A64AC search) themed across every plugin: fzf-lua, lazy, mason, which-key, snacks, noice, trouble, diffview, and git-conflict.
  • Claude Code inside Neovim. coder/claudecode.nvim ships Claude as a snacks-themed split with native diff review and selection tracking.
  • Schema-aware JSON / YAML. SchemaStore.nvim is wired into both jsonls and yamlls — you get completion + validation for package.json, tsconfig.json, GitHub Actions, Kubernetes manifests, docker-compose, and 1200+ other schemas with no manual setup.
  • Per-project LSP overrides. neoconf.nvim auto-merges .neoconf.json and .vscode/settings.json from the project root into the LSP config, so cloning a JS/TS project that ships shared editor settings just works.

Step 1 — Run the Installer

The installer does four things:

  1. Installs Homebrew if it isn't already present.
  2. Installs or upgrades Neovim to the latest stable release (validated against the GitHub releases API — not just whatever Homebrew last cached).
  3. Installs the Claude Code CLI via the official native installer (~/.local/bin/claude, auto-updates in the background) and appends the PATH export to ~/.zshrc if it isn't already there.
  4. Symlinks nvim/ to ~/.config/nvim. If you already have a Neovim config, it gets moved to a timestamped backup first.

Every step prints a colored status line, and the script bails on the first error thanks to set -euo pipefail. Re-running is safe — anything already installed is skipped.

Bash
./install.sh

When it finishes, you'll see something like:

Plain Text
[OK] ACH-NEOVIM setup complete!
Neovim: NVIM v0.11.x
Claude: 1.x.x
Config: /Users/you/.config/nvim -> /path/to/ACH-NEOVIM/nvim
[INFO] Launch Neovim with: nvim

Step 2 — First Launch

Open Neovim:

Bash
nvim

The first launch does a few things in order:

  1. lazy.nvim bootstraps itself (clones from GitHub on first run).
  2. Every plugin in nvim/lua/plugins/ is downloaded.
  3. The snacks.dashboard startup screen appears with quick links to recent files, sessions, and common actions.
  4. As soon as you open a file in any supported language, mason starts installing the matching LSP server, formatter, and linter in the background. You'll see a snacks.notifier toast for every install.

Step 3 — Authenticate GitHub (Optional)

If you want the in-editor GitHub integration via octo.nvim (issues, PRs, code review, full-text search), authenticate the gh CLI once:

Bash
gh auth login

After that, <leader>gi lists issues, <leader>gp lists PRs, <leader>gP searches PRs, and <leader>gS runs a full-text GitHub search — all in fzf-lua pickers, all rendered as Neovim buffers.

The Configuration Tour

Here's what lives in the repo:

Plain Text
ACH-NEOVIM/ ├── install.sh ├── uninstall.sh └── nvim/ ├── init.lua entry point └── lua/ ├── config/ │ ├── icons.lua central Nerd Font glyph table │ ├── lazy.lua lazy.nvim bootstrap │ ├── options.lua vim.opt defaults │ ├── keymaps.lua non-plugin keymaps │ └── autocmds.lua augroups (yank flash, big-file, prose mode, ...) └── plugins/ ├── ai.lua Claude Code (coder/claudecode.nvim) ├── coding.lua blink.cmp, mini.pairs/surround/ai, lazydev ├── colorscheme.lua tokyonight + deep ocean palette ├── editor.lua which-key, fzf-lua, flash, todo-comments, trouble ├── formatting.lua conform.nvim + on-demand mason installer ├── git.lua gitsigns, diffview, git-conflict, lazygit ├── lang.lua render-markdown, markdown-preview, vimtex, venv-selector ├── linting.lua nvim-lint + on-demand mason installer ├── lsp.lua mason + native vim.lsp client + SchemaStore + neoconf ├── lualine.lua statusline (custom ocean theme) ├── terminal.lua toggleterm + language REPLs ├── treesitter.lua nvim-treesitter (main branch) + textobjects + context ├── ui.lua snacks, noice, bufferline, mini.icons, rainbow, colorizer └── util.lua persistence sessions, vim-sleuth, scratch

Each plugin file returns a table of lazy.nvim specs. To add a new plugin, drop a new file in nvim/lua/plugins/ and lazy auto-imports it.

Languages Supported

The whole point of "on-demand everything" is that you don't have to think about this list — but if you're curious whether your language is covered, here's the rundown.

Core stack (used daily)

LanguageLSPFormatterLinter
Lualua_lsstylua
Pythonpyright + ruffruff (organize+fmt)ruff (LSP)
TypeScript / JSts_ls + eslint (LSP)prettierd / prettier + eslinteslint (LSP)
HTML / CSShtml + emmet, csslsprettierd / prettier
JSON / YAMLjsonls / yamlls + SchemaStoreprettierd / prettieryamllint
Markdownmarksmanprettier + markdown-toc + mdlintmarkdownlint
Bash / Zshbashlsshfmtshellcheck
C / C++clangd + clangd_extensionsclang-format
Gogoplsgoimports + gofumptgolangci-lint
LaTeX / BibTeXtexlab + vimtexlatexindent / bibtex-tidy

Web

LanguageLSPFormatterNotes
Angularangularlsprettier
Astroastro-language-serverprettier
Sveltesvelte-language-serverprettier
Vuevue_ls (Volar)prettierstandalone Volar
Tailwind CSStailwindcss-language-serverattaches across html/css/js/ts/...
Prismaprismalsprettier

Systems / Compiled

LanguageLSPFormatterNotes
Rustrust_analyzer (clippy on save)rustfmt
Zigzlszig fmt
Haskellhaskell-language-serverormoluheavy install (~2 GB)
OCamlocaml-lspocamlformat
Elixirelixir-lsmix format
C# / VBomnisharpcsharpier
Kotlinkotlin-language-serverktlint
Scalametalsscalafmt
Javajdtlsgoogle-java-format
PHPintelephensephp-cs-fixer / pint

Infra / Data

LanguageLSPFormatterLinter
Ansibleansible-language-serveransible-lint
CMakecmake-language-servercmake-formatcmakelint
Helmhelm-ls
Terraformterraform-lsterraform fmttflint
TOMLtaplotaplo
SQLsqlssqlfluffsqlfluff
Soliditysolidity_ls_nomicfoundationforge fmtsolhint
Dockerfilehadolint

…plus Ruby, Perl, Swift, R, Julia, Lean, Elm, Typst, Nix, Erlang, Clojure, Gleam, Dart, Twig, Ember, Rego, and more. The full table is in the README.

Design Decisions

On-Demand Everything

This is the part I'm proudest of. Most Neovim configs hard-code an ensure_installed list — every Mason update reinstalls 50 LSPs whether you use them or not. Cloning a fresh config means staring at a progress bar for ten minutes before you can even open a file.

ACH-NEOVIM flips the model. The lsp.lua, formatting.lua, and linting.lua plugin files each register a FileType autocmd. The first time you open a buffer of a given filetype, the autocmd looks up which tools are mapped to that filetype and asks Mason to install them in the background. A snacks.notifier toast tells you when each install starts and finishes. After that, the autocmd is a no-op.

The result: a fresh install boots in seconds. Tooling appears only as you actually need it.

Native LSP Client

Neovim 0.11 introduced vim.lsp.config / vim.lsp.enable — a built-in client that replaces the long-standing nvim-lspconfig.setup() boilerplate. ACH-NEOVIM uses the new API:

  • nvim-lspconfig is still pulled in, but only for its default per-server config files (paths, root markers, init options).
  • vim.lsp.config('*', { capabilities = blink_caps }) merges blink.cmp's completion capabilities into every server.
  • vim.lsp.enable(server_name) is called per server inside the on-demand installer.

It's leaner, faster to start, and matches where the Neovim core is going.

Format + Lint Pipeline

Two plugins, two clearly-separated jobs:

  • conform.nvim handles format-on-save. It uses a prettierd → prettier fallback chain for web files, gated by a prettier --file-info parser check so prettier silently falls back to the LSP formatter on filetypes it can't parse. ESLint auto-fix-on-save runs before prettier via the eslint LSP's source.fixAll.eslint code action — eslint fixes lint issues, prettier has the final word on cosmetic formatting.
  • nvim-lint runs external linters (shellcheck, markdownlint, hadolint, yamllint, golangci-lint, ansible-lint, tflint, sqlfluff, solhint, cmakelint) via a debounced dispatcher and feeds results into vim.diagnostic.

Markdown gets two conditional formatters: markdown-toc only fires on buffers with a <!-- toc --> marker, markdownlint-cli2 only fires when there are existing markdownlint diagnostics. Cheap and surgical.

Central Icon Table

Every Nerd Font glyph used in the config — file tree icons, diagnostic markers, git symbols, which-key entries, lualine separators — lives in nvim/lua/config/icons.lua. Plugin files reference them by name (icons.diagnostics.Error, icons.git.added).

Want to swap a glyph? Change it once. It propagates everywhere. No more grep-and-replace across 15 files.

Sticky Scope Header

nvim-treesitter-context pins the current function/class/method signature to the top of the buffer when you scroll past its definition. Cursor-mode tracking with a 3-line cap so deeply-nested scopes never take over the screen. Toggle with <leader>ut.

Tailwind Class Highlighting

mini.hipatterns renders Tailwind utility class names like bg-blue-500 or text-emerald-300 with the actual color inline (background tint + contrasting fg). Works in html / css / js / ts / vue / svelte / astro / handlebars / twig / postcss. The Tailwind palette lives in config/tailwind_colors.lua as a pure data module.

It coexists with nvim-colorizer (which still handles hex / rgb / hsl / CSS named colors) — zero overlap.

Keymap Cheat Sheet

Leader is <Space>. Holding leader pops up which-key with every binding labelled and iconned.

The headline groups:

PrefixGroup
<leader>aAI / Claude
<leader>bBuffer
<leader>cCode (LSP)
<leader>eExplorer (root)
<leader>fFile / Find
<leader>gGit
<leader>hHarpoon Quick Menu
<leader>lLazy
<leader>mMason
<leader>oOverseer (Tasks)
<leader>pYank History
<leader>qSession
<leader>rRefactor
<leader>sSearch
<leader>tTerminal / REPLs
<leader>uUI toggles
<leader>wWindow
<leader>xDiagnostics / Trouble
<leader>1<leader>9Harpoon jump 1–9

A few standalone bindings worth memorizing on day one:

KeysWhat it does
<C-/>Toggle floating terminal
<C-h/j/k/l>Window navigation
<S-h> / <S-l>Previous / next buffer
<A-j> / <A-k>Move line(s) down / up
s / SFlash jump / treesitter jump
<C-Space>Init / grow treesitter selection
]f / [fNext / prev function
]c / [cNext / prev class
]d / [dNext / prev diagnostic
]h / [hNext / prev git hunk
gco / gcOAdd comment line below / above
gsa / gsd / gsrSurround add / delete / replace
KLSP hover docs
<leader>crRename symbol with live preview
<leader>csToggle symbol outline sidebar
<leader>chSwitch C/C++ source/header
<leader>cvPick a Python virtualenv
<leader>umToggle inline markdown rendering
<leader>utToggle sticky scope header

Customization

Three things you'll probably want to tweak:

1. Add a Plugin

Create a new file in nvim/lua/plugins/ returning a table of lazy.nvim specs. lazy auto-imports it.

Lua
-- nvim/lua/plugins/my-plugin.lua
return {
{
"username/cool-plugin.nvim",
event = "VeryLazy",
opts = {
-- plugin config
},
},
}

If the plugin has keymaps, follow the pattern in terminal.lua: define keys = {} on the spec, then add a parallel which-key.nvim block in the same file with icons sourced from config/icons.lua.

2. Change the Palette

Edit colorscheme.lua. The on_colors callback defines the deep-ocean colors; on_highlights overrides every plugin's themed groups. Change one hex value and the entire UI shifts.

3. Add an LSP / Formatter / Linter

Add an entry to the servers table in lsp.lua (or formatter_to_mason / linter_to_mason in formatting.lua / linting.lua). The on-demand installer will pick it up the next time you open a matching filetype.

Uninstall

Bash
./uninstall.sh

Removes the symlink at ~/.config/nvim and Neovim's data / state / cache directories. Your repo clone stays intact. Re-run install.sh to set everything back up.

Try It

Clone it, fork it, rip out the parts you don't like, and never manually configure Neovim from scratch again:

Bash
git clone https://github.com/anirbanchakraborty-dev/ACH-NEOVIM.git
cd ACH-NEOVIM
./install.sh

If you've already followed Post-Mac-Setup for the rest of your machine, this is the natural next step. Same philosophy: one script, idempotent, hands-off.

neovimluatoolsproductivitytutorial
Was this helpful?