beancount_language_server/
lib.rs1pub mod beancount_data;
2mod capabilities;
3pub mod checkers;
4mod config;
5mod dispatcher;
6pub mod document;
7pub mod forest;
9pub mod handlers;
10pub mod progress;
11pub mod providers;
12mod query_utils;
13pub mod server;
14mod treesitter_utils;
16mod utils;
17
18use crate::config::Config;
19use crate::server::LspServerState;
20use anyhow::Result;
21use lsp_server::Connection;
22use lsp_types::InitializeParams;
23use serde::{Serialize, de::DeserializeOwned};
24use utils::ToFilePath;
25
26pub fn run_server() -> Result<()> {
27 tracing::info!("beancount-language-server started");
28
29 tracing::debug!("Setting up stdio connections");
31 let (connection, io_threads) = lsp_server::Connection::stdio();
32
33 tracing::debug!("Waiting for client initialization");
35 let (request_id, initialize_params) = connection.initialize_start()?;
36 tracing::debug!("Received initialize request: id={}", request_id);
37
38 let initialize_params = match serde_json::from_value::<InitializeParams>(initialize_params) {
39 Ok(params) => {
40 tracing::debug!("Successfully parsed initialization parameters");
41 params
42 }
43 Err(e) => {
44 tracing::error!("Failed to parse initialization parameters: {}", e);
45 return Err(e.into());
46 }
47 };
48
49 if let Some(client_info) = &initialize_params.client_info {
50 tracing::info!(
51 "Connected to client: '{}' version {}",
52 client_info.name,
53 client_info.version.as_deref().unwrap_or("unknown")
54 );
55 } else {
56 tracing::warn!("Client did not provide client info");
57 }
58
59 let config = {
61 let root_file = if let Some(workspace_folders) = &initialize_params.workspace_folders {
62 let root = workspace_folders
63 .first()
64 .and_then(|folder| folder.uri.to_file_path().ok())
65 .unwrap_or_else(|| std::env::current_dir().unwrap_or_default());
66 tracing::info!("Using workspace folder as root: {}", root.display());
67 root
68 } else {
69 #[allow(deprecated)]
70 let root = match initialize_params
71 .root_uri
72 .and_then(|it| it.to_file_path().ok())
73 {
74 Some(it) => it,
75 None => std::env::current_dir()?,
76 };
77 tracing::info!("Using root URI as root: {}", root.display());
78 root
79 };
80
81 let mut config = Config::new(root_file);
82 if let Some(json) = initialize_params.initialization_options {
83 tracing::info!("Applying initialization options: {}", json);
84 match config.update(json) {
85 Ok(()) => tracing::debug!("Configuration updated successfully"),
86 Err(e) => {
87 tracing::warn!("Failed to update configuration: {}", e);
88 return Err(e);
89 }
90 }
91 } else {
92 tracing::debug!("No initialization options provided, using default config");
93 }
94 config
95 };
96
97 let server_capabilities = capabilities::server_capabilities();
98 tracing::debug!("Server capabilities configured");
99
100 let initialize_result = lsp_types::InitializeResult {
101 capabilities: server_capabilities,
102 server_info: Some(lsp_types::ServerInfo {
103 name: String::from("beancount-language-server"),
104 version: Some(String::from(env!("CARGO_PKG_VERSION"))),
105 }),
106 };
107
108 let initialize_result =
109 serde_json::to_value(initialize_result).expect("Failed to serialize InitializeResult");
110
111 connection.initialize_finish(request_id, initialize_result)?;
112 tracing::info!("Initialization completed successfully");
113
114 tracing::debug!("Starting main loop");
115 main_loop(connection, config)?;
116
117 tracing::debug!("Waiting for IO threads to complete");
118 io_threads.join()?;
119 tracing::info!("Language server stopped");
120
121 Ok(())
122}
123
124pub fn main_loop(connection: Connection, config: Config) -> Result<()> {
125 tracing::info!("initial config: {:#?}", config);
126 LspServerState::new(connection.sender, config).run(connection.receiver)
127}
128
129pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
130 T::deserialize(&json)
131 .map_err(|e| anyhow::anyhow!("could not deserialize {}: {} - {}", what, e, json))
132}
133
134pub fn to_json<T: Serialize>(value: T) -> Result<serde_json::Value> {
135 serde_json::to_value(value).map_err(|e| anyhow::anyhow!("could not serialize to json {}", e))
136}