mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 15:31:27 +00:00
* fix(docs): correct outdated and inaccurate LSP documentation
- Remove reference to non-existent `packages/cli/LSP_DEBUGGING_GUIDE.md`
- Remove reference to unimplemented `/lsp status` slash command
- Replace incorrect `DEBUG=lsp*` env var with actual debug log location
(`~/.qwen/debug/` session files with `[LSP]` tag)
- Remove external Claude Code documentation links (`code.claude.com`)
- Document `isPathSafe` constraint: absolute paths outside workspace
are blocked, users must add server binary directory to PATH
- Add practical troubleshooting: `ps aux | grep <server>` to check
if the server process is actually running
- Add clangd-specific guidance: `--background-index`, `compile_commands.json`
location, and `--compile-commands-dir` usage
- Simplify trust documentation (remove vague "configure in settings")
* fix(lsp): allow absolute paths in LSP server command configuration
Previously, `isPathSafe` rejected any command containing a path
separator that resolved outside the workspace directory. This blocked
legitimate use cases where users specify absolute paths to language
server binaries (e.g. `/usr/bin/clangd`, `/opt/tools/jdtls/bin/jdtls`).
The fix allows:
- Bare command names resolved via PATH (unchanged)
- Absolute paths (explicit user intent, already gated by trust checks)
- Relative paths within the workspace (unchanged)
Only relative paths that traverse outside the workspace (e.g.
`../../malicious-binary`) are still blocked.
Closes: server silently fails to start when users configure absolute
paths in `.lsp.json`, with only a debug log warning visible.
* feat(lsp): inject LSP priority instruction into system prompt when enabled
The model was not using the LSP tool because the system prompt's
"Tool Usage" section never mentioned it. The tool description alone
("ALWAYS use LSP as the PRIMARY tool") was insufficient — models
follow system prompt instructions more reliably than tool descriptions.
Changes:
- getCoreSystemPrompt() accepts `options.lspEnabled` parameter
- When LSP is enabled, injects an instruction in the Tool Usage section
telling the model to ALWAYS use the LSP tool FIRST for code
intelligence queries (definitions, references, hover, symbols, etc.)
instead of falling back to grep/readfile
- Updated client.ts to pass config.isLspEnabled() to the prompt builder
- Updated test mocks and snapshots
* feat(lsp): add symbolName parameter for position-free LSP queries
The model avoided calling LSP for findReferences, hover, etc. because
these operations required filePath + line + character which the user
rarely provides. The model would read files directly instead.
Changes:
- Add `symbolName` optional parameter to LspTool
- When symbolName is provided without line/character, auto-resolve
the symbol's position via workspaceSymbol before executing the
actual operation (findReferences, hover, goToImplementation, etc.)
- Update tool description with examples showing symbolName usage
- Move LSP priority instruction to top of system prompt for visibility
- Add debug logging for LSP prompt injection
This enables natural queries like:
{operation: "findReferences", symbolName: "Calculator"}
{operation: "hover", symbolName: "addShape"}
without requiring the user to know exact file positions.
* feat(lsp): add LSP reminder to grep/readfile tool descriptions
When LSP is enabled, the model often chose grep or readfile instead
of LSP for code intelligence queries. Now the competing tools'
descriptions include a note reminding the model to use the LSP tool
for definitions, references, symbols, hover, diagnostics, etc.
This "push-pull" approach:
- System prompt pushes toward LSP (top-level priority instruction)
- Grep/ReadFile descriptions pull away from code intelligence usage
* fix(docs): align LSP doc with isPathSafe change — absolute paths now supported
The doc still said "absolute paths outside the workspace are not
supported" but the code was changed to allow them. Updated all
three places (Required Fields table, Troubleshooting, Debugging)
to reflect that absolute paths are now accepted.
* fix(lsp): improve symbol-based tool resolution
* fix(lsp): normalize display paths across platforms
* fix(lsp): narrow docs and path safety changes
* fix(lsp): add edge-case tests for isPathSafe and fix Chinese comment
- Add test for intermediate path traversal (./a/../../../etc/passwd)
- Add test for forward-slash relative paths (tools/clangd)
- Replace Chinese JSDoc with English on requestUserConsent
* fix(lsp): rename requestUserConsent to checkWorkspaceTrust
The method only checks workspace trust level and does not actually
prompt the user for consent. Rename the method and update the JSDoc
and call-site log message to accurately reflect the behavior.
413 lines
13 KiB
Markdown
413 lines
13 KiB
Markdown
# Language Server Protocol (LSP) Support
|
|
|
|
Qwen Code provides native Language Server Protocol (LSP) support, enabling advanced code intelligence features like go-to-definition, find references, diagnostics, and code actions. This integration allows the AI agent to understand your code more deeply and provide more accurate assistance.
|
|
|
|
## Overview
|
|
|
|
LSP support in Qwen Code works by connecting to language servers that understand your code. Once you configure servers via `.lsp.json` (or extensions), Qwen Code can start them and use them to:
|
|
|
|
- Navigate to symbol definitions
|
|
- Find all references to a symbol
|
|
- Get hover information (documentation, type info)
|
|
- View diagnostic messages (errors, warnings)
|
|
- Access code actions (quick fixes, refactorings)
|
|
- Analyze call hierarchies
|
|
|
|
## Quick Start
|
|
|
|
LSP is an experimental feature in Qwen Code. To enable it, use the `--experimental-lsp` command line flag:
|
|
|
|
```bash
|
|
qwen --experimental-lsp
|
|
```
|
|
|
|
LSP servers are configuration-driven. You must define them in `.lsp.json` (or via extensions) for Qwen Code to start them.
|
|
|
|
### Prerequisites
|
|
|
|
You need to have the language server for your programming language installed:
|
|
|
|
| Language | Language Server | Install Command |
|
|
| --------------------- | -------------------------- | ------------------------------------------------------------------------------ |
|
|
| TypeScript/JavaScript | typescript-language-server | `npm install -g typescript-language-server typescript` |
|
|
| Python | pylsp | `pip install python-lsp-server` |
|
|
| Go | gopls | `go install golang.org/x/tools/gopls@latest` |
|
|
| Rust | rust-analyzer | [Installation guide](https://rust-analyzer.github.io/manual.html#installation) |
|
|
| C/C++ | clangd | Install LLVM/clangd via your package manager |
|
|
| Java | jdtls | Install JDTLS and a JDK |
|
|
|
|
## Configuration
|
|
|
|
### .lsp.json File
|
|
|
|
You can configure language servers using a `.lsp.json` file in your project root. Each top-level key is a language identifier, and its value is the server configuration object.
|
|
|
|
**Basic format:**
|
|
|
|
```json
|
|
{
|
|
"typescript": {
|
|
"command": "typescript-language-server",
|
|
"args": ["--stdio"],
|
|
"extensionToLanguage": {
|
|
".ts": "typescript",
|
|
".tsx": "typescriptreact",
|
|
".js": "javascript",
|
|
".jsx": "javascriptreact"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### C/C++ (clangd) configuration
|
|
|
|
Dependencies:
|
|
|
|
- clangd (LLVM) must be installed and available in PATH.
|
|
- A compile database (`compile_commands.json`) or `compile_flags.txt` is required for accurate results.
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"cpp": {
|
|
"command": "clangd",
|
|
"args": [
|
|
"--background-index",
|
|
"--clang-tidy",
|
|
"--header-insertion=iwyu",
|
|
"--completion-style=detailed"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Java (jdtls) configuration
|
|
|
|
Dependencies:
|
|
|
|
- JDK installed and available in PATH (`java`).
|
|
- JDTLS installed and available in PATH (`jdtls`).
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"java": {
|
|
"command": "jdtls",
|
|
"args": ["-configuration", ".jdtls-config", "-data", ".jdtls-workspace"]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Configuration Options
|
|
|
|
#### Required Fields
|
|
|
|
| Option | Type | Description |
|
|
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `command` | string | Command to start the LSP server. Supports bare command names resolved via `PATH` (e.g. `clangd`) and absolute paths (e.g. `/opt/llvm/bin/clangd`) |
|
|
|
|
#### Optional Fields
|
|
|
|
| Option | Type | Default | Description |
|
|
| ----------------------- | -------- | --------- | ------------------------------------------------------- |
|
|
| `args` | string[] | `[]` | Command line arguments |
|
|
| `transport` | string | `"stdio"` | Transport type: `stdio`, `tcp`, or `socket` |
|
|
| `env` | object | - | Environment variables |
|
|
| `initializationOptions` | object | - | LSP initialization options |
|
|
| `settings` | object | - | Server settings via `workspace/didChangeConfiguration` |
|
|
| `extensionToLanguage` | object | - | Maps file extensions to language identifiers |
|
|
| `workspaceFolder` | string | - | Override workspace folder (must be within project root) |
|
|
| `startupTimeout` | number | `10000` | Startup timeout in milliseconds |
|
|
| `shutdownTimeout` | number | `5000` | Shutdown timeout in milliseconds |
|
|
| `restartOnCrash` | boolean | `false` | Auto-restart on crash |
|
|
| `maxRestarts` | number | `3` | Maximum restart attempts |
|
|
| `trustRequired` | boolean | `true` | Require trusted workspace |
|
|
|
|
### TCP/Socket Transport
|
|
|
|
For servers that use TCP or Unix socket transport:
|
|
|
|
```json
|
|
{
|
|
"remote-lsp": {
|
|
"transport": "tcp",
|
|
"socket": {
|
|
"host": "127.0.0.1",
|
|
"port": 9999
|
|
},
|
|
"extensionToLanguage": {
|
|
".custom": "custom"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Available LSP Operations
|
|
|
|
Qwen Code exposes LSP functionality through the unified `lsp` tool. Here are the available operations:
|
|
|
|
Location-based operations (`goToDefinition`, `findReferences`, `hover`, `goToImplementation`, and `prepareCallHierarchy`) require an exact `filePath` + `line` + `character` position. If you do not know the exact position, use `workspaceSymbol` or `documentSymbol` first to locate the symbol.
|
|
|
|
### Code Navigation
|
|
|
|
#### Go to Definition
|
|
|
|
Find where a symbol is defined.
|
|
|
|
```
|
|
Operation: goToDefinition
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Line number (1-based)
|
|
- character: Column number (1-based)
|
|
```
|
|
|
|
#### Find References
|
|
|
|
Find all references to a symbol.
|
|
|
|
```
|
|
Operation: findReferences
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Line number (1-based)
|
|
- character: Column number (1-based)
|
|
- includeDeclaration: Include the declaration itself (optional)
|
|
```
|
|
|
|
#### Go to Implementation
|
|
|
|
Find implementations of an interface or abstract method.
|
|
|
|
```
|
|
Operation: goToImplementation
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Line number (1-based)
|
|
- character: Column number (1-based)
|
|
```
|
|
|
|
### Symbol Information
|
|
|
|
#### Hover
|
|
|
|
Get documentation and type information for a symbol.
|
|
|
|
```
|
|
Operation: hover
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Line number (1-based)
|
|
- character: Column number (1-based)
|
|
```
|
|
|
|
#### Document Symbols
|
|
|
|
Get all symbols in a document.
|
|
|
|
```
|
|
Operation: documentSymbol
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
```
|
|
|
|
#### Workspace Symbol Search
|
|
|
|
Search for symbols across the workspace.
|
|
|
|
```
|
|
Operation: workspaceSymbol
|
|
Parameters:
|
|
- query: Search query string
|
|
- limit: Maximum results (optional)
|
|
```
|
|
|
|
### Call Hierarchy
|
|
|
|
#### Prepare Call Hierarchy
|
|
|
|
Get the call hierarchy item at a position.
|
|
|
|
```
|
|
Operation: prepareCallHierarchy
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Line number (1-based)
|
|
- character: Column number (1-based)
|
|
```
|
|
|
|
#### Incoming Calls
|
|
|
|
Find all functions that call the given function.
|
|
|
|
```
|
|
Operation: incomingCalls
|
|
Parameters:
|
|
- callHierarchyItem: Item from prepareCallHierarchy
|
|
```
|
|
|
|
#### Outgoing Calls
|
|
|
|
Find all functions called by the given function.
|
|
|
|
```
|
|
Operation: outgoingCalls
|
|
Parameters:
|
|
- callHierarchyItem: Item from prepareCallHierarchy
|
|
```
|
|
|
|
### Diagnostics
|
|
|
|
#### File Diagnostics
|
|
|
|
Get diagnostic messages (errors, warnings) for a file.
|
|
|
|
```
|
|
Operation: diagnostics
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
```
|
|
|
|
#### Workspace Diagnostics
|
|
|
|
Get all diagnostic messages across the workspace.
|
|
|
|
```
|
|
Operation: workspaceDiagnostics
|
|
Parameters:
|
|
- limit: Maximum results (optional)
|
|
```
|
|
|
|
### Code Actions
|
|
|
|
#### Get Code Actions
|
|
|
|
Get available code actions (quick fixes, refactorings) at a location.
|
|
|
|
```
|
|
Operation: codeActions
|
|
Parameters:
|
|
- filePath: Path to the file
|
|
- line: Start line number (1-based)
|
|
- character: Start column number (1-based)
|
|
- endLine: End line number (optional, defaults to line)
|
|
- endCharacter: End column (optional, defaults to character)
|
|
- diagnostics: Diagnostics to get actions for (optional)
|
|
- codeActionKinds: Filter by action kind (optional)
|
|
```
|
|
|
|
Code action kinds:
|
|
|
|
- `quickfix` - Quick fixes for errors/warnings
|
|
- `refactor` - Refactoring operations
|
|
- `refactor.extract` - Extract to function/variable
|
|
- `refactor.inline` - Inline function/variable
|
|
- `source` - Source code actions
|
|
- `source.organizeImports` - Organize imports
|
|
- `source.fixAll` - Fix all auto-fixable issues
|
|
|
|
## Security
|
|
|
|
LSP servers are only started in trusted workspaces by default. This is because language servers run with your user permissions and can execute code.
|
|
|
|
### Trust Controls
|
|
|
|
- **Trusted Workspace**: LSP servers start if configured
|
|
- **Untrusted Workspace**: LSP servers won't start unless `trustRequired: false` is set in the server configuration
|
|
|
|
To mark a workspace as trusted, use the `/trust` command.
|
|
|
|
### Per-Server Trust Override
|
|
|
|
You can override trust requirements for specific servers in their configuration:
|
|
|
|
```json
|
|
{
|
|
"safe-server": {
|
|
"command": "safe-language-server",
|
|
"args": ["--stdio"],
|
|
"trustRequired": false,
|
|
"extensionToLanguage": {
|
|
".safe": "safe"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Server Not Starting
|
|
|
|
1. **Verify `--experimental-lsp` flag**: Make sure you're using the flag when starting Qwen Code
|
|
2. **Check if the server is installed**: Run the command manually (e.g. `clangd --version`) to verify
|
|
3. **Check the command**: The server binary must be in your system `PATH`, or specified as an absolute path (e.g. `/opt/llvm/bin/clangd`). Relative paths that escape the workspace are blocked
|
|
4. **Check workspace trust**: The workspace must be trusted for LSP (use `/trust`)
|
|
5. **Check logs**: Look for `[LSP]` entries in the debug log (see Debugging section below)
|
|
6. **Check the process**: Run `ps aux | grep <server-name>` to verify the server process is running
|
|
|
|
### Slow Performance
|
|
|
|
1. **Large projects**: Consider excluding `node_modules` and other large directories
|
|
2. **Server timeout**: Increase `startupTimeout` in server configuration for slow servers
|
|
|
|
### No Results
|
|
|
|
1. **Server not ready**: The server may still be indexing. For C/C++ projects with clangd, ensure `--background-index` is in the args and a `compile_commands.json` (or `compile_flags.txt`) exists in the project root or a parent directory. Use `--compile-commands-dir=<path>` if it is in a build subdirectory
|
|
2. **File not saved**: Save your file for the server to pick up changes
|
|
3. **Wrong language**: Check if the correct server is running for your language
|
|
4. **Check the process**: Run `ps aux | grep <server-name>` to verify the server is actually running
|
|
|
|
### Debugging
|
|
|
|
LSP debug logs are automatically written to session log files in `~/.qwen/debug/`. To check LSP-related entries:
|
|
|
|
```bash
|
|
# View the latest session log
|
|
grep '\[LSP\]' ~/.qwen/debug/latest
|
|
|
|
# Common error messages to look for:
|
|
# "command path is unsafe" → relative path escapes workspace, use absolute path or add to PATH
|
|
# "command not found" → server binary not installed or not in PATH
|
|
# "requires trusted workspace" → run /trust first
|
|
```
|
|
|
|
You can also verify the server process is running:
|
|
|
|
```bash
|
|
ps aux | grep clangd # or typescript-language-server, jdtls, etc.
|
|
```
|
|
|
|
## Extension LSP Configuration
|
|
|
|
Extensions can provide LSP server configurations through the `lspServers` field in their `plugin.json`. This can be either an inline object or a path to a `.lsp.json` file. Qwen Code loads these configs when the extension is enabled. The format is the same language-keyed layout used in project `.lsp.json` files.
|
|
|
|
## Best Practices
|
|
|
|
1. **Install language servers globally**: This ensures they're available in all projects
|
|
2. **Use project-specific settings**: Configure server options per project when needed via `.lsp.json`
|
|
3. **Keep servers updated**: Update your language servers regularly for best results
|
|
4. **Trust wisely**: Only trust workspaces from trusted sources
|
|
|
|
## FAQ
|
|
|
|
### Q: How do I enable LSP?
|
|
|
|
Use the `--experimental-lsp` flag when starting Qwen Code:
|
|
|
|
```bash
|
|
qwen --experimental-lsp
|
|
```
|
|
|
|
### Q: How do I know which language servers are running?
|
|
|
|
Check the debug log for `[LSP]` entries (`grep '\[LSP\]' ~/.qwen/debug/latest`), or verify the process directly with `ps aux | grep <server-name>`.
|
|
|
|
### Q: Can I use multiple language servers for the same file type?
|
|
|
|
Yes, but only one will be used for each operation. The first server that returns results wins.
|
|
|
|
### Q: Does LSP work in sandbox mode?
|
|
|
|
LSP servers run outside the sandbox to access your code. They're subject to workspace trust controls.
|