/// <summary>
        ///     Stop the language server.
        /// </summary>
        /// <returns>
        ///     A <see cref="Task"/> representing the shutdown operation.
        /// </returns>
        public async Task Shutdown()
        {
            LspConnection connection = _connection;

            if (connection != null)
            {
                if (connection.IsOpen)
                {
                    connection.SendEmptyNotification("shutdown");
                    connection.SendEmptyNotification("exit");
                    connection.Disconnect(flushOutgoing: true);
                }

                await connection.HasHasDisconnected;
            }

            ServerProcess serverProcess = _process;

            if (serverProcess != null)
            {
                if (serverProcess.IsRunning)
                {
                    await serverProcess.Stop();
                }
            }

            IsInitialized    = false;
            _readyCompletion = new TaskCompletionSource <object>();
        }
示例#2
0
        /// <summary>
        ///     Start the language server.
        /// </summary>
        /// <returns>
        ///     A <see cref="Task"/> representing the operation.
        /// </returns>
        async Task Start()
        {
            if (_process == null)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            if (!_process.IsRunning)
            {
                Log.LogDebug("Starting language server...");

                await _process.Start();

                Log.LogDebug("Language server is running.");
            }

            Log.LogDebug("Opening connection to language server...");

            if (_connection == null)
            {
                _connection = new LspConnection(LoggerFactory, input: _process.OutputStream, output: _process.InputStream);
            }

            _connection.Connect(_dispatcher);

            Log.LogDebug("Connection to language server is open.");
        }
