Skip to content

Commit 9afd8aa

Browse files
Copilotobserverw
andcommitted
Add comprehensive tests and documentation for default configurations
Co-authored-by: observerw <[email protected]>
1 parent 0308624 commit 9afd8aa

File tree

2 files changed

+248
-0
lines changed

2 files changed

+248
-0
lines changed

docs/configuration.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,52 @@
22

33
The `lsp-client` SDK provides a robust and flexible way to manage Language Server Protocol (LSP) configurations. It supports global settings, path-based overrides, and automatic synchronization with the server.
44

5+
## Default Configurations
6+
7+
**All built-in clients now come with sensible default configurations that enable extra features out of the box**, including:
8+
- **Inlay hints** for types, parameters, return values, etc.
9+
- **Enhanced diagnostics** and linting
10+
- **Auto-import completions**
11+
- **Code lenses** and other IDE features
12+
13+
This means you can start using clients immediately without needing to manually configure these features. The defaults are automatically applied when the client starts, unless you provide your own `configuration_map`.
14+
15+
### Example: Using Default Configuration
16+
17+
```python
18+
from lsp_client.clients.rust_analyzer import RustAnalyzerClient
19+
20+
# Simply create and use the client - inlay hints and other features are enabled by default
21+
async with RustAnalyzerClient() as client:
22+
hints = await client.request_inlay_hint(file_path="main.rs", range=...)
23+
# Inlay hints are automatically enabled without any configuration!
24+
```
25+
26+
### Customizing Default Configuration
27+
28+
You can still provide your own configuration to override or extend the defaults:
29+
30+
```python
31+
from lsp_client.utils.config import ConfigurationMap
32+
from lsp_client.clients.pyright import PyrightClient
33+
34+
# Create custom configuration
35+
config_map = ConfigurationMap()
36+
config_map.update_global({
37+
"python": {
38+
"analysis": {
39+
"typeCheckingMode": "strict", # Override default
40+
"autoImportCompletions": False, # Disable a feature
41+
}
42+
}
43+
})
44+
45+
# Apply custom configuration
46+
async with PyrightClient() as client:
47+
client.configuration_map = config_map
48+
# Now uses your custom settings instead of defaults
49+
```
50+
551
## ConfigurationMap
652

753
The `ConfigurationMap` is the central utility for managing settings. It implements a tiered configuration logic similar to "User Settings" vs. "Workspace Settings" in popular IDEs.
@@ -104,3 +150,57 @@ When a file matches multiple scope patterns, configurations are merged in the or
104150

