Skip to content

Repository files navigation

Neovim Configuration

中文文档

A modern Neovim configuration built with Lua and lazy.nvim. Aligned with LazyVim conventions for keybindings and plugin choices, with support for Go, C/C++, Python, Java, Web, Bash, JSON, YAML, and LaTeX development.

Requirements

Required:

  • Neovim >= 0.11.3 (uses vim.lsp.config/vim.lsp.enable, vim.hl, vim.diagnostic.jump)
  • Git
  • A Nerd Font for icon display
  • ripgrep (rg) — powers Snacks.picker.grep / live_grep / :grep
  • fd — file finder (used by venv-selector and some pickers)

Optional (feature-specific):

  • lazygit — <leader>gg (project) / <leader>gf (file history)
  • tmux — wraps the selected native-agent TUI inside :terminal to prevent stale or torn frames; auto-detected (see Terminal Integration)
  • GitHub CLI — authenticated gh for <leader>G GitHub pickers and status
  • Claude Code or Codex — selected native coding agent
  • Node.js >= 22 + npm — CodeCompanion ACP bridge processes
  • ANTHROPIC_API_KEY or OPENAI_API_KEY — optional; selected provider's CodeCompanion HTTP inline/command prompts
  • cowsay + lolcat — dashboard banner (silently skipped if either is missing)

Quick install (macOS):

brew install neovim git gh ripgrep fd lazygit tmux cowsay lolcat node
brew install --cask font-jetbrains-mono-nerd-font  # or any Nerd Font
gh auth login                                      # once, for GitHub pickers
npm install -g @agentclientprotocol/claude-agent-acp @agentclientprotocol/codex-acp

Language toolchains — only if you want the matching Mason packages to install:

  • Go — required for gopls, gofumpt, gomodifytags, impl, delve
  • Python >= 3.10 — required for black (a pyenv or uv-managed interpreter works)
  • Node.js + npm — required for eslint-lsp, css-lsp, html-lsp, json-lsp, yaml-language-server, tailwindcss-language-server, vtsls, bash-language-server
  • JDK 17+ — required for jdtls (Java). This config expects SDKMAN! at ~/.sdkman/candidates/java/current (see lua/lang/java.lua)
  • TeX Live + Skim (LaTeX) — brew install --cask mactex-no-gui for latexmk/latexindent/chktex, and brew install --cask skim for the SyncTeX PDF viewer. texlab is installed by Mason. For inverse search set Skim → Preferences → Sync → Custom: command nvim, arguments --headless -c "VimtexInverseSearch %line '%file'"

If a Mason package fails to install, run :Mason (UI) or :MasonLog (raw log) to see the underlying error. The most common cause is a missing toolchain from the list above.

Installation

# Backup existing config
mv ~/.config/nvim ~/.config/nvim.backup

# Clone
git clone https://github.com/huiyu/nvim.git ~/.config/nvim

# Launch Neovim — lazy.nvim auto-installs all plugins
nvim

Project Structure

~/.config/nvim/
├── AGENTS.md                # Repository guidance for coding agents
├── CLAUDE.md                # Claude Code import of AGENTS.md
├── init.lua                  # Entry point
├── lua/
│   ├── options.lua           # Vim options
│   ├── mappings.lua          # Imperative core keymaps (side effects)
│   ├── whichkey_spec.lua     # which-key groups, popup sections, spec keymaps (data)
│   ├── autocmds.lua          # Autocommands
│   ├── bootstrap.lua         # lazy.nvim setup
│   ├── ai/                    # Provider config + native Claude/Codex facade
│   ├── config/
│   │   └── health.lua        # `:checkhealth config` provider
│   ├── lang/                 # Language-specific configs
│   │   ├── bash.lua
│   │   ├── dart.lua
│   │   ├── rust.lua
│   │   ├── c.lua             # C / C++
│   │   ├── frontend.lua      # HTML / CSS / Tailwind
│   │   ├── go.lua
│   │   ├── java.lua
│   │   ├── json.lua
│   │   ├── python.lua
│   │   ├── tex.lua           # LaTeX (VimTeX + texlab)
│   │   ├── typescript.lua    # JS / TS language (LSP, format, DAP)
│   │   └── yaml.lua
│   ├── plugin/
│   │   ├── editor/           # Editor enhancement plugins
│   │   ├── lsp/              # LSP, completion, formatting, debugging
│   │   ├── ui/               # UI and theme plugins
│   │   └── vcs/              # Git integration
│   └── util/                 # Utility modules
├── .github/workflows/       # CI: spec suite + both provider startups
├── scripts/                 # $EDITOR wrapper for the agent TUIs
├── tests/                   # Headless spec suite (tests/run.sh)
└── docs/                     # MANUAL.md, DIAGNOSTICS.md, UTILITIES.md

