Skip to main content

grug_ls/
server.rs

1use lsp_server::{Connection, Message};
2use lsp_types::{ClientCapabilities, CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams, HoverParams};
3use serde::{Deserialize, Serialize};
4use tree_sitter::Parser;
5use vfs::MemoryFS;
6
7use crate::{
8    server::{
9        document::Document, helper::ServerUpdate, mod_api::ModApi,
10    }
11};
12use std::{collections::HashMap, path::PathBuf, sync::mpsc::Receiver};
13
14mod document;
15mod helper;
16mod hover;
17pub mod init;
18mod mod_api;
19mod text_sync;
20mod utils;
21mod completion;
22
23use log::error;
24use log::info;
25
26pub enum ServerWrapper {
27    Inactive,
28    Active(Server),
29    Shutdown,
30}
31
32pub enum ServerFileElement {
33    File(String),
34    Directory(String, Vec<ServerFileElement>),
35}
36
37impl ServerWrapper {
38    pub fn new() -> ServerWrapper {
39        ServerWrapper::Inactive
40    }
41
42}
43
44#[derive(Serialize, Deserialize, Debug, Default)]
45struct TextDocumentClientCapabilities {
46    #[serde(default)]
47    synchronization: TextDocumentSyncClientCapabilities,
48}
49
50#[derive(Serialize, Deserialize, Debug, Default)]
51struct TextDocumentSyncClientCapabilities {
52    #[serde(rename = "dynamicRegistration")]
53    #[serde(default)]
54    dynamic_registration: bool,
55}
56
57#[derive(Debug)]
58pub struct Server {
59    pub should_exit: bool,
60    root_path: PathBuf,
61    client_capabilities: ClientCapabilities,
62    mod_api: ModApi,
63    file_system: MemoryFS,
64    document_map: HashMap<String, Document>,
65    messages_chan: Receiver<ServerUpdate>,
66}
67
68impl Server {
69    pub fn handle_message(&mut self, message: Message, connection: &mut Connection, parser: &mut Parser) {
70        self.handle_worker_messages();
71
72        let (id, method, params) = match message {
73            Message::Request(req) => {
74                (Some(req.id), req.method, req.params)
75            }
76            Message::Notification(notif) => {
77                (None, notif.method, notif.params)
78            }
79            _ => {
80                return;
81            }
82        };
83
84        match method.as_str() {
85            "textDocument/didOpen" => {
86                let did_open_notification: DidOpenTextDocumentParams =
87                    serde_json::from_value(params).unwrap();
88
89                self.handle_did_open(did_open_notification, parser);
90            }
91            "textDocument/didChange" => {
92                let did_change_notification: DidChangeTextDocumentParams =
93                    serde_json::from_value(params).unwrap();
94
95                self.handle_did_change(did_change_notification, parser);
96            }
97            "textDocument/didSave" => {
98                info!("Saved file");
99            }
100            "shutdown" => {
101                info!("Shutting down");
102                self.should_exit = true;
103            }
104            "textDocument/hover" => {
105                let req: HoverParams =
106                    serde_json::from_value(params).unwrap();
107
108                self.handle_hover(req, connection, id.unwrap());
109            }
110            "textDocument/completion" => {
111                let req: CompletionParams =
112                    serde_json::from_value(params).unwrap();
113
114                self.handle_completion(req, connection, id.unwrap());
115            }
116            "exit" => {
117                self.should_exit = true;
118            }
119            _ => error!("Unknown message method: {}", method),
120        }
121    }
122}