0
# Feature System
1
2
Base interfaces and classes for implementing static and dynamic language server features.
3
4
## Capabilities
5
6
### Core Feature Interfaces
7
8
Base interfaces defining the feature system architecture.
9
10
```typescript { .api }
11
/**
12
* Base interface for all language client features
13
*/
14
interface Feature {
15
/** Get the current state of the feature */
16
getState(): FeatureState;
17
18
/** Clear the feature state and cleanup resources */
19
clear(): void;
20
}
21
22
/**
23
* Feature state enumeration
24
*/
25
enum FeatureState {
26
/** Feature is not initialized */
27
Initial,
28
/** Feature is starting */
29
Starting,
30
/** Feature is active and running */
31
Started,
32
/** Feature has been stopped */
33
Stopped,
34
/** Feature is disposing */
35
Disposing,
36
/** Feature has been disposed */
37
Disposed
38
}
39
```
40
41
### Static Features
42
43
Features that are registered once during client initialization.
44
45
```typescript { .api }
46
/**
47
* Interface for static language server features
48
* Static features are registered once during initialization and don't support dynamic registration
49
*/
50
interface StaticFeature extends Feature {
51
/**
52
* Fill initialization parameters sent to the server
53
* Called before client initialization
54
*/
55
fillInitializeParams?(params: InitializeParams): void;
56
57
/**
58
* Fill client capabilities advertised to the server
59
* Called during client initialization
60
*/
61
fillClientCapabilities(capabilities: ClientCapabilities): void;
62
63
/**
64
* Pre-initialization hook called before the feature is initialized
65
* Used for setup that requires server capabilities
66
*/
67
preInitialize?(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void;
68
69
/**
70
* Initialize the feature with server capabilities
71
* Called after successful server initialization
72
*/
73
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void;
74
}
75
```
76
77
**Usage Examples:**
78
79
Implementing a static feature:
80
81
```typescript
82
class CustomStaticFeature implements StaticFeature {
83
private _state: FeatureState = FeatureState.Initial;
84
85
fillClientCapabilities(capabilities: ClientCapabilities): void {
86
// Add custom capabilities
87
capabilities.experimental = {
88
...capabilities.experimental,
89
customFeature: true
90
};
91
}
92
93
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void {
94
if (capabilities.experimental?.customFeature) {
95
this._state = FeatureState.Started;
96
// Initialize feature logic
97
}
98
}
99
100
getState(): FeatureState {
101
return this._state;
102
}
103
104
clear(): void {
105
this._state = FeatureState.Disposed;
106
// Cleanup resources
107
}
108
}
109
```
110
111
### Dynamic Features
112
113
Features that support dynamic registration and unregistration.
114
115
```typescript { .api }
116
/**
117
* Interface for dynamic language server features
118
* Dynamic features can be registered and unregistered at runtime
119
*/
120
interface DynamicFeature<RO> extends StaticFeature {
121
/** Registration type that identifies this feature */
122
readonly registrationType: RegistrationType<RO>;
123
124
/**
125
* Register the feature with specific options
126
* Called when server requests feature registration
127
*/
128
register(data: RegistrationData<RO>): void;
129
130
/**
131
* Unregister the feature by ID
132
* Called when server requests feature unregistration
133
*/
134
unregister(id: string): void;
135
}
136
137
/**
138
* Registration data for dynamic features
139
*/
140
interface RegistrationData<T> {
141
/** Unique registration identifier */
142
id: string;
143
/** Registration method name */
144
method: string;
145
/** Registration options specific to the feature */
146
registerOptions?: T;
147
}
148
149
/**
150
* Registration type interface
151
*/
152
interface RegistrationType<RO> {
153
/** LSP method name for this registration type */
154
readonly method: string;
155
}
156
```
157
158
**Usage Examples:**
159
160
Implementing a dynamic feature:
161
162
```typescript
163
class CustomDynamicFeature implements DynamicFeature<CustomRegistrationOptions> {
164
private _state: FeatureState = FeatureState.Initial;
165
private _registrations = new Map<string, CustomRegistration>();
166
167
readonly registrationType: RegistrationType<CustomRegistrationOptions> = {
168
method: 'textDocument/customFeature'
169
};
170
171
fillClientCapabilities(capabilities: ClientCapabilities): void {
172
capabilities.textDocument = capabilities.textDocument || {};
173
capabilities.textDocument.customFeature = {
174
dynamicRegistration: true
175
};
176
}
177
178
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void {
179
this._state = FeatureState.Started;
180
}
181
182
register(data: RegistrationData<CustomRegistrationOptions>): void {
183
const registration = new CustomRegistration(data.id, data.registerOptions);
184
this._registrations.set(data.id, registration);
185
}
186
187
unregister(id: string): void {
188
const registration = this._registrations.get(id);
189
if (registration) {
190
registration.dispose();
191
this._registrations.delete(id);
192
}
193
}
194
195
getState(): FeatureState {
196
return this._state;
197
}
198
199
clear(): void {
200
for (const registration of this._registrations.values()) {
201
registration.dispose();
202
}
203
this._registrations.clear();
204
this._state = FeatureState.Disposed;
205
}
206
}
207
```
208
209
### Provider Features
210
211
Specialized interfaces for features that provide VS Code providers.
212
213
```typescript { .api }
214
/**
215
* Mixin interface for text document provider features
216
* Features implementing this can provide providers per text document
217
*/
218
interface TextDocumentProviderFeature<T> {
219
/**
220
* Get the provider for a specific text document
221
* @param textDocument - The text document to get provider for
222
* @returns Provider instance or undefined if not available
223
*/
224
getProvider(textDocument: TextDocument): T | undefined;
225
}
226
227
/**
228
* Interface for workspace provider features
229
* Features implementing this provide workspace-wide functionality
230
*/
231
interface WorkspaceProviderFeature<PR> {
232
/**
233
* Get all providers registered for workspace operations
234
* @returns Array of provider instances or undefined
235
*/
236
getProviders(): PR[] | undefined;
237
}
238
239
/**
240
* Interface for features that can be client-specific
241
*/
242
interface FeatureClient<M, PO> {
243
/** Get the method name for this feature */
244
getRegistrationType(): RegistrationType<PO>;
245
246
/** Fill client capabilities for this feature */
247
fillClientCapabilities(capabilities: ClientCapabilities): void;
248
249
/** Initialize the feature */
250
initialize(capabilities: M, documentSelector: DocumentSelector | undefined): void;
251
252
/** Register options for dynamic registration */
253
register(data: RegistrationData<PO>): void;
254
255
/** Unregister by ID */
256
unregister(id: string): void;
257
258
/** Dispose the feature */
259
dispose(): void;
260
}
261
```
262
263
### Text Document Features
264
265
Base classes for text document-based features.
266
267
```typescript { .api }
268
/**
269
* Base class for text document synchronization features
270
*/
271
abstract class TextDocumentSendFeature<T> implements DynamicFeature<T> {
272
protected _client: BaseLanguageClient;
273
protected _registrationType: RegistrationType<T>;
274
275
constructor(client: BaseLanguageClient, registrationType: RegistrationType<T>);
276
277
abstract fillClientCapabilities(capabilities: ClientCapabilities): void;
278
abstract initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void;
279
280
register(data: RegistrationData<T>): void;
281
unregister(id: string): void;
282
getState(): FeatureState;
283
clear(): void;
284
285
get registrationType(): RegistrationType<T>;
286
}
287
288
/**
289
* Interface for features that send text document notifications
290
*/
291
interface DidOpenTextDocumentFeatureShape {
292
/** Handle document open event */
293
didOpen(textDocument: TextDocument): void;
294
}
295
296
/**
297
* Interface for features that send text document close notifications
298
*/
299
interface DidCloseTextDocumentFeatureShape {
300
/** Handle document close event */
301
didClose(textDocument: TextDocument): void;
302
}
303
304
/**
305
* Interface for features that send text document change notifications
306
*/
307
interface DidChangeTextDocumentFeatureShape {
308
/** Handle document change event */
309
didChange(event: TextDocumentChangeEvent): void;
310
}
311
312
/**
313
* Interface for features that send text document save notifications
314
*/
315
interface DidSaveTextDocumentFeatureShape {
316
/** Handle document save event */
317
didSave(textDocument: TextDocument): void;
318
}
319
```
320
321
### Provider Shape Interfaces
322
323
Standard shapes for VS Code language providers.
324
325
```typescript { .api }
326
/**
327
* Shape interface for code lens providers
328
*/
329
interface CodeLensProviderShape {
330
/** Provide code lenses for a document */
331
provideCodeLenses(document: TextDocument, token: CancellationToken): ProviderResult<CodeLens[]>;
332
333
/** Resolve a code lens */
334
resolveCodeLens?(codeLens: CodeLens, token: CancellationToken): ProviderResult<CodeLens>;
335
336
/** Event fired when code lenses should be refreshed */
337
onDidChangeCodeLenses?: Event<void>;
338
}
339
340
/**
341
* Shape interface for diagnostic providers
342
*/
343
interface DiagnosticProviderShape {
344
/** Event fired when diagnostics change */
345
onDidChangeDiagnostics: Event<void>;
346
347
/** Provide diagnostics for a document */
348
provideDiagnostics(
349
document: TextDocument | Uri,
350
previousResultId: string | undefined,
351
token: CancellationToken
352
): ProviderResult<DocumentDiagnosticReport>;
353
354
/** Provide workspace diagnostics */
355
provideWorkspaceDiagnostics?(
356
resultIds: PreviousResultId[],
357
token: CancellationToken,
358
resultReporter: ResultReporter
359
): ProviderResult<WorkspaceDiagnosticReport>;
360
}
361
362
/**
363
* Shape interface for semantic tokens providers
364
*/
365
interface SemanticTokensProviderShape {
366
/** Provide semantic tokens for entire document */
367
provideDocumentSemanticTokens(document: TextDocument, token: CancellationToken): ProviderResult<SemanticTokens>;
368
369
/** Provide semantic token edits */
370
provideDocumentSemanticTokensEdits?(
371
document: TextDocument,
372
previousResultId: string,
373
token: CancellationToken
374
): ProviderResult<SemanticTokensEdits | SemanticTokens>;
375
376
/** Provide semantic tokens for a range */
377
provideDocumentRangeSemanticTokens?(
378
document: TextDocument,
379
range: Range,
380
token: CancellationToken
381
): ProviderResult<SemanticTokens>;
382
}
383
384
/**
385
* Shape interface for inlay hints providers
386
*/
387
interface InlayHintsProviderShape {
388
/** Provide inlay hints for a document range */
389
provideInlayHints(document: TextDocument, range: Range, token: CancellationToken): ProviderResult<InlayHint[]>;
390
391
/** Resolve an inlay hint */
392
resolveInlayHint?(item: InlayHint, token: CancellationToken): ProviderResult<InlayHint>;
393
394
/** Event fired when inlay hints should be refreshed */
395
onDidChangeInlayHints?: Event<void>;
396
}
397
398
/**
399
* Shape interface for inline value providers
400
*/
401
interface InlineValueProviderShape {
402
/** Provide inline values for a document range */
403
provideInlineValues(
404
document: TextDocument,
405
viewPort: Range,
406
context: InlineValueContext,
407
token: CancellationToken
408
): ProviderResult<InlineValue[]>;
409
410
/** Event fired when inline values should be refreshed */
411
onDidChangeInlineValues?: Event<void>;
412
}
413
```
414
415
### Feature Registration
416
417
Utilities for feature registration and management.
418
419
```typescript { .api }
420
/**
421
* Ensure a registration data object is properly formatted
422
*/
423
function ensure<T>(target: T, key: keyof T): T[typeof key];
424
425
/**
426
* Language Server Protocol cancellation error
427
*/
428
class LSPCancellationError extends Error {
429
/** LSP error data */
430
readonly data: any;
431
432
constructor(data: any);
433
}
434
435
/**
436
* Create all proposed features for experimental LSP capabilities
437
*/
438
function createAll(): (StaticFeature | DynamicFeature<any>)[];
439
```
440
441
**Usage Examples:**
442
443
Registering features with client:
444
445
```typescript
446
import { LanguageClient } from "vscode-languageclient/node";
447
448
const client = new LanguageClient(/* ... */);
449
450
// Register a static feature
451
const staticFeature = new CustomStaticFeature();
452
client.registerFeature(staticFeature);
453
454
// Register a dynamic feature
455
const dynamicFeature = new CustomDynamicFeature();
456
client.registerFeature(dynamicFeature);
457
458
// Register proposed features
459
const proposedFeatures = createAll();
460
proposedFeatures.forEach(feature => client.registerFeature(feature));
461
```
462
463
Feature with provider interface:
464
465
```typescript
466
class CustomProviderFeature implements DynamicFeature<CustomOptions>, TextDocumentProviderFeature<CustomProvider> {
467
private _providers = new Map<string, CustomProvider>();
468
469
getProvider(textDocument: TextDocument): CustomProvider | undefined {
470
// Find appropriate provider for document
471
for (const provider of this._providers.values()) {
472
if (provider.canHandle(textDocument)) {
473
return provider;
474
}
475
}
476
return undefined;
477
}
478
479
register(data: RegistrationData<CustomOptions>): void {
480
const provider = new CustomProvider(data.registerOptions);
481
this._providers.set(data.id, provider);
482
}
483
484
// ... implement other DynamicFeature methods
485
}
486
```