Plugins

UI

Plugin Description
solarized-osaka Colorscheme
lualine Status line with a ● REC @q macro recording indicator
incline Top-right filename labels in file windows; pink for the focused window, [+] for unsaved changes
bufferline Buffer tabs with pin/close/pick
noice Enhanced cmdline/messages; bordered LSP docs and quiet empty-hover notifications
treesitter Syntax highlighting, text objects
treesitter-context Sticky function/class header (<leader>uC)
nvim-ts-autotag Auto-close HTML/JSX tags
nvim-ufo Modern code folding
todo-comments TODO/FIXME highlights
illuminate Highlight word under cursor
colorizer Hex/RGB/HSL and CSS variable previews; Tailwind colors in frontend files
render-markdown In-editor markdown rendering (,m)

Editor

Plugin Description
flash Fast navigation with labels
which-key Keybinding help popup
snacks Picker, dashboard, terminal, indent guides, smooth scroll, rename, zen mode (sz)
aerial Code outline / symbol navigation
grug-far Search and replace
harpoon Pinned-file jumps (;1-;9, ;h menu)
yanky Yank history ring
dial Increment/decrement booleans, dates, etc.; let / const in JS/TS
refactoring Extract function/variable, inline
mini.ai Enhanced text objects
mini.splitjoin Toggle single-line/multi-line (gS)
mini.bracketed Extra [/] motions on the suffixes this config leaves free (x conflict, i indent, c comment, j jump, o oldfile, u undo)
nvim-surround Surround manipulation
nvim-autopairs Auto-close pairs
persistence Session management
guess-indent Auto-detect indentation
oil Edit a directory as a buffer: rename, move (dd/p) and create files as text. - for the parent directory, ;o for a float

LSP & Development

Plugin Description
nvim-lspconfig LSP configuration
mason LSP/DAP/linter/formatter installer
blink.cmp Completion engine with friendly-snippets
conform Code formatting (with autoformat toggle)
nvim-lint Linting
nvim-dap Debug Adapter Protocol
neotest Testing framework
neogen Generate annotations/docstrings
SchemaStore JSON/YAML schema validation
lazydev Lua development (type completion)
inc-rename LSP rename with live preview, on ,r
claudecode Native Claude Code integration (Claude provider only)
CodeCompanion Provider-aware ACP chat plus HTTP inline/command prompts
codecompanion-history Auto-saved, project-aware CodeCompanion chat history

Version Control

Plugin Description
gitsigns Git signs, hunk actions, blame
diffview Diff and file history viewer

Language Support

Language LSP Formatter Linter Test Debug
C / C++ clangd clang-format - - codelldb
Go gopls gopls organize imports + gofumpt golangci-lint neotest-golang nvim-dap-go
Python basedpyright, ruff black ruff neotest-python nvim-dap-python
Java jdtls (+ Lombok) jdtls - java-test java-debug-adapter
Rust - - - Cargo test (DAP) codelldb + Cargo
Dart / Flutter - - - SDK test (DAP) SDK DAP
TypeScript/JS vtsls prettier eslint Vitest (DAP) js-debug-adapter
HTML/CSS html, cssls, tailwindcss prettier - - -
JSON jsonls + SchemaStore prettier - - -
YAML yamlls + SchemaStore prettier - - -
Bash bashls shfmt - - -
LaTeX texlab (+ VimTeX) latexindent chktex - -
Lua lua_ls - - - -

Debugging

<leader>df debugs the current file, <leader>td the nearest test, and <leader>tF the current test file. These entries share keys across languages; each language owns its target selection (JS/TS tests use Vitest).

<leader>dA / :DapAttach attaches to an existing process, with presets for Go, Python, Java, C/C++, Rust, Node/Chrome, Dart/Flutter and Electron.

