squawk-server 2.63.0

LSP server for Squawk
Documentation
use anyhow::Result;
use gen_lsp_types::{
    CodeActionKind, CodeActionOptions, CodeActionProvider, CompletionOptions, DefinitionProvider,
    DiagnosticOptions, DiagnosticProvider, DocumentSymbolProvider, FoldingRangeProvider, Full,
    HoverProvider, InitializeParams, InlayHintProvider, ReferencesProvider, SelectionRangeProvider,
    SemanticTokensLegend, SemanticTokensOptions, SemanticTokensOptionsRange,
    SemanticTokensProvider, ServerCapabilities, TextDocumentSync, TextDocumentSyncKind,
    WorkDoneProgressOptions,
};
use log::info;
use lsp_server::Connection;

use crate::{
    global_state::GlobalState,
    semantic_tokens::{SUPPORTED_MODIFIERS, SUPPORTED_TYPES},
};

pub fn run() -> Result<()> {
    info!("Starting Squawk LSP server");

    let (connection, io_threads) = Connection::stdio();

    let server_capabilities = serde_json::to_value(&ServerCapabilities {
        text_document_sync: Some(TextDocumentSync::Kind(TextDocumentSyncKind::Incremental)),
        code_action_provider: Some(CodeActionProvider::CodeActionOptions(CodeActionOptions {
            code_action_kinds: Some(vec![
                CodeActionKind::QuickFix,
                CodeActionKind::RefactorRewrite,
            ]),
            work_done_progress_options: WorkDoneProgressOptions {
                work_done_progress: None,
            },
            resolve_provider: None,
            documentation: None,
        })),
        selection_range_provider: Some(SelectionRangeProvider::Bool(true)),
        references_provider: Some(ReferencesProvider::Bool(true)),
        definition_provider: Some(DefinitionProvider::Bool(true)),
        hover_provider: Some(HoverProvider::Bool(true)),
        inlay_hint_provider: Some(InlayHintProvider::Bool(true)),
        diagnostic_provider: Some(DiagnosticProvider::DiagnosticOptions(DiagnosticOptions {
            identifier: None,
            inter_file_dependencies: false,
            workspace_diagnostics: false,
            work_done_progress_options: WorkDoneProgressOptions {
                work_done_progress: None,
            },
        })),
        document_symbol_provider: Some(DocumentSymbolProvider::Bool(true)),
        folding_range_provider: Some(FoldingRangeProvider::Bool(true)),
        completion_provider: Some(CompletionOptions {
            resolve_provider: Some(false),
            trigger_characters: Some(vec![".".to_owned()]),
            all_commit_characters: None,
            work_done_progress_options: WorkDoneProgressOptions {
                work_done_progress: None,
            },
            completion_item: None,
        }),
        semantic_tokens_provider: Some(SemanticTokensProvider::SemanticTokensOptions(
            SemanticTokensOptions {
                work_done_progress_options: WorkDoneProgressOptions {
                    work_done_progress: None,
                },
                legend: SemanticTokensLegend {
                    token_types: SUPPORTED_TYPES.iter().cloned().map(String::from).collect(),
                    token_modifiers: SUPPORTED_MODIFIERS
                        .iter()
                        .cloned()
                        .map(String::from)
                        .collect(),
                },
                range: Some(SemanticTokensOptionsRange::Bool(true)),
                full: Some(Full::Bool(true)),
            },
        )),
        ..Default::default()
    })
    .unwrap();

    info!("LSP server initializing connection...");
    let initialization_params = connection.initialize(server_capabilities)?;
    info!("LSP server initialized, entering main loop");

    main_loop(connection, initialization_params)?;

    info!("LSP server shutting down");

    io_threads.join()?;
    Ok(())
}

fn main_loop(connection: Connection, params: serde_json::Value) -> Result<()> {
    info!("Server main loop");

    let init_params: InitializeParams = serde_json::from_value(params).unwrap_or_default();
    info!("Client process ID: {:?}", init_params.process_id);
    let client_name = init_params.client_info.map(|x| x.name);
    info!("Client name: {client_name:?}");

    GlobalState::new(connection.sender).run(connection.receiver)
}