Skip to main content

squawk_server/
server.rs

1use anyhow::Result;
2use log::info;
3use lsp_server::Connection;
4use lsp_types::{
5    CodeActionKind, CodeActionOptions, CodeActionProviderCapability, CompletionOptions,
6    DiagnosticOptions, DiagnosticServerCapabilities, FoldingRangeProviderCapability,
7    HoverProviderCapability, InitializeParams, OneOf, SelectionRangeProviderCapability,
8    SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions,
9    SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentSyncCapability,
10    TextDocumentSyncKind, WorkDoneProgressOptions,
11};
12
13use crate::{
14    global_state::GlobalState,
15    semantic_tokens::{SUPPORTED_MODIFIERS, SUPPORTED_TYPES},
16};
17
18pub fn run() -> Result<()> {
19    info!("Starting Squawk LSP server");
20
21    let (connection, io_threads) = Connection::stdio();
22
23    let server_capabilities = serde_json::to_value(&ServerCapabilities {
24        text_document_sync: Some(TextDocumentSyncCapability::Kind(
25            TextDocumentSyncKind::INCREMENTAL,
26        )),
27        code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions {
28            code_action_kinds: Some(vec![
29                CodeActionKind::QUICKFIX,
30                CodeActionKind::REFACTOR_REWRITE,
31            ]),
32            work_done_progress_options: WorkDoneProgressOptions {
33                work_done_progress: None,
34            },
35            resolve_provider: None,
36        })),
37        selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
38        references_provider: Some(OneOf::Left(true)),
39        definition_provider: Some(OneOf::Left(true)),
40        hover_provider: Some(HoverProviderCapability::Simple(true)),
41        inlay_hint_provider: Some(OneOf::Left(true)),
42        diagnostic_provider: Some(DiagnosticServerCapabilities::Options(DiagnosticOptions {
43            identifier: None,
44            inter_file_dependencies: false,
45            workspace_diagnostics: false,
46            work_done_progress_options: WorkDoneProgressOptions {
47                work_done_progress: None,
48            },
49        })),
50        document_symbol_provider: Some(OneOf::Left(true)),
51        folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
52        completion_provider: Some(CompletionOptions {
53            resolve_provider: Some(false),
54            trigger_characters: Some(vec![".".to_owned()]),
55            all_commit_characters: None,
56            work_done_progress_options: WorkDoneProgressOptions {
57                work_done_progress: None,
58            },
59            completion_item: None,
60        }),
61        semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensOptions(
62            SemanticTokensOptions {
63                work_done_progress_options: WorkDoneProgressOptions {
64                    work_done_progress: None,
65                },
66                legend: SemanticTokensLegend {
67                    token_types: SUPPORTED_TYPES.to_vec(),
68                    token_modifiers: SUPPORTED_MODIFIERS.to_vec(),
69                },
70                range: Some(true),
71                full: Some(SemanticTokensFullOptions::Bool(true)),
72            },
73        )),
74        ..Default::default()
75    })
76    .unwrap();
77
78    info!("LSP server initializing connection...");
79    let initialization_params = connection.initialize(server_capabilities)?;
80    info!("LSP server initialized, entering main loop");
81
82    main_loop(connection, initialization_params)?;
83
84    info!("LSP server shutting down");
85
86    io_threads.join()?;
87    Ok(())
88}
89
90fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> {
91    info!("Server main loop");
92
93    let init_params: InitializeParams = serde_json::from_value(params).unwrap_or_default();
94    info!("Client process ID: {:?}", init_params.process_id);
95    let client_name = init_params.client_info.map(|x| x.name);
96    info!("Client name: {client_name:?}");
97
98    GlobalState::new(connection.sender).run(connection.receiver)
99}