1use anyhow::Result;
2use gen_lsp_types::{
3 CodeActionKind, CodeActionOptions, CodeActionProvider, CompletionOptions, DefinitionProvider,
4 DiagnosticOptions, DiagnosticProvider, DocumentSymbolProvider, FoldingRangeProvider, Full,
5 HoverProvider, InitializeParams, InlayHintProvider, ReferencesProvider, SelectionRangeProvider,
6 SemanticTokensLegend, SemanticTokensOptions, SemanticTokensOptionsRange,
7 SemanticTokensProvider, ServerCapabilities, TextDocumentSync, TextDocumentSyncKind,
8 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 folding_range_provider: Some(FoldingRangeProvider::Bool(true)),
51 completion_provider: Some(CompletionOptions {
52 resolve_provider: Some(false),
53 trigger_characters: Some(vec![".".to_owned()]),
54 all_commit_characters: None,
55 work_done_progress_options: WorkDoneProgressOptions {
56 work_done_progress: None,
57 },
58 completion_item: None,
59 }),
60 semantic_tokens_provider: Some(SemanticTokensProvider::SemanticTokensOptions(
61 SemanticTokensOptions {
62 work_done_progress_options: WorkDoneProgressOptions {
63 work_done_progress: None,
64 },
65 legend: SemanticTokensLegend {
66 token_types: SUPPORTED_TYPES.iter().cloned().map(String::from).collect(),
67 token_modifiers: SUPPORTED_MODIFIERS
68 .iter()
69 .cloned()
70 .map(String::from)
71 .collect(),
72 },
73 range: Some(SemanticTokensOptionsRange::Bool(true)),
74 full: Some(Full::Bool(true)),
75 },
76 )),
77 ..Default::default()
78 })
79 .unwrap();
80
81 info!("LSP server initializing connection...");
82 let initialization_params = connection.initialize(server_capabilities)?;
83 info!("LSP server initialized, entering main loop");
84
85 main_loop(connection, initialization_params)?;
86
87 info!("LSP server shutting down");
88
89 io_threads.join()?;
90 Ok(())
91}
92
93fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> {
94 info!("Server main loop");
95
96 let init_params: InitializeParams = serde_json::from_value(params).unwrap_or_default();
97 info!("Client process ID: {:?}", init_params.process_id);
98 let client_name = init_params.client_info.map(|x| x.name);
99 info!("Client name: {client_name:?}");
100
101 GlobalState::new(connection.sender).run(connection.receiver)
102}