示例#3
0
        public async Task Server_HandleEmptyNotification_Success()
        {
            var testCompletion = new TaskCompletionSource <object>();

            LspConnection clientConnection = await CreateClientConnection();

            LspConnection serverConnection = await CreateServerConnection();

            var clientDispatcher = new LspDispatcher();

            clientDispatcher.HandleEmptyNotification("test", () =>
            {
                Log.LogInformation("Got notification.");

                testCompletion.SetResult(null);
            });
            clientConnection.Connect(clientDispatcher);

            serverConnection.Connect(new LspDispatcher());
            serverConnection.SendEmptyNotification("test");

            await testCompletion.Task;

            serverConnection.Disconnect(flushOutgoing: true);
            clientConnection.Disconnect();

            await Task.WhenAll(clientConnection.HasHasDisconnected, serverConnection.HasHasDisconnected);
        }
        public async Task Server_HandleRequest_Success()
        {
            LspConnection clientConnection = await CreateClientConnection();

            LspConnection serverConnection = await CreateServerConnection();

            var clientDispatcher = new LspDispatcher();

            clientDispatcher.HandleRequest <TestRequest, TestResponse>("test", (request, cancellationToken) =>
            {
                Log.LogInformation("Got request: {@Request}", request);

                return(Task.FromResult(new TestResponse
                {
                    Value = request.Value.ToString()
                }));
            });
            clientConnection.Connect(clientDispatcher);

            serverConnection.Connect(new LspDispatcher());
            TestResponse response = await serverConnection.SendRequest <TestResponse>("test", new TestRequest
            {
                Value = 1234
            });

            Assert.Equal("1234", response.Value);

            Log.LogInformation("Got response: {@Response}", response);

            serverConnection.Disconnect(flushOutgoing: true);
            clientConnection.Disconnect();

            await Task.WhenAll(clientConnection.HasHasDisconnected, serverConnection.HasHasDisconnected);
        }
        public async Task Client_HandleCommandRequest_Success()
        {
            LspConnection clientConnection = await CreateClientConnection();

            LspConnection serverConnection = await CreateServerConnection();

            var serverDispatcher = new LspDispatcher();

            serverDispatcher.HandleRequest <TestRequest>("test", (request, cancellationToken) =>
            {
                Log.LogInformation("Got request: {@Request}", request);

                Assert.Equal(1234, request.Value);

                return(Task.CompletedTask);
            });
            serverConnection.Connect(serverDispatcher);

            clientConnection.Connect(new LspDispatcher());
            await clientConnection.SendRequest("test", new TestRequest
            {
                Value = 1234
            });

            clientConnection.Disconnect(flushOutgoing: true);
            serverConnection.Disconnect();

            await Task.WhenAll(clientConnection.HasHasDisconnected, serverConnection.HasHasDisconnected);
        }
        /// <summary>
        ///     Dispose of resources being used by the client.
        /// </summary>
        public void Dispose()
        {
            LspConnection connection = Interlocked.Exchange(ref _connection, null);

            connection?.Dispose();

            ServerProcess serverProcess = Interlocked.Exchange(ref _process, null);

            serverProcess?.Dispose();
        }
        /// <summary>
        ///     Send a request to the language server.
        /// </summary>
        /// <typeparam name="TResponse">
        ///     The response message type.
        /// </typeparam>
        /// <param name="method">
        ///     The request method name.
        /// </param>
        /// <param name="request">
        ///     The request message.
        /// </param>
        /// <param name="cancellation">
        ///     An optional cancellation token that can be used to cancel the request.
        /// </param>
        /// <returns>
        ///     A <see cref="Task{TResult}"/> representing the response.
        /// </returns>
        public Task <TResponse> SendRequest <TResponse>(string method, object request, CancellationToken cancellation = default(CancellationToken))
        {
            LspConnection connection = _connection;

            if (connection == null || !connection.IsOpen)
            {
                throw new InvalidOperationException("Not connected to the language server.");
            }

            return(connection.SendRequest <TResponse>(method, request, cancellation));
        }
        /// <summary>
        ///     Send a notification message to the language server.
        /// </summary>
        /// <param name="method">
        ///     The notification method name.
        /// </param>
        /// <param name="notification">
        ///     The notification message.
        /// </param>
        public void SendNotification(string method, object notification)
        {
            LspConnection connection = _connection;

            if (connection == null || !connection.IsOpen)
            {
                throw new InvalidOperationException("Not connected to the language server.");
            }

            connection.SendNotification(method, notification);
        }
        /// <summary>
        ///     Connect the client and server.
        /// </summary>
        /// <param name="handleServerInitialize">
        ///     Add standard handlers for server initialisation?
        /// </param>
        async Task Connect(bool handleServerInitialize = true)
        {
            ServerConnection = await CreateServerConnection();

            ServerConnection.Connect(ServerDispatcher);

            if (handleServerInitialize)
            {
                HandleServerInitialize();
            }

            LanguageClient = await CreateClient(initialize : true);
        }
        /// <summary>
        ///     Create a <see cref="LspConnection"/> that uses the client ends of the the test's <see cref="PipeServerProcess"/> streams.
        /// </summary>
        /// <returns>
        ///     The <see cref="LspConnection"/>.
        /// </returns>
        protected async Task <LspConnection> CreateClientConnection()
        {
            if (!_serverProcess.IsRunning)
            {
                await StartServer();
            }

            await _serverProcess.HasStarted;

            LspConnection connection = new LspConnection(LoggerFactory, input: ServerOutputStream, output: ServerInputStream);

            Disposal.Add(connection);

            return(connection);
        }
        /// <summary>
        ///     Called when the server process has exited.
        /// </summary>
        /// <param name="sender">
        ///     The event sender.
        /// </param>
        /// <param name="args">
        ///     The event arguments.
        /// </param>
        async void ServerProcess_Exit(object sender, EventArgs args)
        {
            Log.LogDebug("Server process has exited; language client is shutting down...");

            LspConnection connection = Interlocked.Exchange(ref _connection, null);

            if (connection != null)
            {
                using (connection)
                {
                    connection.Disconnect();
                    await connection.HasHasDisconnected;
                }
            }

            await Shutdown();

            Log.LogDebug("Language client shutdown complete.");
        }