/// <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>(); }
/// <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."); }
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."); }