UNPKG

vscode-languageclient

Version:
1,943 lines 89.8 kB
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProposedFeatures = exports.LanguageClient = exports.BaseLanguageClient = exports.ShutdownMode = exports.MessageTransports = exports.SuspendMode = exports.State = exports.CloseAction = exports.ErrorAction = exports.RevealOutputChannelOn = void 0;
/* --------------------------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 * ------------------------------------------------------------------------------------------ */
const vscode_1 = require("vscode");
const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
const c2p = __importStar(require("./codeConverter"));
const p2c = __importStar(require("./protocolConverter"));
const Is = __importStar(require("./utils/is"));
const async_1 = require("./utils/async");
const UUID = __importStar(require("./utils/uuid"));
const progressPart_1 = require("./progressPart");
const features_1 = require("./features");
const diagnostic_1 = require("./diagnostic");
const notebook_1 = require("./notebook");
const configuration_1 = require("./configuration");
const textSynchronization_1 = require("./textSynchronization");
const completion_1 = require("./completion");
const hover_1 = require("./hover");
const definition_1 = require("./definition");
const signatureHelp_1 = require("./signatureHelp");
const documentHighlight_1 = require("./documentHighlight");
const documentSymbol_1 = require("./documentSymbol");
const workspaceSymbol_1 = require("./workspaceSymbol");
const reference_1 = require("./reference");
const typeDefinition_1 = require("./typeDefinition");
const implementation_1 = require("./implementation");
const colorProvider_1 = require("./colorProvider");
const codeAction_1 = require("./codeAction");
const codeLens_1 = require("./codeLens");
const formatting_1 = require("./formatting");
const rename_1 = require("./rename");
const documentLink_1 = require("./documentLink");
const executeCommand_1 = require("./executeCommand");
const foldingRange_1 = require("./foldingRange");
const declaration_1 = require("./declaration");
const selectionRange_1 = require("./selectionRange");
const callHierarchy_1 = require("./callHierarchy");
const semanticTokens_1 = require("./semanticTokens");
const linkedEditingRange_1 = require("./linkedEditingRange");
const typeHierarchy_1 = require("./typeHierarchy");
const inlineValue_1 = require("./inlineValue");
const inlayHint_1 = require("./inlayHint");
const workspaceFolder_1 = require("./workspaceFolder");
const fileOperations_1 = require("./fileOperations");
const inlineCompletion_1 = require("./inlineCompletion");
const textDocumentContent_1 = require("./textDocumentContent");
const fileSystemWatcher_1 = require("./fileSystemWatcher");
const progress_1 = require("./progress");
/**
 * Controls when the output channel is revealed.
 */
var RevealOutputChannelOn;
(function (RevealOutputChannelOn) {
    RevealOutputChannelOn[RevealOutputChannelOn["Debug"] = 0] = "Debug";
    RevealOutputChannelOn[RevealOutputChannelOn["Info"] = 1] = "Info";
    RevealOutputChannelOn[RevealOutputChannelOn["Warn"] = 2] = "Warn";
    RevealOutputChannelOn[RevealOutputChannelOn["Error"] = 3] = "Error";
    RevealOutputChannelOn[RevealOutputChannelOn["Never"] = 4] = "Never";
})(RevealOutputChannelOn || (exports.RevealOutputChannelOn = RevealOutputChannelOn = {}));
/**
 * 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 = 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 = CloseAction = {}));
/**
 * Signals in which state the language client is in.
 */
