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}