1use std::{path::PathBuf, str::FromStr};
2
3use lsp_types::InitializeParams;
4use serde::{Deserialize, Serialize};
5use vfs::MemoryFS;
6
7use crate::{server::{helper::spawn_worker, mod_api::ModApi, Server}};
8
9use std::collections::HashMap;
10
11use log::error;
12
13#[derive(Serialize, Deserialize)]
14pub struct ServerInfo {
15 pub name: String,
16 pub version: Option<String>,
17}
18
19#[derive(Serialize, Deserialize)]
20pub struct InitResponse {
21 pub id: serde_json::Value,
22 pub result: InitResult,
23}
24
25#[derive(Serialize, Deserialize)]
26pub struct InitResult {
27 pub capabilities: ServerCapabilities,
28
29 #[serde(rename = "serverInfo")]
30 pub server_info: Option<ServerInfo>,
31}
32
33#[derive(Serialize, Deserialize)]
34pub struct ServerCapabilities {
35 #[serde(rename = "positionEncoding")]
36 pub position_encoding: String,
37
38 #[serde(rename = "textDocumentSync")]
39 pub text_document_sync: usize,
40
41 #[serde(rename = "hoverProvider")]
42 pub hover_provider: bool,
43
44 #[serde(rename = "completionProvider")]
45 pub completion_provider: HashMap<(), ()>,
46}
47
48#[derive(Debug, Serialize)]
49pub enum ServerInitError {
50 NoRootPath,
51 RootPathParseError,
52 NoModApi,
53 InitParseError(String),
54
55 #[serde(rename = "modApiReadError")]
56 ModApiIOError(String),
57 ModApiParseError(String),
58}
59impl Server {
60 pub fn from_request(params: InitializeParams) -> Result<Server, ServerInitError> {
61 let mut root_path: Option<String> = None;
62
63 #[allow(deprecated)]
64 if let Some(ref folders) = params.workspace_folders {
65 root_path = Some(folders[0].name.to_string());
66 } else if let Some(ref uri) = params.root_uri {
67 let uri = uri.as_str();
68 assert!(uri.starts_with("file://"));
69 root_path = Some(uri["file://".len()..].to_string());
70 }
71
72 let root_path = match root_path {
73 Some(root_path) => root_path,
74 None => {
75 error!("Couldn't get a root path");
76 error!("Init Request: {:?}", params);
77 return Err(ServerInitError::NoRootPath);
78 }
79 };
80
81 let mut root_path = match PathBuf::from_str(&root_path) {
82 Ok(root_path) => root_path,
83 Err(_) => {
84 return Err(ServerInitError::RootPathParseError);
85 }
86 };
87
88 if root_path.is_relative() {
89 if let Some(cwd) = std::env::current_dir().ok().map(|cwd| cwd.parent().map(|p| p.to_path_buf())).flatten() {
91 root_path = cwd.join(root_path);
92 }
93 }
94
95 let mod_api_json = match std::fs::read_to_string(&root_path.join("mod_api.json")) {
96 Ok(json) => json,
97 Err(err) => {
98 return Err(ServerInitError::ModApiIOError(format!("At {}: {}", root_path.to_string_lossy().into_owned(), err.to_string())));
99 }
100 };
101 let mod_api: ModApi = serde_json::from_str(&mod_api_json).unwrap_or(ModApi::default());
102
103 let chan = spawn_worker(root_path.clone()).unwrap();
104
105 let client_capabilities = params.capabilities;
106
107 Ok(Server {
108 file_system: MemoryFS::new(),
109 root_path,
110 client_capabilities,
111 document_map: std::collections::HashMap::new(),
112 messages_chan: chan,
113 mod_api,
114 should_exit: false,
115 })
116 }
117}