105151
### Path Resolution
106152
The `scope_uri` provided by the server is automatically converted to a local filesystem path before pattern matching, allowing you to use standard Glob patterns.
153+
154+
## Default Configurations by Client
155+
156+
Each built-in client provides default configurations tailored to the language server's capabilities:
157+
158+
### Rust Analyzer
159+
- Inlay hints: Types, parameters, lifetimes, closures, reborrow hints
160+
- Diagnostics: Enabled with experimental features
161+
- Completion: Auto-import, auto-self, callable snippets
162+
- Check on save: Enabled
163+
- Code lenses: Run, debug, implementations, references
164+
165+
### Gopls (Go)
166+
- Inlay hints: All types (variables, parameters, function types, etc.)
167+
- Code lenses: Generate, test, tidy, upgrade dependencies, vulnerability checks
168+
- Analyses: Field alignment, nilness, unused params/writes
169+
- Completion: Documentation, deep completion, fuzzy matching, placeholders
170+
- Semantic tokens: Enabled
171+
172+
### Pyright (Python)
173+
- Inlay hints: Variable types, function return types, call arguments, pytest parameters
174+
- Auto-import completions: Enabled
175+
- Type checking mode: Basic (can be overridden)
176+
- Diagnostics: Open files only
177+
- Auto-search paths and indexing: Enabled
178+
179+
### TypeScript Language Server
180+
- Inlay hints: All types for both TypeScript and JavaScript
181+
- Suggestions: Auto-imports, complete function calls, module exports
182+
- Preferences: Package.json auto-imports, shortest import specifier
183+
184+
### Deno
185+
- Inlay hints: All parameter and type hints
186+
- Linting: Enabled
187+
- Unstable features: Enabled
188+
- Code lenses: Implementations, references, tests
189+
- Import suggestions: Auto-discover from deno.land and esm.sh
190+
191+
### Pyrefly (Python)
192+
- Inlay hints: Variable types, function return types, parameter types
193+
- Diagnostics and auto-imports: Enabled
194+
195+
### Ty (Python)
196+
- Diagnostics and auto-imports: Enabled
197+
198+
You can always inspect the default configuration for any client:
199+
200+
```python
201+
from lsp_client.clients.rust_analyzer import RustAnalyzerClient
202+
203+
client = RustAnalyzerClient()
204+
config_map = client.create_default_configuration_map()
205+
print(config_map._global_config) # View the default settings
206+
```
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from lsp_client.capability.server_request import WithRespondConfigurationRequest
6+
from lsp_client.clients import clients
7+
from lsp_client.utils.config import ConfigurationMap
8+
9+
10+
@pytest.mark.parametrize("client_cls", clients)
11+
def test_clients_have_default_configuration_method(client_cls):
12+
"""Test that all clients have a create_default_configuration_map method."""
13+
assert hasattr(
14+
client_cls, "create_default_configuration_map"
15+
), f"{client_cls.__name__} should have create_default_configuration_map method"
16+
17+
18+
@pytest.mark.parametrize("client_cls", clients)
19+
def test_default_configuration_returns_valid_type(client_cls):
20+
"""Test that create_default_configuration_map returns None or ConfigurationMap."""
21+
client = client_cls()
22+
result = client.create_default_configuration_map()
23+
assert result is None or isinstance(
24+
result, ConfigurationMap
25+
), f"{client_cls.__name__}.create_default_configuration_map() should return None or ConfigurationMap"
26+
27+
28+
@pytest.mark.parametrize("client_cls", clients)
29+
def test_clients_with_configuration_support_have_defaults(client_cls):
30+
"""Test that clients supporting configuration have default configuration maps."""
31+
client = client_cls()
32+
33+
# Check if client supports configuration request
34+
if not isinstance(client, WithRespondConfigurationRequest):
35+
pytest.skip(
36+
f"{client_cls.__name__} does not support WithRespondConfigurationRequest"
37+
)
38+
39+
# Get default configuration
40+
config_map = client.create_default_configuration_map()
41+
42+
# Clients with configuration support should have defaults
43+
# (especially those with inlay hints, diagnostics, etc.)
44+
assert config_map is not None, (
45+
f"{client_cls.__name__} supports configuration requests "
46+
f"and should provide default configuration"
47+
)
48+
49+
# Verify it's a proper ConfigurationMap instance
50+
assert isinstance(config_map, ConfigurationMap)
51+
52+
53+
@pytest.mark.parametrize("client_cls", clients)
54+
def test_default_configuration_has_content(client_cls):
55+
"""Test that default configurations contain actual settings."""
56+
client = client_cls()
57+
config_map = client.create_default_configuration_map()
58+
59+
if config_map is None:
60+
pytest.skip(f"{client_cls.__name__} has no default configuration")
61+
62+
# Check that the configuration map has some content
63+
# Access the private attribute to check if global config has content
64+
assert (
65+
config_map._global_config
66+
), f"{client_cls.__name__} default configuration should not be empty"
67+
68+
69+
@pytest.mark.asyncio
70+
@pytest.mark.parametrize("client_cls", clients)
71+
async def test_configuration_initialized_on_client_startup(client_cls):
72+
"""Test that configuration is automatically initialized when client starts."""
73+
# This test would require actually starting the language server
74+
# For now, we just verify the client can be instantiated
75+
client = client_cls()
76+
77+
# Check if client supports configuration
78+
if isinstance(client, WithRespondConfigurationRequest):
79+
# Before async context, configuration_map should be None
80+
assert client.configuration_map is None
81+
82+
# Note: Full integration test would require:
83+
# async with client as c:
84+
# if isinstance(c, WithRespondConfigurationRequest):
85+
# assert c.configuration_map is not None
86+
# But this requires language servers to be installed
87+
88+
89+
def test_rust_analyzer_default_config_has_inlay_hints():
90+
"""Test that rust-analyzer default config enables inlay hints."""
91+
from lsp_client.clients.rust_analyzer import RustAnalyzerClient
92+
93+
client = RustAnalyzerClient()
94+
config_map = client.create_default_configuration_map()
95+
96+
assert config_map is not None
97+
config = config_map.get(None, "rust-analyzer.inlayHints.enable")
98+
assert config is True, "rust-analyzer should enable inlay hints by default"
99+
100+
101+
def test_gopls_default_config_has_hints():
102+
"""Test that gopls default config enables hints."""
103+
from lsp_client.clients.gopls import GoplsClient
104+
105+
client = GoplsClient()
106+
config_map = client.create_default_configuration_map()
107+
108+
assert config_map is not None
109+
config = config_map.get(None, "gopls.hints")
110+
assert config is not None, "gopls should have hints configuration"
111+
assert isinstance(config, dict), "gopls hints should be a dict"
112+
113+
114+
def test_pyright_default_config_has_inlay_hints():
115+
"""Test that pyright default config enables inlay hints."""
116+
from lsp_client.clients.pyright import PyrightClient
117+
118+
client = PyrightClient()
119+
config_map = client.create_default_configuration_map()
120+
121+
assert config_map is not None
122+
config = config_map.get(None, "python.analysis.inlayHints")
123+
assert config is not None, "pyright should have inlay hints configuration"
124+
assert isinstance(config, dict), "pyright inlay hints should be a dict"
125+
126+
127+
def test_typescript_default_config_has_inlay_hints():
128+
"""Test that typescript-language-server default config enables inlay hints."""
129+
from lsp_client.clients.typescript import TypescriptClient
130+
131+
client = TypescriptClient()
132+
config_map = client.create_default_configuration_map()
133+
134+
assert config_map is not None
135+
config = config_map.get(None, "typescript.inlayHints")
136+
assert config is not None, "typescript should have inlay hints configuration"
137+
138+
139+
def test_deno_default_config_has_inlay_hints():
140+
"""Test that deno default config enables inlay hints."""
141+
from lsp_client.clients.deno import DenoClient
142+
143+
client = DenoClient()
144+
config_map = client.create_default_configuration_map()
145+
146+
assert config_map is not None
147+
config = config_map.get(None, "deno.inlayHints")
148+
assert config is not None, "deno should have inlay hints configuration"

0 commit comments

Comments
 (0)