<leader>d covers breakpoints, stepping and sessions: de exception breakpoints, dL logpoints, dR restart, dD disconnect while keeping the target running, du the debug view, dw evaluate expression/selection, and dW add a watch. The debug view opens in a tabpage of its own, so a session never rearranges the windows you were editing in; stepping stays in whichever tabpage you are in. See the debugging workflow for each language's dependencies, launch/attach commands, tests and project launch.json examples. Install the Dart/Flutter SDK separately.

LaTeX Workflow

LaTeX is split between two tools: VimTeX drives compilation/viewing/motions, while texlab provides LSP intelligence (completion, goto, label rename) and chktex linting. They are configured not to overlap — texlab's own build is disabled so only VimTeX compiles.

One-time setup

brew install --cask mactex-no-gui   # TeX Live: latexmk, latexindent, chktex
brew install --cask skim            # PDF viewer with SyncTeX

texlab installs itself through Mason on first launch — no extra step. For inverse search (click in the PDF → jump to source), set Skim → Preferences → Sync → Preset: Custom, Command nvim, Arguments:

--headless -c "VimtexInverseSearch %line '%file'"

Daily use — open any .tex file, then:

  • ,Ll — toggle continuous compilation (recompiles on save while running)
  • ,Lv — forward search: open/jump Skim to the cursor's line
  • ,Lt — table of contents; ,Lc clean, ,Le errors
  • Save the file to auto-format with latexindent (toggle with <leader>uf)

The everyday actions are also one key shorter, in the LaTeX sections of the , which-key popup:

Key Action
,b Compile (toggle continuous)
,v View PDF in Skim
,s Stop compilation
,K Clean aux files
,t Toggle table of contents
,E Show error list
,x One-shot latexmk build to PDF (the generic "run this file" key)

TeX buffers also enable soft wrap and spell by default (toggle with <leader>uw / <leader>us).

Keybindings

Leader: Space · Actions / local leader: , · Cheat sheet: <leader>?

Every key answers one question, and the prefix says which:

Prefix Question Examples
; Which file / symbol / position do I want? ;<space> smart find, ;f files, ;/ grep, ;s symbols, ;1-;9 pinned files
, What can I do in this file / view? ,a code action, ,f format, ,r rename, ,o organize imports (Go/Python); terminal-local ,1-,9
s What about this window? ss/sv split, sd close, se editor window, s= equalize
<leader> Everything else, by domain g git, G GitHub, d debug, t test, a AI, x diagnostics, m manage, s session, y yank, u toggles, b buffer, q quit

Frequent actions use short keys. Related commands can share a subgroup, such as ,e… for extraction and ,L… for VimTeX; <leader> groups global domains. Press any prefix and wait — which-key lists the current mappings.

The , menu separates general editing from the current language's operations (imports/environment, compilation/preview, test debugging) and view actions. Diffview adds its own section alongside the source file's language section. The search-and-replace panel keeps its actions under ,S…. See the filetype and view actions for the full key list. The local leader shares the comma menu; it is not a fifth prefix. Restart Nvim after updating to remove the old backslash bindings from existing buffers.

Unprefixed keys worth knowing:

Key Action
f / F Flash jump / Treesitter jump (Normal + Visual; df-, ct) stay native)
<C-h/j/k/l> Move between windows — works from terminal input too
<C-,> Jump to the editor area, press again to return
<C-/> Toggle terminal; 3<C-/> selects terminal 3 from a file; ,1-,9 switch from terminal-Normal
<S-h> / <S-l> · [b / ]b Previous / next buffer
g · [ / ] · z Goto+LSP (from the symbol under the cursor) · prev/next thing · folds and spelling
- Open the current directory in oil (edit it as text)
jk · <C-]> / <C-\> Input-safe Escape; in Normal, use its input source

→ docs/MANUAL.md walks through all of it, starting with the composition rules the keys are built on.

Terminal Integration

Native coding-agent terminals no longer resize automatically when entering Terminal-mode, so moving into one with <C-h/j/k/l> does not produce a one-row flash. If a TUI drifts, exit terminal input with <C-]> (or jk) and use <leader>md to repair it. Opening a numbered bottom terminal still repairs the visible agent after the layout changes.

