|
| 1 | +# Configuration Management |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +## ConfigurationMap |
| 6 | + |
| 7 | +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. |
| 8 | + |
| 9 | +### Core Features |
| 10 | + |
| 11 | +- **Global Config**: Default settings applied to all files. |
| 12 | +- **Scoped Overrides**: High-priority settings applied to files matching specific Glob patterns (e.g., `**/tests/**`). |
| 13 | +- **Deep Merging**: Nested dictionaries are merged recursively, ensuring that partial updates don't wipe out unrelated settings. |
| 14 | +- **Auto-Sync**: Automatically notifies the server when configurations change. |
| 15 | + |
| 16 | +### Basic Usage |
| 17 | + |
| 18 | +```python |
| 19 | +from lsp_client.utils.config import ConfigurationMap |
| 20 | +from lsp_client.clients.pyright import PyrightClient |
| 21 | + |
| 22 | +# 1. Initialize the map |
| 23 | +config_map = ConfigurationMap() |
| 24 | + |
| 25 | +# 2. Set global configurations |
| 26 | +config_map.update_global({ |
| 27 | + "python": { |
| 28 | + "analysis": { |
| 29 | + "typeCheckingMode": "basic", |
| 30 | + "autoImportCompletions": True |
| 31 | + } |
| 32 | + } |
| 33 | +}) |
| 34 | + |
| 35 | +# 3. Add path-specific overrides |
| 36 | +# For example, disable type checking for the tests directory |
| 37 | +config_map.add_scope( |
| 38 | + pattern="**/tests/**", |
| 39 | + config={ |
| 40 | + "python": { |
| 41 | + "analysis": { |
| 42 | + "typeCheckingMode": "off" |
| 43 | + } |
| 44 | + } |
| 45 | + } |
| 46 | +) |
| 47 | +``` |
| 48 | + |
| 49 | +## Integrating with the Client |
| 50 | + |
| 51 | +To enable configuration support, assign your `config_map` to the client's `configuration_map` attribute. |
| 52 | + |
| 53 | +```python |
| 54 | +async with PyrightClient(workspace=Path.cwd()) as client: |
| 55 | + client.configuration_map = config_map |
| 56 | + # The SDK will now handle 'workspace/configuration' requests automatically |
| 57 | +``` |
| 58 | + |
| 59 | +## Automatic Synchronization |
| 60 | + |
| 61 | +One of the most powerful features is **Automatic Sync**. If your client supports the `workspace/didChangeConfiguration` capability (standard in most built-in clients like `PyrightClient`), the SDK will automatically notify the server whenever you update the `ConfigurationMap`. |
| 62 | + |
| 63 | +### How it Works |
| 64 | + |
| 65 | +1. You update the `config_map` using `update_global` or `add_scope`. |
| 66 | +2. The SDK detects the change and sends a `workspace/didChangeConfiguration` notification to the server. |
| 67 | +3. The server, upon receiving the notification, typically clears its cache and requests fresh configuration from the client. |
| 68 | + |
| 69 | +```python |
| 70 | +# Updating config at runtime |
| 71 | +config_map.update_global({"python.analysis.typeCheckingMode": "strict"}) |
| 72 | + |
| 73 | +# The server is automatically notified and will see the "strict" mode immediately. |
| 74 | +``` |
| 75 | + |
| 76 | +## Advanced: Change Listeners |
| 77 | + |
| 78 | +You can register custom listeners to react to configuration changes. Listeners must follow the `ConfigurationChangeListener` protocol. |
| 79 | + |
| 80 | +```python |
| 81 | +def my_listener(config_map, **kwargs): |
| 82 | + reason = kwargs.get("reason", "unknown") |
| 83 | + print(f"Config changed! Reason: {reason}") |
| 84 | + |
| 85 | +config_map.on_change(my_listener) |
| 86 | + |
| 87 | +# Pass context to your listeners |
| 88 | +config_map.update_global({"setting": True}, reason="User Preference Update") |
| 89 | +``` |
| 90 | + |
| 91 | +## Implementation Details |
| 92 | + |
| 93 | +### Merge Strategy |
| 94 | +When a file matches multiple scope patterns, configurations are merged in the order they were added. The merge is **deep**, meaning: |
| 95 | + |
| 96 | +```python |
| 97 | +# Base |
| 98 | +{"a": {"b": 1, "c": 2}} |
| 99 | +# Update |
| 100 | +{"a": {"b": 3}} |
| 101 | +# Result |
| 102 | +{"a": {"b": 3, "c": 2}} # "c" is preserved |
| 103 | +``` |
| 104 | + |
| 105 | +### Path Resolution |
| 106 | +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. |
0 commit comments