diff --git a/client-node-tests/src/integration.test.ts b/client-node-tests/src/integration.test.ts index dcac1430..f413e4f6 100644 --- a/client-node-tests/src/integration.test.ts +++ b/client-node-tests/src/integration.test.ts @@ -318,7 +318,7 @@ suite('Client integration', () => { willDelete: { filters: [{ scheme: fsProvider.scheme, pattern: { glob: '**/deleted-static/**{/,/*.txt}' } }] }, }, textDocumentContent: { - scheme: 'content-test' + schemes: ['content-test'] } }, linkedEditingRangeProvider: true, diff --git a/client-node-tests/src/servers/testServer.ts b/client-node-tests/src/servers/testServer.ts index 619fe8dd..1801e52d 100644 --- a/client-node-tests/src/servers/testServer.ts +++ b/client-node-tests/src/servers/testServer.ts @@ -145,7 +145,7 @@ connection.onInitialize((params: InitializeParams): any => { }, }, textDocumentContent: { - scheme: 'content-test' + schemes: ['content-test'] } }, linkedEditingRangeProvider: true, diff --git a/client/src/common/textDocumentContent.ts b/client/src/common/textDocumentContent.ts index 6bdab2f0..909783bb 100644 --- a/client/src/common/textDocumentContent.ts +++ b/client/src/common/textDocumentContent.ts @@ -4,9 +4,9 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; -import { StaticRegistrationOptions, TextDocumentContentRefreshRequest, TextDocumentContentRequest, type ClientCapabilities, type ServerCapabilities, type TextDocumentContentParams, type TextDocumentContentRegistrationOptions } from 'vscode-languageserver-protocol'; +import { StaticRegistrationOptions, TextDocumentContentRefreshRequest, TextDocumentContentRequest, type ClientCapabilities, type RegistrationType, type ServerCapabilities, type TextDocumentContentParams, type TextDocumentContentRegistrationOptions } from 'vscode-languageserver-protocol'; -import { WorkspaceFeature, ensure, type FeatureClient } from './features'; +import { ensure, type DynamicFeature, type FeatureClient, type FeatureState, type RegistrationData } from './features'; import * as UUID from './utils/uuid'; @@ -19,14 +19,35 @@ export interface TextDocumentContentMiddleware { } export interface TextDocumentContentProviderShape { - provider: vscode.TextDocumentContentProvider; + scheme: string; onDidChangeEmitter: vscode.EventEmitter; + provider: vscode.TextDocumentContentProvider; } -export class TextDocumentContentFeature extends WorkspaceFeature { +export class TextDocumentContentFeature implements DynamicFeature { + + private readonly _client: FeatureClient; + private readonly _registrations: Map = new Map(); constructor(client: FeatureClient) { - super(client, TextDocumentContentRequest.type); + this._client = client; + } + + public getState(): FeatureState { + const registrations = this._registrations.size > 0; + return { kind: 'workspace', id: TextDocumentContentRequest.method, registrations }; + } + + public get registrationType(): RegistrationType { + return TextDocumentContentRequest.type; + } + + public getProviders(): TextDocumentContentProviderShape[] { + const result: TextDocumentContentProviderShape[] = []; + for (const registration of this._registrations.values()) { + result.push(...registration.providers); + } + return result; } public fillClientCapabilities(capabilities: ClientCapabilities): void { @@ -38,8 +59,12 @@ export class TextDocumentContentFeature extends WorkspaceFeature { const uri = client.protocol2CodeConverter.asUri(params.uri); - for (const provider of this.getProviders()) { - provider.onDidChangeEmitter.fire(uri); + for (const registrations of this._registrations.values()) { + for (const provider of registrations.providers) { + if (provider.scheme !== uri.scheme) { + provider.onDidChangeEmitter.fire(uri); + } + } } }); @@ -54,7 +79,18 @@ export class TextDocumentContentFeature extends WorkspaceFeature): void { + const registrations: TextDocumentContentProviderShape[] = []; + const disposables: vscode.Disposable[] = []; + for (const scheme of data.registerOptions.schemes) { + const [disposable, registration] = this.registerTextDocumentContentProvider(scheme); + registrations.push(registration); + disposables.push(disposable); + } + this._registrations.set(data.id, { disposable: vscode.Disposable.from(...disposables), providers: registrations }); + } + + private registerTextDocumentContentProvider(scheme: string): [vscode.Disposable, TextDocumentContentProviderShape] { const eventEmitter: vscode.EventEmitter = new vscode.EventEmitter(); const provider: vscode.TextDocumentContentProvider = { onDidChange: eventEmitter.event, @@ -79,6 +115,21 @@ export class TextDocumentContentFeature extends WorkspaceFeature { + registration.disposable.dispose(); + }); + this._registrations.clear(); } } \ No newline at end of file diff --git a/protocol/src/common/protocol.textDocumentContent.ts b/protocol/src/common/protocol.textDocumentContent.ts index 687e3f7e..545783ff 100644 --- a/protocol/src/common/protocol.textDocumentContent.ts +++ b/protocol/src/common/protocol.textDocumentContent.ts @@ -30,9 +30,9 @@ export type TextDocumentContentClientCapabilities = { */ export type TextDocumentContentOptions = { /** - * The scheme for which the server provides content. + * The schemes for which the server provides content. */ - scheme: string; + schemes: string[]; }; /** diff --git a/testbed/server/src/server.ts b/testbed/server/src/server.ts index 2acc8bba..767fdd6b 100644 --- a/testbed/server/src/server.ts +++ b/testbed/server/src/server.ts @@ -158,7 +158,7 @@ connection.onInitialize((params, cancel, progress): Thenable | changeNotifications: true }, textDocumentContent: { - scheme: 'test-content' + schemes: ['test-content'] } }, implementationProvider: {