1use std::collections::HashMap;
20
21use super::task_pool::TaskPool;
22use super::InitOptions;
23use super::Session;
24use auto_lsp_core::errors::{ExtensionError, RuntimeError};
25use lsp_server::{Connection, ReqQueue};
26use lsp_types::{InitializeParams, InitializeResult, PositionEncodingKind};
27use serde::Deserialize;
28#[cfg(target_arch = "wasm32")]
29use std::fs;
30use texter::core::text::Text;
31
32#[allow(non_snake_case, reason = "JSON")]
33#[derive(Debug, Deserialize)]
34struct InitializationOptions {
35 perFileParser: HashMap<String, String>,
40}
41
42pub(crate) type TextFn = fn(String) -> Text;
44
45fn decide_encoding(encs: Option<&[PositionEncodingKind]>) -> (TextFn, PositionEncodingKind) {
46 const DEFAULT: (TextFn, PositionEncodingKind) = (Text::new_utf16, PositionEncodingKind::UTF16);
47 let Some(encs) = encs else {
48 return DEFAULT;
49 };
50
51 for enc in encs {
52 if *enc == PositionEncodingKind::UTF16 {
53 return (Text::new_utf16, enc.clone());
54 } else if *enc == PositionEncodingKind::UTF8 {
55 return (Text::new, enc.clone());
56 }
57 }
58
59 DEFAULT
60}
61
62impl<Db: salsa::Database> Session<Db> {
63 pub(crate) fn new(
64 init_options: InitOptions,
65 connection: Connection,
66 text_fn: TextFn,
67 db: Db,
68 ) -> Self {
69 let (sender, task_rx) = crossbeam_channel::unbounded();
70
71 let max_threads = std::thread::available_parallelism().unwrap().get();
72
73 log::info!("Max threads: {max_threads}");
74
75 Self {
76 init_options,
77 connection,
78 text_fn,
79 extensions: HashMap::new(),
80 req_queue: ReqQueue::default(),
81 db,
82 task_rx,
83 task_pool: TaskPool::new_with_threads(sender, max_threads),
84 }
85 }
86
87 pub fn create(
91 mut init_options: InitOptions,
92 connection: Connection,
93 db: Db,
94 ) -> anyhow::Result<(Session<Db>, InitializeParams)> {
95 #[cfg(target_arch = "wasm32")]
98 fs::metadata("/workspace").unwrap();
99
100 log::info!("Starting LSP server");
101 log::info!("");
102
103 let (id, resp) = connection.initialize_start()?;
106 let params: InitializeParams = serde_json::from_value(resp)?;
107
108 let pos_encoding = params
109 .capabilities
110 .general
111 .as_ref()
112 .and_then(|g| g.position_encodings.as_deref());
113
114 let (t_fn, enc) = decide_encoding(pos_encoding);
115 init_options.capabilities.position_encoding = Some(enc);
116
117 let server_capabilities = serde_json::to_value(&InitializeResult {
118 capabilities: init_options.capabilities.clone(),
119 server_info: init_options.server_info.clone(),
120 })
121 .unwrap();
122
123 connection.initialize_finish(id, server_capabilities)?;
124
125 let mut session = Session::new(init_options, connection, t_fn, db);
126
127 let options = InitializationOptions::deserialize(
128 params
129 .clone()
130 .initialization_options
131 .ok_or(RuntimeError::MissingPerFileParser)?,
132 )
133 .unwrap();
134
135 for (file_extension, parser) in &options.perFileParser {
137 if !session.init_options.parsers.contains_key(parser.as_str()) {
138 return Err(RuntimeError::from(ExtensionError::UnknownParser {
139 extension: file_extension.clone(),
140 available: session.init_options.parsers.keys().cloned().collect(),
141 })
142 .into());
143 }
144 }
145
146 session.extensions = options.perFileParser;
148
149 Ok((session, params))
150 }
151}