<C-]> is the uniform, input-method-safe exit key: in Editor Insert mode it acts as <Esc>; in every terminal, including Claude/Codex panels, it reaches terminal-Normal without sending the chord to the child process. In Normal mode it remains an Escape instead of invoking Nvim's native tag jump and also returns a manually selected input method to the Normal-mode layout, so it never turns the word under the cursor into an E426 lookup. help and man buffers keep the builtin tag jump, since <C-]> is how they follow a link and they have no second key for it; <Esc> and <C-\> still clear the search highlight there.

<C-h/j/k/l> is owned by Neovim in both Normal and terminal-input mode, so it can move directly between editor and terminal windows. This replaces the TUI's original Ctrl shortcuts; use Backspace for delete-backward, <S-Enter> for a newline in the agent's input box, and arrow keys in pickers. <C-S-l> forwards the original Ctrl+L byte to redraw either the Codex or Claude Code TUI. At a layout edge the key is a no-op that keeps terminal input active, and a floating terminal (lazygit, a float-shaped <C-/> shell) counts as all edges — otherwise a shell's own <C-h> or <C-l> would jump out from under the float.

Because <C-\> sits beside <C-]>, it performs the same safe Escape in Normal, Insert, Visual, and terminal-input modes. Repeated presses remain harmless in Normal mode: they neither change modes nor overwrite the source awaiting restoration, so either adjacent chord can be used without an accidental window jump.

<C-,> jumps directly from terminal input or a sidebar to the editor window. Pressing it from the editor returns to the source window. It relies on the extended-key protocol negotiated by Ghostty and Nvim to remain distinct from a plain comma; an outer tmux must have extended-keys enabled. Where that protocol is unavailable — a bare Terminal.app, an ssh session, an older tmux — se does the same jump with plain keys. Terminal numbers avoid the protocol altogether: terminal-local ,1-,9 are plain keys because Ghostty encodes Ctrl+digit as legacy bytes under an outer tmux, so the old <C-1>-<C-9> chords never arrived there.

The number mappings exist only in terminal buffers, in Normal mode (jk or <C-]> first from terminal input). Ordinary files show their language actions in the same comma menu. From a file, use <C-/> to reopen the last terminal, or 3<C-/> to select terminal 3 directly.

Inside an agent panel, <Esc> belongs to the agent, not to Nvim. Both CLIs read a quick double Esc as "go back a message", so neither Snacks' double-tap nor the global <Esc><Esc> applies there. <C-]> or the adjacent <C-\> reaches terminal-Normal, jk does the same without a modifier, and <C-,> jumps straight back to the editor. Ordinary :terminal buffers keep <Esc><Esc>.

A click inside an agent panel also stays in terminal-input mode. Nvim only hands a mouse event to the terminal job when that job asked for mouse reporting, and neither TUI does, so without this a click -- including the one that returns focus to the terminal window after switching apps -- left the panel in Normal mode. Under the tmux wrapper tmux asks for it and handles the click itself; without the wrapper Nvim swallows clicks that land in the panel. Clicking a different window still moves there.

An agent that fails to start keeps its panel open with its own error still on screen, and closes on the next <Enter>. Both wrappers end with tmux teardown that reports success to Nvim however the agent exited, so without this the panel closed silently and the message went with the tmux server -- nothing reached :messages either.

Scrollback works the same way under both providers, because both wrappers run tmux with mouse on and a 50000-line history. tmux owns the real transcript; Nvim's terminal buffer only holds the screenful tmux last composed, so scrolling goes through tmux. Stay in terminal-input mode and use the mouse wheel or <PageUp> to enter tmux copy-mode; scroll down with the wheel or <PageDown>, then press q or <Esc> to return to the agent's input. Leaving terminal input and entering it again by any Normal-mode entry key (i, a, I, A, and so on) also exits copy-mode and snaps to the live bottom. If you are already in terminal-Normal mode, the same scroll keys -- plus <C-u>/<C-d> -- are forwarded to tmux and terminal input is restored without exiting copy-mode, so the next wheel event continues through the history. With CLAUDE_WRAP_TMUX=0 or CODEX_WRAP_TMUX=0 there is no tmux to ask, so use jk and Nvim's normal scroll commands instead.

Codex runs with --no-alt-screen --yolo inside Nvim. YOLO mode bypasses Codex approvals and its built-in sandbox, while --no-alt-screen lets completed chat output enter the wrapper tmux history.

