backtrace_ls/lsp/
server.rs

1//! LSP server entry point.
2
3use std::sync::Arc;
4
5use async_lsp::{
6    client_monitor::ClientProcessMonitorLayer,
7    concurrency::ConcurrencyLayer,
8    lsp_types::{
9        CodeActionKind, CodeActionOptions, CodeActionProviderCapability, DiagnosticOptions,
10        DiagnosticServerCapabilities, ExecuteCommandOptions, ServerCapabilities, ServerInfo,
11        TextDocumentSyncCapability, TextDocumentSyncKind, WorkDoneProgressOptions,
12    },
13    panic::CatchUnwindLayer,
14    router::Router,
15    server::LifecycleLayer,
16};
17use tokio::io::{stdin, stdout};
18use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
19use tower::ServiceBuilder;
20
21use super::{code_action, handlers, state::ServerState};
22use crate::{Config, error::LSError};
23
24#[must_use]
25pub fn server_capabilities() -> ServerCapabilities {
26    ServerCapabilities {
27        diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions {
28            identifier: None,
29            inter_file_dependencies: false,
30            workspace_diagnostics: true,
31            work_done_progress_options: WorkDoneProgressOptions::default(),
32        })),
33        text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::NONE)),
34        code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions {
35            code_action_kinds: Some(vec![CodeActionKind::QUICKFIX]),
36            work_done_progress_options: WorkDoneProgressOptions::default(),
37            resolve_provider: None,
38        })),
39        execute_command_provider: Some(ExecuteCommandOptions {
40            commands: code_action::all_commands(),
41            work_done_progress_options: WorkDoneProgressOptions::default(),
42        }),
43        ..ServerCapabilities::default()
44    }
45}
46
47#[must_use]
48pub fn server_info() -> ServerInfo {
49    ServerInfo {
50        name: "backtrace-ls".to_string(),
51        version: Some(env!("CARGO_PKG_VERSION").to_string()),
52    }
53}
54
55/// Runs the LSP server.
56pub async fn run(config: Config) -> Result<(), LSError> {
57    let (server, _) = async_lsp::MainLoop::new_server(|client| {
58        let state = ServerState::new(client.clone(), config.clone());
59        let mut router = Router::new(Arc::clone(&state));
60
61        handlers::register_all(&mut router, &state);
62
63        ServiceBuilder::new()
64            .layer(LifecycleLayer::default())
65            .layer(CatchUnwindLayer::default())
66            .layer(ConcurrencyLayer::default())
67            .layer(ClientProcessMonitorLayer::new(client))
68            .service(router)
69    });
70
71    let (stdin, stdout) = (stdin().compat(), stdout().compat_write());
72
73    server
74        .run_buffered(stdin, stdout)
75        .await
76        .map_err(|e| LSError::Generic(format!("LSP server error: {e}")))?;
77
78    Ok(())
79}