1
use serde::{Deserialize, Serialize};
2
use serde_json::Value;
3

            
4
use tower_lsp::{
5
    Client, LanguageServer, LspService, Server,
6
    jsonrpc::{Error, Result},
7
    lsp_types::{
8
        ExecuteCommandOptions, ExecuteCommandParams, InitializeParams, InitializeResult,
9
        InitializedParams, MessageType, ServerCapabilities, notification::Notification,
10
    },
11
};
12

            
13
#[derive(Debug, Serialize, Deserialize)]
14
struct NotifactionParams {
15
    title: String,
16
    message: String,
17
    description: String,
18
}
19

            
20
enum CustomNotifciation {}
21

            
22
impl Notification for CustomNotifciation {
23
    type Params = NotifactionParams;
24

            
25
    const METHOD: &'static str = "custom/notification";
26
}
27

            
28
#[derive(Debug)]
29
struct Backend {
30
    client: Client,
31
}
32

            
33
#[tower_lsp::async_trait]
34
impl LanguageServer for Backend {
35
    //this is the server implementation and manages the server response to client requests
36
    async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> {
37
        //first request of client to server
38
        Ok(InitializeResult {
39
            server_info: None,
40
            capabilities: ServerCapabilities {
41
                //
42
                execute_command_provider: Some(ExecuteCommandOptions {
43
                    commands: vec![String::from("custom.notification")],
44
                    work_done_progress_options: Default::default(),
45
                }),
46
                ..ServerCapabilities::default()
47
            },
48
        })
49
    }
50
    async fn initialized(&self, _: InitializedParams) {
51
        //request after recieving result of initialise() and before anything else
52
        self.client
53
            .log_message(MessageType::INFO, "server initialised!") //client logs message of initialised
54
            .await;
55
    }
56
    async fn shutdown(&self) -> Result<()> {
57
        Ok(())
58
    }
59
    async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<Value>> {
60
        if params.command == "custom.notification" {
61
            //one of the commands that we support (see line 34)
62
            self.client
63
                .send_notification::<CustomNotifciation>(NotifactionParams {
64
                    //send_notification is defined by the client
65
                    title: String::from("Hello Notification"),
66
                    message: String::from("This is a test message"),
67
                    description: String::from("This is a description"),
68
                })
69
                .await;
70

            
71
            self.client
72
                .log_message(
73
                    MessageType::INFO,
74
                    format!("Command executed successfully with params: {params:?}"),
75
                )
76
                .await;
77
            Ok(None)
78
        }
79
        //can add additional commands here in an if-else block
80
        else {
81
            Err(Error::invalid_request())
82
        }
83
    }
84
}
85

            
86
#[tokio::main]
87
pub async fn main() {
88
    let stdin = tokio::io::stdin();
89
    let stdout = tokio::io::stdout();
90

            
91
    let (service, socket) = LspService::build(|client| Backend { client }).finish();
92

            
93
    Server::new(stdin, stdout, socket).serve(service).await;
94
}