Editing the prompt in a buffer

<leader>ai opens the agent's prompt in a floating buffer, so a long prompt is written with the whole editor instead of the TUI's input box. It exists because Terminal-mode gives <C-h/j/k/l> to window navigation, which are exactly the agent TUI's editing keys.

Key Action
<C-d> return the prompt to the agent (works from Insert mode)
<C-v> attach the clipboard image
<C-c> cancel, leaving the input box as it was
:wq / ZZ return the prompt
:q! cancel

Whatever is already in the input box comes across, and from Visual mode the selection is added to it first, using the same text form <leader>as produces. Nothing is submitted — closing the buffer hands the text back to the box, and you still press Enter yourself.

The float is modal: window navigation (<C-h/j/k/l>, <C-w>) and the adjacent Escape chord (<C-\>) do not leave it, and a focus change that slips past that is undone. While it is open the agent is blocked on the editor and ignores its pty, so there would be no way back otherwise — <leader>ai pressed again returns to the open prompt (adding a Visual selection to it) instead of sending a ctrl+g the TUI would swallow. Two agents side by side may each have a prompt open; the newer one keeps focus.

This is not a buffer of ours: it is the agent's own ctrl+g ("edit this prompt in $EDITOR"), which both Claude Code and Codex implement. $EDITOR points at scripts/agent-editor, which opens the prompt in this Nvim instead of starting a second one inside the :terminal. <leader>ai simply sends ctrl+g to the TUI, so pressing ctrl+g there directly does the same thing.

Going through the CLI is what makes it exact. The CLI writes the box to a temp .md file, waits for the editor, and re-reads it — so newlines survive, and the CLI performs the write-back itself. Reading the box off the terminal screen instead cannot work: a real newline and a soft wrap render identically in both TUIs (a two-space-indented continuation line either way), so scraped text can never be reassembled reliably.

$NVIM is what makes the round trip possible: Nvim sets it in every :terminal child, and it holds the RPC socket back to the instance that owns the terminal. The wrapper polls for a sentinel file rather than using --remote-wait, which Nvim does not implement (E5600: Wait commands not yet implemented in Nvim).

If the agent is not running, <leader>ai starts it and waits for its input box before sending the key — a ctrl+g fired at a booting TUI is swallowed with nothing on screen to show for it. Readiness is the one thing read off the rendered screen, and only as a trigger: being wrong costs a keystroke, not a corrupted prompt.

@ file mentions

Typing @ plus a fragment completes project files, the way the TUIs' own input box does. Candidates come from the project root this Nvim runs in and respect .gitignore — git ls-files, falling back to fd and then rg --files; with none of them available the menu simply stays empty. The query narrows over the full relative path, slashes included, and accepting inserts @path/to/file.

An @ directly after a word character is not a mention, so jeff@gmail.com stays an email; other scripts do count as a boundary, so 看看@init completes. What the agent does with the text differs per provider: Claude Code parses the returned @path into a real file mention on submit, Codex treats it as a path its agent opens itself — both end up reading the file. The source lives in lua/ai/mention.lua and is enabled only for these prompt buffers, so ordinary markdown never sees it.

Attaching images

<C-v> in the prompt buffer stages the clipboard image; it attaches when you return the prompt. Staged images show as virtual lines at the end of the buffer, which are not buffer text — so they are visible while you write without being sent as literal text. Pressing ctrl+v in the TUI itself still works too. macOS only.

Nothing is written into the buffer, because the image cannot travel through the prompt file — that is plain markdown, and only the CLI can put image bytes into its request. So the staged file is replayed through the TUI's own ctrl+v, and the CLI writes its own [Image #N] marker.

The replay waits until the buffer has closed. Measured: while the prompt is open the agent is blocked on the editor and throws pty input away, so a ctrl+v sent during the edit never arrives — the same one sent afterwards does. Cancelling discards the staged files rather than bolting them onto a prompt you threw away.

Reading past output

<leader>at renders the current project's newest session into a read-only Markdown buffer, and <leader>aT picks from that project's session history. Inside the buffer, R re-reads from disk and q closes it. Prose is visible; thinking and tool calls are folded, so zR opens everything and za opens one.

The source is the CLI's own JSONL transcript, not the terminal. Claude runs on the alternate screen, so its tmux wrapper keeps no scrollback at all — there is nothing to capture from the pane. Reading the recorded transcript is the only approach that works for both providers, it survives restarting Nvim, and it needs no change to the tmux wrappers.

Neither CLI persists its reasoning text, so folded "thinking" sections will normally be absent rather than empty.

AI provider selection

One Nvim process selects one provider at startup. Claude remains the default; the native and CodeCompanion shortcuts stay unchanged. The shell aliases used by this setup are:

vi                 # default provider (Claude unless overridden)
vic                # NVIM_AI_PROVIDER=claude nvim
vix                # NVIM_AI_PROVIDER=codex CODEX_HOME="$HOME/.codex-oauth" nvim

<leader>as attaches the visual selection to the native agent's input box and does not submit it, leaving room for an instruction. With Codex, a saved buffer becomes an @path lines X-Y draft. For a modified or unnamed buffer, the exact selected text is pasted instead because Codex file mentions read the saved file. Add the instruction you want, then press Enter yourself.

The same setting selects CodeCompanion's ACP Chat agent (claude_code / codex). Chat therefore uses the coding agent's stateful protocol and tools; Inline and command prompts remain lightweight HTTP interactions (anthropic / openai_responses) and require the matching API key. Codex ACP uses ChatGPT authentication and inherits CODEX_HOME from vix.

CodeCompanion chats are auto-saved by codecompanion-history. Open them with <leader>aph (or :CodeCompanionHistory); inside a chat, gh opens the same history browser. Entries use the Snacks picker and can be renamed manually; automatic model-generated titles are disabled to avoid an extra request. History restores the local CodeCompanion transcript. To continue the agent's actual stateful ACP session, use /resume from a fresh ACP chat.

Run :AIInfo to inspect the resolved Native/ACP/HTTP mapping and :checkhealth config to see missing CLIs, ACP bridges, or HTTP credentials.

Shift+Enter (iTerm2)

When running terminal apps inside Neovim (e.g. Claude Code), Shift+Enter requires iTerm2 configuration:

iTerm2 setup: Settings → Profiles → Keys → Key Mappings → Add:

  • Shortcut: Shift + Return
  • Action: Send Escape Sequence
  • Value: [13;2u

Native-agent tmux wrappers

Claude Code and Codex are launched inside provider-specific, dedicated tmux servers. See lua/plugin/lsp/ai.lua and lua/ai/backend/codex.lua.

Why: both TUIs emit DEC mode 2026 (Synchronized Output) escape sequences for atomic frame updates. Nvim's :terminal buffer does not understand this protocol, so without a wrapper a partial frame can leave duplicated status bars or stale cells. tmux composes the synchronized frame and sends ordinary terminal updates to Nvim. This is independent of the host terminal because the relevant layer is Nvim's embedded libvterm.

Trade-off: Inside the wrapped tmux, CJK wide-character widths can disagree between tmux, the host terminal, and the agent TUI. This can produce minor misalignment in box-bordered UI.

Keys: both wrappers run tmux with extended-keys always and extended-keys-format csi-u. tmux's default (extended-keys off) turns the ESC[13;2u that <S-Enter> sends into a bare Enter, which submits the message instead of inserting a newline. always keeps the modifier without waiting for the TUI to request it, and CSI u is the form both Claude Code and Codex parse. Every key with a legacy encoding reaches the TUI unchanged.

Teardown: closing the panel or quitting Nvim runs scripts/agent-teardown, which kills the wrapper server and then whatever the agent left running in process groups of its own -- a Codex exec_command dev server, a background Bash job -- since tmux only signals the pane's own process. Shared daemons the agent may have started (emulator, Gradle daemon, container runtime) are spared; set NVIM_AGENT_TEARDOWN_IGNORE to an awk regex to change that list. Runs are logged to ~/.local/state/nvim/agent-teardown.log.

Overrides:

  • CLAUDE_WRAP_TMUX=0 nvim — disable for one-off A/B testing
  • vim.g.claude_wrap_tmux = false in init.lua — disable permanently
  • CODEX_WRAP_TMUX=0 nvim / vim.g.codex_wrap_tmux = false — equivalent Codex overrides
  • Both wrappers default to on when tmux is installed

Tip — suppress the recap CJK box: Claude Code's session recap is the most visible CJK width offender. Set "awaySummaryEnabled": false in ~/.claude/settings.json to suppress it. This is Claude Code's global config, not nvim's.

macOS input method

When macism is available, Nvim keeps Normal and Terminal-Normal modes on the detected Latin keyboard layout. Entering Insert or terminal-input mode restores the input source that was active before leaving it; leaving those modes captures the current source before switching back to English. This preserves both cases: English stays English, while Sogou/Apple Pinyin is restored after returning to text entry.

If an input method is selected manually while already in Normal mode, press <C-\> or (outside help/man) <C-]> to capture it and return to the Normal layout without leaving Normal mode. The next Insert or terminal-input entry restores that source only when Nvim actually switched it away. Repeating the key is idempotent; if the Normal layout was already active, entering input mode does not apply a stale saved source.

