Fork of daniellemaywood.uk/gleam — Wasm codegen work
3.6 kB
106 lines
1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 The Gleam contributors
3
4use debug_ignore::DebugIgnore;
5use lsp_types::{
6 InitializeParams, LspAny, ProgressParams, ProgressToken, WorkDoneProgressBegin,
7 WorkDoneProgressCreateParams, WorkDoneProgressEnd,
8};
9
10const DOWNLOADING_TOKEN: &str = "downloading-dependencies";
11
12pub trait ProgressReporter {
13 fn compilation_started(&self);
14 fn compilation_finished(&self);
15 fn dependency_downloading_started(&self);
16 fn dependency_downloading_finished(&self);
17}
18
19// Used to publish progress notifications to the client without waiting for
20// the usual request-response loop of the language server.
21#[derive(Debug, Clone)]
22pub struct ConnectionProgressReporter<'a> {
23 connection: DebugIgnore<&'a lsp_server::Connection>,
24}
25
26impl<'a> ConnectionProgressReporter<'a> {
27 pub fn new(
28 connection: &'a lsp_server::Connection,
29 // We don't actually need these but we take them anyway to ensure that
30 // this object is only created after the server has been initialised.
31 // If it was created before then the creation of the progress token
32 // would fail.
33 _initialise_params: &InitializeParams,
34 ) -> Self {
35 create_token(DOWNLOADING_TOKEN, connection);
36 Self {
37 connection: connection.into(),
38 }
39 }
40
41 fn send_notification(&self, token: &str, work_done: LspAny) {
42 let params = ProgressParams {
43 token: ProgressToken::String(token.to_string()),
44 value: work_done,
45 };
46 let notification = lsp_server::Notification {
47 method: "$/progress".into(),
48 params: serde_json::to_value(params).expect("ProgressParams json"),
49 };
50 self.connection
51 .sender
52 .send(lsp_server::Message::Notification(notification))
53 .expect("send_work_done_notification send")
54 }
55}
56
57impl ProgressReporter for ConnectionProgressReporter<'_> {
58 fn compilation_started(&self) {
59 // Do nothing. This is only used for tests currently.
60 // In future we could make this emit a message to the client if compilation is taking a
61 // long time.
62 }
63
64 fn compilation_finished(&self) {
65 // Do nothing. This is only used for tests currently.
66 }
67
68 fn dependency_downloading_started(&self) {
69 let title = "Downloading Gleam dependencies";
70 self.send_notification(DOWNLOADING_TOKEN, begin_message(title));
71 }
72
73 fn dependency_downloading_finished(&self) {
74 self.send_notification(DOWNLOADING_TOKEN, end_message());
75 }
76}
77
78fn end_message() -> LspAny {
79 serde_json::to_value(WorkDoneProgressEnd { message: None })
80 .expect("Failed to serialize WorkDoneProgressEnd")
81}
82
83fn begin_message(title: &str) -> LspAny {
84 serde_json::to_value(WorkDoneProgressBegin {
85 title: title.into(),
86 cancellable: Some(false),
87 message: None,
88 percentage: None,
89 })
90 .expect("Failed to serialize WorkDoneProgressBegin")
91}
92
93fn create_token(token: &str, connection: &lsp_server::Connection) {
94 let params = WorkDoneProgressCreateParams {
95 token: ProgressToken::String(token.into()),
96 };
97 let request = lsp_server::Request {
98 id: format!("create-token--{token}").into(),
99 method: "window/workDoneProgress/create".into(),
100 params: serde_json::to_value(params).expect("WorkDoneProgressCreateParams json"),
101 };
102 connection
103 .sender
104 .send(lsp_server::Message::Request(request))
105 .expect("WorkDoneProgressCreate");
106}