Skip to main content

squawk_server/
server.rs

1use anyhow::Result;
2use gen_lsp_types::{
3    CodeActionKind, CodeActionOptions, CodeActionProvider, CompletionOptions, DefinitionProvider,
4    DiagnosticOptions, DiagnosticProvider, DocumentFormattingProvider, DocumentSymbolProvider,
5    FoldingRangeProvider, Full, HoverProvider, InitializeParams, InlayHintProvider,
6    ReferencesProvider, SelectionRangeProvider, SemanticTokensLegend, SemanticTokensOptions,
7    SemanticTokensOptionsRange, SemanticTokensProvider, ServerCapabilities, TextDocumentSync,
8    TextDocumentSyncKind, WorkDoneProgressOptions,
9};
10use log::info;
11use lsp_server::Connection;
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(TextDocumentSync::Kind(TextDocumentSyncKind::Incremental)),
25        code_action_provider: Some(CodeActionProvider::CodeActionOptions(CodeActionOptions {
26            code_action_kinds: Some(vec![
27                CodeActionKind::QuickFix,
28                CodeActionKind::RefactorRewrite,
29            ]),
30            work_done_progress_options: WorkDoneProgressOptions {
31                work_done_progress: None,
32            },
33            resolve_provider: None,
34            documentation: None,
35        })),
36        selection_range_provider: Some(SelectionRangeProvider::Bool(true)),
37        references_provider: Some(ReferencesProvider::Bool(true)),
38        definition_provider: Some(DefinitionProvider::Bool(true)),
39        hover_provider: Some(HoverProvider::Bool(true)),
40        inlay_hint_provider: Some(InlayHintProvider::Bool(true)),
41        diagnostic_provider: Some(DiagnosticProvider::DiagnosticOptions(DiagnosticOptions {
42            identifier: None,
43            inter_file_dependencies: false,
44            workspace_diagnostics: false,
45            work_done_progress_options: WorkDoneProgressOptions {
46                work_done_progress: None,
47            },
48        })),
49        document_symbol_provider: Some(DocumentSymbolProvider::Bool(true)),
50        document_formatting_provider: Some(DocumentFormattingProvider::Bool(true)),
51        folding_range_provider: Some(FoldingRangeProvider::Bool(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(SemanticTokensProvider::SemanticTokensOptions(
62            SemanticTokensOptions {
63                work_done_progress_options: WorkDoneProgressOptions {
64                    work_done_progress: None,
65                },
66                legend: SemanticTokensLegend {
67                    token_types: SUPPORTED_TYPES.iter().cloned().map(String::from).collect(),
68                    token_modifiers: SUPPORTED_MODIFIERS
69                        .iter()
70                        .cloned()
71                        .map(String::from)
72                        .collect(),
73                },
74                range: Some(SemanticTokensOptionsRange::Bool(true)),
75                full: Some(Full::Bool(true)),
76            },
77        )),
78        ..Default::default()
79    })
80    .unwrap();
81
82    info!("LSP server initializing connection...");
83    let initialization_params = connection.initialize(server_capabilities)?;
84    info!("LSP server initialized, entering main loop");
85
86    main_loop(connection, initialization_params)?;
87
88    info!("LSP server shutting down");
89
90    io_threads.join()?;
91    Ok(())
92}
93
94fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> {
95    info!("Server main loop");
96
97    let init_params: InitializeParams = serde_json::from_value(params).unwrap_or_default();
98    info!("Client process ID: {:?}", init_params.process_id);
99    let client_name = init_params.client_info.map(|x| x.name);
100    info!("Client name: {client_name:?}");
101
102    GlobalState::new(connection.sender).run(connection.receiver)
103}