"use strict"; /* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseLanguageClient = exports.MessageTransports = exports.TextDocumentFeature = exports.State = exports.RevealOutputChannelOn = exports.CloseAction = exports.ErrorAction = void 0; const vscode_1 = require("vscode"); const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol"); const configuration_1 = require("./configuration"); const c2p = require("./codeConverter"); const p2c = require("./protocolConverter"); const Is = require("./utils/is"); const async_1 = require("./utils/async"); const UUID = require("./utils/uuid"); const progressPart_1 = require("./progressPart"); class ConsoleLogger { error(message) { vscode_languageserver_protocol_1.RAL().console.error(message); } warn(message) { vscode_languageserver_protocol_1.RAL().console.warn(message); } info(message) { vscode_languageserver_protocol_1.RAL().console.info(message); } log(message) { vscode_languageserver_protocol_1.RAL().console.log(message); } } function createConnection(input, output, errorHandler, closeHandler, options) { let logger = new ConsoleLogger(); let connection = vscode_languageserver_protocol_1.createProtocolConnection(input, output, logger, options); 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), onProgress: connection.onProgress, sendProgress: connection.sendProgress, trace: (value, tracer, sendNotificationOrTraceOptions) => { const defaultTraceOptions = { sendNotification: false, traceFormat: vscode_languageserver_protocol_1.TraceFormat.Text }; if (sendNotificationOrTraceOptions === undefined) { connection.trace(value, tracer, defaultTraceOptions); } else if (Is.boolean(sendNotificationOrTraceOptions)) { connection.trace(value, tracer, sendNotificationOrTraceOptions); } else { connection.trace(value, tracer, sendNotificationOrTraceOptions); } }, 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), end: () => connection.end(), 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, maxRestartCount) { this.name = name; this.maxRestartCount = maxRestartCount; 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 <= this.maxRestartCount) { 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 ${this.maxRestartCount + 1} 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["Starting"] = 3] = "Starting"; 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 SupportedSymbolKinds = [ 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 ]; const SupportedSymbolTags = [ vscode_languageserver_protocol_1.SymbolTag.Deprecated ]; function ensure(target, key) { if (target[key] === undefined) { target[key] = {}; } return target[key]; } var FileFormattingOptions; (function (FileFormattingOptions) { function fromConfiguration(document) { const filesConfig = vscode_1.workspace.getConfiguration('files', document); return { trimTrailingWhitespace: filesConfig.get('trimTrailingWhitespace'), trimFinalNewlines: filesConfig.get('trimFinalNewlines'), insertFinalNewline: filesConfig.get('insertFinalNewline'), }; } FileFormattingOptions.fromConfiguration = fromConfiguration; })(FileFormattingOptions || (FileFormattingOptions = {})); 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.registrationType !== undefined; } DynamicFeature.is = is; })(DynamicFeature || (DynamicFeature = {})); class DocumentNotifications { 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(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(); this._listener = undefined; } } getProvider(document) { for (const selector of this._selectors.values()) { if (vscode_1.languages.match(selector, document)) { return { send: (data) => { this.callback(data); } }; } } return undefined; } } class DidOpenTextDocumentFeature extends DocumentNotifications { constructor(client, _syncedDocuments) { super(client, vscode_1.workspace.onDidOpenTextDocument, vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type, client.clientOptions.middleware.didOpen, (textDocument) => client.code2ProtocolConverter.asOpenTextDocumentParams(textDocument), DocumentNotifications.textDocumentFilter); this._syncedDocuments = _syncedDocuments; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true; } initialize(capabilities, documentSelector) { let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) { this.register({ id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } get registrationType() { return vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type; } register(data) { super.register(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 DocumentNotifications { constructor(client, _syncedDocuments) { super(client, vscode_1.workspace.onDidCloseTextDocument, vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type, client.clientOptions.middleware.didClose, (textDocument) => client.code2ProtocolConverter.asCloseTextDocumentParams(textDocument), DocumentNotifications.textDocumentFilter); this._syncedDocuments = _syncedDocuments; } get registrationType() { 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({ 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 registrationType() { 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 !== undefined && textDocumentSyncOptions.change !== vscode_languageserver_protocol_1.TextDocumentSyncKind.None) { this.register({ id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, { syncKind: textDocumentSyncOptions.change }) }); } } register(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 / un-dirty 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; } } getProvider(document) { for (const changeData of this._changeData.values()) { if (vscode_1.languages.match(changeData.documentSelector, document)) { return { send: (event) => { this.callback(event); } }; } } return undefined; } } class WillSaveFeature extends DocumentNotifications { 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) => DocumentNotifications.textDocumentFilter(selectors, willSaveEvent.document)); } get registrationType() { 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({ id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } } class WillSaveWaitUntilFeature { constructor(_client) { this._client = _client; this._selectors = new Map(); } get registrationType() { 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({ id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } }); } } register(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 (DocumentNotifications.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 === undefined ? [] : 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 DocumentNotifications { 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), DocumentNotifications.textDocumentFilter); this._includeText = false; } get registrationType() { return vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'synchronization').didSave = true; } initialize(capabilities, documentSelector) { const textDocumentSyncOptions = capabilities.resolvedTextDocumentSync; if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.save) { const saveOptions = typeof textDocumentSyncOptions.save === 'boolean' ? { includeText: false } : { includeText: !!textDocumentSyncOptions.save.includeText }; this.register({ id: UUID.generateUuid(), registerOptions: Object.assign({}, { documentSelector: documentSelector }, saveOptions) }); } } register(data) { this._includeText = !!data.registerOptions.includeText; super.register(data); } } class FileSystemWatcherFeature { constructor(_client, _notifyFileEvent) { this._client = _client; this._notifyFileEvent = _notifyFileEvent; this._watchers = new Map(); } get registrationType() { return vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'workspace'), 'didChangeWatchedFiles').dynamicRegistration = true; } initialize(_capabilities, _documentSelector) { } register(data) { if (!Array.isArray(data.registerOptions.watchers)) { return; } let disposables = []; for (let watcher of data.registerOptions.watchers) { if (!Is.string(watcher.globPattern)) { continue; } let watchCreate = true, watchChange = true, watchDelete = true; if (watcher.kind !== undefined && 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); disposables.push(fileSystemWatcher); } this._watchers.set(data.id, disposables); } registerRaw(id, fileSystemWatchers) { let disposables = []; for (let fileSystemWatcher of fileSystemWatchers) { this.hookListeners(fileSystemWatcher, true, true, true, disposables); } this._watchers.set(id, disposables); } 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 disposables = this._watchers.get(id); if (disposables) { for (let disposable of disposables) { disposable.dispose(); } } } dispose() { this._watchers.forEach((disposables) => { for (let disposable of disposables) { disposable.dispose(); } }); this._watchers.clear(); } } class TextDocumentFeature { constructor(_client, _registrationType) { this._client = _client; this._registrationType = _registrationType; this._registrations = new Map(); } get registrationType() { return this._registrationType; } register(data) { if (!data.registerOptions.documentSelector) { return; } let registration = this.registerLanguageProvider(data.registerOptions); this._registrations.set(data.id, { disposable: registration[0], data, provider: registration[1] }); } unregister(id) { let registration = this._registrations.get(id); if (registration !== undefined) { registration.disposable.dispose(); } } dispose() { this._registrations.forEach((value) => { value.disposable.dispose(); }); this._registrations.clear(); } getRegistration(documentSelector, capability) { if (!capability) { return [undefined, undefined]; } else if (vscode_languageserver_protocol_1.TextDocumentRegistrationOptions.is(capability)) { const id = vscode_languageserver_protocol_1.StaticRegistrationOptions.hasId(capability) ? capability.id : UUID.generateUuid(); const selector = capability.documentSelector || documentSelector; if (selector) { return [id, Object.assign({}, capability, { documentSelector: selector })]; } } else if (Is.boolean(capability) && capability === true || vscode_languageserver_protocol_1.WorkDoneProgressOptions.is(capability)) { if (!documentSelector) { return [undefined, undefined]; } let options = (Is.boolean(capability) && capability === true ? { documentSelector } : Object.assign({}, capability, { documentSelector })); return [UUID.generateUuid(), options]; } return [undefined, undefined]; } getRegistrationOptions(documentSelector, capability) { if (!documentSelector || !capability) { return undefined; } return (Is.boolean(capability) && capability === true ? { documentSelector } : Object.assign({}, capability, { documentSelector })); } getProvider(textDocument) { for (const registration of this._registrations.values()) { let selector = registration.data.registerOptions.documentSelector; if (selector !== null && vscode_1.languages.match(selector, textDocument)) { return registration.provider; } } return undefined; } getAllProviders() { const result = []; for (const item of this._registrations.values()) { result.push(item.provider); } return result; } } exports.TextDocumentFeature = TextDocumentFeature; class WorkspaceFeature { constructor(_client, _registrationType) { this._client = _client; this._registrationType = _registrationType; this._registrations = new Map(); } get registrationType() { return this._registrationType; } register(data) { const registration = this.registerLanguageProvider(data.registerOptions); this._registrations.set(data.id, { disposable: registration[0], provider: registration[1] }); } unregister(id) { let registration = this._registrations.get(id); if (registration !== undefined) { registration.disposable.dispose(); } } dispose() { this._registrations.forEach((registration) => { registration.disposable.dispose(); }); this._registrations.clear(); } getProviders() { const result = []; for (const registration of this._registrations.values()) { result.push(registration.provider); } return result; } } class CompletionItemFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CompletionRequest.type); } fillClientCapabilities(capabilities) { let completion = ensure(ensure(capabilities, '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, tagSupport: { valueSet: [vscode_languageserver_protocol_1.CompletionItemTag.Deprecated] }, insertReplaceSupport: true, resolveSupport: { properties: ['documentation', 'detail', 'additionalTextEdits'] }, insertTextModeSupport: { valueSet: [vscode_languageserver_protocol_1.InsertTextMode.asIs, vscode_languageserver_protocol_1.InsertTextMode.adjustIndentation] } }; completion.completionItemKind = { valueSet: SupportedCompletionItemKinds }; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.completionProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const triggerCharacters = options.triggerCharacters || []; const provider = { provideCompletionItems: (document, position, token, context) => { const client = this._client; const middleware = this._client.clientOptions.middleware; const 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) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CompletionRequest.type, error, null); }); }; return middleware.provideCompletionItem ? middleware.provideCompletionItem(document, position, context, token, provideCompletionItems) : provideCompletionItems(document, position, context, token); }, resolveCompletionItem: options.resolveProvider ? (item, token) => { const client = this._client; const middleware = this._client.clientOptions.middleware; const resolveCompletionItem = (item, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, client.code2ProtocolConverter.asCompletionItem(item), token).then(client.protocol2CodeConverter.asCompletionItem, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, error, item); }); }; return middleware.resolveCompletionItem ? middleware.resolveCompletionItem(item, token, resolveCompletionItem) : resolveCompletionItem(item, token); } : undefined }; return [vscode_1.languages.registerCompletionItemProvider(options.documentSelector, provider, ...triggerCharacters), provider]; } } class HoverFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.HoverRequest.type); } fillClientCapabilities(capabilities) { const hoverCapability = (ensure(ensure(capabilities, 'textDocument'), 'hover')); hoverCapability.dynamicRegistration = true; hoverCapability.contentFormat = [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText]; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.hoverProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideHover: (document, position, token) => { const client = this._client; const provideHover = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asHover, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.HoverRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideHover ? middleware.provideHover(document, position, token, provideHover) : provideHover(document, position, token); } }; return [vscode_1.languages.registerHoverProvider(options.documentSelector, provider), provider]; } } class SignatureHelpFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.SignatureHelpRequest.type); } fillClientCapabilities(capabilities) { let config = ensure(ensure(capabilities, 'textDocument'), 'signatureHelp'); config.dynamicRegistration = true; config.signatureInformation = { documentationFormat: [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText] }; config.signatureInformation.parameterInformation = { labelOffsetSupport: true }; config.signatureInformation.activeParameterSupport = true; config.contextSupport = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.signatureHelpProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideSignatureHelp: (document, position, token, context) => { const client = this._client; const providerSignatureHelp = (document, position, context, token) => { return client.sendRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, client.code2ProtocolConverter.asSignatureHelpParams(document, position, context), token).then(client.protocol2CodeConverter.asSignatureHelp, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideSignatureHelp ? middleware.provideSignatureHelp(document, position, context, token, providerSignatureHelp) : providerSignatureHelp(document, position, context, token); } }; let disposable; if (options.retriggerCharacters === undefined) { const triggerCharacters = options.triggerCharacters || []; disposable = vscode_1.languages.registerSignatureHelpProvider(options.documentSelector, provider, ...triggerCharacters); } else { const metaData = { triggerCharacters: options.triggerCharacters || [], retriggerCharacters: options.retriggerCharacters || [] }; disposable = vscode_1.languages.registerSignatureHelpProvider(options.documentSelector, provider, metaData); } return [disposable, provider]; } } class DefinitionFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DefinitionRequest.type); } fillClientCapabilities(capabilities) { let definitionSupport = ensure(ensure(capabilities, 'textDocument'), 'definition'); definitionSupport.dynamicRegistration = true; definitionSupport.linkSupport = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.definitionProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDefinition: (document, position, token) => { const client = this._client; const provideDefinition = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDefinitionResult, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDefinition ? middleware.provideDefinition(document, position, token, provideDefinition) : provideDefinition(document, position, token); } }; return [vscode_1.languages.registerDefinitionProvider(options.documentSelector, provider), provider]; } } class ReferencesFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.ReferencesRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'references').dynamicRegistration = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.referencesProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideReferences: (document, position, options, token) => { const client = this._client; const _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) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.ReferencesRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideReferences ? middleware.provideReferences(document, position, options, token, _providerReferences) : _providerReferences(document, position, options, token); } }; return [vscode_1.languages.registerReferenceProvider(options.documentSelector, provider), provider]; } } class DocumentHighlightFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentHighlightRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'documentHighlight').dynamicRegistration = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentHighlightProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDocumentHighlights: (document, position, token) => { const client = this._client; const _provideDocumentHighlights = (document, position, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDocumentHighlights, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDocumentHighlights ? middleware.provideDocumentHighlights(document, position, token, _provideDocumentHighlights) : _provideDocumentHighlights(document, position, token); } }; return [vscode_1.languages.registerDocumentHighlightProvider(options.documentSelector, provider), provider]; } } class DocumentSymbolFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentSymbolRequest.type); } fillClientCapabilities(capabilities) { let symbolCapabilities = ensure(ensure(capabilities, 'textDocument'), 'documentSymbol'); symbolCapabilities.dynamicRegistration = true; symbolCapabilities.symbolKind = { valueSet: SupportedSymbolKinds }; symbolCapabilities.hierarchicalDocumentSymbolSupport = true; symbolCapabilities.tagSupport = { valueSet: SupportedSymbolTags }; symbolCapabilities.labelSupport = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentSymbolProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDocumentSymbols: (document, token) => { const client = this._client; const _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) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentSymbolRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDocumentSymbols ? middleware.provideDocumentSymbols(document, token, _provideDocumentSymbols) : _provideDocumentSymbols(document, token); } }; const metaData = options.label !== undefined ? { label: options.label } : undefined; return [vscode_1.languages.registerDocumentSymbolProvider(options.documentSelector, provider, metaData), provider]; } } class WorkspaceSymbolFeature extends WorkspaceFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type); } fillClientCapabilities(capabilities) { let symbolCapabilities = ensure(ensure(capabilities, 'workspace'), 'symbol'); symbolCapabilities.dynamicRegistration = true; symbolCapabilities.symbolKind = { valueSet: SupportedSymbolKinds }; symbolCapabilities.tagSupport = { valueSet: SupportedSymbolTags }; } initialize(capabilities) { if (!capabilities.workspaceSymbolProvider) { return; } this.register({ id: UUID.generateUuid(), registerOptions: capabilities.workspaceSymbolProvider === true ? { workDoneProgress: false } : capabilities.workspaceSymbolProvider }); } registerLanguageProvider(_options) { const provider = { provideWorkspaceSymbols: (query, token) => { const client = this._client; const provideWorkspaceSymbols = (query, token) => { return client.sendRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, { query }, token).then(client.protocol2CodeConverter.asSymbolInformations, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideWorkspaceSymbols ? middleware.provideWorkspaceSymbols(query, token, provideWorkspaceSymbols) : provideWorkspaceSymbols(query, token); } }; return [vscode_1.languages.registerWorkspaceSymbolProvider(provider), provider]; } } class CodeActionFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CodeActionRequest.type); } fillClientCapabilities(capabilities) { const cap = ensure(ensure(capabilities, 'textDocument'), 'codeAction'); cap.dynamicRegistration = true; cap.isPreferredSupport = true; cap.disabledSupport = true; cap.dataSupport = true; // We can only resolve the edit property. cap.resolveSupport = { properties: ['edit'] }; cap.codeActionLiteralSupport = { codeActionKind: { valueSet: [ vscode_languageserver_protocol_1.CodeActionKind.Empty, 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 ] } }; cap.honorsChangeAnnotations = false; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.codeActionProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideCodeActions: (document, range, context, token) => { const client = this._client; const _provideCodeActions = (document, range, context, token) => { const 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; } const 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) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CodeActionRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideCodeActions ? middleware.provideCodeActions(document, range, context, token, _provideCodeActions) : _provideCodeActions(document, range, context, token); }, resolveCodeAction: options.resolveProvider ? (item, token) => { const client = this._client; const middleware = this._client.clientOptions.middleware; const resolveCodeAction = (item, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CodeActionResolveRequest.type, client.code2ProtocolConverter.asCodeAction(item), token).then(client.protocol2CodeConverter.asCodeAction, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CodeActionResolveRequest.type, error, item); }); }; return middleware.resolveCodeAction ? middleware.resolveCodeAction(item, token, resolveCodeAction) : resolveCodeAction(item, token); } : undefined }; return [vscode_1.languages.registerCodeActionsProvider(options.documentSelector, provider, (options.codeActionKinds ? { providedCodeActionKinds: this._client.protocol2CodeConverter.asCodeActionKinds(options.codeActionKinds) } : undefined)), provider]; } } class CodeLensFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.CodeLensRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'codeLens').dynamicRegistration = true; ensure(ensure(capabilities, 'workspace'), 'codeLens').refreshSupport = true; } initialize(capabilities, documentSelector) { const client = this._client; client.onRequest(vscode_languageserver_protocol_1.CodeLensRefreshRequest.type, async () => { for (const provider of this.getAllProviders()) { provider.onDidChangeCodeLensEmitter.fire(); } }); const options = this.getRegistrationOptions(documentSelector, capabilities.codeLensProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const eventEmitter = new vscode_1.EventEmitter(); const provider = { onDidChangeCodeLenses: eventEmitter.event, provideCodeLenses: (document, token) => { const client = this._client; const provideCodeLenses = (document, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, client.code2ProtocolConverter.asCodeLensParams(document), token).then(client.protocol2CodeConverter.asCodeLenses, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideCodeLenses ? middleware.provideCodeLenses(document, token, provideCodeLenses) : provideCodeLenses(document, token); }, resolveCodeLens: (options.resolveProvider) ? (codeLens, token) => { const client = this._client; const resolveCodeLens = (codeLens, token) => { return client.sendRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, client.code2ProtocolConverter.asCodeLens(codeLens), token).then(client.protocol2CodeConverter.asCodeLens, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, error, codeLens); }); }; const middleware = client.clientOptions.middleware; return middleware.resolveCodeLens ? middleware.resolveCodeLens(codeLens, token, resolveCodeLens) : resolveCodeLens(codeLens, token); } : undefined }; return [vscode_1.languages.registerCodeLensProvider(options.documentSelector, provider), { provider, onDidChangeCodeLensEmitter: eventEmitter }]; } } class DocumentFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentFormattingRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'formatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentFormattingProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDocumentFormattingEdits: (document, options, token) => { const client = this._client; const provideDocumentFormattingEdits = (document, options, token) => { const params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), options: client.code2ProtocolConverter.asFormattingOptions(options, FileFormattingOptions.fromConfiguration(document)) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDocumentFormattingEdits ? middleware.provideDocumentFormattingEdits(document, options, token, provideDocumentFormattingEdits) : provideDocumentFormattingEdits(document, options, token); } }; return [vscode_1.languages.registerDocumentFormattingEditProvider(options.documentSelector, provider), provider]; } } class DocumentRangeFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'rangeFormatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentRangeFormattingProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDocumentRangeFormattingEdits: (document, range, options, token) => { const client = this._client; const provideDocumentRangeFormattingEdits = (document, range, options, token) => { const params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), range: client.code2ProtocolConverter.asRange(range), options: client.code2ProtocolConverter.asFormattingOptions(options, FileFormattingOptions.fromConfiguration(document)) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDocumentRangeFormattingEdits ? middleware.provideDocumentRangeFormattingEdits(document, range, options, token, provideDocumentRangeFormattingEdits) : provideDocumentRangeFormattingEdits(document, range, options, token); } }; return [vscode_1.languages.registerDocumentRangeFormattingEditProvider(options.documentSelector, provider), provider]; } } class DocumentOnTypeFormattingFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type); } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'textDocument'), 'onTypeFormatting').dynamicRegistration = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentOnTypeFormattingProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideOnTypeFormattingEdits: (document, position, ch, options, token) => { const client = this._client; const 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, FileFormattingOptions.fromConfiguration(document)) }; return client.sendRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideOnTypeFormattingEdits ? middleware.provideOnTypeFormattingEdits(document, position, ch, options, token, provideOnTypeFormattingEdits) : provideOnTypeFormattingEdits(document, position, ch, options, token); } }; const moreTriggerCharacter = options.moreTriggerCharacter || []; return [vscode_1.languages.registerOnTypeFormattingEditProvider(options.documentSelector, provider, options.firstTriggerCharacter, ...moreTriggerCharacter), provider]; } } class RenameFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.RenameRequest.type); } fillClientCapabilities(capabilities) { let rename = ensure(ensure(capabilities, 'textDocument'), 'rename'); rename.dynamicRegistration = true; rename.prepareSupport = true; rename.prepareSupportDefaultBehavior = vscode_languageserver_protocol_1.PrepareSupportDefaultBehavior.Identifier; rename.honorsChangeAnnotations = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.renameProvider); if (!options) { return; } if (Is.boolean(capabilities.renameProvider)) { options.prepareProvider = false; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideRenameEdits: (document, position, newName, token) => { const client = this._client; const 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) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.RenameRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideRenameEdits ? middleware.provideRenameEdits(document, position, newName, token, provideRenameEdits) : provideRenameEdits(document, position, newName, token); }, prepareRename: options.prepareProvider ? (document, position, token) => { const client = this._client; const prepareRename = (document, position, token) => { let params = { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document), position: client.code2ProtocolConverter.asPosition(position), }; return client.sendRequest(vscode_languageserver_protocol_1.PrepareRenameRequest.type, params, token).then((result) => { if (vscode_languageserver_protocol_1.Range.is(result)) { return client.protocol2CodeConverter.asRange(result); } else if (this.isDefaultBehavior(result)) { return result.defaultBehavior === true ? null : Promise.reject(new Error(`The element can't be renamed.`)); } else if (result && vscode_languageserver_protocol_1.Range.is(result.range)) { return { range: client.protocol2CodeConverter.asRange(result.range), placeholder: result.placeholder }; } // To cancel the rename vscode API expects a rejected promise. return Promise.reject(new Error(`The element can't be renamed.`)); }, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.PrepareRenameRequest.type, error, undefined); }); }; const middleware = client.clientOptions.middleware; return middleware.prepareRename ? middleware.prepareRename(document, position, token, prepareRename) : prepareRename(document, position, token); } : undefined }; return [vscode_1.languages.registerRenameProvider(options.documentSelector, provider), provider]; } isDefaultBehavior(value) { const candidate = value; return candidate && Is.boolean(candidate.defaultBehavior); } } class DocumentLinkFeature extends TextDocumentFeature { constructor(client) { super(client, vscode_languageserver_protocol_1.DocumentLinkRequest.type); } fillClientCapabilities(capabilities) { const documentLinkCapabilities = ensure(ensure(capabilities, 'textDocument'), 'documentLink'); documentLinkCapabilities.dynamicRegistration = true; documentLinkCapabilities.tooltipSupport = true; } initialize(capabilities, documentSelector) { const options = this.getRegistrationOptions(documentSelector, capabilities.documentLinkProvider); if (!options) { return; } this.register({ id: UUID.generateUuid(), registerOptions: options }); } registerLanguageProvider(options) { const provider = { provideDocumentLinks: (document, token) => { const client = this._client; const provideDocumentLinks = (document, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, client.code2ProtocolConverter.asDocumentLinkParams(document), token).then(client.protocol2CodeConverter.asDocumentLinks, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, error, null); }); }; const middleware = client.clientOptions.middleware; return middleware.provideDocumentLinks ? middleware.provideDocumentLinks(document, token, provideDocumentLinks) : provideDocumentLinks(document, token); }, resolveDocumentLink: options.resolveProvider ? (link, token) => { const client = this._client; let resolveDocumentLink = (link, token) => { return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, client.code2ProtocolConverter.asDocumentLink(link), token).then(client.protocol2CodeConverter.asDocumentLink, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, error, link); }); }; const middleware = client.clientOptions.middleware; return middleware.resolveDocumentLink ? middleware.resolveDocumentLink(link, token, resolveDocumentLink) : resolveDocumentLink(link, token); } : undefined }; return [vscode_1.languages.registerDocumentLinkProvider(options.documentSelector, provider), provider]; } } class ConfigurationFeature { constructor(_client) { this._client = _client; this._listeners = new Map(); } get registrationType() { 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 !== undefined) { this.register({ id: UUID.generateUuid(), registerOptions: { section: section } }); } } register(data) { let disposable = vscode_1.workspace.onDidChangeConfiguration((event) => { this.onDidChangeConfiguration(data.registerOptions.section, event); }); this._listeners.set(data.id, disposable); if (data.registerOptions.section !== undefined) { 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 !== undefined && event !== undefined) { let affected = sections.some((section) => event.affectsConfiguration(section)); if (!affected) { return; } } let didChangeConfiguration = (sections) => { if (sections === undefined) { 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(undefined, resource).get(key); } if (config) { let path = keys[i].split('.'); ensurePath(result, path)[path[path.length - 1]] = configuration_1.toJSONObject(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 registrationType() { return vscode_languageserver_protocol_1.ExecuteCommandRequest.type; } fillClientCapabilities(capabilities) { ensure(ensure(capabilities, 'workspace'), 'executeCommand').dynamicRegistration = true; } initialize(capabilities) { if (!capabilities.executeCommandProvider) { return; } this.register({ id: UUID.generateUuid(), registerOptions: Object.assign({}, capabilities.executeCommandProvider) }); } register(data) { const client = this._client; const middleware = client.clientOptions.middleware; const executeCommand = (command, args) => { let params = { command, arguments: args }; return client.sendRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, params).then(undefined, (error) => { return client.handleFailedRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, error, undefined); }); }; if (data.registerOptions.commands) { const disposables = []; for (const command of data.registerOptions.commands) { disposables.push(vscode_1.commands.registerCommand(command, (...args) => { return middleware.executeCommand ? middleware.executeCommand(command, args, executeCommand) : executeCommand(command, args); })); } this._commands.set(data.id, disposables); } } unregister(id) { let disposables = this._commands.get(id); if (disposables) { disposables.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 OnReady { constructor(_resolve, _reject) { this._resolve = _resolve; this._reject = _reject; this._used = false; } get isUsed() { return this._used; } resolve() { this._used = true; this._resolve(); } reject(error) { this._used = true; this._reject(error); } } class BaseLanguageClient { constructor(id, name, clientOptions) { var _a; this._traceFormat = vscode_languageserver_protocol_1.TraceFormat.Text; this._features = []; this._dynamicFeatures = new Map(); this._id = id; this._name = name; clientOptions = clientOptions || {}; const markdown = { isTrusted: false }; if (clientOptions.markdown !== undefined && clientOptions.markdown.isTrusted === true) { markdown.isTrusted = true; } 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, progressOnInitialization: !!clientOptions.progressOnInitialization, errorHandler: clientOptions.errorHandler || this.createDefaultErrorHandler((_a = clientOptions.connectionOptions) === null || _a === void 0 ? void 0 : _a.maxRestartCount), middleware: clientOptions.middleware || {}, uriConverters: clientOptions.uriConverters, workspaceFolder: clientOptions.workspaceFolder, connectionOptions: clientOptions.connectionOptions, markdown }; 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._traceOutputChannel = clientOptions.traceOutputChannel; 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 = new OnReady(resolve, reject); }); this._onStop = undefined; this._telemetryEmitter = new vscode_languageserver_protocol_1.Emitter(); this._stateChangeEmitter = new vscode_languageserver_protocol_1.Emitter(); this._trace = vscode_languageserver_protocol_1.Trace.Off; this._tracer = { log: (messageOrDataObject, data) => { if (Is.string(messageOrDataObject)) { this.logTrace(messageOrDataObject, data); } else { this.logObjectTrace(messageOrDataObject); } }, }; this._c2p = c2p.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined); this._p2c = p2c.createConverter(clientOptions.uriConverters ? clientOptions.uriConverters.protocol2Code : undefined, this._clientOptions.markdown.isTrusted); 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 if (this.state === ClientState.Starting) { return State.Starting; } 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 { return 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 { return this._resolvedConnection.onNotification(type, handler); } catch (error) { this.error(`Registering notification handler ${Is.string(type) ? type : type.method} failed.`, error); throw error; } } onProgress(type, token, handler) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } try { if (vscode_languageserver_protocol_1.WorkDoneProgress.is(type)) { const handleWorkDoneProgress = this._clientOptions.middleware.handleWorkDoneProgress; if (handleWorkDoneProgress !== undefined) { return this._resolvedConnection.onProgress(type, token, (params) => { handleWorkDoneProgress(token, params, () => handler(params)); }); } } return this._resolvedConnection.onProgress(type, token, handler); } catch (error) { this.error(`Registering progress handler for token ${token} failed.`, error); throw error; } } sendProgress(type, token, value) { if (!this.isConnectionActive()) { throw new Error('Language client is not ready yet'); } this.forceDocumentSync(); try { this._resolvedConnection.sendProgress(type, token, value); } catch (error) { this.error(`Sending progress for token ${token} 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 traceOutputChannel() { if (this._traceOutputChannel) { return this._traceOutputChannel; } return this.outputChannel; } get diagnostics() { return this._diagnostics; } createDefaultErrorHandler(maxRestartCount) { if (maxRestartCount !== undefined && maxRestartCount < 0) { throw new Error(`Invalid maxRestartCount: ${maxRestartCount}`); } return new DefaultErrorHandler(this._name, maxRestartCount !== null && maxRestartCount !== void 0 ? maxRestartCount : 4); } set trace(value) { this._trace = value; this.onReady().then(() => { this.resolveConnection().then((connection) => { connection.trace(this._trace, this._tracer, { sendNotification: false, traceFormat: this._traceFormat }); }); }, () => { }); } 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, showNotification = true) { this.outputChannel.appendLine(`[Info - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) { this.showNotificationMessage(); } } warn(message, data, showNotification = true) { this.outputChannel.appendLine(`[Warn - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) { this.showNotificationMessage(); } } error(message, data, showNotification = true) { this.outputChannel.appendLine(`[Error - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.outputChannel.appendLine(this.data2String(data)); } if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error) { this.showNotificationMessage(); } } showNotificationMessage() { vscode_1.window.showInformationMessage('A request has failed. See the output for more information.', 'Go to output').then(() => { this.outputChannel.show(true); }); } logTrace(message, data) { this.traceOutputChannel.appendLine(`[Trace - ${(new Date().toLocaleTimeString())}] ${message}`); if (data) { this.traceOutputChannel.appendLine(this.data2String(data)); } } logObjectTrace(data) { if (data.isLSPMessage && data.type) { this.traceOutputChannel.append(`[LSP - ${(new Date().toLocaleTimeString())}] `); } else { this.traceOutputChannel.append(`[Trace - ${(new Date().toLocaleTimeString())}] `); } if (data) { this.traceOutputChannel.appendLine(`${JSON.stringify(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() { if (this._onReadyCallbacks.isUsed) { this._onReady = new Promise((resolve, reject) => { this._onReadyCallbacks = new OnReady(resolve, reject); }); } 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, undefined, false); break; case vscode_languageserver_protocol_1.MessageType.Warning: this.warn(message.message, undefined, false); break; case vscode_languageserver_protocol_1.MessageType.Info: this.info(message.message, undefined, false); 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.onRequest(vscode_languageserver_protocol_1.ShowDocumentRequest.type, async (params) => { var _a; const showDocument = async (params) => { const uri = this.protocol2CodeConverter.asUri(params.uri); try { if (params.external === true) { const success = await vscode_1.env.openExternal(uri); return { success }; } else { const options = {}; if (params.selection !== undefined) { options.selection = this.protocol2CodeConverter.asRange(params.selection); } if (params.takeFocus === undefined || params.takeFocus === false) { options.preserveFocus = true; } else if (params.takeFocus === true) { options.preserveFocus = false; } await vscode_1.window.showTextDocument(uri, options); return { success: true }; } } catch (error) { return { success: true }; } }; const middleware = (_a = this._clientOptions.middleware.window) === null || _a === void 0 ? void 0 : _a.showDocument; if (middleware !== undefined) { return middleware(params, showDocument); } else { return showDocument(params); } }); connection.listen(); // Error is handled in the initialize 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: null, clientInfo: { name: vscode_1.env.appName, version: vscode_1.version }, locale: this.getLocale(), 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); if (this._clientOptions.progressOnInitialization) { const token = UUID.generateUuid(); const part = new progressPart_1.ProgressPart(connection, token); initParams.workDoneToken = token; return this.doInitialize(connection, initParams).then((result) => { part.done(); return result; }, (error) => { part.cancel(); throw error; }); } else { return this.doInitialize(connection, initParams); } } doInitialize(connection, 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)) { if (result.capabilities.textDocumentSync === vscode_languageserver_protocol_1.TextDocumentSyncKind.None) { textDocumentSyncOptions = { openClose: false, change: vscode_languageserver_protocol_1.TextDocumentSyncKind.None, save: undefined }; } else { textDocumentSyncOptions = { openClose: true, change: result.capabilities.textDocumentSync, save: { includeText: false } }; } } else if (result.capabilities.textDocumentSync !== undefined && 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); } throw 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(false); // unhook listeners return this._onStop = this.resolveConnection().then(connection => { return connection.shutdown().then(() => { connection.exit(); connection.end(); connection.dispose(); this.state = ClientState.Stopped; this.cleanUpChannel(); 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 (const feature of this._features.values()) { feature.dispose(); } if (channel) { this.cleanUpChannel(); } if (diagnostics && this._diagnostics) { this._diagnostics.dispose(); this._diagnostics = undefined; } } cleanUpChannel() { if (this._outputChannel && this._disposeOutputChannel) { this._outputChannel.dispose(); this._outputChannel = undefined; } } notifyFileEvent(event) { var _a; const client = this; function didChangeWatchedFile(event) { client._fileEvents.push(event); client._fileEventDelayer.trigger(() => { client.onReady().then(() => { client.resolveConnection().then(connection => { if (client.isConnectionActive()) { client.forceDocumentSync(); connection.didChangeWatchedFiles({ changes: client._fileEvents }); } client._fileEvents = []; }); }, (error) => { client.error(`Notify file events failed.`, error); }); }); } const workSpaceMiddleware = (_a = this.clientOptions.middleware) === null || _a === void 0 ? void 0 : _a.workspace; (workSpaceMiddleware === null || workSpaceMiddleware === void 0 ? void 0 : workSpaceMiddleware.didChangeWatchedFile) ? workSpaceMiddleware.didChangeWatchedFile(event, didChangeWatchedFile) : didChangeWatchedFile(event); } forceDocumentSync() { if (this._didChangeTextDocumentFeature === undefined) { this._didChangeTextDocumentFeature = this._dynamicFeatures.get(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type.method); } this._didChangeTextDocumentFeature.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; if (middleware.handleDiagnostics) { middleware.handleDiagnostics(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, this._clientOptions.connectionOptions); }); } 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.'); if (this.state === ClientState.Starting) { this._onReadyCallbacks.reject(new Error(`Connection to server got closed. Server will not be restarted.`)); this.state = ClientState.StartFailed; } else { 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; let traceFormat = vscode_languageserver_protocol_1.TraceFormat.Text; if (config) { const traceConfig = config.get('trace.server', 'off'); if (typeof traceConfig === 'string') { trace = vscode_languageserver_protocol_1.Trace.fromString(traceConfig); } else { trace = vscode_languageserver_protocol_1.Trace.fromString(config.get('trace.server.verbosity', 'off')); traceFormat = vscode_languageserver_protocol_1.TraceFormat.fromString(config.get('trace.server.format', 'text')); } } this._trace = trace; this._traceFormat = traceFormat; connection.trace(this._trace, this._tracer, { sendNotification, traceFormat: this._traceFormat }); } 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)) { const registrationType = feature.registrationType; this._dynamicFeatures.set(registrationType.method, feature); } } getFeature(request) { return this._dynamicFeatures.get(request); } 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() { const result = {}; ensure(result, 'workspace').applyEdit = true; const workspaceEdit = ensure(ensure(result, 'workspace'), 'workspaceEdit'); workspaceEdit.documentChanges = true; workspaceEdit.resourceOperations = [vscode_languageserver_protocol_1.ResourceOperationKind.Create, vscode_languageserver_protocol_1.ResourceOperationKind.Rename, vscode_languageserver_protocol_1.ResourceOperationKind.Delete]; workspaceEdit.failureHandling = vscode_languageserver_protocol_1.FailureHandlingKind.TextOnlyTransactional; workspaceEdit.normalizesLineEndings = true; workspaceEdit.changeAnnotationSupport = { groupsOnLabel: true }; const diagnostics = ensure(ensure(result, 'textDocument'), 'publishDiagnostics'); diagnostics.relatedInformation = true; diagnostics.versionSupport = false; diagnostics.tagSupport = { valueSet: [vscode_languageserver_protocol_1.DiagnosticTag.Unnecessary, vscode_languageserver_protocol_1.DiagnosticTag.Deprecated] }; diagnostics.codeDescriptionSupport = true; diagnostics.dataSupport = true; const windowCapabilities = ensure(result, 'window'); const showMessage = ensure(windowCapabilities, 'showMessage'); showMessage.messageActionItem = { additionalPropertiesSupport: true }; const showDocument = ensure(windowCapabilities, 'showDocument'); showDocument.support = true; const generalCapabilities = ensure(result, 'general'); generalCapabilities.regularExpressions = { engine: 'ECMAScript', version: 'ES2020' }; generalCapabilities.markdown = { parser: 'marked', version: '1.1.0' }; 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 (const registration of params.registrations) { const feature = this._dynamicFeatures.get(registration.method); if (feature === undefined) { 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 }; try { feature.register(data); } catch (err) { reject(err); return; } } 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 (vscode_languageserver_protocol_1.TextDocumentEdit.is(change) && 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 Is.asPromise(vscode_1.workspace.applyEdit(this._p2c.asWorkspaceEdit(params.edit)).then((value) => { return { applied: value }; })); } handleFailedRequest(type, error, defaultValue) { // If we get a request cancel or a content modified don't log anything. if (error instanceof vscode_languageserver_protocol_1.ResponseError) { if (error.code === vscode_languageserver_protocol_1.LSPErrorCodes.RequestCancelled) { throw this.makeCancelError(); } else if (error.code === vscode_languageserver_protocol_1.LSPErrorCodes.ContentModified) { return defaultValue; } } this.error(`Request ${type.method} failed.`, error); throw error; } makeCancelError() { const result = new Error(BaseLanguageClient.Canceled); result.name = BaseLanguageClient.Canceled; return result; } } exports.BaseLanguageClient = BaseLanguageClient; BaseLanguageClient.Canceled = 'Canceled'; //# sourceMappingURL=client.js.map