xiaohongshu
xiaohongshu
This skill guides working with Neovim configuration including testing changes headlessly, managing plugins with lazy.nvim, configuring LSP servers, and troubleshooting startup errors. Use this when modifying nvim config files or debugging nvim issues.
Full skill instructions
This skill provides patterns for modifying and testing Neovim configuration safely and efficiently.
The critical pattern for working with nvim configuration is testing headlessly before manually launching nvim. This catches errors immediately without disrupting your workflow.
# Test if nvim loads without errors
nvim --headless -c "echo 'Config loaded successfully'" -c "quit" 2>&1
What this does:
--headless: Run without UI-c "command": Execute vim command-c "quit": Exit after commands2>&1: Capture stderr to see errorsSuccess output:
Config loaded successfully
Error output shows:
# Test plugin loading
nvim --headless -c "lua print('Plugins loaded')" -c "sleep 2" -c "quit" 2>&1
# Test LSP configuration
nvim --headless -c "lua print('LSP config:', vim.inspect(vim.lsp))" -c "quit" 2>&1
# Test with a specific file type
cd /tmp && echo 'print("test")' > test.lua && \
nvim --headless test.lua -c "lua print('Buffer filetype:', vim.bo.filetype)" -c "quit" 2>&1
# Test if LSP attaches to a buffer (requires servers installed)
cd /tmp && echo 'print("hello")' > test.lua && \
nvim --headless test.lua \
-c "lua vim.defer_fn(function() print('LSP clients:', vim.inspect(vim.lsp.get_clients())) end, 2000)" \
-c "sleep 3" \
-c "quit" 2>&1 | grep -A5 "LSP clients"
Why defer_fn? LSP servers need time to start and attach. The 2000ms delay allows initialization.
~/.config/nvim/init.lua~/.config/nvim/lua/plugins/*.lua~/.config/nvim/lua/user/*.lua~/.config/nvim/lua/config/lazy.lua~/.config/nvim/lua/plugins/:-- ~/.config/nvim/lua/plugins/my-plugin.lua
return {
"username/plugin-name",
lazy = false, -- Load immediately (or set to true for lazy loading)
config = function()
require("plugin-name").setup({
-- Plugin configuration here
})
end,
}
nvim --headless -c "lua print('Testing plugin load')" -c "sleep 2" -c "quit" 2>&1
The modern approach uses three plugins:
mason.nvim - Installs language serversmason-lspconfig.nvim - Bridges mason and lspconfignvim-lspconfig - Configures LSP clientsRecommended structure (~/.config/nvim/lua/plugins/lsp.lua):
return {
-- Mason for installing language servers
{
"williamboman/mason.nvim",
lazy = false,
priority = 1000,
config = function()
require("mason").setup()
end,
},
-- LSP configuration (load early as dependency)
{
"neovim/nvim-lspconfig",
lazy = false,
},
-- Mason-lspconfig bridge
{
"williamboman/mason-lspconfig.nvim",
lazy = false,
dependencies = {
"williamboman/mason.nvim",
"neovim/nvim-lspconfig",
"hrsh7th/cmp-nvim-lsp",
},
config = function()
-- Setup mason-lspconfig
require("mason-lspconfig").setup({
ensure_installed = {
"lua_ls", -- Lua
"pyright", -- Python
"ts_ls", -- TypeScript/JavaScript
"rust_analyzer", -- Rust
-- Add more servers as needed
},
})
-- Define on_attach for keymaps
local on_attach = function(_, bufnr)
local map = function(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, desc = desc })
end
-- Navigation
map("n", "gd", vim.lsp.buf.definition, "Go to definition")
map("n", "gD", vim.lsp.buf.declaration, "Go to declaration")
map("n", "gr", vim.lsp.buf.references, "Go to references")
map("n", "K", vim.lsp.buf.hover, "Hover documentation")
end
-- Get capabilities
local capabilities = require("cmp_nvim_lsp").default_capabilities()
-- Configure each server
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup({
on_attach = on_attach,
capabilities = capabilities,
settings = {
Lua = {
diagnostics = { globals = { "vim" } },
},
},
})
-- Add more server configs as needed
end,
},
}
Test LSP config loads:
nvim --headless -c "lua print('Testing LSP')" -c "sleep 2" -c "quit" 2>&1
Common errors:
attempt to call field 'setup_handlers' - Don't use setup_handlers, configure servers manuallymodule 'cmp_nvim_lsp' not found - Add nvim-cmp as dependencypriority values (1000, 900, 800)cat ~/.config/nvim/lua/plugins/target-plugin.lua
Make your changes using the Edit tool
Test headlessly immediately:
nvim --headless -c "lua print('Config updated')" -c "quit" 2>&1
If errors appear, fix them before launching nvim normally
Launch nvim to verify behavior
# Check plugin loads
nvim --headless -c "lua print('Plugins OK')" -c "sleep 2" -c "quit" 2>&1
# Check for errors (should be empty)
nvim --headless -c "quit" 2>&1 | grep -i error
# Verify LSP config loads
nvim --headless -c "lua print('LSP:', vim.inspect(vim.lsp))" -c "quit" 2>&1
# Test with actual file (after servers installed)
cd /tmp && echo 'def hello(): pass' > test.py && \
nvim --headless test.py -c "sleep 3" -c "lua print('Clients:', #vim.lsp.get_clients())" -c "quit" 2>&1
# Check specific keymap exists
nvim --headless -c "lua print('Leader key:', vim.g.mapleader)" -c "quit" 2>&1
config for pluginSymptom: Error during plugin config function execution
Cause: Lua error in plugin's config = function() block
Solution:
require() statementFix dependency loading:
-- Add explicit dependencies and priority
{
"my-plugin",
dependencies = { "required-plugin" },
priority = 900, -- Lower number = loads later
}
Symptom: module 'xyz' not found
Cause: Plugin not installed or wrong name
Solution:
# Check if plugin directory exists
ls ~/.local/share/nvim/lazy/
# Launch nvim normally to let lazy.nvim install
nvim
# Or force plugin sync
nvim --headless -c "lua require('lazy').sync()" -c "sleep 5" -c "quit"
Symptom: attempt to call field 'setup' (a nil value)
Cause:
Solution:
Symptom: LSP features don't work, no diagnostics
Diagnosis:
# Check if LSP clients exist
nvim some-file.lua -c "lua vim.defer_fn(function() print(vim.inspect(vim.lsp.get_clients())) end, 2000)" -c "sleep 3" -c "quit"
Common causes:
:Mason in nvim to install:set filetype? in nvim:LspInfo for errorsSolution:
# Verify mason installed servers
ls ~/.local/share/nvim/mason/bin/
# Check server executable works
~/.local/share/nvim/mason/bin/lua-language-server --version
Symptom: Warning about require('lspconfig') being deprecated
Cause: Neovim 0.11+ has new LSP config API
Impact: Warning only - still works fine
Future fix: Migration guide will be available when nvim-lspconfig v3.0.0 releases
Diagnosis:
# Profile startup time
nvim --startuptime startup.log -c "quit"
cat startup.log | tail -20
Common causes:
Solution:
-- Lazy load plugins
{
"heavy-plugin",
lazy = true, -- Don't load at startup
event = "VeryLazy", -- Load after UI renders
-- or
cmd = "PluginCommand", -- Load on command
-- or
ft = "python", -- Load on filetype
}
# GOOD: Test before manual launch
nvim --headless -c "echo 'OK'" -c "quit" 2>&1 && echo "Safe to launch nvim"
# BAD: Edit config, launch nvim, hit error, can't see anything
nvim # Might crash immediately
-- For plugins that depend on each other, set priorities
{
"base-plugin",
priority = 1000, -- Loads first
}
{
"dependent-plugin",
priority = 900, -- Loads second
dependencies = { "base-plugin" },
}
~/.config/nvim/
├── init.lua # Entry point (minimal)
├── lua/
│ ├── config/
│ │ └── lazy.lua # Plugin manager setup
│ ├── plugins/ # One file per plugin
│ │ ├── lsp.lua
│ │ ├── telescope.lua
│ │ └── treesitter.lua
│ └── user/ # User settings
│ ├── mappings.lua
│ └── settings.lua
Benefits:
-- Good: Explain why
{
"williamboman/mason.nvim",
priority = 1000, -- Must load before mason-lspconfig
lazy = false, -- Required at startup for LSP
config = function()
require("mason").setup()
end,
}
-- Bad: No context
{
"williamboman/mason.nvim",
config = function()
require("mason").setup()
end,
}
When debugging mysterious issues:
# Start nvim with no config
nvim -u NONE
# Start with minimal config
echo "vim.opt.number = true" > /tmp/minimal.lua
nvim -u /tmp/minimal.lua
# Before restructuring LSP config
cp ~/.config/nvim/lua/plugins/lsp.lua ~/.config/nvim/lua/plugins/lsp.lua.backup
# Or use git
cd ~/.config/nvim
git diff # Review changes
git checkout -- file.lua # Revert if needed
# 1. Make your changes
# 2. Test headlessly
nvim --headless -c "quit" 2>&1
# 3. If errors, see the stack trace and fix
# 4. When clean, test with a file
cd /tmp && echo 'test' > test.txt && nvim --headless test.txt -c "quit" 2>&1
# 5. Launch normally
nvim
# 1. Add to ensure_installed in lsp.lua
# 2. Add server config in lsp.lua
# 3. Test config loads
nvim --headless -c "quit" 2>&1
# 4. Launch nvim - mason auto-installs
nvim
# 5. Wait for mason to finish installing
# 6. Open a file of that language
# 7. Verify LSP attached: :LspInfo
# 1. Delete plugin file
rm ~/.config/nvim/lua/plugins/unwanted-plugin.lua
# 2. Test config loads
nvim --headless -c "quit" 2>&1
# 3. Launch nvim
nvim
# 4. Clean up plugin directory
# In nvim: :Lazy clean
# Test config loads
nvim --headless -c "quit" 2>&1
# Test with delay for async operations
nvim --headless -c "sleep 2" -c "quit" 2>&1
# Test LSP configuration
nvim --headless -c "lua print(vim.inspect(vim.lsp))" -c "quit" 2>&1
# Test with specific file type
nvim --headless test.lua -c "quit" 2>&1
# Check plugin installation
ls ~/.local/share/nvim/lazy/
# Check LSP servers installed
ls ~/.local/share/nvim/mason/bin/
# Profile startup time
nvim --startuptime startup.log -c "quit" && tail -20 startup.log
# Launch with no config (debugging)
nvim -u NONE
# Force plugin sync
nvim --headless -c "lua require('lazy').sync()" -c "sleep 10" -c "quit"
# Test if specific plugin is loaded
nvim --headless -c "lua print('Telescope:', require('telescope') ~= nil)" -c "quit" 2>&1
# Add prints in config functions to trace loading
config = function()
print("Loading plugin X...")
require("plugin").setup()
print("Plugin X loaded")
end
# Open file and try keymap programmatically
nvim --headless test.lua \
-c "normal gd" \
-c "echo 'Keymap executed'" \
-c "quit" 2>&1
This pattern lets you verify keymaps trigger without manual testing.
The most important practice: always test nvim config changes headlessly before launching nvim manually. This catches errors immediately and shows you exactly where the problem is.
The basic workflow:
nvim --headless -c "quit" 2>&1This saves enormous amounts of time and frustration compared to trial-and-error with manual launches.
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience