LSP & Completion
Language intelligence that just works
This configuration provides full Language Server Protocol (LSP) support for 11+ languages, making Neovim feel like a modern IDE. Everything is automatically installed and configured through Mason, so you can focus on writing code instead of managing tools.
Configured Language Servers
All servers are installed automatically via Mason when you open a file of that type:
| Server | Languages | Features |
|---|---|---|
lua_ls | Lua | Neovim API completion via lazydev |
ts_ls | TypeScript, JavaScript | Full IntelliSense, refactoring |
eslint | JS/TS | Linting with auto-fix |
biome | JS/TS | Fast formatting and linting |
volar | Vue.js | Vue 3 component intelligence |
html | HTML | Tag completion, validation |
cssls | CSS, SCSS, LESS | Property completion, color preview |
jsonls | JSON | Schema validation, IntelliSense |
yamlls | YAML | Schema validation |
tailwindcss | Tailwind CSS | Class completion in JSX/HTML |
graphql | GraphQL | Query completion, validation |
Rust users: The pack.rust from AstroCommunity includes rustaceanvim, which provides enhanced rust-analyzer integration beyond basic LSP.
TypeScript users: The pack.typescript provides vtsls, an optimized fork of ts_ls with better performance.
LSP Features
Code Actions
Trigger: Space l a
Code actions provide quick fixes and refactoring options based on context:
- Quick fixes - Automatically fix linting errors
- Refactoring - Extract function/variable, inline variable
- Source actions - Organize imports, remove unused imports
- Import management - Add missing imports automatically
Example workflows:
1. Cursor on an error → Space l a → Select fix
2. Select a block of code → Space l a → Extract to function
3. On an import → Space l a → Organize importsGo To Actions
Navigate your codebase like a pro:
| Keybinding | Action | Description |
|---|---|---|
g d | Go to definition | Jump to where symbol is defined |
g D | Go to declaration | Jump to declaration (for C/C++) |
g i | Go to implementation | Jump to implementation of interface |
g r | Go to references | Show all usages of symbol |
g y | Go to type definition | Jump to type definition |
Pro tip: Use Ctrl-o to jump back to where you came from, Ctrl-i to jump forward.
Hover Documentation
Trigger: K in normal mode
Shows documentation for the symbol under cursor:
- Function signatures
- Type information
- Documentation comments
- Source code snippets
Press K twice to jump into the hover window for scrolling through long documentation.
Signature Help
Trigger: g K in normal mode, or automatic in insert mode
As you type function calls, signature help shows:
- Parameter names and types
- Current parameter highlighted
- Multiple overload signatures
- Parameter documentation
The lsp_signature plugin provides real-time signature hints as you type.
Diagnostics
Inline diagnostics with multiple severity levels:
- Error - Red, code won't compile/run
- Warning - Yellow, potential issues
- Info - Blue, suggestions
- Hint - Gray, optional improvements
Display options:
- Sign column indicators (left gutter)
- Virtual text at end of line
- Underlines in code
- Floating windows with details (
gl)
Navigation:
]d- Next diagnostic[d- Previous diagnosticgl- Show line diagnostic in floatSpace l d- All buffer diagnostics (Trouble)Space l D- All project diagnostics (Trouble)
Toggle diagnostics:
Space u d- Cycle between modes (all / no virtual text / off)
Symbol Renaming
Trigger: Space l r
Rename a symbol across your entire project:
- Place cursor on symbol
- Press
Space l r - Type new name
- Press Enter
LSP will:
- Find all references across files
- Update all usages
- Handle imports/exports
- Preserve code formatting
Works across:
- Variables and functions
- Classes and interfaces
- Component props
- Import paths
Document Symbols
Trigger: Space l s
Shows a searchable list of all symbols in the current file:
- Functions and methods
- Classes and interfaces
- Variables and constants
- Types and enums
Workspace symbols: Use Space l S to search symbols across all project files.
Formatting
Trigger: Space l f
Format the current buffer using the configured formatter.
Configured formatters (via none-ls):
- prettier - JavaScript, TypeScript, JSON, YAML, Markdown, HTML, CSS
- stylua - Lua
- biome - JavaScript/TypeScript (faster alternative to prettier)
Format on save:
Currently disabled by default. To enable, add to nvim/lua/plugins/astrolsp.lua:
formatting = {
format_on_save = {
enabled = true,
allow_filetypes = {
"lua",
"javascript",
"typescript",
-- Add more filetypes
},
},
},Pro tip: Use Space l a for source actions like "Organize Imports" before formatting.
Codelens
Shows inline actionable information above functions/classes:
- Test runner actions
- Reference counts
- Implementation counts
- Debug options
Auto-refreshes on:
InsertLeave- When you exit insert modeBufEnter- When you enter a buffer
Note: Codelens support depends on the language server. Works great with rust-analyzer and gopls.
Semantic Tokens
Enhanced syntax highlighting based on semantic information from LSP:
- Distinguish between different variable types
- Highlight mutable vs immutable
- Show unused variables differently
- Color based on scope and context
Toggle: Space u Y (buffer-local toggle)
Completion Engine
Powered by nvim-cmp with multiple intelligent sources.
Completion Sources
Sources are prioritized in this order:
- LSP - Language server completions (highest priority)
- LuaSnip - Snippet expansions
- Buffer - Words from current buffer
- Path - File and directory paths
Completion Keybindings
| Key | Action | Mode | Description |
|---|---|---|---|
C-Space | Trigger completion | i | Manually show completion menu |
Tab | Next item | i | Select next completion |
S-Tab | Previous item | i | Select previous completion |
Enter | Confirm selection | i | Accept completion |
C-e | Close menu | i | Dismiss completion menu |
C-d | Scroll docs down | i | Scroll completion documentation |
C-u | Scroll docs up | i | Scroll completion documentation |
Completion Behavior
Auto-trigger:
- Appears after typing 1 character
- Filters as you type
- Shows documentation preview
- Ghost text for current selection
Smart completion:
- Context-aware suggestions
- Snippet expansion
- Auto-import insertion
- Parameter hints
Snippets
Powered by LuaSnip with extensive snippet libraries.
Navigation:
Tab- Jump to next placeholderS-Tab- Jump to previous placeholder- Type to replace placeholder
Extended snippets:
- JavaScript snippets work in React files
- TypeScript snippets in
.tsxfiles - Custom snippets in
~/.config/nvim/snippets/
Example workflow:
1. Type 'log' in JavaScript
2. See 'console.log()' in completion
3. Press Tab to expand
4. Type your message
5. Press Tab to jump outTreesitter Integration
Treesitter complements LSP by providing:
Accurate Syntax Highlighting
Unlike regex-based highlighting, Treesitter:
- Parses your code into an AST
- Understands code structure
- Highlights based on grammar rules
- Never gets confused by complex syntax
Enabled parsers (25+):
Web: html, css, javascript, typescript, tsx, vue
Data: json, yaml, toml
Systems: c, cpp, rust, go, python, java
Shell: bash, fish, zsh
DevOps: dockerfile, terraform
Markup: markdown, markdown_inline
Git: git_config, git_rebase, gitcommit
Other: lua, vim, vimdoc, regex, querySmart Indentation
Treesitter provides context-aware indentation:
- Understands nesting levels
- Handles multi-line expressions
- Works across languages consistently
Special handling:
- YAML: Fixed to use simple autoindent (avoids smart indent issues)
- HTML/JSX: Auto-close tags via nvim-ts-autotag
Incremental Selection
Select increasingly larger syntax nodes:
Ctrl-Space- Start selection- Keep pressing to expand selection
- Selects: variable → expression → statement → function → class
Use case: Quickly select a function body or entire class for refactoring.
Text Objects
Navigate and operate on syntax nodes:
vaf- Select around functionvif- Select inside functionvac- Select around class- Similar to built-in text objects like
viw(inside word)
LSP Performance
Efficient Server Management
On-demand startup:
- Servers start only for opened filetypes
- Multiple buffers share one server
- Auto-restart on crash
Resource limits:
- Large files (>256KB) disable Treesitter
- Smart throttling of diagnostics
- Debounced completion triggers
Diagnostic Performance
Update triggers:
- On text change (debounced 300ms)
- On save
- On mode change
Display optimization:
- Virtual text only in normal mode
- Floating windows on demand
- Trouble panel for bulk review
Adding Language Support
Install New LSP Server
Find the server name at LSP Server Configurations
Add to
nvim/lua/plugins/mason.lua:
ensure_installed = {
"lua_ls",
"ts_ls",
"your_server_here", -- Add this
},- Install via Mason:
:Masonor restart Neovim (auto-installs on next open).
- Server auto-configures on first use.
Add Custom Server Settings
Edit nvim/lua/plugins/astrolsp.lua:
config = {
your_server_name = {
settings = {
-- Server-specific settings here
},
},
},Example for TypeScript:
config = {
ts_ls = {
settings = {
typescript = {
inlayHints = {
includeInlayParameterNameHints = "all",
},
},
},
},
},Add Formatters/Linters
Find tool at Mason Registry
Install via Mason:
:MasonInstall prettier
:MasonInstall stylua- Configure in
nvim/lua/plugins/none-ls.lua:
local null_ls = require("null-ls")
local formatting = null_ls.builtins.formatting
local diagnostics = null_ls.builtins.diagnostics
return {
sources = {
formatting.prettier,
formatting.stylua,
-- Add your tools:
formatting.your_formatter,
diagnostics.your_linter,
},
}Add Treesitter Parser
Edit nvim/lua/plugins/treesitter.lua:
ensure_installed = {
"lua", "vim", "javascript",
"your_language", -- Add here
},Or install on-demand:
:TSInstall your_languageTroubleshooting
LSP Not Working
Check server status:
:LspInfoShows:
- Active servers
- Server status
- Attached buffers
- Configuration issues
Restart LSP:
:LspRestartCheck Mason installation:
:MasonVerify server is installed (green checkmark).
Completion Not Showing
Check sources:
:CmpStatusManually trigger: Press Ctrl-Space in insert mode.
Check if disabled:
:lua vim.print(vim.g.cmp_enabled)Should return true. Toggle with Space u c.
Diagnostics Too Noisy
Toggle virtual text:
Space u dCycles through:
- All diagnostics
- Signs only (no virtual text)
- Diagnostics off
Hide specific severity:
Edit diagnostic config in nvim/lua/plugins/astrolsp.lua.
Formatting Issues
Check formatter availability:
:MasonFormat manually:
Space l fCheck which formatter is used:
:lua print(vim.inspect(vim.lsp.buf_get_clients()))Best Practices
Workflow Tips
- Use Trouble for diagnostics - Better than jumping error-to-error
- Learn go-to-definition -
gdis your most-used keybinding - Master code actions -
Space l afixes most issues - Hover for docs -
Ksaves trips to documentation - Rename safely -
Space l rupdates everywhere
Performance Optimization
- Disable for large files - Auto-disabled at 256KB
- Use format on save sparingly - Can cause lag on huge files
- Close unused buffers - Each buffer keeps its LSP connection
- Restart LSP if sluggish -
:LspRestartclears state
Language-Specific Tips
TypeScript:
- Use
Space l ato add missing imports - Enable inlay hints for parameter names
- Use
gdon imports to jump to definitions
Lua:
- Lazydev provides Neovim API completion
- Hover on Neovim functions for docs
- Use
styluafor consistent formatting
Rust:
- rustaceanvim provides enhanced features
- Hover shows detailed type information
- Use code actions for derive macros
Vue:
- Volar understands both script and template
- Separate TypeScript server for
<script>blocks - CSS language server for
<style>blocks
Advanced Configuration
Disable LSP for Specific Filetype
In nvim/lua/plugins/astrolsp.lua:
on_attach = function(client, bufnr)
if vim.bo[bufnr].filetype == "markdown" then
vim.lsp.buf_detach_client(bufnr, client.id)
end
endCustom LSP Handlers
Override how LSP responses are displayed:
vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(
vim.lsp.handlers.hover, {
border = "rounded",
max_width = 80,
}
)Inlay Hints
Show inline type annotations (experimental):
vim.lsp.inlay_hint.enable(true)Toggle with custom keybinding.
Conclusion
This LSP configuration provides IDE-level features while maintaining Neovim's speed and flexibility. The combination of LSP, Treesitter, and intelligent completion creates a powerful development environment that works across 11+ languages with zero manual setup.
Key takeaway: Everything auto-installs and auto-configures. Just open a file and start coding.