The Normal-mode layout comes from NVIM_ENGLISH_INPUT_SOURCE, falling back to an enabled macOS keyboard layout — a Latin one in preference to whatever the system lists first — and then to the last-used layout. There are deliberately no FocusGained/FocusLost hooks, so moving between Nvim and another application does not rewrite the other application's input-source state.

NVIM_MACISM_WAIT_TIME_MS=0 disables macism's temporary focus window and its visible Ghostty focus flash. This trades away macism's CJK activation workaround and may let the first characters through as English on macOS 26; leave the variable unset to use macism's built-in wait (currently 150ms).

Configuration

Set these in init.lua before plugins load.

Option Description
vim.g.terminal_position "float" (default) or "bottom". Where numbered terminals open. Chosen once, not toggled at runtime — Snacks fixes a window's shape when it opens one and edgy decides separately whether a terminal belongs to its bottom edge, so a runtime toggle means keeping those two in agreement through every hide, show and relayout.

Environment Variables

Variable Description
NVIM_AI_PROVIDER claude (default) or codex; selects the native agent, CodeCompanion ACP Chat, and HTTP inline adapter for this Nvim process
NVIM_ENGLISH_INPUT_SOURCE macOS input-source ID used in Normal mode; falls back to an enabled keyboard layout reported by macOS, preferring a Latin one
NVIM_MACISM_WAIT_TIME_MS Optional macism CJK workaround wait; 0 removes the temporary focus window at the cost of possible first-character races
NVIM_LOG_LEVEL util.logger threshold: DEBUG/INFO/WARN/ERROR (default WARN)
NVIM_DEV=1 Sets util.logger to DEBUG (verbose logging)
CLAUDE_WRAP_TMUX 1/0 — override default Claude Code tmux wrap. Default on. See native-agent tmux wrappers.
CODEX_WRAP_TMUX 1/0 — override default Codex tmux wrap. Default on. See native-agent tmux wrappers.
CLAUDE_CHROME 1/0 — enable or disable Claude in Chrome for the native Claude process. Default on.

Diagnostics

For troubleshooting (slow startup, LSP not attaching, missing formatter, etc.) see docs/DIAGNOSTICS.md. Run :checkhealth config to verify external dependencies, key Mason packages, and the Neovim version.

Customization

Add a plugin — create a file in the appropriate lua/plugin/*/ directory.

Add language support, an LSP server, or a formatter — create or edit the matching contribution in lua/lang/. Language files extend the shared nvim-lspconfig, Conform, lint, Treesitter, DAP, and test specs; the files in lua/plugin/lsp/ contain editor-wide defaults only.

Tune file/grep search scope — the file (;f) and grep (;/) pickers show hidden and gitignored files (hidden/ignored in lua/plugin/editor/snacks.lua). .git/ is always excluded; heavy build/dependency dirs (node_modules, target, .venv, Pods, …) are skipped via the shared search_exclude list in the same file. Add a dir to that list to hide it, or remove one to search it. Note: exclude drops any dir of that name unconditionally — even git-tracked source — so generic names (bin, out, vendor) are intentionally left out.

Use ;i (files) or ;? (text) to respect .gitignore instead, with hidden files still visible and no extra directory exclusions. Under Manage, <leader>mf searches this configuration and <leader>mF searches installed plugin source files.

License

This configuration is provided as-is for personal use.

About

My Personal Neovim Config

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages