LSP and Code Intelligence
LSP and Code Intelligence
LSP (Language Server Protocol) gives LazyVim IDE-like features: autocomplete, go to definition, refactoring, inline errors, and more. Understanding how to use LSP effectively makes you 10Γ faster.
What is LSP?
LSP is a protocol that allows editors to communicate with language-specific servers that understand your code.
LazyVim (client) ββ typescript-language-server (server)
ββ pyright (Python)
ββ lua-language-server (Lua)
What LSP provides:
- β Autocomplete with type information
- β Go to definition/references
- β Inline error diagnostics
- β Hover documentation
- β Code actions (refactoring)
- β Rename symbols across files
- β Signature help (function parameters)
What LSP does NOT do:
- Run your code (that's a REPL/debugger)
- Format your code (that's a formatter like Prettier)
- Lint your code (that's a linter like ESLint - though some LSPs include it)
Essential LSP Keybindings
Go to Definition
gd
What it does: Jumps to where a function/variable is defined.
Example:
typescript// In file A: import { calculateTotal } from './utils'; const result = calculateTotal(100, 0.2); β cursor here // Press gd β Jumps to file B: export function calculateTotal(price: number, tax: number) { return price + (price * tax); }
Return to previous location:
Ctrl+o # Jump back
Go to Type Definition
gy
What it does: Jumps to the type definition.
Example:
typescriptconst user: User = getUser(); β cursor here // Press gy β Jumps to: interface User { name: string; email: string; }
Find References
gr
What it does: Shows everywhere a symbol is used.
Example:
typescriptfunction calculateTotal(a, b) { return a + b; } β cursor here // Press gr β Shows list: 1. src/utils.ts:12 - function calculateTotal 2. src/App.tsx:45 - const total = calculateTotal(x, y) 3. src/Cart.tsx:23 - return calculateTotal(price, tax)
Hover Documentation
K (Shift+k)
What it does: Shows documentation for symbol under cursor.
Example:
typescriptconst result = Math.max(10, 20); β cursor here // Press K β Shows popup: βββββββββββββββββββββββββββββββββββββββ β Math.max(...values: number[]): number β β β β Returns the larger of a set of β β supplied numeric expressions. β βββββββββββββββββββββββββββββββββββββββ
Close popup: Press K again or Esc
Code Actions
Space + c + a
What it does: Shows available refactorings and quick fixes.
Examples:
Import missing symbol:
typescriptconst result = calculateTotal(10, 20); β (red underline: not imported) Space + c + a β Shows: 1. Import calculateTotal from './utils' 2. Create function calculateTotal
Extract to constant:
typescriptreturn price * 0.2; β select "price * 0.2" Space + c + a β Shows: 1. Extract to constant 2. Extract to function
Fix all in file:
Space + c + A # Capital A
Rename Symbol
Space + c + r
What it does: Renames a symbol everywhere in the project.
Example:
typescriptfunction calculateTotal(price, tax) { return price + tax; } const result = calculateTotal(100, 20); β cursor on "calculateTotal" Space + c + r Type: "computeSum" β Renames in ALL files where it's used
This is extremely powerful:
- Refactor safely across entire codebase
- Renames in imports/exports too
- Updates all references
Signature Help
# Automatically shows when typing function call
# Or manually trigger:
Ctrl+k
Example:
typescriptMath.max( β cursor here // Automatically shows: ββββββββββββββββββββββββββββββββββββ β max(value1: number, value2: number, ...values: number[]): number β β ^^^^^^ β ββββββββββββββββββββββββββββββββββββ
Shows which parameter you're on and its type.
Diagnostics (Errors/Warnings)
LSP shows errors and warnings inline.
See Diagnostics
Visual indicators:
- Red underline = Error
- Yellow underline = Warning
- Blue underline = Info
- Gray text = Hint
See full diagnostic message:
# Hover over error
K
Navigate Diagnostics
]d # Next diagnostic
[d # Previous diagnostic
Show All Diagnostics
Space + x + x # Diagnostics in current file
Space + x + X # Diagnostics in all files
Opens list:
1. error: Cannot find name 'calculateTotal'
2. warning: Unused variable 'result'
3. info: Consider using const instead of let
Fix Diagnostic
# Cursor on error
Space + c + a # Shows available fixes
Autocomplete
LazyVim has intelligent autocomplete via nvim-cmp.
Trigger Autocomplete
Autocomplete triggers automatically as you type.
Manual trigger:
Ctrl+Space
Navigate Completions
Ctrl+n # Next item
Ctrl+p # Previous item
Ctrl+y # Accept (yes)
Ctrl+e # Cancel (exit)
Enter # Accept selected
Autocomplete Sources
LazyVim pulls suggestions from:
- LSP (functions, variables, types)
- Buffer (words in current file)
- Path (file paths)
- Snippets (code templates)
Example:
typescriptconst user = { name: "John", email: "[email protected]" }; user. β Press Ctrl+Space β Shows: name: string email: string
Code Actions Examples
Import Missing Modules
typescriptconst result = calculateTotal(10, 20); β Red underline Space + c + a β Import calculateTotal from './utils'
Add Missing Types
typescriptfunction greet(name) { β Space + c + a β Infer type from usage β Add explicit type annotation
Extract to Function
typescriptconst total = price * (1 + taxRate); β Select expression Space + c + a β Extract to function β Extract to constant
Organize Imports
Space + c + o
What it does:
- Removes unused imports
- Sorts imports
- Groups imports by type
Format Document
Space + c + f
Uses configured formatter:
- Prettier for JS/TS
- Black for Python
- stylua for Lua
LSP Server Management
Check LSP Status
:LspInfo
Shows:
- Active LSP servers
- Server capabilities
- Configuration details
Install Language Server
:Mason
Interface:
i- Install serveru- Update serverX- Uninstall server
Recommended servers:
typescript-language-server (JS/TS)
pyright (Python)
lua-language-server (Lua)
rust-analyzer (Rust)
gopls (Go)
Restart LSP
:LspRestart
Use when:
- Changed configuration
- Server is behaving strangely
- After installing new dependencies
Snippets
Snippets are code templates that expand.
Trigger Snippet
# Type trigger word
# Press Tab to expand
Examples:
TypeScript:
fun<Tab>
β Expands to:
function name(params) {
}
React:
rfc<Tab>
β Expands to:
import React from 'react';
export const ComponentName = () => {
return <div></div>;
};
Navigate Snippet Placeholders
Tab # Next placeholder
Shift+Tab # Previous placeholder
Example:
typescriptfun<Tab> β function |name|(params) { } β cursor here Tab β function name(|params|) { } β cursor here
Advanced Features
Workspace Symbols
Space + s + S # Capital S
Search for symbols across entire project:
Type: "User"
β Shows:
interface User (types.ts)
class UserService (services.ts)
const userSchema (schemas.ts)
Peek Definition
gD # Capital D
Shows definition in popup without jumping:
typescriptconst result = calculateTotal(10, 20); β gD β Shows popup with function definition β Close with Esc, don't lose your place
Show Call Hierarchy
Space + c + h
Shows:
- Where function is called (incoming calls)
- What function calls (outgoing calls)
Code Lens
Some LSP servers show inline information:
typescriptfunction test() { // β 3 references // ... }
Click or Space + c + l to trigger code lens action.
Language-Specific Features
TypeScript
typescript// Organize imports Space + c + o // Auto-import on complete Ctrl+Space β Select β Auto-imports // Type checking :TSServer typeCoverage
Python
python# Auto-import Space + c + a β Import missing module # Rename Space + c + r β Renames across all files # Sort imports Space + c + o
Lua (Neovim config)
lua-- Hover for Neovim API docs K β Shows documentation for vim.opt, etc. -- Go to source gd β Jump to where function is defined
Common Workflows
Workflow 1: Explore Unfamiliar Code
1. Open file
2. Cursor on function name
3. K β Read documentation
4. gd β See implementation
5. gr β Find where it's used
6. Ctrl+o β Jump back
Workflow 2: Refactor Function Name
1. Cursor on function name
2. Space + c + r β Rename symbol
3. Type new name
4. Enter β Renames everywhere
Workflow 3: Fix Import Errors
1. See red underline
2. Space + c + a β Code actions
3. Select "Import from..."
4. Done
Workflow 4: Extract Repeated Code
1. Visual select code
2. Space + c + a
3. "Extract to function"
4. Name the function
5. LSP updates all call sites
Workflow 5: Add Types to Untyped Code
typescriptfunction greet(name) { return "Hello, " + name; } 1. Cursor on "name" 2. Space + c + a 3. "Add type annotation" 4. Select inferred type
Keybinding Reference
| Action | Keybinding | Description |
|---|---|---|
| Go to definition | gd | Jump to where symbol is defined |
| Go to type def | gy | Jump to type definition |
| Find references | gr | Show all uses of symbol |
| Hover docs | K | Show documentation |
| Code actions | Space c a | Show refactorings/fixes |
| Rename | Space c r | Rename symbol everywhere |
| Next diagnostic | ]d | Jump to next error/warning |
| Prev diagnostic | [d | Jump to previous error/warning |
| Signature help | Ctrl+k | Show function parameters |
| Format | Space c f | Format document |
| Organize imports | Space c o | Clean up imports |
Tips and Tricks
1. Learn gd and gr first
- These are the most-used LSP features
- Navigate code like a pro
2. Use K liberally
- Hover documentation saves trips to MDN/docs
- Learn APIs without leaving editor
3. Space c a fixes most issues
- Auto-import missing modules
- Convert to const/let
- Extract code
- Add types
4. Rename is safer than find-replace
Space c runderstands scope- Won't rename unrelated symbols
5. Organize imports frequently
Space c oafter adding imports- Keeps code clean
6. Use diagnostics to learn
- Red underlines teach best practices
- Read the full error message with
K
Common Mistakes
β Not installing language servers
β Run :Mason and install servers for your languages
β Ignoring code actions
β Space c a solves most issues automatically
β Using find-replace instead of rename
β Space c r is scope-aware and safer
β Not reading hover docs
β K shows types and documentation inline
β Manually fixing imports
β Space c o organizes imports automatically
Troubleshooting
LSP not working:
vim:LspInfo # Check server status :Mason # Install missing server :LspRestart # Restart server
Autocomplete not showing:
vim:checkhealth nvim-cmp # Check completion health Ctrl+Space # Manually trigger
Diagnostics not appearing:
vim:LspInfo # Verify server is attached :checkhealth lsp # Check LSP health
Wrong language server:
lua-- In ~/.config/nvim/lua/config/lsp.lua -- Configure which server for which filetype
Related:
- File Navigation in LazyVim - Finding code
- Code Editing Workflows - Making changes
- Git Integration in LazyVim - Committing changes
- LazyVim Setup - Installing language servers