|
| 1 | +/*--------------------------------------------------------------------------------------------- |
| 2 | + * Copyright (c) Microsoft Corporation. All rights reserved. |
| 3 | + * Licensed under the MIT License. See License.txt in the project root for license information. |
| 4 | + *--------------------------------------------------------------------------------------------*/ |
| 5 | + |
| 6 | +import { |
| 7 | + languages as Languages, |
| 8 | + workspace as Workspace, |
| 9 | + DocumentSelector as VDocumentSelector, |
| 10 | + TextDocument, |
| 11 | +} from 'vscode'; |
| 12 | + |
| 13 | +import { DynamicFeature, FeatureState, LanguageClient, RegistrationData, ensure } from 'vscode-languageclient/node'; |
| 14 | + |
| 15 | +import { |
| 16 | + ClientCapabilities, |
| 17 | + DocumentSelector, |
| 18 | + InitializeParams, |
| 19 | + ProtocolRequestType, |
| 20 | + RegistrationType, |
| 21 | + ServerCapabilities, |
| 22 | +} from 'vscode-languageserver-protocol'; |
| 23 | + |
| 24 | +import * as RoslynProtocol from './roslynProtocol'; |
| 25 | +import * as Is from 'vscode-languageclient/lib/common/utils/is'; |
| 26 | +import * as UUID from 'vscode-languageclient/lib/common/utils/uuid'; |
| 27 | + |
| 28 | +export class OnAutoInsertFeature implements DynamicFeature<RoslynProtocol.OnAutoInsertRegistrationOptions> { |
| 29 | + private readonly _client: LanguageClient; |
| 30 | + private readonly _registrations: Map<string, RegistrationData<RoslynProtocol.OnAutoInsertRegistrationOptions>>; |
| 31 | + |
| 32 | + constructor(client: LanguageClient) { |
| 33 | + this._client = client; |
| 34 | + this._registrations = new Map(); |
| 35 | + this.registrationType = new ProtocolRequestType< |
| 36 | + RoslynProtocol.OnAutoInsertParams, |
| 37 | + RoslynProtocol.OnAutoInsertResponseItem | null, |
| 38 | + never, |
| 39 | + void, |
| 40 | + RoslynProtocol.OnAutoInsertRegistrationOptions |
| 41 | + >(RoslynProtocol.OnAutoInsertRequest.method); |
| 42 | + } |
| 43 | + fillInitializeParams?: ((params: InitializeParams) => void) | undefined; |
| 44 | + preInitialize?: |
| 45 | + | ((capabilities: ServerCapabilities<any>, documentSelector: DocumentSelector | undefined) => void) |
| 46 | + | undefined; |
| 47 | + registrationType: RegistrationType<RoslynProtocol.OnAutoInsertRegistrationOptions>; |
| 48 | + register(data: RegistrationData<RoslynProtocol.OnAutoInsertRegistrationOptions>): void { |
| 49 | + if (!data.registerOptions.documentSelector) { |
| 50 | + return; |
| 51 | + } |
| 52 | + this._registrations.set(data.id, data); |
| 53 | + } |
| 54 | + unregister(id: string): void { |
| 55 | + const registration = this._registrations.get(id); |
| 56 | + if (registration !== undefined) { |
| 57 | + this._registrations.delete(id); |
| 58 | + } |
| 59 | + } |
| 60 | + dispose(): void { |
| 61 | + this._registrations.clear(); |
| 62 | + } |
| 63 | + |
| 64 | + public getState(): FeatureState { |
| 65 | + const selectors = this.getDocumentSelectors(); |
| 66 | + |
| 67 | + let count = 0; |
| 68 | + for (const selector of selectors) { |
| 69 | + count++; |
| 70 | + for (const document of Workspace.textDocuments) { |
| 71 | + if (Languages.match(selector, document) > 0) { |
| 72 | + return { kind: 'document', id: this.registrationType.method, registrations: true, matches: true }; |
| 73 | + } |
| 74 | + } |
| 75 | + } |
| 76 | + const registrations = count > 0; |
| 77 | + return { kind: 'document', id: this.registrationType.method, registrations, matches: false }; |
| 78 | + } |
| 79 | + |
| 80 | + public fillClientCapabilities(capabilities: ClientCapabilities): void { |
| 81 | + const textDocumentCapabilities: any = ensure(capabilities, 'textDocument')!; |
| 82 | + if (textDocumentCapabilities['_vs_onAutoInsert'] === undefined) { |
| 83 | + textDocumentCapabilities['_vs_onAutoInsert'] = {} as any; |
| 84 | + } |
| 85 | + const onAutoInsertCapability = textDocumentCapabilities['_vs_onAutoInsert']; |
| 86 | + onAutoInsertCapability.dynamicRegistration = true; |
| 87 | + } |
| 88 | + |
| 89 | + public initialize(_capabilities: ServerCapabilities, documentSelector: DocumentSelector): void { |
| 90 | + const capabilities: any = _capabilities; |
| 91 | + const options = this.getRegistrationOptions(documentSelector, capabilities._vs_onAutoInsertProvider); |
| 92 | + if (!options) { |
| 93 | + return; |
| 94 | + } |
| 95 | + this.register({ |
| 96 | + id: UUID.generateUuid(), |
| 97 | + registerOptions: options, |
| 98 | + }); |
| 99 | + } |
| 100 | + |
| 101 | + public getOptions(textDocument: TextDocument): RoslynProtocol.OnAutoInsertOptions | undefined { |
| 102 | + for (const registration of this._registrations.values()) { |
| 103 | + const selector = registration.registerOptions.documentSelector; |
| 104 | + if ( |
| 105 | + selector !== null && |
| 106 | + Languages.match(this._client.protocol2CodeConverter.asDocumentSelector(selector), textDocument) > 0 |
| 107 | + ) { |
| 108 | + return registration.registerOptions; |
| 109 | + } |
| 110 | + } |
| 111 | + return undefined; |
| 112 | + } |
| 113 | + |
| 114 | + private *getDocumentSelectors(): IterableIterator<VDocumentSelector> { |
| 115 | + for (const registration of this._registrations.values()) { |
| 116 | + const selector = registration.registerOptions.documentSelector; |
| 117 | + if (selector === null) { |
| 118 | + continue; |
| 119 | + } |
| 120 | + yield this._client.protocol2CodeConverter.asDocumentSelector(selector); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + private getRegistrationOptions( |
| 125 | + documentSelector: DocumentSelector | undefined, |
| 126 | + capability: undefined | boolean | RoslynProtocol.OnAutoInsertOptions |
| 127 | + ): (RoslynProtocol.OnAutoInsertRegistrationOptions & { documentSelector: DocumentSelector }) | undefined { |
| 128 | + if (!documentSelector || !capability) { |
| 129 | + return undefined; |
| 130 | + } |
| 131 | + return ( |
| 132 | + Is.boolean(capability) && capability === true |
| 133 | + ? { documentSelector } |
| 134 | + : Object.assign({}, capability, { documentSelector }) |
| 135 | + ) as RoslynProtocol.OnAutoInsertRegistrationOptions & { documentSelector: DocumentSelector }; |
| 136 | + } |
| 137 | +} |
0 commit comments