var State;
(function (State) {
    /**
     * The client is stopped or got never started.
     */
    State[State["Stopped"] = 1] = "Stopped";
    /**
     * The client is starting but not ready yet.
     */
    State[State["Starting"] = 3] = "Starting";
    /**
     * The start has failed.
     */
    State[State["StartFailed"] = 4] = "StartFailed";
    /**
     * The client is running and ready.
     */
    State[State["Running"] = 2] = "Running";
})(State || (exports.State = State = {}));
var SuspendMode;
(function (SuspendMode) {
    /**
     * Don't allow suspend mode.
     */
    SuspendMode["off"] = "off";
    /**
     * Support suspend mode even if not all
     * registered providers have a corresponding
     * activation listener.
     */
    SuspendMode["on"] = "on";
})(SuspendMode || (exports.SuspendMode = SuspendMode = {}));
var ResolvedClientOptions;
(function (ResolvedClientOptions) {
    function sanitizeIsTrusted(isTrusted) {
        if (isTrusted === undefined || isTrusted === null) {
            return false;
        }
        if ((typeof isTrusted === 'boolean') || (typeof isTrusted === 'object' && isTrusted !== null && Is.stringArray(isTrusted.enabledCommands))) {
            return isTrusted;
        }
        return false;
    }
    ResolvedClientOptions.sanitizeIsTrusted = sanitizeIsTrusted;
})(ResolvedClientOptions || (ResolvedClientOptions = {}));
class DefaultErrorHandler {
    client;
    maxRestartCount;
    restarts;
    constructor(client, maxRestartCount) {
        this.client = client;
        this.maxRestartCount = maxRestartCount;
        this.restarts = [];
    }
    error(_error, _message, count) {
        if (count && count <= 3) {
            return { action: ErrorAction.Continue };
        }
        return { action: ErrorAction.Shutdown };
    }
    closed() {
        this.restarts.push(Date.now());
        if (this.restarts.length <= this.maxRestartCount) {
            return { action: CloseAction.Restart };
        }
        else {
            const diff = this.restarts[this.restarts.length - 1] - this.restarts[0];
            if (diff <= 3 * 60 * 1000) {
                return { action: CloseAction.DoNotRestart, message: `The ${this.client.name} server crashed ${this.maxRestartCount + 1} times in the last 3 minutes. The server will not be restarted. See the output for more information.` };
            }
            else {
                this.restarts.shift();
                return { action: CloseAction.Restart };
            }
        }
    }
}
var ClientState;
(function (ClientState) {
    ClientState["Initial"] = "initial";
    ClientState["Starting"] = "starting";
    ClientState["StartFailed"] = "startFailed";
    ClientState["Running"] = "running";
    ClientState["Stopping"] = "stopping";
    ClientState["Stopped"] = "stopped";
})(ClientState || (ClientState = {}));
var MessageTransports;
(function (MessageTransports) {
    function is(value) {
        const 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 = MessageTransports = {}));
var ShutdownMode;
(function (ShutdownMode) {
    ShutdownMode["Restart"] = "restart";
    ShutdownMode["Stop"] = "stop";
})(ShutdownMode || (exports.ShutdownMode = ShutdownMode = {}));
/**
 * Manages the open tabs. We don't directly use the tab API since for
 * diagnostics we need to de-dupe tabs that show the same resources since
 * we pull on the model not the UI.
 */
class VisibleDocumentsImpl {
    open;
    _onOpen;
    _onClose;
    disposables;
    constructor() {
        this.disposables = [];
        this.open = new Set();
        this._onOpen = new vscode_1.EventEmitter();
        this._onClose = new vscode_1.EventEmitter();
        VisibleDocumentsImpl.fillVisibleResources(this.open);
        const updateVisibleDocuments = () => {
            const oldTabs = this.open;
            const currentTabs = new Set();
            VisibleDocumentsImpl.fillVisibleResources(currentTabs);
            const closed = new Set();
            const opened = new Set(currentTabs);
            for (const tab of oldTabs.values()) {
                if (currentTabs.has(tab)) {
                    opened.delete(tab);
                }
                else {
                    closed.add(tab);
                }
            }
            this.open = currentTabs;
            if (closed.size > 0) {
                const toFire = new Set();
                for (const item of closed) {
                    toFire.add(vscode_1.Uri.parse(item));
                }
                this._onClose.fire(toFire);
            }
            if (opened.size > 0) {
                const toFire = new Set();
                for (const item of opened) {
                    toFire.add(vscode_1.Uri.parse(item));
                }
                this._onOpen.fire(toFire);
            }
        };
        this.disposables.push(vscode_1.window.tabGroups.onDidChangeTabs((event) => {
            if (event.closed.length === 0 && event.opened.length === 0) {
                return;
            }
            updateVisibleDocuments();
        }));
        this.disposables.push(vscode_1.window.onDidChangeVisibleTextEditors((_editors) => {
            updateVisibleDocuments();
        }));
    }
    get onClose() {
        return this._onClose.event;
    }
    get onOpen() {
        return this._onOpen.event;
    }
    dispose() {
        this.disposables.forEach(disposable => disposable.dispose());
    }
    isActive(document) {
        return document instanceof vscode_1.Uri
            ? vscode_1.window.activeTextEditor?.document.uri === document
            : vscode_1.window.activeTextEditor?.document === document;
    }
    isVisible(document) {
        const uri = document instanceof vscode_1.Uri ? document : document.uri;
        if (uri.scheme === notebook_1.NotebookDocumentSyncFeature.CellScheme) {
            // Notebook cells aren't in the list of tabs, but the notebook should be.
            return vscode_1.workspace.notebookDocuments.some(notebook => {
                if (this.open.has(notebook.uri.toString())) {
                    const cell = notebook.getCells().find(cell => cell.document.uri.toString() === uri.toString());
                    return cell !== undefined;
                }
                return false;
            });
        }
        return this.open.has(uri.toString());
    }
    getResources() {
        const result = new Set();
        VisibleDocumentsImpl.fillVisibleResources(new Set(), result);
        return result;
    }
    static fillVisibleResources(strings, uris) {
        const seen = strings ?? new Set();
        for (const group of vscode_1.window.tabGroups.all) {
            for (const tab of group.tabs) {
                const input = tab.input;
                let uri;
                if (input instanceof vscode_1.TabInputText) {
                    uri = input.uri;
                }
                else if (input instanceof vscode_1.TabInputTextDiff) {
                    uri = input.modified;
                }
                else if (input instanceof vscode_1.TabInputCustom) {
                    uri = input.uri;
                }
                else if (input instanceof vscode_1.TabInputNotebook) {
                    uri = input.uri;
                }
                if (uri !== undefined && !seen.has(uri.toString())) {
                    seen.add(uri.toString());
                    uris !== undefined && uris.add(uri);
                }
            }
        }
        // Peek editors are not part of tabs but should be considered visible
        for (const editor of vscode_1.window.visibleTextEditors) {
            const uri = editor.document.uri;
            if (!seen.has(uri.toString())) {
                seen.add(uri.toString());
                uris !== undefined && uris.add(uri);
            }
        }
    }
}
class BaseLanguageClient {
    _id;
    _name;
    _clientOptions;
    _state;
    _onStart;
    _onStop;
    _connection;
    _idleInterval;
    _ignoredRegistrations;
    // private _idleStart: number | undefined;
    _listeners;
    _disposed;
    _notificationHandlers;
    _notificationDisposables;
    _pendingNotificationHandlers;
    _requestHandlers;
    _requestDisposables;
    _pendingRequestHandlers;
    _progressHandlers;
    _pendingProgressHandlers;
    _progressDisposables;
    _initializeResult;
    _outputChannel;
    _disposeOutputChannel;
    _traceOutputChannel;
    _traceLogLevel;
    _capabilities;
    // undefined: allow lazy creation of the diagnostic collection.
    // null: the diagnostic collection has been disposed and should not be
    // recreated.
    _diagnostics;
    _syncedDocuments;
    _didChangeTextDocumentFeature;
    _inFlightOpenNotifications;
    _pendingChangeSemaphore;
    _pendingChangeDelayer;
    _didOpenTextDocumentFeature;
    _fileEvents;
    _fileEventDelayer;
    _telemetryEmitter;
    _stateChangeEmitter;
    _trace;
    _traceFormat = vscode_languageserver_protocol_1.TraceFormat.Text;
    _tracer;
    _c2p;
    _p2c;
    _visibleDocuments;
    constructor(id, name, clientOptions) {
        this._id = id;
        this._name = name;
        clientOptions = clientOptions || {};
        const markdown = {
            isTrusted: false,
            supportHtml: false,
            supportThemeIcons: false
        };
        if (clientOptions.markdown !== undefined) {
            markdown.isTrusted = ResolvedClientOptions.sanitizeIsTrusted(clientOptions.markdown.isTrusted);
            markdown.supportHtml = clientOptions.markdown.supportHtml === true;
            markdown.supportThemeIcons = clientOptions.markdown.supportThemeIcons === true;
        }
        // const defaultInterval = (clientOptions as TestOptions).$testMode ? 50 : 60000;
        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(clientOptions.connectionOptions?.maxRestartCount),
            middleware: clientOptions.middleware ?? {},
            uriConverters: clientOptions.uriConverters,
            workspaceFolder: clientOptions.workspaceFolder,
            connectionOptions: clientOptions.connectionOptions,
            markdown,
            // suspend: {
            // 	mode: clientOptions.suspend?.mode ?? SuspendMode.off,
            // 	callback: clientOptions.suspend?.callback ?? (() => Promise.resolve(true)),
            // 	interval: clientOptions.suspend?.interval ? Math.max(clientOptions.suspend.interval, defaultInterval) : defaultInterval
            // },
            diagnosticPullOptions: clientOptions.diagnosticPullOptions ?? { onChange: true, onSave: false },
            diagnosticCollectionProvider: clientOptions.diagnosticCollectionProvider ?? new features_1.DefaultDiagnosticCollectionProvider(),
            notebookDocumentOptions: clientOptions.notebookDocumentOptions ?? {},
            textSynchronization: this.createTextSynchronizationOptions(clientOptions.textSynchronization)
        };
        this._clientOptions.synchronize = this._clientOptions.synchronize || {};
        this._state = ClientState.Initial;
        this._ignoredRegistrations = new Set();
        this._listeners = [];
        this._notificationHandlers = new Map();
        this._pendingNotificationHandlers = new Map();
        this._notificationDisposables = new Map();
        this._requestHandlers = new Map();
        this._pendingRequestHandlers = new Map();
        this._requestDisposables = new Map();
        this._progressHandlers = new Map();
        this._pendingProgressHandlers = new Map();
        this._progressDisposables = new Map();
        this._connection = undefined;
        // this._idleStart = undefined;
        this._initializeResult = undefined;
        if (clientOptions.outputChannel) {
            this._outputChannel = clientOptions.outputChannel;
            this._disposeOutputChannel = false;
            this._traceLogLevel = this._outputChannel.logLevel;
        }
        else {
            this._outputChannel = undefined;
            this._disposeOutputChannel = true;
            this._traceLogLevel = vscode_1.LogLevel.Info;
        }
        this._traceOutputChannel = clientOptions.traceOutputChannel;
        if (this._traceOutputChannel !== undefined) {
            this._traceLogLevel = this._traceOutputChannel.logLevel;
        }
        // Allow lazy creation of the diagnostic collection.
        this._diagnostics = undefined;
        this._inFlightOpenNotifications = new Set();
        this._pendingChangeSemaphore = new async_1.Semaphore(1);
        this._pendingChangeDelayer = new async_1.Delayer(250);
        this._fileEvents = [];
        this._fileEventDelayer = new async_1.Delayer(250);
        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.trace(messageOrDataObject, data);
                }
                else {
                    this.traceObject(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._clientOptions.markdown.supportHtml, this._clientOptions.markdown.supportThemeIcons);
        this._syncedDocuments = new Map();
        this.registerBuiltinFeatures();
    }
    createTextSynchronizationOptions(options) {
        if (!options) {
            return { delayOpenNotifications: false };
        }
        if (typeof options.delayOpenNotifications === 'boolean') {
            return { delayOpenNotifications: options.delayOpenNotifications };
        }
        return { delayOpenNotifications: false };
    }
    get name() {
        return this._name;
    }
    get middleware() {
        return this._clientOptions.middleware ?? Object.create(null);
    }
    get clientOptions() {
        return this._clientOptions;
    }
    get protocol2CodeConverter() {
        return this._p2c;
    }
    get code2ProtocolConverter() {
        return this._c2p;
    }
    get visibleDocuments() {
        if (this._visibleDocuments === undefined) {
            this._visibleDocuments = new VisibleDocumentsImpl();
        }
        return this._visibleDocuments;
    }
    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, { log: true });
            if (this._traceOutputChannel === undefined) {
                this._traceLogLevel = this._outputChannel.logLevel;
            }
        }
        return this._outputChannel;
    }
    get traceOutputChannel() {
        return this._traceOutputChannel ? this._traceOutputChannel : this.outputChannel;
    }
    get diagnostics() {
        if (this._diagnostics === null) {
            return undefined;
        }
        if (this._diagnostics === undefined) {
            this._diagnostics = this._clientOptions.diagnosticCollectionProvider.create(this._clientOptions.diagnosticCollectionName ?? this._id, features_1.DiagnosticCollectionSource.push);
        }
        return this._diagnostics;
    }
    get state() {
        return this.getPublicState();
    }
    get $state() {
        return this._state;
    }
    set $state(value) {
        const oldState = this.getPublicState();
        this._state = value;
        const newState = this.getPublicState();
        if (newState !== oldState) {
            this._stateChangeEmitter.fire({ oldState, newState });
        }
    }
    getPublicState() {
        switch (this.$state) {
            case ClientState.Starting:
                return State.Starting;
            case ClientState.Running:
                return State.Running;
            case ClientState.StartFailed:
                return State.StartFailed;
            default:
                return State.Stopped;
        }
    }
    get initializeResult() {
        return this._initializeResult;
    }
    async sendRequest(type, ...params) {
        if (this.$state === ClientState.StartFailed || this.$state === ClientState.Stopping || this.$state === ClientState.Stopped) {
            return Promise.reject(new vscode_languageserver_protocol_1.ResponseError(vscode_languageserver_protocol_1.ErrorCodes.ConnectionInactive, `Client is not running`));
        }
        // Ensure we have a connection before we force the document sync.
        const connection = await this.$start();
        // Send ony depending open notifications
        await this._didOpenTextDocumentFeature.sendPendingOpenNotifications();
        // If any document is synced in full mode make sure we flush any pending
        // full document syncs.
        if (this._didChangeTextDocumentFeature.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Full) {
            await this.sendPendingFullTextDocumentChanges(connection);
        }
        let param = undefined;
        let token = undefined;
        // Separate cancellation tokens from other parameters for a better client interface
        if (params.length === 1) {
            // CancellationToken is an interface, so we need to check if the first param complies to it
            if (vscode_languageserver_protocol_1.CancellationToken.is(params[0])) {
                token = params[0];
            }
            else {
                param = params[0];
            }
        }
        else if (params.length === 2) {
            param = params[0];
            token = params[1];
        }
        if (token !== undefined && token.isCancellationRequested) {
            return Promise.reject(new vscode_languageserver_protocol_1.ResponseError(vscode_languageserver_protocol_1.LSPErrorCodes.RequestCancelled, 'Request got cancelled'));
        }
        const _sendRequest = this._clientOptions.middleware?.sendRequest;
        if (_sendRequest !== undefined) {
            // Return the general middleware invocation defining `next` as a utility function that reorganizes parameters to
            // pass them to the original sendRequest function.
            return _sendRequest(type, param, token, (type, param, token) => {
                const params = [];
                // Add the parameters if there are any
                if (param !== undefined) {
                    params.push(param);
                }
                // Add the cancellation token if there is one
                if (token !== undefined) {
                    params.push(token);
                }
                return connection.sendRequest(type, ...params);
            });
        }
        else {
            return connection.sendRequest(type, ...params);
        }
    }
    onRequest(type, handler) {
        const method = typeof type === 'string' ? type : type.method;
        this._requestHandlers.set(method, handler);
        const connection = this.activeConnection();
        let disposable;
        if (connection !== undefined) {
            this._requestDisposables.set(method, connection.onRequest(type, handler));
            disposable = {
                dispose: () => {
                    const disposable = this._requestDisposables.get(method);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._requestDisposables.delete(method);
                    }
                }
            };
        }
        else {
            this._pendingRequestHandlers.set(method, handler);
            disposable = {
                dispose: () => {
                    this._pendingRequestHandlers.delete(method);
                    const disposable = this._requestDisposables.get(method);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._requestDisposables.delete(method);
                    }
                }
            };
        }
        return {
            dispose: () => {
                this._requestHandlers.delete(method);
                disposable.dispose();
            }
        };
    }
    async sendNotification(type, params) {
        if (this.$state === ClientState.StartFailed || this.$state === ClientState.Stopping || this.$state === ClientState.Stopped) {
            return Promise.reject(new vscode_languageserver_protocol_1.ResponseError(vscode_languageserver_protocol_1.ErrorCodes.ConnectionInactive, `Client is not running`));
        }
        const needsPendingFullTextDocumentSync = this._didChangeTextDocumentFeature.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Full;
        let openNotification;
        if (needsPendingFullTextDocumentSync && typeof type !== 'string' && type.method === vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.method) {
            openNotification = params?.textDocument.uri;
            this._inFlightOpenNotifications.add(openNotification);
        }
        let documentToClose;
        if (typeof type !== 'string' && type.method === vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.method) {
            documentToClose = params.textDocument.uri;
        }
        // Ensure we have a connection before we force the document sync.
        const connection = await this.$start();
        // Send any depending open notifications
        const didDropOpenNotification = await this._didOpenTextDocumentFeature.sendPendingOpenNotifications(documentToClose);
        if (didDropOpenNotification) {
            // Don't forward this close notification if we dropped the
            // corresponding open notification.
            return;
        }
        // If any document is synced in full mode make sure we flush any pending
        // full document syncs.
        if (needsPendingFullTextDocumentSync) {
            await this.sendPendingFullTextDocumentChanges(connection);
        }
        // We need to remove the pending open notification before we actually
        // send the notification over the connection. Otherwise there could be
        // a request coming in that although the open notification got already put
        // onto the wire will ignore pending document changes.
        //
        // Since the code path of connection.sendNotification is actually sync
        // until the message is handed off to the writer and the writer has a semaphore
        // lock with a capacity of 1 no additional async scheduling can happen until
        // the message is actually handed off.
        if (openNotification !== undefined) {
            this._inFlightOpenNotifications.delete(openNotification);
        }
        const _sendNotification = this._clientOptions.middleware?.sendNotification;
        return _sendNotification
            ? _sendNotification(type, connection.sendNotification.bind(connection), params)
            : connection.sendNotification(type, params);
    }
    onNotification(type, handler) {
        const method = typeof type === 'string' ? type : type.method;
        this._notificationHandlers.set(method, handler);
        const connection = this.activeConnection();
        let disposable;
        if (connection !== undefined) {
            this._notificationDisposables.set(method, connection.onNotification(type, handler));
            disposable = {
                dispose: () => {
                    const disposable = this._notificationDisposables.get(method);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._notificationDisposables.delete(method);
                    }
                }
            };
        }
        else {
            this._pendingNotificationHandlers.set(method, handler);
            disposable = {
                dispose: () => {
                    this._pendingNotificationHandlers.delete(method);
                    const disposable = this._notificationDisposables.get(method);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._notificationDisposables.delete(method);
                    }
                }
            };
        }
        return {
            dispose: () => {
                this._notificationHandlers.delete(method);
                disposable.dispose();
            }
        };
    }
    async sendProgress(type, token, value) {
        if (this.$state === ClientState.StartFailed || this.$state === ClientState.Stopping || this.$state === ClientState.Stopped) {
            return Promise.reject(new vscode_languageserver_protocol_1.ResponseError(vscode_languageserver_protocol_1.ErrorCodes.ConnectionInactive, `Client is not running`));
        }
        try {
            // Ensure we have a connection before we force the document sync.
            const connection = await this.$start();
            return connection.sendProgress(type, token, value);
        }
        catch (error) {
            this.error(`Sending progress for token ${token} failed.`, error);
            throw error;
        }
    }
    onProgress(type, token, handler) {
        this._progressHandlers.set(token, { type, handler });
        const connection = this.activeConnection();
        let disposable;
        const handleWorkDoneProgress = this._clientOptions.middleware?.handleWorkDoneProgress;
        const realHandler = vscode_languageserver_protocol_1.WorkDoneProgress.is(type) && handleWorkDoneProgress !== undefined
            ? (params) => {
                handleWorkDoneProgress(token, params, () => handler(params));
            }
            : handler;
        if (connection !== undefined) {
            this._progressDisposables.set(token, connection.onProgress(type, token, realHandler));
            disposable = {
                dispose: () => {
                    const disposable = this._progressDisposables.get(token);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._progressDisposables.delete(token);
                    }
                }
            };
        }
        else {
            this._pendingProgressHandlers.set(token, { type, handler });
            disposable = {
                dispose: () => {
                    this._pendingProgressHandlers.delete(token);
                    const disposable = this._progressDisposables.get(token);
                    if (disposable !== undefined) {
                        disposable.dispose();
                        this._progressDisposables.delete(token);
                    }
                }
            };
        }
        return {
            dispose: () => {
                this._progressHandlers.delete(token);
                disposable.dispose();
            }
        };
    }
    createDefaultErrorHandler(maxRestartCount) {
        if (maxRestartCount !== undefined && maxRestartCount < 0) {
            throw new Error(`Invalid maxRestartCount: ${maxRestartCount}`);
        }
        return new DefaultErrorHandler(this, maxRestartCount ?? 4);
    }
    async setTrace(value) {
        this._trace = value;
        const connection = this.activeConnection();
        if (connection !== undefined) {
            await 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();
    }
    shouldLogToOutputChannel() {
        if (this.$state !== ClientState.Stopped) {
            return true;
        }
        return this._outputChannel !== undefined;
    }
    error(message, data, showNotification = true) {
        if (this.shouldLogToOutputChannel()) {
            this.outputChannel.error(this.getLogMessage(message, data));
        }
        if (showNotification === 'force' || (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error)) {
            this.showNotificationMessage(vscode_languageserver_protocol_1.MessageType.Error, message, data);
        }
    }
    warn(message, data, showNotification = true) {
        if (this.shouldLogToOutputChannel()) {
            this.outputChannel.warn(this.getLogMessage(message, data));
        }
        if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) {
            this.showNotificationMessage(vscode_languageserver_protocol_1.MessageType.Warning, message, data);
        }
    }
    info(message, data, showNotification = true) {
        if (this.shouldLogToOutputChannel()) {
            this.outputChannel.info(this.getLogMessage(message, data));
        }
        if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) {
            this.showNotificationMessage(vscode_languageserver_protocol_1.MessageType.Info, message, data);
        }
    }
    debug(message, data, showNotification = true) {
        if (this.shouldLogToOutputChannel()) {
            this.outputChannel.debug(this.getLogMessage(message, data));
        }
        if (showNotification && this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Debug) {
            this.showNotificationMessage(vscode_languageserver_protocol_1.MessageType.Debug, message, data);
        }
    }
    trace(message, data) {
        this.traceOutputChannel.trace(this.getLogMessage(message, data));
    }
    traceObject(data) {
        this.traceOutputChannel.trace(JSON.stringify(data));
    }
    showNotificationMessage(type, message, data) {
        message = message ?? 'A request has failed. See the output for more information.';
        if (data) {
            message += '\n' + this.data2String(data);
        }
        const messageFunc = type === vscode_languageserver_protocol_1.MessageType.Error
            ? vscode_1.window.showErrorMessage
            : type === vscode_languageserver_protocol_1.MessageType.Warning
                ? vscode_1.window.showWarningMessage
                : vscode_1.window.showInformationMessage;
        void messageFunc(message, 'Go to output').then((selection) => {
            if (selection !== undefined) {
                this.outputChannel.show(true);
            }
        });
    }
    getLogMessage(message, data) {
        return data !== null && data !== undefined ? `${message}\n${this.data2String(data)}` : message;
    }
    needsStart() {
        return this.$state === ClientState.Initial || this.$state === ClientState.Stopping || this.$state === ClientState.Stopped;
    }
    needsStop() {
        return this.$state === ClientState.Starting || this.$state === ClientState.Running;
    }
    activeConnection() {
        return this.$state === ClientState.Running && this._connection !== undefined ? this._connection : undefined;
    }
    isRunning() {
        return this.$state === ClientState.Running;
    }
    async start() {
        if (this._disposed === 'disposing' || this._disposed === 'disposed') {
            throw new Error(`Client got disposed and can't be restarted.`);
        }
        if (this.$state === ClientState.Stopping) {
            throw new Error(`Client is currently stopping. Can only restart a full stopped client`);
        }
        // We are already running or are in the process of getting up
        // to speed.
        if (this._onStart !== undefined) {
            return this._onStart;
        }
        const [promise, resolve, reject] = this.createOnStartPromise();
        this._onStart = promise;
        // A previous shutdown disposed the diagnostic collection and set it to
        // `null` to prevent recreation. On (re)start we re-enable lazy creation.
        this._diagnostics = undefined;
        // When we start make all buffer handlers pending so that they
        // get added.
        for (const [method, handler] of this._notificationHandlers) {
            if (!this._pendingNotificationHandlers.has(method)) {
                this._pendingNotificationHandlers.set(method, handler);
            }
        }
        for (const [method, handler] of this._requestHandlers) {
            if (!this._pendingRequestHandlers.has(method)) {
                this._pendingRequestHandlers.set(method, handler);
            }
        }
        for (const [token, data] of this._progressHandlers) {
            if (!this._pendingProgressHandlers.has(token)) {
                this._pendingProgressHandlers.set(token, data);
            }
        }
        this.$state = ClientState.Starting;
        try {
            const connection = await this.createConnection();
            connection.onNotification(vscode_languageserver_protocol_1.LogMessageNotification.type, (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;
                    case vscode_languageserver_protocol_1.MessageType.Debug:
                        this.debug(message.message, undefined, false);
                        break;
                    default:
                        this.outputChannel.appendLine(message.message);
                }
            });
            connection.onNotification(vscode_languageserver_protocol_1.ShowMessageNotification.type, (message) => {
                switch (message.type) {
                    case vscode_languageserver_protocol_1.MessageType.Error:
                        void vscode_1.window.showErrorMessage(message.message);
                        break;
                    case vscode_languageserver_protocol_1.MessageType.Warning:
                        void vscode_1.window.showWarningMessage(message.message);
                        break;
                    case vscode_languageserver_protocol_1.MessageType.Info:
                        void vscode_1.window.showInformationMessage(message.message);
                        break;
                    default:
                        void 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;
                }
                const actions = params.actions || [];
                return messageFunc(params.message, ...actions);
            });
            connection.onNotification(vscode_languageserver_protocol_1.TelemetryEventNotification.type, (data) => {
                this._telemetryEmitter.fire(data);
            });
            connection.onRequest(vscode_languageserver_protocol_1.ShowDocumentRequest.type, async (params, token) => {
                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: false };
                    }
                };
                const middleware = this._clientOptions.middleware.window?.showDocument;
                if (middleware !== undefined) {
                    return middleware(params, token, showDocument);
                }
                else {
                    return showDocument(params);
                }
            });
            connection.listen();
            await this.initialize(connection);
            resolve();
        }
        catch (error) {
            this.$state = ClientState.StartFailed;
            this.error(`${this._name} client: couldn't create connection to server.`, error, 'force');
            reject(error);
        }
        return this._onStart;
    }
    createOnStartPromise() {
        let resolve;
        let reject;
        const promise = new Promise((_resolve, _reject) => {
            resolve = _resolve;
            reject = _reject;
        });
        return [promise, resolve, reject];
    }
    async initialize(connection) {
        this.refreshTrace(connection, false);
        const initOption = this._clientOptions.initializationOptions;
        // If the client is locked to a workspace folder use it. In this case the workspace folder
        // feature is not registered and we need to initialize the value here.
        const [rootPath, workspaceFolders] = this._clientOptions.workspaceFolder !== undefined
            ? [this._clientOptions.workspaceFolder.uri.fsPath, [{ uri: this._c2p.asUri(this._clientOptions.workspaceFolder.uri), name: this._clientOptions.workspaceFolder.name }]]
            : [this._clientGetRootPath(), null];
        const 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: workspaceFolders
        };
        this.fillInitializeParams(initParams);
        if (this._clientOptions.progressOnInitialization) {
            const token = UUID.generateUuid();
            const part = new progressPart_1.ProgressPart(connection, token);
            initParams.workDoneToken = token;
            try {
                const result = await this.doInitialize(connection, initParams);
                part.done();
                return result;
            }
            catch (error) {
                part.cancel();
                throw error;
            }
        }
        else {
            return this.doInitialize(connection, initParams);
        }
    }
    async doInitialize(connection, initParams) {
        try {
            const result = await connection.initialize(initParams);
            if (result.capabilities.positionEncoding !== undefined && result.capabilities.positionEncoding !== vscode_languageserver_protocol_1.PositionEncodingKind.UTF16) {
                throw new Error(`Unsupported position encoding (${result.capabilities.positionEncoding}) received from server ${this.name}`);
            }
            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.onNotification(vscode_languageserver_protocol_1.PublishDiagnosticsNotification.type, 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));
            // Add pending notification, request and progress handlers.
            for (const [method, handler] of this._pendingNotificationHandlers) {
                this._notificationDisposables.set(method, connection.onNotification(method, handler));
            }
            this._pendingNotificationHandlers.clear();
            for (const [method, handler] of this._pendingRequestHandlers) {
                this._requestDisposables.set(method, connection.onRequest(method, handler));
            }
            this._pendingRequestHandlers.clear();
            for (const [token, data] of this._pendingProgressHandlers) {
                this._progressDisposables.set(token, connection.onProgress(data.type, token, data.handler));
            }
            this._pendingProgressHandlers.clear();
            // if (this._clientOptions.suspend.mode !== SuspendMode.off) {
            // 	this._idleInterval =  RAL().timer.setInterval(() => this.checkSuspend(), this._clientOptions.suspend.interval);
            // }
            await connection.sendNotification(vscode_languageserver_protocol_1.InitializedNotification.type, {});
            this.hookFileEvents(connection);
            this.hookLogLevelChanged(connection);
            this.hookConfigurationChanged(connection);
            this.initializeFeatures(connection);
            return result;
        }
        catch (error) {
            if (this._clientOptions.initializationFailedHandler) {
                if (this._clientOptions.initializationFailedHandler(error)) {
                    void this.initialize(connection);
                }
                else {
                    void this.stop();
                }
            }
            else if (error instanceof vscode_languageserver_protocol_1.ResponseError && error.data && error.data.retry) {
                void vscode_1.window.showErrorMessage(error.message, { title: 'Retry', id: 'retry' }).then(item => {
                    if (item && item.id === 'retry') {
                        void this.initialize(connection);
                    }
                    else {
                        void this.stop();
                    }
                });
            }
            else {
                if (error && error.message) {
                    void vscode_1.window.showErrorMessage(error.message);
                }
                this.error('Server initialization failed.', error);
                void this.stop();
            }
            throw error;
        }
    }
    _clientGetRootPath() {
        const folders = vscode_1.workspace.workspaceFolders;
        if (!folders || folders.length === 0) {
            return undefined;
        }
        const folder = folders[0];
        if (folder.uri.scheme === 'file') {
            return folder.uri.fsPath;
        }
        return undefined;
    }
    stop(timeout = 2000) {
        // Wait 2 seconds on stop
        return this.shutdown(ShutdownMode.Stop, timeout);
    }
    dispose(timeout = 2000) {
        try {
            this._disposed = 'disposing';
            return this.stop(timeout);
        }
        finally {
            this._disposed = 'disposed';
        }
    }
    async shutdown(mode, timeout = 2000) {
        // If the client is stopped or in its initial state return.
        if (this.$state === ClientState.Stopped || this.$state === ClientState.Initial) {
            return;
        }
        // If we are stopping the client and have a stop promise return it.
        if (this.$state === ClientState.Stopping) {
            if (this._onStop !== undefined) {
                return this._onStop;
            }
            else {
                throw new Error(`Client is stopping but no stop promise available.`);
            }
        }
        const connection = this.activeConnection();
        // We can't stop a client that is not running (e.g. has no connection). Especially not
        // on that us starting since it can't be correctly synchronized.
        if (connection === undefined || this.$state !== ClientState.Running) {
            throw new Error(`Client is not running and can't be stopped. It's current state is: ${this.$state}`);
        }
        this._initializeResult = undefined;
        this.$state = ClientState.Stopping;
        this.cleanUp(mode);
        const tp = new Promise(c => { (0, vscode_languageserver_protocol_1.RAL)().timer.setTimeout(c, timeout); });
        const shutdown = (async (connection) => {
            await connection.shutdown();
            await connection.exit();
            return connection;
        })(connection);
        return this._onStop = Promise.race([tp, shutdown]).then((connection) => {
            // The connection won the race with the timeout.
            if (connection !== undefined) {
                connection.end();
                connection.dispose();
            }
            else {
                this.error(`Stopping server timed out`, undefined, false);
                throw new Error(`Stopping the server timed out`);
            }
        }, (error) => {
            this.error(`Stopping server failed`, error, false);
            throw error;
        }).finally(() => {
            this.$state = ClientState.Stopped;
            mode === ShutdownMode.Stop && this.cleanUpChannel();
            this._onStart = undefined;
            this._onStop = undefined;
            this._connection = undefined;
            this._ignoredRegistrations.clear();
        });
    }
    cleanUp(mode) {
        // purge outstanding file events.
        this._fileEvents = [];
        this._fileEventDelayer.cancel();
        const disposables = this._listeners.splice(0, this._listeners.length);
        for (const disposable of disposables) {
            disposable.dispose();
        }
        if (this._syncedDocuments) {
            this._syncedDocuments.clear();
        }
        // Clear features in reverse order;
        for (const feature of Array.from(this._features.entries()).map(entry => entry[1]).reverse()) {
            feature.clear();
        }
        if ((mode === ShutdownMode.Stop || mode === ShutdownMode.Restart)) {
            if (this._diagnostics === undefined) {
                this._diagnostics = null;
            }
            if (this._diagnostics !== null) {
                this._clientOptions.diagnosticCollectionProvider.dispose(this._diagnostics, features_1.DiagnosticCollectionSource.push);
                this._diagnostics = null;
            }
        }
        if (this._idleInterval !== undefined) {
            this._idleInterval.dispose();
            this._idleInterval = undefined;
        }
        // this._idleStart = undefined;
    }
    cleanUpChannel() {
        if (this._outputChannel !== undefined && this._disposeOutputChannel) {
            this._outputChannel.dispose();
            this._outputChannel = undefined;
        }
    }
    notifyFileEvent(event) {
        const client = this;
        async function didChangeWatchedFile(event) {
            client._fileEvents.push(event);
            return client._fileEventDelayer.trigger(async () => {
                const fileEvents = client._fileEvents;
                client._fileEvents = [];
                try {
                    await client.sendNotification(vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type, { changes: fileEvents });
                }
                catch (error) {
                    // Restore the file events.
                    client._fileEvents.push(...fileEvents);
                    throw error;
                }
            });
        }
        const workSpaceMiddleware = this.clientOptions.middleware?.workspace;
        (workSpaceMiddleware?.didChangeWatchedFile ? workSpaceMiddleware.didChangeWatchedFile(event, didChangeWatchedFile) : didChangeWatchedFile(event)).catch((error) => {
            client.error(`Notifying file events failed.`, error);
        });
    }
    async sendPendingFullTextDocumentChanges(connection) {
        return this._pendingChangeSemaphore.lock(async () => {
            try {
                const changes = this._didChangeTextDocumentFeature.getPendingDocumentChanges(this._inFlightOpenNotifications);
                if (changes.length === 0) {
                    return;
                }
                for (const document of changes) {
                    const params = this.code2ProtocolConverter.asChangeTextDocumentParams(document);
                    // We await the send and not the delivery since it is more or less the same for
                    // notifications.
                    this._didChangeTextDocumentFeature.aboutToSendNotification(document, vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params);
                    await connection.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params);
                    this._didChangeTextDocumentFeature.notificationSent(document, vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params);
                }
            }
            catch (error) {
                this.error(`Sending pending changes failed`, error, false);
                throw error;
            }
        });
    }
    triggerPendingChangeDelivery() {
        this._pendingChangeDelayer.trigger(async () => {
            const connection = this.activeConnection();
            if (connection === undefined) {
                this.triggerPendingChangeDelivery();
                return;
            }
            await this.sendPendingFullTextDocumentChanges(connection);
        }).catch((error) => this.error(`Delivering pending changes failed`, error, false));
    }
    _diagnosticQueue = new Map();
    _diagnosticQueueState = { state: 'idle' };
    handleDiagnostics(params) {
        if (this._diagnostics === null) {
            return;
        }
        const key = params.uri;
        if (this._diagnosticQueueState.state === 'busy' && this._diagnosticQueueState.document === key) {
            // Cancel the active run;
            this._diagnosticQueueState.tokenSource.cancel();
        }
        this._diagnosticQueue.set(params.uri, params.diagnostics);
        this.triggerDiagnosticQueue();
    }
    triggerDiagnosticQueue() {
        (0, vscode_languageserver_protocol_1.RAL)().timer.setImmediate(() => { this.workDiagnosticQueue(); });
    }
    workDiagnosticQueue() {
        if (this._diagnosticQueueState.state === 'busy') {
            return;
        }
        const next = this._diagnosticQueue.entries().next();
        if (next.done === true) {
            // Nothing in the queue
            return;
        }
        const [document, diagnostics] = next.value;
        this._diagnosticQueue.delete(document);
        const tokenSource = new vscode_1.CancellationTokenSource();
        this._diagnosticQueueState = { state: 'busy', document: document, tokenSource };
        this._p2c.asDiagnostics(diagnostics, tokenSource.token).then((converted) => {
            if (!tokenSource.token.isCancellationRequested) {
                const uri = this._p2c.asUri(document);
                const middleware = this.clientOptions.middleware;
                if (middleware.handleDiagnostics) {
                    middleware.handleDiagnostics(uri, converted, (uri, diagnostics) => this.setDiagnostics(uri, diagnostics));
                }
                else {
                    this.setDiagnostics(uri, converted);
                }
            }
        }).catch((error) => {
            this.error(`Processing diagnostic queue failed.`, error);
        }).finally(() => {
            this._diagnosticQueueState = { state: 'idle' };
            this.triggerDiagnosticQueue();
        });
    }
    setDiagnostics(uri, diagnostics) {
        if (this._diagnostics === null) {
            return;
        }
        const diagnosticsCollection = this.diagnostics;
        if (diagnosticsCollection !== undefined) {
            diagnosticsCollection.set(uri, diagnostics);
        }
    }
    getLocale() {
        return vscode_1.env.language;
    }
    async $start() {
        if (this.$state === ClientState.StartFailed) {
            throw new Error(`Previous start failed. Can't restart server.`);
        }
        await this.start();
        const connection = this.activeConnection();
        if (connection === undefined) {
            throw new Error(`Starting server failed`);
        }
        return connection;
    }
    async createConnection() {
        const errorHandler = (error, message, count) => {
            this.handleConnectionError(error, message, count).catch((error) => this.error(`Handling connection error failed`, error));
        };
        const closeHandler = () => {
            this.handleConnectionClosed().catch((error) => this.error(`Handling connection close failed`, error));
        };
        const transports = await this.createMessageTransports(this._clientOptions.stdioEncoding || 'utf8');
        this._connection = createConnection(transports.reader, transports.writer, errorHandler, closeHandler, this._clientOptions.connectionOptions);
        return this._connection;
    }
    async handleConnectionClosed() {
        // Check whether this is a normal shutdown in progress or the client stopped normally.
        if (this.$state === ClientState.Stopped) {
            return;
        }
        try {
            if (this._connection !== undefined) {
                this._connection.dispose();
            }
        }
        catch (error) {
            // Disposing a connection could fail if error cases.
        }
        let handlerResult = { action: CloseAction.DoNotRestart };
        if (this.$state !== ClientState.Stopping) {
            try {
                handlerResult = await this._clientOptions.errorHandler.closed();
            }
            catch (error) {
                // Ignore errors coming from the error handler.
            }
        }
        this._connection = undefined;
        if (handlerResult.action === CloseAction.DoNotRestart) {
            this.error(handlerResult.message ?? 'Connection to server got closed. Server will not be restarted.', undefined, handlerResult.handled === true ? false : 'force');
            this.cleanUp(ShutdownMode.Stop);
            if (this.$state === ClientState.Starting) {
                this.$state = ClientState.StartFailed;
            }
            else {
                this.$state = ClientState.Stopped;
            }
            this._onStop = Promise.resolve();
            this._onStart = undefined;
        }
        else if (handlerResult.action === CloseAction.Restart) {
            this.info(handlerResult.message ?? 'Connection to server got closed. Server will restart.', undefined, !handlerResult.handled);
            this.cleanUp(ShutdownMode.Restart);
            this.$state = ClientState.Initial;
            this._onStop = Promise.resolve();
            this._onStart = undefined;
            this.start().catch((error) => this.error(`Restarting server failed`, error, 'force'));
        }
    }
    async handleConnectionError(error, message, count) {
        const handlerResult = await this._clientOptions.errorHandler.error(error, message, count);
        if (handlerResult.action === ErrorAction.Shutdown) {
            this.error(handlerResult.message ?? `Client ${this._name}: connection to server is erroring.\n${error.message}\nShutting down server.`, undefined, handlerResult.handled === true ? false : 'force');
            this.stop().catch((error) => {
                this.error(`Stopping server failed`, error, false);
            });
        }
        else {
            this.error(handlerResult.message ??
                `Client ${this._name}: connection to server is erroring.\n${error.message}`, undefined, handlerResult.handled === true ? false : 'force');
        }
    }
    hookConfigurationChanged(connection) {
        this._listeners.push(vscode_1.workspace.onDidChangeConfiguration(() => {
            this.refreshTrace(connection, true);
        }));
    }
    hookLogLevelChanged(connection) {
        this._listeners.push(this.traceOutputChannel.onDidChangeLogLevel((level) => {
            this._traceLogLevel = level;
            this.refreshTrace(connection, true);
        }));
    }
    refreshTrace(connection, sendNotification = false) {
        const config = vscode_1.workspace.getConfiguration(this._id);
        let trace = this._traceLogLevel !== vscode_1.LogLevel.Trace ? vscode_languageserver_protocol_1.Trace.Off : vscode_languageserver_protocol_1.Trace.Messages;
        let traceFormat = vscode_languageserver_protocol_1.TraceFormat.Text;
        if (config && trace !== vscode_languageserver_protocol_1.Trace.Off) {
            const traceConfig = config.get('trace.server', 'messages');
            if (typeof traceConfig === 'string') {
                trace = vscode_languageserver_protocol_1.Trace.fromString(traceConfig);
                if (trace === vscode_languageserver_protocol_1.Trace.Off) {
                    trace = vscode_languageserver_protocol_1.Trace.Messages;
                }
            }
            else {
                trace = vscode_languageserver_protocol_1.Trace.fromString(config.get('trace.server.verbosity', 'messages'));
                if (trace === vscode_languageserver_protocol_1.Trace.Off) {
                    trace = vscode_languageserver_protocol_1.Trace.Messages;
                }
                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
        }).catch((error) => { this.error(`Updating trace failed with error`, error, false); });
    }
    hookFileEvents(_connection) {
        const 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);
    }
    _features = [];
    _dynamicFeatures = new Map();
    registerFeatures(features) {
        for (const feature of features) {
            this.registerFeature(feature);
        }
    }
    registerFeature(feature) {
        this._features.push(feature);
        if (features_1.DynamicFeature.is(feature)) {
            const registrationType = feature.registrationType;
            this._dynamicFeatures.set(registrationType.method, feature);
        }
    }
    getFeature(request) {
        return this._dynamicFeatures.get(request);
    }
    hasDedicatedTextSynchronizationFeature(textDocument) {
        const feature = this.getFeature(vscode_languageserver_protocol_1.NotebookDocumentSyncRegistrationType.method);
        if (feature === undefined || !(feature instanceof notebook_1.NotebookDocumentSyncFeature)) {
            return false;
        }
        return feature.handles(textDocument);
    }
    registerBuiltinFeatures() {
        const pendingFullTextDocumentChanges = new Map();
        this.registerFeature(new configuration_1.ConfigurationFeature(this));
        this._didOpenTextDocumentFeature = new textSynchronization_1.DidOpenTextDocumentFeature(this, this._syncedDocuments);
        this.registerFeature(this._didOpenTextDocumentFeature);
        this._didChangeTextDocumentFeature = new textSynchronization_1.DidChangeTextDocumentFeature(this, pendingFullTextDocumentChanges);
        this._didChangeTextDocumentFeature.onPendingChangeAdded(() => {
            this.triggerPendingChangeDelivery();
        });
        this.registerFeature(this._didChangeTextDocumentFeature);
        this.registerFeature(new textSynchronization_1.WillSaveFeature(this));
        this.registerFeature(new textSynchronization_1.WillSaveWaitUntilFeature(this));
        this.registerFeature(new textSynchronization_1.DidSaveTextDocumentFeature(this));
        this.registerFeature(new textSynchronization_1.DidCloseTextDocumentFeature(this, this._syncedDocuments, pendingFullTextDocumentChanges));
        this.registerFeature(new fileSystemWatcher_1.FileSystemWatcherFeature(this, (event) => this.notifyFileEvent(event)));
        this.registerFeature(new completion_1.CompletionItemFeature(this));
        this.registerFeature(new hover_1.HoverFeature(this));
        this.registerFeature(new signatureHelp_1.SignatureHelpFeature(this));
        this.registerFeature(new definition_1.DefinitionFeature(this));
        this.registerFeature(new reference_1.ReferencesFeature(this));
        this.registerFeature(new documentHighlight_1.DocumentHighlightFeature(this));
        this.registerFeature(new documentSymbol_1.DocumentSymbolFeature(this));
        this.registerFeature(new workspaceSymbol_1.WorkspaceSymbolFeature(this));
        this.registerFeature(new codeAction_1.CodeActionFeature(this));
        this.registerFeature(new codeLens_1.CodeLensFeature(this));
        this.registerFeature(new formatting_1.DocumentFormattingFeature(this));
        this.registerFeature(new formatting_1.DocumentRangeFormattingFeature(this));
        this.registerFeature(new formatting_1.DocumentOnTypeFormattingFeature(this));
        this.registerFeature(new rename_1.RenameFeature(this));
        this.registerFeature(new documentLink_1.DocumentLinkFeature(this));
        this.registerFeature(new executeCommand_1.ExecuteCommandFeature(this));
        this.registerFeature(new configuration_1.SyncConfigurationFeature(this));
        this.registerFeature(new typeDefinition_1.TypeDefinitionFeature(this));
        this.registerFeature(new implementation_1.ImplementationFeature(this));
        this.registerFeature(new colorProvider_1.ColorProviderFeature(this));
        // We only register the workspace folder feature if the client is not locked
        // to a specific workspace folder.
        if (this.clientOptions.workspaceFolder === undefined) {
            this.registerFeature(new workspaceFolder_1.WorkspaceFoldersFeature(this));
        }
        this.registerFeature(new foldingRange_1.FoldingRangeFeature(this));
        this.registerFeature(new declaration_1.DeclarationFeature(this));
        this.registerFeature(new selectionRange_1.SelectionRangeFeature(this));
        this.registerFeature(new progress_1.ProgressFeature(this));
        this.registerFeature(new callHierarchy_1.CallHierarchyFeature(this));
        this.registerFeature(new semanticTokens_1.SemanticTokensFeature(this));
        this.registerFeature(new linkedEditingRange_1.LinkedEditingFeature(this));
        this.registerFeature(new fileOperations_1.DidCreateFilesFeature(this));
        this.registerFeature(new fileOperations_1.DidRenameFilesFeature(this));
        this.registerFeature(new fileOperations_1.DidDeleteFilesFeature(this));
        this.registerFeature(new fileOperations_1.WillCreateFilesFeature(this));
        this.registerFeature(new fileOperations_1.WillRenameFilesFeature(this));
        this.registerFeature(new fileOperations_1.WillDeleteFilesFeature(this));
        this.registerFeature(new typeHierarchy_1.TypeHierarchyFeature(this));
        this.registerFeature(new inlineValue_1.InlineValueFeature(this));
        this.registerFeature(new inlayHint_1.InlayHintsFeature(this));
        this.registerFeature(new diagnostic_1.DiagnosticFeature(this));
        this.registerFeature(new notebook_1.NotebookDocumentSyncFeature(this));
        this.registerFeature(new inlineCompletion_1.InlineCompletionItemFeature(this));
        this.registerFeature(new textDocumentContent_1.TextDocumentContentFeature(this));
    }
    registerProposedFeatures() {
        this.registerFeatures(ProposedFeatures.createAll(this));
    }
    fillInitializeParams(params) {
        for (const feature of this._features) {
            if (Is.func(feature.fillInitializeParams)) {
                feature.fillInitializeParams(params);
            }
        }
    }
    computeClientCapabilities() {
        const result = {};
        (0, features_1.ensure)(result, 'workspace').applyEdit = true;
        const workspaceEdit = (0, features_1.ensure)((0, features_1.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
        };
        workspaceEdit.metadataSupport = true;
        workspaceEdit.snippetEditSupport = true;
        const diagnostics = (0, features_1.ensure)((0, features_1.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 textDocumentFilter = (0, features_1.ensure)((0, features_1.ensure)(result, 'textDocument'), 'filters');
        textDocumentFilter.relativePatternSupport = true;
        const windowCapabilities = (0, features_1.ensure)(result, 'window');
        const showMessage = (0, features_1.ensure)(windowCapabilities, 'showMessage');
        showMessage.messageActionItem = { additionalPropertiesSupport: true };
        const showDocument = (0, features_1.ensure)(windowCapabilities, 'showDocument');
        showDocument.support = true;
        const generalCapabilities = (0, features_1.ensure)(result, 'general');
        generalCapabilities.staleRequestSupport = {
            cancel: true,
            retryOnContentModified: Array.from(BaseLanguageClient.RequestsToCancelOnContentModified)
        };
        generalCapabilities.regularExpressions = { engine: 'ECMAScript', version: 'ES2020' };
        generalCapabilities.markdown = {
            parser: 'marked',
            version: '1.1.0',
        };
        generalCapabilities.positionEncodings = ['utf-16'];
        if (this._clientOptions.markdown.supportHtml) {
            generalCapabilities.markdown.allowedTags = ['ul', 'li', 'p', 'code', 'blockquote', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'em', 'pre', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'div', 'del', 'a', 'strong', 'br', 'img', 'span'];
        }
        for (const feature of this._features) {
            feature.fillClientCapabilities(result);
        }
        return result;
    }
    initializeFeatures(_connection) {
        const documentSelector = this._clientOptions.documentSelector;
        for (const feature of this._features) {
            if (Is.func(feature.preInitialize)) {
                feature.preInitialize(this._capabilities, documentSelector);
            }
        }
        for (const feature of this._features) {
            feature.initialize(this._capabilities, documentSelector);
        }
    }
    async handleRegistrationRequest(params) {
        const middleware = this.clientOptions.middleware?.handleRegisterCapability;
        if (middleware) {
            return middleware(params, nextParams => this.doRegisterCapability(nextParams));
        }
        else {
            return this.doRegisterCapability(params);
        }
    }
    async doRegisterCapability(params) {
        // We will not receive a registration call before a client is running
        // from a server. However if we stop or shutdown we might which might
        // try to restart the server. So ignore registrations if we are not running
        if (!this.isRunning()) {
            for (const registration of params.registrations) {
                this._ignoredRegistrations.add(registration.id);
            }
            return;
        }
        for (const registration of params.registrations) {
            const feature = this._dynamicFeatures.get(registration.method);
            if (feature === undefined) {
                return Promise.reject(new Error(`No feature implementation for ${registration.method} found. Registration failed.`));
            }
            const options = registration.registerOptions ?? {};
            options.documentSelector = options.documentSelector ?? this._clientOptions.documentSelector;
            const data = {
                id: registration.id,
                registerOptions: options
            };
            try {
                feature.register(data);
            }
            catch (err) {
                return Promise.reject(err);
            }
        }
    }
    async handleUnregistrationRequest(params) {
        const middleware = this.clientOptions.middleware?.handleUnregisterCapability;
        if (middleware) {
            return middleware(params, nextParams => this.doUnregisterCapability(nextParams));
        }
        else {
            return this.doUnregisterCapability(params);
        }
    }
    async doUnregisterCapability(params) {
        for (const unregistration of params.unregisterations) {
            if (this._ignoredRegistrations.has(unregistration.id)) {
                continue;
            }
            const feature = this._dynamicFeatures.get(unregistration.method);
            if (!feature) {
                return Promise.reject(new Error(`No feature implementation for ${unregistration.method} found. Unregistration failed.`));
            }
            feature.unregister(unregistration.id);
        }
    }
    async handleApplyWorkspaceEdit(params) {
        const middleware = this.clientOptions.middleware?.workspace?.handleApplyEdit;
        if (middleware) {
            const resultOrError = await middleware(params, nextParams => this.doHandleApplyWorkspaceEdit(nextParams));
            if (resultOrError instanceof vscode_languageserver_protocol_1.ResponseError) {
                return Promise.reject(resultOrError);
            }
            return resultOrError;
        }
        else {
            return this.doHandleApplyWorkspaceEdit(params);
        }
    }
    workspaceEditLock = new async_1.Semaphore(1);
    async doHandleApplyWorkspaceEdit(params) {
        const workspaceEdit = params.edit;
        // Make sure we convert workspace edits one after the other. Otherwise
        // we might execute a workspace edit received first after we received another
        // one since the conversion might race.
        const converted = await this.workspaceEditLock.lock(() => {
            return this._p2c.asWorkspaceEdit(workspaceEdit);
        });
        // Check whether the version provided in the workspace edit matches the version of the open text document.
        // If not, we can't apply the workspace edit since it might be based on an old version of the document.
        // CRITICAL: make sure that after this check has run no async operation happens which might cause that
        // the version of the text document changes. Otherwise we might apply a workspace edit based on an old
        // version of the document.
        const valid = this.validateWorkspaceEdit(workspaceEdit);
        if (!valid) {
            return Promise.resolve({ applied: false });
        }
        return Is.asPromise(vscode_1.workspace.applyEdit(converted, { isRefactoring: params.metadata?.isRefactoring }).then((value) => { return { applied: value }; }));
    }
    validateWorkspaceEdit(workspaceEdit) {
        const openTextDocuments = new Map();
        vscode_1.workspace.textDocuments.forEach((document) => openTextDocuments.set(document.uri.toString(), document));
        if (workspaceEdit.documentChanges) {
            for (const change of workspaceEdit.documentChanges) {
                if (vscode_languageserver_protocol_1.TextDocumentEdit.is(change) && change.textDocument.version !== null && change.textDocument.version >= 0) {
                    const changeUri = this._p2c.asUri(change.textDocument.uri).toString();
                    const textDocument = openTextDocuments.get(changeUri);
                    if (textDocument && textDocument.version !== change.textDocument.version) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    static RequestsToCancelOnContentModified = new Set([
        vscode_languageserver_protocol_1.SemanticTokensRequest.method,
        vscode_languageserver_protocol_1.SemanticTokensRangeRequest.method,
        vscode_languageserver_protocol_1.SemanticTokensDeltaRequest.method
    ]);
    static CancellableResolveCalls = new Set([
        vscode_languageserver_protocol_1.CompletionResolveRequest.method,
        vscode_languageserver_protocol_1.CodeLensResolveRequest.method,
        vscode_languageserver_protocol_1.CodeActionResolveRequest.method,
        vscode_languageserver_protocol_1.InlayHintResolveRequest.method,
        vscode_languageserver_protocol_1.DocumentLinkResolveRequest.method,
        vscode_languageserver_protocol_1.WorkspaceSymbolResolveRequest.method
    ]);
    handleFailedRequest(type, token, error, defaultValue, showNotification = true, throwOnCancel = false) {
        // If we get a request cancel or a content modified don't log anything.
        if (error instanceof vscode_languageserver_protocol_1.ResponseError) {
            // The connection got disposed while we were waiting for a response.
            // Simply return the default value. Is the best we can do.
            if (error.code === vscode_languageserver_protocol_1.ErrorCodes.PendingResponseRejected || error.code === vscode_languageserver_protocol_1.ErrorCodes.ConnectionInactive) {
                return defaultValue;
            }
            if (error.code === vscode_languageserver_protocol_1.LSPErrorCodes.RequestCancelled || error.code === vscode_languageserver_protocol_1.LSPErrorCodes.ServerCancelled) {
                if (token !== undefined && token.isCancellationRequested && !throwOnCancel) {
                    return defaultValue;
                }
                else {
                    if (error.data !== undefined) {
                        throw new features_1.LSPCancellationError(error.data);
                    }
                    else {
                        throw new vscode_1.CancellationError();
                    }
                }
            }
            else if (error.code === vscode_languageserver_protocol_1.LSPErrorCodes.ContentModified) {
                if (BaseLanguageClient.RequestsToCancelOnContentModified.has(type.method) || BaseLanguageClient.CancellableResolveCalls.has(type.method)) {
                    throw new vscode_1.CancellationError();
                }
                else {
                    return defaultValue;
                }
            }
        }
        this.error(`Request ${type.method} failed.`, error, showNotification);
        throw error;
    }
}
exports.BaseLanguageClient = BaseLanguageClient;
class LanguageClient extends BaseLanguageClient {
    serverOptions;
    constructor(id, name, serverOptions, clientOptions) {
        super(id, name, clientOptions);
        this.serverOptions = serverOptions;
    }
    async createMessageTransports(_encoding) {
        return this.serverOptions();
    }
}
exports.LanguageClient = LanguageClient;
class ConsoleLogger {
    error(message) {
        (0, vscode_languageserver_protocol_1.RAL)().console.error(message);
    }
    warn(message) {
        (0, vscode_languageserver_protocol_1.RAL)().console.warn(message);
    }
    info(message) {
        (0, vscode_languageserver_protocol_1.RAL)().console.info(message);
    }
    log(message) {
        (0, vscode_languageserver_protocol_1.RAL)().console.log(message);
    }
}
function createConnection(input, output, errorHandler, closeHandler, options) {
    const logger = new ConsoleLogger();
    const connection = (0, vscode_languageserver_protocol_1.createProtocolConnection)(input, output, logger, options);
    connection.onError((data) => { errorHandler(data[0], data[1], data[2]); });
    connection.onClose(closeHandler);
    const result = {
        listen: () => connection.listen(),
        sendRequest: connection.sendRequest,
        onRequest: connection.onRequest,
        hasPendingResponse: connection.hasPendingResponse,
        sendNotification: connection.sendNotification,
        onNotification: connection.onNotification,
        onProgress: connection.onProgress,
        sendProgress: connection.sendProgress,
        trace: (value, tracer, sendNotificationOrTraceOptions) => {
            const defaultTraceOptions = {
                sendNotification: false,
                traceFormat: vscode_languageserver_protocol_1.TraceFormat.Text
            };
            if (sendNotificationOrTraceOptions === undefined) {
                return connection.trace(value, tracer, defaultTraceOptions);
            }
            else if (Is.boolean(sendNotificationOrTraceOptions)) {
                return connection.trace(value, tracer, sendNotificationOrTraceOptions);
            }
            else {
                return connection.trace(value, tracer, sendNotificationOrTraceOptions);
            }
        },
        initialize: (params) => {
            // This needs to return and MUST not be await to avoid any async
            // scheduling. Otherwise messages might overtake each other.
            return connection.sendRequest(vscode_languageserver_protocol_1.InitializeRequest.type, params);
        },
        shutdown: () => {
            // This needs to return and MUST not be await to avoid any async
            // scheduling. Otherwise messages might overtake each other.
            return connection.sendRequest(vscode_languageserver_protocol_1.ShutdownRequest.type, undefined);
        },
        exit: () => {
            // This needs to return and MUST not be await to avoid any async
            // scheduling. Otherwise messages might overtake each other.
            return connection.sendNotification(vscode_languageserver_protocol_1.ExitNotification.type);
        },
        end: () => connection.end(),
        dispose: () => connection.dispose()
    };
    return result;
}
// Exporting proposed protocol.
var ProposedFeatures;
(function (ProposedFeatures) {
    function createAll(_client) {
        const result = [];
        return result;
    }
    ProposedFeatures.createAll = createAll;
})(ProposedFeatures || (exports.ProposedFeatures = ProposedFeatures = {}));