/* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ 'use strict'; function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); const vscode_1 = require("vscode"); const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol"); const c2p = require("./codeConverter"); const p2c = require("./protocolConverter"); const Is = require("./utils/is"); const async_1 = require("./utils/async"); const UUID = require("./utils/uuid"); __export(require("vscode-languageserver-protocol")); class ConsoleLogger { error(message) { console.error(message); } warn(message) { console.warn(message); } info(message) { console.info(message); } log(message) { console.log(message); } } function createConnection(input, output, errorHandler, closeHandler) { let logger = new ConsoleLogger(); let connection = vscode_languageserver_protocol_1.createProtocolConnection(input, output, logger); connection.onError((data) => { errorHandler(data[0], data[1], data[2]); }); connection.onClose(closeHandler); let result = { listen: () => connection.listen(), sendRequest: (type, ...params) => connection.sendRequest(Is.string(type) ? type : type.method, ...params), onRequest: (type, handler) => connection.onRequest(Is.string(type) ? type : type.method, handler), sendNotification: (type, params) => connection.sendNotification(Is.string(type) ? type : type.method, params), onNotification: (type, handler) => connection.onNotification(Is.string(type) ? type : type.method, handler), trace: (value, tracer, sendNotification = false) => connection.trace(value, tracer, sendNotification), initialize: (params) => connection.sendRequest(vscode_languageserver_protocol_1.InitializeRequest.type, params), shutdown: () => connection.sendRequest(vscode_languageserver_protocol_1.ShutdownRequest.type, undefined), exit: () => connection.sendNotification(vscode_languageserver_protocol_1.ExitNotification.type), onLogMessage: (handler) => connection.onNotification(vscode_languageserver_protocol_1.LogMessageNotification.type, handler), onShowMessage: (handler) => connection.onNotification(vscode_languageserver_protocol_1.ShowMessageNotification.type, handler), onTelemetry: (handler) => connection.onNotification(vscode_languageserver_protocol_1.TelemetryEventNotification.type, handler), didChangeConfiguration: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type, params), didChangeWatchedFiles: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type, params), didOpenTextDocument: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type, params), didChangeTextDocument: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params), didCloseTextDocument: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type, params), didSaveTextDocument: (params) => connection.sendNotification(vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type, params), onDiagnostics: (handler) => connection.onNotification(vscode_languageserver_protocol_1.PublishDiagnosticsNotification.type, handler), dispose: () => connection.dispose() }; return result; } /** * An action to be performed when the connection is producing errors. */ var ErrorAction; (function (ErrorAction) { /** * Continue running the server. */ ErrorAction[ErrorAction["Continue"] = 1] = "Continue"; /** * Shutdown the server. */ ErrorAction[ErrorAction["Shutdown"] = 2] = "Shutdown"; })(ErrorAction = exports.ErrorAction || (exports.ErrorAction = {})); /** * An action to be performed when the connection to a server got closed. */ var CloseAction; (function (CloseAction) { /** * Don't restart the server. The connection stays closed. */ CloseAction[CloseAction["DoNotRestart"] = 1] = "DoNotRestart"; /** * Restart the server. */ CloseAction[CloseAction["Restart"] = 2] = "Restart"; })(CloseAction = exports.CloseAction || (exports.CloseAction = {})); class DefaultErrorHandler { constructor(name) { this.name = name; this.restarts = []; } error(_error, _message, count) { if (count && count <= 3) { return ErrorAction.Continue; } return ErrorAction.Shutdown; } closed() { this.restarts.push(Date.now()); if (this.restarts.length < 5) { return CloseAction.Restart; } else { let diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; if (diff <= 3 * 60 * 1000) { vscode_1.window.showErrorMessage(`The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`); return CloseAction.DoNotRestart; } else { this.restarts.shift(); return CloseAction.Restart; } } } } var RevealOutputChannelOn; (function (RevealOutputChannelOn) { RevealOutputChannelOn[RevealOutputChannelOn["Info"] = 1] = "Info"; RevealOutputChannelOn[RevealOutputChannelOn["Warn"] = 2] = "Warn"; RevealOutputChannelOn[RevealOutputChannelOn["Error"] = 3] = "Error"; RevealOutputChannelOn[RevealOutputChannelOn["Never"] = 4] = "Never"; })(RevealOutputChannelOn = exports.RevealOutputChannelOn || (exports.RevealOutputChannelOn = {})); var State; (function (State) { State[State["Stopped"] = 1] = "Stopped"; State[State["Running"] = 2] = "Running"; })(State = exports.State || (exports.State = {})); var ClientState; (function (ClientState) { ClientState[ClientState["Initial"] = 0] = "Initial"; ClientState[ClientState["Starting"] = 1] = "Starting"; ClientState[ClientState["StartFailed"] = 2] = "StartFailed"; ClientState[ClientState["Running"] = 3] = "Running"; ClientState[ClientState["Stopping"] = 4] = "Stopping"; ClientState[ClientState["Stopped"] = 5] = "Stopped"; })(ClientState || (ClientState = {})); const SupporedSymbolKinds = [ vscode_languageserver_protocol_1.SymbolKind.File, vscode_languageserver_protocol_1.SymbolKind.Module, vscode_languageserver_protocol_1.SymbolKind.Namespace, vscode_languageserver_protocol_1.SymbolKind.Package, vscode_languageserver_protocol_1.SymbolKind.Class, vscode_languageserver_protocol_1.SymbolKind.Method, vscode_languageserver_protocol_1.SymbolKind.Property, vscode_languageserver_protocol_1.SymbolKind.Field, vscode_languageserver_protocol_1.SymbolKind.Constructor, vscode_languageserver_protocol_1.SymbolKind.Enum, vscode_languageserver_protocol_1.SymbolKind.Interface, vscode_languageserver_protocol_1.SymbolKind.Function, vscode_languageserver_protocol_1.SymbolKind.Variable, vscode_languageserver_protocol_1.SymbolKind.Constant, vscode_languageserver_protocol_1.SymbolKind.String, vscode_languageserver_protocol_1.SymbolKind.Number, vscode_languageserver_protocol_1.SymbolKind.Boolean, vscode_languageserver_protocol_1.SymbolKind.Array, vscode_languageserver_protocol_1.SymbolKind.Object, vscode_languageserver_protocol_1.SymbolKind.Key, vscode_languageserver_protocol_1.SymbolKind.Null, vscode_languageserver_protocol_1.SymbolKind.EnumMember, vscode_languageserver_protocol_1.SymbolKind.Struct, vscode_languageserver_protocol_1.SymbolKind.Event, vscode_languageserver_protocol_1.SymbolKind.Operator, vscode_languageserver_protocol_1.SymbolKind.TypeParameter ]; const SupportedCompletionItemKinds = [ vscode_languageserver_protocol_1.CompletionItemKind.Text, vscode_languageserver_protocol_1.CompletionItemKind.Method, vscode_languageserver_protocol_1.CompletionItemKind.Function, vscode_languageserver_protocol_1.CompletionItemKind.Constructor, vscode_languageserver_protocol_1.CompletionItemKind.Field, vscode_languageserver_protocol_1.CompletionItemKind.Variable, vscode_languageserver_protocol_1.CompletionItemKind.Class, vscode_languageserver_protocol_1.CompletionItemKind.Interface, vscode_languageserver_protocol_1.CompletionItemKind.Module, vscode_languageserver_protocol_1.CompletionItemKind.Property, vscode_languageserver_protocol_1.CompletionItemKind.Unit, vscode_languageserver_protocol_1.CompletionItemKind.Value, vscode_languageserver_protocol_1.CompletionItemKind.Enum, vscode_languageserver_protocol_1.CompletionItemKind.Keyword, vscode_languageserver_protocol_1.CompletionItemKind.Snippet, vscode_languageserver_protocol_1.CompletionItemKind.Color, vscode_languageserver_protocol_1.CompletionItemKind.File, vscode_languageserver_protocol_1.CompletionItemKind.Reference, vscode_languageserver_protocol_1.CompletionItemKind.Folder, vscode_languageserver_protocol_1.CompletionItemKind.EnumMember, vscode_languageserver_protocol_1.CompletionItemKind.Constant, vscode_languageserver_protocol_1.CompletionItemKind.Struct, vscode_languageserver_protocol_1.CompletionItemKind.Event, vscode_languageserver_protocol_1.CompletionItemKind.Operator, vscode_languageserver_protocol_1.CompletionItemKind.TypeParameter ]; function ensure(target, key) { if (target[key] === void 0) { target[key] = {}; } return target[key]; } var DynamicFeature; (function (DynamicFeature) { function is(value) { let candidate = value; return candidate && Is.func(candidate.register) && Is.func(candidate.unregister) && Is.func(candidate.dispose) && candidate.messages !== void 0; } DynamicFeature.is = is; })(DynamicFeature || (DynamicFeature = {})); class DocumentNotifiactions { constructor(_client, _event, _type, _middleware, _createParams, _selectorFilter) { this._client = _client; this._event = _event; this._type = _type; this._middleware = _middleware; this._createParams = _createParams; this._selectorFilter = _selectorFilter; this._selectors = new Map(); } static textDocumentFilter(selectors, textDocument) { for (const selector of selectors) { if (vscode_1.languages.match(selector, textDocument)) { return true; } } return false; } register(_message, data) { if (!data.registerOptions.documentSelector) { return; } if (!this._listener) { this._listener = this._event(this.callback, this); } this._selectors.set(data.id, data.registerOptions.documentSelector); } callback(data) { if (!this._selectorFilter || this._selectorFilter(this._selectors.values(), data)) { if (this._middleware) { this._middleware(data, (data) => this._client.sendNotification(this._type, this._createParams(data))); } else { this._client.sendNotification(this._type, this._createParams(data)); } this.notificationSent(data); } } notificationSent(_data) { } unregister(id) { this._selectors.delete(id); if (this._selectors.size === 0 && this._listener) { this._listener.dispose(); this._listener = undefined; } } dispose() { this._selectors.clear(); if (this._listener) { this._listener.dispose(); } } } class DidOpenTextDocumentFeature extends DocumentNotifiactions { constructor(client, _syncedDocuments) { super(client, vscode_1.workspace.onDidOpenTextDocument, vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type, client.clientOptions.middleware.didOpen, (textDocument) => client.code2ProtocolConverter.asOpenTextDocumentParams(textDocument), DocumentNotifiactions.textDocumentFilter); this._syncedDocuments = _syncedDocuments; } get messages() { return vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } register(message, data) { super.register(message, data); if (!data.registerOptions.documentSelector) { return; } let documentSelector = data.registerOptions.documentSelector; vscode_1.workspace.textDocuments.forEach((textDocument) => { let uri = textDocument.uri.toString(); if (this._syncedDocuments.has(uri)) { return; } if (vscode_1.languages.match(documentSelector, textDocument)) { let middleware = this._client.clientOptions.middleware; let didOpen = (textDocument) => { this._client.sendNotification(this._type, this._createParams(textDocument)); }; if (middleware.didOpen) { middleware.didOpen(textDocument, didOpen); } else { didOpen(textDocument); } this._syncedDocuments.set(uri, textDocument); } }); } notificationSent(textDocument) { super.notificationSent(textDocument); this._syncedDocuments.set(textDocument.uri.toString(), textDocument); } } class DidCloseTextDocumentFeature extends DocumentNotifiactions { constructor(client, _syncedDocuments) { super(client, vscode_1.workspace.onDidCloseTextDocument, vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type, client.clientOptions.middleware.didClose, (textDocument) => client.code2ProtocolConverter.asCloseTextDocumentParams(textDocument), DocumentNotifiactions.textDocumentFilter); this._syncedDocuments = _syncedDocuments; } get messages() { return vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } notificationSent(textDocument) { super.notificationSent(textDocument); this._syncedDocuments.delete(textDocument.uri.toString()); } unregister(id) { let selector = this._selectors.get(id); // The super call removed the selector from the map // of selectors. super.unregister(id); let selectors = this._selectors.values(); this._syncedDocuments.forEach((textDocument) => { if (vscode_1.languages.match(selector, textDocument) && !this._selectorFilter(selectors, textDocument)) { let middleware = this._client.clientOptions.middleware; let didClose = (textDocument) => { this._client.sendNotification(this._type, this._createParams(textDocument)); }; this._syncedDocuments.delete(textDocument.uri.toString()); if (middleware.didClose) { middleware.didClose(textDocument, didClose); } else { didClose(textDocument); } } }); } } class DidChangeTextDocumentFeature { constructor(_client) { this._client = _client; this._changeData = new Map(); this._forcingDelivery = false; } get messages() { return vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.change !== void 0 && textDocumentSyncOptions.change !== vscode_languageserver_protocol_1.TextDocumentSyncKind.None) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, { syncKind: textDocumentSyncOptions.change }) }); } } register(_message, data) { if (!data.registerOptions.documentSelector) { return; } if (!this._listener) { this._listener = vscode_1.workspace.onDidChangeTextDocument(this.callback, this); } this._changeData.set(data.id, { documentSelector: data.registerOptions.documentSelector, syncKind: data.registerOptions.syncKind }); } callback(event) { // Text document changes are send for dirty changes as well. We don't // have dirty / undirty events in the LSP so we ignore content changes // with length zero. if (event.contentChanges.length === 0) { return; } for (const changeData of this._changeData.values()) { if (vscode_1.languages.match(changeData.documentSelector, event.document)) { let middleware = this._client.clientOptions.middleware; if (changeData.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Incremental) { let params = this._client.code2ProtocolConverter.asChangeTextDocumentParams(event); if (middleware.didChange) { middleware.didChange(event, () => this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params)); } else { this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params); } } else if (changeData.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Full) { let didChange = (event) => { if (this._changeDelayer) { if (this._changeDelayer.uri !== event.document.uri.toString()) { // Use this force delivery to track boolean state. Otherwise we might call two times. this.forceDelivery(); this._changeDelayer.uri = event.document.uri.toString(); } this._changeDelayer.delayer.trigger(() => { this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, this._client.code2ProtocolConverter.asChangeTextDocumentParams(event.document)); }); } else { this._changeDelayer = { uri: event.document.uri.toString(), delayer: new async_1.Delayer(200) }; this._changeDelayer.delayer.trigger(() => { this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, this._client.code2ProtocolConverter.asChangeTextDocumentParams(event.document)); }, -1); } }; if (middleware.didChange) { middleware.didChange(event, didChange); } else { didChange(event); } } } } } unregister(id) { this._changeData.delete(id); if (this._changeData.size === 0 && this._listener) { this._listener.dispose(); this._listener = undefined; } } dispose() { this._changeDelayer = undefined; this._forcingDelivery = false; this._changeData.clear(); if (this._listener) { this._listener.dispose(); this._listener = undefined; } } forceDelivery() { if (this._forcingDelivery || !this._changeDelayer) { return; } try { this._forcingDelivery = true; this._changeDelayer.delayer.forceDelivery(); } finally { this._forcingDelivery = false; } } } class WillSaveFeature extends DocumentNotifiactions { constructor(client) { super(client, vscode_1.workspace.onWillSaveTextDocument, vscode_languageserver_protocol_1.WillSaveTextDocumentNotification.type, client.clientOptions.middleware.willSave, (willSaveEvent) => client.code2ProtocolConverter.asWillSaveTextDocumentParams(willSaveEvent), (selectors, willSaveEvent) => DocumentNotifiactions.textDocumentFilter(selectors, willSaveEvent.document)); } get messages() { return vscode_languageserver_protocol_1.WillSaveTextDocumentNotification.type; } fillClientCapabilities(capabilities) { let value = ensure(ensure(capabilities, 'textDocument'), 'synchronization'); value.willSave = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.willSave) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } } class WillSaveWaitUntilFeature { constructor(_client) { this._client = _client; this._selectors = new Map(); } get messages() { return vscode_languageserver_protocol_1.WillSaveTextDocumentWaitUntilRequest.type; } fillClientCapabilities(capabilities) { let value = ensure(ensure(capabilities, 'textDocument'), 'synchronization'); value.willSaveWaitUntil = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.willSaveWaitUntil) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } register(_message, data) { if (!data.registerOptions.documentSelector) { return; } if (!this._listener) { this._listener = vscode_1.workspace.onWillSaveTextDocument(this.callback, this); } this._selectors.set(data.id, data.registerOptions.documentSelector); } callback(event) { if (DocumentNotifiactions.textDocumentFilter(this._selectors.values(), event.document)) { let middleware = this._client.clientOptions.middleware; let willSaveWaitUntil = (event) => { return this._client.sendRequest(vscode_languageserver_protocol_1.WillSaveTextDocumentWaitUntilRequest.type, this._client.code2ProtocolConverter.asWillSaveTextDocumentParams(event)).then((edits) => { let vEdits = this._client.protocol2CodeConverter.asTextEdits(edits); return vEdits === void 0 ? [] : vEdits; }); }; event.waitUntil(middleware.willSaveWaitUntil ? middleware.willSaveWaitUntil(event, willSaveWaitUntil) : willSaveWaitUntil(event)); } } unregister(id) { this._selectors.delete(id); if (this._selectors.size === 0 && this._listener) { this._listener.dispose(); this._listener = undefined; } } dispose() { this._selectors.clear(); if (this._listener) { this._listener.dispose(); this._listener = undefined; } } } class DidSaveTextDocumentFeature extends DocumentNotifiactions { constructor(client) { super(client, vscode_1.workspace.onDidSaveTextDocument, vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type, client.clientOptions.middleware.didSave, (textDocument) => client.code2ProtocolConverter.asSaveTextDocumentParams(textDocument, this._includeText), DocumentNotifiactions.textDocumentFilter); } get messages() { return vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').didSave = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.save) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, { includeText: !!textDocumentSyncOptions.save.includeText }) }); } } register(method, data) { this._includeText = !!data.registerOptions.includeText; super.register(method, data); } } class FileSystemWatcherFeature { constructor(_client, _notifyFileEvent) { this._client = _client; this._notifyFileEvent = _notifyFileEvent; this._watchers = new Map(); } get messages() { return vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'workspace'), 'didChangeWatchedFiles').dynamicRegistration = true; } initialize(_capabilities, _documentSelector) { } register(_method, data) { if (!Array.isArray(data.registerOptions.watchers)) { return; } let disposeables = []; for (let watcher of data.registerOptions.watchers) { if (!Is.string(watcher.globPattern)) { continue; } let watchCreate = true, watchChange = true, watchDelete = true; if (watcher.kind !== void 0 && watcher.kind !== null) { watchCreate = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Create) !== 0; watchChange = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Change) != 0; watchDelete = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Delete) != 0; } let fileSystemWatcher = vscode_1.workspace.createFileSystemWatcher(watcher.globPattern, !watchCreate, !watchChange, !watchDelete); this.hookListeners(fileSystemWatcher, watchCreate, watchChange, watchDelete); disposeables.push(fileSystemWatcher); } this._watchers.set(data.id, disposeables); } registerRaw(id, fileSystemWatchers) { let disposeables = []; for (let fileSystemWatcher of fileSystemWatchers) { this.hookListeners(fileSystemWatcher, true, true, true, disposeables); } this._watchers.set(id, disposeables); } hookListeners(fileSystemWatcher, watchCreate, watchChange, watchDelete, listeners) { if (watchCreate) { fileSystemWatcher.onDidCreate((resource) => this._notifyFileEvent({ uri: this._client.code2ProtocolConverter.asUri(resource), type: vscode_languageserver_protocol_1.FileChangeType.Created }), null, listeners); } if (watchChange) { fileSystemWatcher.onDidChange((resource) => this._notifyFileEvent({ uri: this._client.code2ProtocolConverter.asUri(resource), type: vscode_languageserver_protocol_1.FileChangeType.Changed }), null, listeners); } if (watchDelete) { fileSystemWatcher.onDidDelete((resource) => this._notifyFileEvent({ uri: this._client.code2ProtocolConverter.asUri(resource), type: vscode_languageserver_protocol_1.FileChangeType.Deleted }), null, listeners); } } unregister(id) { let disposeables = this._watchers.get(id); if (disposeables) { for (let disposable of disposeables) { disposable.dispose(); } } } dispose() { this._watchers.forEach((disposeables) => { for (let disposable of disposeables) { disposable.dispose(); } }); this._watchers.clear(); } } class TextDocumentFeature { constructor(_client, _message) { this._client = _client; this._message = _message; this._providers = new Map(); } get messages() { return this._message; } register(message, data) { if (message.method !== this.messages.method) { throw new Error(`Register called on wrong feature. Requested ${message.method} but reached feature ${this.messages.method}`); } if (!data.registerOptions.documentSelector) { return; } let provider = this.registerLanguageProvider(data.registerOptions); if (provider) { this._providers.set(data.id, provider); } } unregister(id) { let provider = this._providers.get(id); if (provider) { provider.dispose(); } } dispose() { this._providers.forEach((value) => { value.dispose(); }); this._providers.clear(); } } exports.TextDocumentFeature = TextDocumentFeature; class WorkspaceFeature { constructor(_client, _message) { this._client = _client; this._message = _message; this._providers = new Map(); } get messages() { return this._message; } register(message, data) { if (message.method !== this.messages.method) { throw new Error(`Register called on wron feature. Requested ${message.method} but reached feature ${this.messages.method}`); } let provider = this.registerLanguageProvider(data.registerOptions); if (provider) { this._providers.set(data.id, provider); } } unregister(id) { let provider = this._providers.get(id); if (provider) { provider.dispose(); } } dispose() { this._providers.forEach((value) => { value.dispose(); }); this._providers.clear(); } } class CompletionItemFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CompletionRequest.type); } fillClientCapabilities(capabilites) { let completion = ensure(ensure(capabilites, 'textDocument'), 'completion'); completion.dynamicRegistration = true; completion.contextSupport = true; completion.completionItem = { snippetSupport: true, commitCharactersSupport: true, documentationFormat: [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText], deprecatedSupport: true, preselectSupport: true }; completion.completionItemKind = { valueSet: SupportedCompletionItemKinds }; } initialize(capabilities, documentSelector) { if (!capabilities.completionProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.completionProvider) }); } registerLanguageProvider(options) { let triggerCharacters = options.triggerCharacters || []; let client = this._client; let provideCompletionItems = (document, position, context, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CompletionRequest.type, client.code2ProtocolConverter.asCompletionParams(document, position, context), token).then(client.protocol2CodeConverter.asCompletionResult, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.CompletionRequest.type, error); return Promise.resolve([]); }); }; let resolveCompletionItem = (item, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, client.code2ProtocolConverter.asCompletionItem(item), token).then(client.protocol2CodeConverter.asCompletionItem, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, error); return Promise.resolve(item); }); }; let middleware = this._client.clientOptions.middleware; return vscode_1.languages.registerCompletionItemProvider(options.documentSelector, { provideCompletionItems: (document, position, token, context) => { return middleware.provideCompletionItem ? middleware.provideCompletionItem(document, position, context, token, provideCompletionItems) : provideCompletionItems(document, position, context, token); }, resolveCompletionItem: options.resolveProvider ? (item, token) => { return middleware.resolveCompletionItem ? middleware.resolveCompletionItem(item, token, resolveCompletionItem) : resolveCompletionItem(item, token); } : undefined }, ...triggerCharacters); } } class HoverFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.HoverRequest.type); } fillClientCapabilities(capabilites) { const hoverCapability = (ensure(ensure(capabilites, 'textDocument'), 'hover')); hoverCapability.dynamicRegistration = true; hoverCapability.contentFormat = [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText]; } initialize(capabilities, documentSelector) { if (!capabilities.hoverProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideHover = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asHover, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.HoverRequest.type, error); return Promise.resolve(null); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerHoverProvider(options.documentSelector, { provideHover: (document, position, token) => { return middleware.provideHover ? middleware.provideHover(document, position, token, provideHover) : provideHover(document, position, token); } }); } } class SignatureHelpFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.SignatureHelpRequest.type); } fillClientCapabilities(capabilites) { let config = ensure(ensure(capabilites, 'textDocument'), 'signatureHelp'); config.dynamicRegistration = true; config.signatureInformation = { documentationFormat: [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText] }; } initialize(capabilities, documentSelector) { if (!capabilities.signatureHelpProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.signatureHelpProvider) }); } registerLanguageProvider(options) { let client = this._client; let providerSignatureHelp = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asSignatureHelp, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, error); return Promise.resolve(null); }); }; let middleware = client.clientOptions.middleware; let triggerCharacters = options.triggerCharacters || []; return vscode_1.languages.registerSignatureHelpProvider(options.documentSelector, { provideSignatureHelp: (document, position, token) => { return middleware.provideSignatureHelp ? middleware.provideSignatureHelp(document, position, token, providerSignatureHelp) : providerSignatureHelp(document, position, token); } }, ...triggerCharacters); } } class DefinitionFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DefinitionRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'definition').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.definitionProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideDefinition = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDefinitionResult, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, error); return Promise.resolve(null); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDefinitionProvider(options.documentSelector, { provideDefinition: (document, position, token) => { return middleware.provideDefinition ? middleware.provideDefinition(document, position, token, provideDefinition) : provideDefinition(document, position, token); } }); } } class ReferencesFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.ReferencesRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'references').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.referencesProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let providerReferences = (document, position, options, token) => { return client.sendRequest(vscode_languageserver_protocol_1.ReferencesRequest.type, client.code2ProtocolConverter.asReferenceParams(document, position, options), token).then(client.protocol2CodeConverter.asReferences, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.ReferencesRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerReferenceProvider(options.documentSelector, { provideReferences: (document, position, options, token) => { return middleware.provideReferences ? middleware.provideReferences(document, position, options, token, providerReferences) : providerReferences(document, position, options, token); } }); } } class DocumentHighlightFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentHighlightRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'documentHighlight').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentHighlightProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideDocumentHighlights = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDocumentHighlights, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDocumentHighlightProvider(options.documentSelector, { provideDocumentHighlights: (document, position, token) => { return middleware.provideDocumentHighlights ? middleware.provideDocumentHighlights(document, position, token, provideDocumentHighlights) : provideDocumentHighlights(document, position, token); } }); } } class DocumentSymbolFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentSymbolRequest.type); } fillClientCapabilities(capabilites) { let symbolCapabilities = ensure(ensure(capabilites, 'textDocument'), 'documentSymbol'); symbolCapabilities.dynamicRegistration = true; symbolCapabilities.symbolKind = { valueSet: SupporedSymbolKinds }; symbolCapabilities.hierarchicalDocumentSymbolSupport = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentSymbolProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideDocumentSymbols = (document, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentSymbolRequest.type, client.code2ProtocolConverter.asDocumentSymbolParams(document), token).then((data) => { if (data === null) { return undefined; } if (data.length === 0) { return []; } else { let element = data[0]; if (vscode_languageserver_protocol_1.DocumentSymbol.is(element)) { return client.protocol2CodeConverter.asDocumentSymbols(data); } else { return client.protocol2CodeConverter.asSymbolInformations(data); } } }, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentSymbolRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDocumentSymbolProvider(options.documentSelector, { provideDocumentSymbols: (document, token) => { return middleware.provideDocumentSymbols ? middleware.provideDocumentSymbols(document, token, provideDocumentSymbols) : provideDocumentSymbols(document, token); } }); } } class WorkspaceSymbolFeature extends WorkspaceFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type); } fillClientCapabilities(capabilites) { let symbolCapabilities = ensure(ensure(capabilites, 'workspace'), 'symbol'); symbolCapabilities.dynamicRegistration = true; symbolCapabilities.symbolKind = { valueSet: SupporedSymbolKinds }; } initialize(capabilities) { if (!capabilities.workspaceSymbolProvider) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: undefined }); } registerLanguageProvider(_options) { let client = this._client; let provideWorkspaceSymbols = (query, token) => { return client.sendRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, { query }, token).then(client.protocol2CodeConverter.asSymbolInformations, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerWorkspaceSymbolProvider({ provideWorkspaceSymbols: (query, token) => { return middleware.provideWorkspaceSymbols ? middleware.provideWorkspaceSymbols(query, token, provideWorkspaceSymbols) : provideWorkspaceSymbols(query, token); } }); } } class CodeActionFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CodeActionRequest.type); } fillClientCapabilities(capabilites) { const cap = ensure(ensure(capabilites, 'textDocument'), 'codeAction'); cap.dynamicRegistration = true; cap.codeActionLiteralSupport = { codeActionKind: { valueSet: [ '', vscode_languageserver_protocol_1.CodeActionKind.QuickFix, vscode_languageserver_protocol_1.CodeActionKind.Refactor, vscode_languageserver_protocol_1.CodeActionKind.RefactorExtract, vscode_languageserver_protocol_1.CodeActionKind.RefactorInline, vscode_languageserver_protocol_1.CodeActionKind.RefactorRewrite, vscode_languageserver_protocol_1.CodeActionKind.Source, vscode_languageserver_protocol_1.CodeActionKind.SourceOrganizeImports ] } }; } initialize(capabilities, documentSelector) { if (!capabilities.codeActionProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideCodeActions = (document, range, context, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), range: client.code2ProtocolConverter.asRange(range), context: client.code2ProtocolConverter.asCodeActionContext(context) }; return client.sendRequest(vscode_languageserver_protocol_1.CodeActionRequest.type, params, token).then((values) => { if (values === null) { return undefined; } let result = []; for (let item of values) { if (vscode_languageserver_protocol_1.Command.is(item)) { result.push(client.protocol2CodeConverter.asCommand(item)); } else { result.push(client.protocol2CodeConverter.asCodeAction(item)); } ; } return result; }, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.CodeActionRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerCodeActionsProvider(options.documentSelector, { provideCodeActions: (document, range, context, token) => { return middleware.provideCodeActions ? middleware.provideCodeActions(document, range, context, token, provideCodeActions) : provideCodeActions(document, range, context, token); } }); } } class CodeLensFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CodeLensRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'codeLens').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.codeLensProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.codeLensProvider) }); } registerLanguageProvider(options) { let client = this._client; let provideCodeLenses = (document, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, client.code2ProtocolConverter.asCodeLensParams(document), token).then(client.protocol2CodeConverter.asCodeLenses, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, error); return Promise.resolve([]); }); }; let resolveCodeLens = (codeLens, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, client.code2ProtocolConverter.asCodeLens(codeLens), token).then(client.protocol2CodeConverter.asCodeLens, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, error); return codeLens; }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerCodeLensProvider(options.documentSelector, { provideCodeLenses: (document, token) => { return middleware.provideCodeLenses ? middleware.provideCodeLenses(document, token, provideCodeLenses) : provideCodeLenses(document, token); }, resolveCodeLens: (options.resolveProvider) ? (codeLens, token) => { return middleware.resolveCodeLens ? middleware.resolveCodeLens(codeLens, token, resolveCodeLens) : resolveCodeLens(codeLens, token); } : undefined }); } } class DocumentFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentFormattingRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'formatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentFormattingProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideDocumentFormattingEdits = (document, options, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), options: client.code2ProtocolConverter.asFormattingOptions(options) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDocumentFormattingEditProvider(options.documentSelector, { provideDocumentFormattingEdits: (document, options, token) => { return middleware.provideDocumentFormattingEdits ? middleware.provideDocumentFormattingEdits(document, options, token, provideDocumentFormattingEdits) : provideDocumentFormattingEdits(document, options, token); } }); } } class DocumentRangeFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'rangeFormatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentRangeFormattingProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideDocumentRangeFormattingEdits = (document, range, options, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), range: client.code2ProtocolConverter.asRange(range), options: client.code2ProtocolConverter.asFormattingOptions(options) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDocumentRangeFormattingEditProvider(options.documentSelector, { provideDocumentRangeFormattingEdits: (document, range, options, token) => { return middleware.provideDocumentRangeFormattingEdits ? middleware.provideDocumentRangeFormattingEdits(document, range, options, token, provideDocumentRangeFormattingEdits) : provideDocumentRangeFormattingEdits(document, range, options, token); } }); } } class DocumentOnTypeFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'onTypeFormatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentOnTypeFormattingProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.documentOnTypeFormattingProvider) }); } registerLanguageProvider(options) { let client = this._client; let moreTriggerCharacter = options.moreTriggerCharacter || []; let provideOnTypeFormattingEdits = (document, position, ch, options, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), position: client.code2ProtocolConverter.asPosition(position), ch: ch, options: client.code2ProtocolConverter.asFormattingOptions(options) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, error); return Promise.resolve([]); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerOnTypeFormattingEditProvider(options.documentSelector, { provideOnTypeFormattingEdits: (document, position, ch, options, token) => { return middleware.provideOnTypeFormattingEdits ? middleware.provideOnTypeFormattingEdits(document, position, ch, options, token, provideOnTypeFormattingEdits) : provideOnTypeFormattingEdits(document, position, ch, options, token); } }, options.firstTriggerCharacter, ...moreTriggerCharacter); } } class RenameFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.RenameRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'rename').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.renameProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }) }); } registerLanguageProvider(options) { let client = this._client; let provideRenameEdits = (document, position, newName, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), position: client.code2ProtocolConverter.asPosition(position), newName: newName }; return client.sendRequest(vscode_languageserver_protocol_1.RenameRequest.type, params, token).then(client.protocol2CodeConverter.asWorkspaceEdit, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.RenameRequest.type, error); return Promise.reject(new Error(error.message)); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerRenameProvider(options.documentSelector, { provideRenameEdits: (document, position, newName, token) => { return middleware.provideRenameEdits ? middleware.provideRenameEdits(document, position, newName, token, provideRenameEdits) : provideRenameEdits(document, position, newName, token); } }); } } class DocumentLinkFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentLinkRequest.type); } fillClientCapabilities(capabilites) { ensure(ensure(capabilites, 'textDocument'), 'documentLink').dynamicRegistration = true; } initialize(capabilities, documentSelector) { if (!capabilities.documentLinkProvider || !documentSelector) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.documentLinkProvider) }); } registerLanguageProvider(options) { let client = this._client; let provideDocumentLinks = (document, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, client.code2ProtocolConverter.asDocumentLinkParams(document), token).then(client.protocol2CodeConverter.asDocumentLinks, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, error); Promise.resolve(new Error(error.message)); }); }; let resolveDocumentLink = (link, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, client.code2ProtocolConverter.asDocumentLink(link), token).then(client.protocol2CodeConverter.asDocumentLink, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, error); Promise.resolve(new Error(error.message)); }); }; let middleware = client.clientOptions.middleware; return vscode_1.languages.registerDocumentLinkProvider(options.documentSelector, { provideDocumentLinks: (document, token) => { return middleware.provideDocumentLinks ? middleware.provideDocumentLinks(document, token, provideDocumentLinks) : provideDocumentLinks(document, token); }, resolveDocumentLink: options.resolveProvider ? (link, token) => { return middleware.resolveDocumentLink ? middleware.resolveDocumentLink(link, token, resolveDocumentLink) : resolveDocumentLink(link, token); } : undefined }); } } class ConfigurationFeature { constructor(_client) { this._client = _client; this._listeners = new Map(); } get messages() { return vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'workspace'), 'didChangeConfiguration').dynamicRegistration = true; } initialize() { let section = this._client.clientOptions.synchronize.configurationSection; if (section !== void 0) { this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { section: section } }); } } register(_message, data) { let disposable = vscode_1.workspace.onDidChangeConfiguration((event) => { this.onDidChangeConfiguration(data.registerOptions.section, event); }); this._listeners.set(data.id, disposable); if (data.registerOptions.section !== void 0) { this.onDidChangeConfiguration(data.registerOptions.section, undefined); } } unregister(id) { let disposable = this._listeners.get(id); if (disposable) { this._listeners.delete(id); disposable.dispose(); } } dispose() { for (let disposable of this._listeners.values()) { disposable.dispose(); } this._listeners.clear(); } onDidChangeConfiguration(configurationSection, event) { let sections; if (Is.string(configurationSection)) { sections = [configurationSection]; } else { sections = configurationSection; } if (sections !== void 0 && event !== void 0) { let affected = sections.some((section) => event.affectsConfiguration(section)); if (!affected) { return; } } let didChangeConfiguration = (sections) => { if (sections === void 0) { this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type, { settings: null }); return; } this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type, { settings: this.extractSettingsInformation(sections) }); }; let middleware = this.getMiddleware(); middleware ? middleware(sections, didChangeConfiguration) : didChangeConfiguration(sections); } extractSettingsInformation(keys) { function ensurePath(config, path) { let current = config; for (let i = 0; i < path.length - 1; i++) { let obj = current[path[i]]; if (!obj) { obj = Object.create(null); current[path[i]] = obj; } current = obj; } return current; } let resource = this._client.clientOptions.workspaceFolder ? this._client.clientOptions.workspaceFolder.uri : undefined; let result = Object.create(null); for (let i = 0; i < keys.length; i++) { let key = keys[i]; let index = key.indexOf('.'); let config = null; if (index >= 0) { config = vscode_1.workspace.getConfiguration(key.substr(0, index), resource).get(key.substr(index + 1)); } else { config = vscode_1.workspace.getConfiguration(key, resource); } if (config) { let path = keys[i].split('.'); ensurePath(result, path)[path[path.length - 1]] = config; } } return result; } getMiddleware() { let middleware = this._client.clientOptions.middleware; if (middleware.workspace && middleware.workspace.didChangeConfiguration) { return middleware.workspace.didChangeConfiguration; } else { return undefined; } } } class ExecuteCommandFeature { constructor(_client) { this._client = _client; this._commands = new Map(); } get messages() { return vscode_languageserver_protocol_1.ExecuteCommandRequest.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'workspace'), 'executeCommand').dynamicRegistration = true; } initialize(capabilities) { if (!capabilities.executeCommandProvider) { return; } this.register(this.messages, { id: UUID.generateUuid(), registerOptions: Object.assign({}, capabilities.executeCommandProvider) }); } register(_message, data) { let client = this._client; if (data.registerOptions.commands) { let disposeables = []; for (const command of data.registerOptions.commands) { disposeables.push(vscode_1.commands.registerCommand(command, (...args) => { let params = { command, arguments: args }; return client.sendRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, params).then(undefined, (error) => { client.logFailedRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, error); }); })); } this._commands.set(data.id, disposeables); } } unregister(id) { let disposeables = this._commands.get(id); if (disposeables) { disposeables.forEach(disposable => disposable.dispose()); } } dispose() { this._commands.forEach((value) => { value.forEach(disposable => disposable.dispose()); }); this._commands.clear(); } } var MessageTransports; (function (MessageTransports) { function is(value) { let candidate = value; return candidate && vscode_languageserver_protocol_1.MessageReader.is(value.reader) && vscode_languageserver_protocol_1.MessageWriter.is(value.writer); } MessageTransports.is = is; })(MessageTransports = exports.MessageTransports || (exports.MessageTransports = {})); class BaseLanguageClient { constructor(id, name, clientOptions) { this._features = []; this._method2Message = new Map(); this._dynamicFeatures = new Map(); this._id = id; this._name = name; clientOptions = clientOptions || {}; this._clientOptions = { documentSelector: clientOptions.documentSelector || [], synchronize: clientOptions.synchronize || {}, diagnosticCollectionName: clientOptions.diagnosticCollectionName, outputChannelName: clientOptions.outputChannelName || this._name, revealOutputChannelOn: clientOptions.revealOutputChannelOn || RevealOutputChannelOn.Error, stdioEncoding: clientOptions.stdioEncoding || 'utf8', initializationOptions: clientOptions.initializationOptions, initializationFailedHandler: clientOptions.initializationFailedHandler, errorHandler: clientOptions.errorHandler || new DefaultErrorHandler(this._name), middleware: clientOptions.middleware || {}, uriConverters: clientOptions.uriConverters, workspaceFolder: clientOptions.workspaceFolder }; this._clientOptions.synchronize = this._clientOptions.synchronize || {}; this.state = ClientState.Initial; this._connectionPromise = undefined; this._resolvedConnection = undefined; this._initializeResult = undefined; if (clientOptions.outputChannel) { this._outputChannel = clientOptions.outputChannel; this._disposeOutputChannel = false; } else { this._outputChannel = undefined; this._disposeOutputChannel = true; } this._listeners = undefined; this._providers = undefined; this._diagnostics = undefined; this._fileEvents = []; this._fileEventDelayer = new async_1.Delayer(250); this._onReady = new Promise((resolve, reject) => { this._onReadyCallbacks = { resolve, reject }; }); this._onStop = undefined; this._telemetryEmitter = new vscode_languageserver_protocol_1.Emitter(); this._stateChangeEmitter = new vscode_languageserver_protocol_1.Emitter(); this._tracer = { log: (message, data) => { this.logTrace(message, data); } }; this._c2p = c2p.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined); this._p2c = p2c.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.protocol2Code : undefined); this._syncedDocuments = new Map(); this.registerBuiltinFeatures(); } get state() { return this._state; } set state(value) { let oldState = this.getPublicState(); this._state = value; let newState = this.getPublicState(); if (newState !== oldState) { this._stateChangeEmitter.fire({ oldState, newState }); } } getPublicState() { if (this.state === ClientState.Running) { return State.Running; } else { return State.Stopped; } } get initializeResult() { return this._initializeResult; } sendRequest(type, ...params) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } this.forceDocumentSync(); try { return this._resolvedConnection.sendRequest(type, ...params); } catch (error) { this.error(`Sending request ${Is.string(type) ? type : type.method} failed.`, error); throw error; } } onRequest(type, handler) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } try { this._resolvedConnection.onRequest(type, handler); } catch (error) { this.error(`Registering request handler ${Is.string(type) ? type : type.method} failed.`, error); throw error; } } sendNotification(type, params) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } this.forceDocumentSync(); try { this._resolvedConnection.sendNotification(type, params); } catch (error) { this.error(`Sending notification ${Is.string(type) ? type : type.method} failed.`, error); throw error; } } onNotification(type, handler) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } try { this._resolvedConnection.onNotification(type, handler); } catch (error) { this.error(`Registering notification handler ${Is.string(type) ? type : type.method} failed.`, error); throw error; } } get clientOptions() { return this._clientOptions; } get protocol2CodeConverter() { return this._p2c; } get code2ProtocolConverter() { return this._c2p; } get onTelemetry() { return this._telemetryEmitter.event; } get onDidChangeState() { return this._stateChangeEmitter.event; } get outputChannel() { if (!this._outputChannel) { this._outputChannel = vscode_1.window.createOutputChannel(this._clientOptions.outputChannelName ? this._clientOptions.outputChannelName : this._name); } return this._outputChannel; } get diagnostics() { return this._diagnostics; } createDefaultErrorHandler() { return new DefaultErrorHandler(this._name); } set trace(value) { this._trace = value; this.onReady().then(() => { this.resolveConnection().then((connection) => { connection.trace(value, this._tracer); }); }, () => { }); } data2String(data) { if (data instanceof vscode_languageserver_protocol_1.ResponseError) { const responseError = data; return ` Message: ${responseError.message}\n Code: ${responseError.code} ${responseError.data ? '\n' + responseError.data.toString() : ''}`; } if (data instanceof Error) { if (Is.string(data.stack)) { return data.stack; } return data.message; } if (Is.string(data)) { return data; } return data.toString(); } info(message, data) { this.outputChannel.appendLine(`[Info - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) { this.outputChannel.show(true); } } warn(message, data) { this.outputChannel.appendLine(`[Warn - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) { this.outputChannel.show(true); } } error(message, data) { this.outputChannel.appendLine(`[Error - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error) { this.outputChannel.show(true); } } logTrace(message, data) { this.outputChannel.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } } needsStart() { return this.state === ClientState.Initial || this.state === ClientState.Stopping || this.state === ClientState.Stopped; } needsStop() { return this.state === ClientState.Starting || this.state === ClientState.Running; } onReady() { return this._onReady; } isConnectionActive() { return this.state === ClientState.Running && !!this._resolvedConnection; } start() { this._listeners = []; this._providers = []; // If we restart then the diagnostics collection is reused. if (!this._diagnostics) { this._diagnostics = this._clientOptions.diagnosticCollectionName ? vscode_1.languages.createDiagnosticCollection(this._clientOptions.diagnosticCollectionName) : vscode_1.languages.createDiagnosticCollection(); } this.state = ClientState.Starting; this.resolveConnection().then((connection) => { connection.onLogMessage((message) => { switch (message.type) { case vscode_languageserver_protocol_1.MessageType.Error: this.error(message.message); break; case vscode_languageserver_protocol_1.MessageType.Warning: this.warn(message.message); break; case vscode_languageserver_protocol_1.MessageType.Info: this.info(message.message); break; default: this.outputChannel.appendLine(message.message); } }); connection.onShowMessage((message) => { switch (message.type) { case vscode_languageserver_protocol_1.MessageType.Error: vscode_1.window.showErrorMessage(message.message); break; case vscode_languageserver_protocol_1.MessageType.Warning: vscode_1.window.showWarningMessage(message.message); break; case vscode_languageserver_protocol_1.MessageType.Info: vscode_1.window.showInformationMessage(message.message); break; default: vscode_1.window.showInformationMessage(message.message); } }); connection.onRequest(vscode_languageserver_protocol_1.ShowMessageRequest.type, (params) => { let messageFunc; switch (params.type) { case vscode_languageserver_protocol_1.MessageType.Error: messageFunc = vscode_1.window.showErrorMessage; break; case vscode_languageserver_protocol_1.MessageType.Warning: messageFunc = vscode_1.window.showWarningMessage; break; case vscode_languageserver_protocol_1.MessageType.Info: messageFunc = vscode_1.window.showInformationMessage; break; default: messageFunc = vscode_1.window.showInformationMessage; } let actions = params.actions || []; return messageFunc(params.message, ...actions); }); connection.onTelemetry((data) => { this._telemetryEmitter.fire(data); }); connection.listen(); // Error is handled in the intialize call. return this.initialize(connection); }).then(undefined, (error) => { this.state = ClientState.StartFailed; this._onReadyCallbacks.reject(error); this.error('Starting client failed', error); vscode_1.window.showErrorMessage(`Couldn't start client ${this._name}`); }); return new vscode_1.Disposable(() => { if (this.needsStop()) { this.stop(); } }); } resolveConnection() { if (!this._connectionPromise) { this._connectionPromise = this.createConnection(); } return this._connectionPromise; } initialize(connection) { this.refreshTrace(connection, false); let initOption = this._clientOptions.initializationOptions; let rootPath = this._clientOptions.workspaceFolder ? this._clientOptions.workspaceFolder.uri.fsPath : this._clientGetRootPath(); let initParams = { processId: process.pid, rootPath: rootPath ? rootPath : null, rootUri: rootPath ? this._c2p.asUri(vscode_1.Uri.file(rootPath)) : null, capabilities: this.computeClientCapabilities(), initializationOptions: Is.func(initOption) ? initOption() : initOption, trace: vscode_languageserver_protocol_1.Trace.toString(this._trace), workspaceFolders: null }; this.fillInitializeParams(initParams); return connection.initialize(initParams).then((result) => { this._resolvedConnection = connection; this._initializeResult = result; this.state = ClientState.Running; let textDocumentSyncOptions = undefined; if (Is.number(result.capabilities.textDocumentSync) && result.capabilities.textDocumentSync !== vscode_languageserver_protocol_1.TextDocumentSyncKind.None) { textDocumentSyncOptions = { openClose: true, change: result.capabilities.textDocumentSync, save: { includeText: false } }; } else if (result.capabilities.textDocumentSync !== void 0 && result.capabilities.textDocumentSync !== null) { textDocumentSyncOptions = result.capabilities.textDocumentSync; } this._capabilities = Object.assign({}, result.capabilities, { resolvedTextDocumentSync: textDocumentSyncOptions }); connection.onDiagnostics(params => this.handleDiagnostics(params)); connection.onRequest(vscode_languageserver_protocol_1.RegistrationRequest.type, params => this.handleRegistrationRequest(params)); // See https://github.com/Microsoft/vscode-languageserver-node/issues/199 connection.onRequest('client/registerFeature', params => this.handleRegistrationRequest(params)); connection.onRequest(vscode_languageserver_protocol_1.UnregistrationRequest.type, params => this.handleUnregistrationRequest(params)); // See https://github.com/Microsoft/vscode-languageserver-node/issues/199 connection.onRequest('client/unregisterFeature', params => this.handleUnregistrationRequest(params)); connection.onRequest(vscode_languageserver_protocol_1.ApplyWorkspaceEditRequest.type, params => this.handleApplyWorkspaceEdit(params)); connection.sendNotification(vscode_languageserver_protocol_1.InitializedNotification.type, {}); this.hookFileEvents(connection); this.hookConfigurationChanged(connection); this.initializeFeatures(connection); this._onReadyCallbacks.resolve(); return result; }).then(undefined, (error) => { if (this._clientOptions.initializationFailedHandler) { if (this._clientOptions.initializationFailedHandler(error)) { this.initialize(connection); } else { this.stop(); this._onReadyCallbacks.reject(error); } } else if (error instanceof vscode_languageserver_protocol_1.ResponseError && error.data && error.data.retry) { vscode_1.window.showErrorMessage(error.message, { title: 'Retry', id: "retry" }).then(item => { if (item && item.id === 'retry') { this.initialize(connection); } else { this.stop(); this._onReadyCallbacks.reject(error); } }); } else { if (error && error.message) { vscode_1.window.showErrorMessage(error.message); } this.error('Server initialization failed.', error); this.stop(); this._onReadyCallbacks.reject(error); } }); } _clientGetRootPath() { let folders = vscode_1.workspace.workspaceFolders; if (!folders || folders.length === 0) { return undefined; } let folder = folders[0]; if (folder.uri.scheme === 'file') { return folder.uri.fsPath; } return undefined; } stop() { this._initializeResult = undefined; if (!this._connectionPromise) { this.state = ClientState.Stopped; return Promise.resolve(); } if (this.state === ClientState.Stopping && this._onStop) { return this._onStop; } this.state = ClientState.Stopping; this.cleanUp(); // unkook listeners return this._onStop = this.resolveConnection().then(connection => { return connection.shutdown().then(() => { connection.exit(); connection.dispose(); this.state = ClientState.Stopped; this._onStop = undefined; this._connectionPromise = undefined; this._resolvedConnection = undefined; }); }); } cleanUp(channel = true, diagnostics = true) { if (this._listeners) { this._listeners.forEach(listener => listener.dispose()); this._listeners = undefined; } if (this._providers) { this._providers.forEach(provider => provider.dispose()); this._providers = undefined; } if (this._syncedDocuments) { this._syncedDocuments.clear(); } for (let handler of this._dynamicFeatures.values()) { handler.dispose(); } if (channel && this._outputChannel && this._disposeOutputChannel) { this._outputChannel.dispose(); this._outputChannel = undefined; } if (diagnostics && this._diagnostics) { this._diagnostics.dispose(); this._diagnostics = undefined; } } notifyFileEvent(event) { this._fileEvents.push(event); this._fileEventDelayer.trigger(() => { this.onReady().then(() => { this.resolveConnection().then(connection => { if (this.isConnectionActive()) { connection.didChangeWatchedFiles({ changes: this._fileEvents }); } this._fileEvents = []; }); }, (error) => { this.error(`Notify file events failed.`, error); }); }); } forceDocumentSync() { this._dynamicFeatures.get(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type.method).forceDelivery(); } handleDiagnostics(params) { if (!this._diagnostics) { return; } let uri = this._p2c.asUri(params.uri); let diagnostics = this._p2c.asDiagnostics(params.diagnostics); let middleware = this.clientOptions.middleware.handleDiagnostics; if (middleware) { middleware(uri, diagnostics, (uri, diagnostics) => this.setDiagnostics(uri, diagnostics)); } else { this.setDiagnostics(uri, diagnostics); } } setDiagnostics(uri, diagnostics) { if (!this._diagnostics) { return; } this._diagnostics.set(uri, diagnostics); } createConnection() { let errorHandler = (error, message, count) => { this.handleConnectionError(error, message, count); }; let closeHandler = () => { this.handleConnectionClosed(); }; return this.createMessageTransports(this._clientOptions.stdioEncoding || 'utf8').then((transports) => { return createConnection(transports.reader, transports.writer, errorHandler, closeHandler); }); } handleConnectionClosed() { // Check whether this is a normal shutdown in progress or the client stopped normally. if (this.state === ClientState.Stopping || this.state === ClientState.Stopped) { return; } try { if (this._resolvedConnection) { this._resolvedConnection.dispose(); } } catch (error) { // Disposing a connection could fail if error cases. } let action = CloseAction.DoNotRestart; try { action = this._clientOptions.errorHandler.closed(); } catch (error) { // Ignore errors coming from the error handler. } this._connectionPromise = undefined; this._resolvedConnection = undefined; if (action === CloseAction.DoNotRestart) { this.error('Connection to server got closed. Server will not be restarted.'); this.state = ClientState.Stopped; this.cleanUp(false, true); } else if (action === CloseAction.Restart) { this.info('Connection to server got closed. Server will restart.'); this.cleanUp(false, false); this.state = ClientState.Initial; this.start(); } } handleConnectionError(error, message, count) { let action = this._clientOptions.errorHandler.error(error, message, count); if (action === ErrorAction.Shutdown) { this.error('Connection to server is erroring. Shutting down server.'); this.stop(); } } hookConfigurationChanged(connection) { vscode_1.workspace.onDidChangeConfiguration(() => { this.refreshTrace(connection, true); }); } refreshTrace(connection, sendNotification = false) { let config = vscode_1.workspace.getConfiguration(this._id); let trace = vscode_languageserver_protocol_1.Trace.Off; if (config) { trace = vscode_languageserver_protocol_1.Trace.fromString(config.get('trace.server', 'off')); } this._trace = trace; connection.trace(this._trace, this._tracer, sendNotification); } hookFileEvents(_connection) { let fileEvents = this._clientOptions.synchronize.fileEvents; if (!fileEvents) { return; } let watchers; if (Is.array(fileEvents)) { watchers = fileEvents; } else { watchers = [fileEvents]; } if (!watchers) { return; } this._dynamicFeatures.get(vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type.method).registerRaw(UUID.generateUuid(), watchers); } registerFeatures(features) { for (let feature of features) { this.registerFeature(feature); } } registerFeature(feature) { this._features.push(feature); if (DynamicFeature.is(feature)) { let messages = feature.messages; if (Array.isArray(messages)) { for (let message of messages) { this._method2Message.set(message.method, message); this._dynamicFeatures.set(message.method, feature); } } else { this._method2Message.set(messages.method, messages); this._dynamicFeatures.set(messages.method, feature); } } } registerBuiltinFeatures() { this.registerFeature(new ConfigurationFeature(this)); this.registerFeature(new DidOpenTextDocumentFeature(this, this._syncedDocuments)); this.registerFeature(new DidChangeTextDocumentFeature(this)); this.registerFeature(new WillSaveFeature(this)); this.registerFeature(new WillSaveWaitUntilFeature(this)); this.registerFeature(new DidSaveTextDocumentFeature(this)); this.registerFeature(new DidCloseTextDocumentFeature(this, this._syncedDocuments)); this.registerFeature(new FileSystemWatcherFeature(this, (event) => this.notifyFileEvent(event))); this.registerFeature(new CompletionItemFeature(this)); this.registerFeature(new HoverFeature(this)); this.registerFeature(new SignatureHelpFeature(this)); this.registerFeature(new DefinitionFeature(this)); this.registerFeature(new ReferencesFeature(this)); this.registerFeature(new DocumentHighlightFeature(this)); this.registerFeature(new DocumentSymbolFeature(this)); this.registerFeature(new WorkspaceSymbolFeature(this)); this.registerFeature(new CodeActionFeature(this)); this.registerFeature(new CodeLensFeature(this)); this.registerFeature(new DocumentFormattingFeature(this)); this.registerFeature(new DocumentRangeFormattingFeature(this)); this.registerFeature(new DocumentOnTypeFormattingFeature(this)); this.registerFeature(new RenameFeature(this)); this.registerFeature(new DocumentLinkFeature(this)); this.registerFeature(new ExecuteCommandFeature(this)); } fillInitializeParams(params) { for (let feature of this._features) { if (Is.func(feature.fillInitializeParams)) { feature.fillInitializeParams(params); } } } computeClientCapabilities() { let result = {}; ensure(result, 'workspace').applyEdit = true; ensure(ensure(result, 'workspace'), 'workspaceEdit').documentChanges = true; ensure(ensure(result, 'textDocument'), 'publishDiagnostics').relatedInformation = true; for (let feature of this._features) { feature.fillClientCapabilities(result); } return result; } initializeFeatures(_connection) { let documentSelector = this._clientOptions.documentSelector; for (let feature of this._features) { feature.initialize(this._capabilities, documentSelector); } } handleRegistrationRequest(params) { return new Promise((resolve, reject) => { for (let registration of params.registrations) { const feature = this._dynamicFeatures.get(registration.method); if (!feature) { reject(new Error(`No feature implementation for ${registration.method} found. Registration failed.`)); return; } const options = registration.registerOptions || {}; options.documentSelector = options.documentSelector || this._clientOptions.documentSelector; const data = { id: registration.id, registerOptions: options }; feature.register(this._method2Message.get(registration.method), data); } resolve(); }); } handleUnregistrationRequest(params) { return new Promise((resolve, reject) => { for (let unregistration of params.unregisterations) { const feature = this._dynamicFeatures.get(unregistration.method); if (!feature) { reject(new Error(`No feature implementation for ${unregistration.method} found. Unregistration failed.`)); return; } feature.unregister(unregistration.id); } ; resolve(); }); } handleApplyWorkspaceEdit(params) { // This is some sort of workaround since the version check should be done by VS Code in the Workspace.applyEdit. // However doing it here adds some safety since the server can lag more behind then an extension. let workspaceEdit = params.edit; let openTextDocuments = new Map(); vscode_1.workspace.textDocuments.forEach((document) => openTextDocuments.set(document.uri.toString(), document)); let versionMismatch = false; if (workspaceEdit.documentChanges) { for (const change of workspaceEdit.documentChanges) { if (change.textDocument.version && change.textDocument.version >= 0) { let textDocument = openTextDocuments.get(change.textDocument.uri); if (textDocument && textDocument.version !== change.textDocument.version) { versionMismatch = true; break; } } } } if (versionMismatch) { return Promise.resolve({ applied: false }); } return vscode_1.workspace.applyEdit(this._p2c.asWorkspaceEdit(params.edit)).then((value) => { return { applied: value }; }); } ; logFailedRequest(type, error) { // If we get a request cancel don't log anything. if (error instanceof vscode_languageserver_protocol_1.ResponseError && error.code === vscode_languageserver_protocol_1.ErrorCodes.RequestCancelled) { return; } this.error(`Request ${type.method} failed.`, error); } } exports.BaseLanguageClient = BaseLanguageClient;