Skip to main content

grug_ls/server/
init.rs

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            // Vscode
90            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}