Skip to main content

lsp_max/service/client/
lsp_methods.rs

1use lsp_types_max::*;
2use serde::Serialize;
3use serde_json::Value;
4use std::fmt::Display;
5
6use super::Client;
7use crate::jsonrpc;
8
9impl Client {
10    // Lifecycle Messages
11
12    /// Registers a new capability with the client.
13    ///
14    /// This corresponds to the [`client/registerCapability`] request.
15    ///
16    /// [`client/registerCapability`]: https://microsoft.github.io/language-server-protocol/specification#client_registerCapability
17    ///
18    /// # Initialization
19    ///
20    /// If the request is sent to the client before the server has been initialized, this will
21    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
22    ///
23    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
24    pub async fn register_capability(
25        &self,
26        registrations: Vec<Registration>,
27    ) -> jsonrpc::Result<()> {
28        use lsp_types_max::request::RegisterCapability;
29        self.send_request::<RegisterCapability>(RegistrationParams { registrations })
30            .await
31    }
32
33    /// Unregisters a capability with the client.
34    ///
35    /// This corresponds to the [`client/unregisterCapability`] request.
36    ///
37    /// [`client/unregisterCapability`]: https://microsoft.github.io/language-server-protocol/specification#client_unregisterCapability
38    ///
39    /// # Initialization
40    ///
41    /// If the request is sent to the client before the server has been initialized, this will
42    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
43    ///
44    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
45    pub async fn unregister_capability(
46        &self,
47        unregisterations: Vec<Unregistration>,
48    ) -> jsonrpc::Result<()> {
49        use lsp_types_max::request::UnregisterCapability;
50        self.send_request::<UnregisterCapability>(UnregistrationParams { unregisterations })
51            .await
52    }
53
54    // Window Features
55
56    /// Notifies the client to display a particular message in the user interface.
57    ///
58    /// This corresponds to the [`window/showMessage`] notification.
59    ///
60    /// [`window/showMessage`]: https://microsoft.github.io/language-server-protocol/specification#window_showMessage
61    pub async fn show_message<M: Display>(&self, typ: MessageType, message: M) {
62        use lsp_types_max::notification::ShowMessage;
63        self.send_notification_unchecked::<ShowMessage>(ShowMessageParams {
64            typ,
65            message: message.to_string(),
66        })
67        .await;
68    }
69
70    /// Requests the client to display a particular message in the user interface.
71    ///
72    /// Unlike the `show_message` notification, this request can also pass a list of actions and
73    /// wait for an answer from the client.
74    ///
75    /// This corresponds to the [`window/showMessageRequest`] request.
76    ///
77    /// [`window/showMessageRequest`]: https://microsoft.github.io/language-server-protocol/specification#window_showMessageRequest
78    pub async fn show_message_request<M: Display>(
79        &self,
80        typ: MessageType,
81        message: M,
82        actions: Option<Vec<MessageActionItem>>,
83    ) -> jsonrpc::Result<Option<MessageActionItem>> {
84        use lsp_types_max::request::ShowMessageRequest;
85        self.send_request_unchecked::<ShowMessageRequest>(ShowMessageRequestParams {
86            typ,
87            message: message.to_string(),
88            actions,
89        })
90        .await
91    }
92
93    /// Notifies the client to log a particular message.
94    ///
95    /// This corresponds to the [`window/logMessage`] notification.
96    ///
97    /// [`window/logMessage`]: https://microsoft.github.io/language-server-protocol/specification#window_logMessage
98    pub async fn log_message<M: Display>(&self, typ: MessageType, message: M) {
99        use lsp_types_max::notification::LogMessage;
100        self.send_notification_unchecked::<LogMessage>(LogMessageParams {
101            typ,
102            message: message.to_string(),
103        })
104        .await;
105    }
106
107    /// Notifies the client to log a trace.
108    ///
109    /// This corresponds to the [`$/logTrace`] notification.
110    ///
111    /// [`$/logTrace`]: https://microsoft.github.io/language-server-protocol/specification#logTrace
112    pub async fn log_trace(&self, params: LogTraceParams) {
113        use lsp_types_max::notification::LogTrace;
114        self.send_notification_unchecked::<LogTrace>(params).await;
115    }
116
117    /// Asks the client to display a particular resource referenced by a URI in the user interface.
118    ///
119    /// Returns `Ok(true)` if the document was successfully shown, or `Ok(false)` otherwise.
120    ///
121    /// This corresponds to the [`window/showDocument`] request.
122    ///
123    /// [`window/showDocument`]: https://microsoft.github.io/language-server-protocol/specification#window_showDocument
124    ///
125    /// # Initialization
126    ///
127    /// If the request is sent to the client before the server has been initialized, this will
128    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
129    ///
130    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
131    ///
132    /// # Compatibility
133    ///
134    /// This request was introduced in specification version 3.16.0.
135    pub async fn show_document(&self, params: ShowDocumentParams) -> jsonrpc::Result<bool> {
136        use lsp_types_max::request::ShowDocument;
137        let response = self.send_request::<ShowDocument>(params).await?;
138        Ok(response.success)
139    }
140
141    /// Asks the client to create a work done progress token.
142    ///
143    /// This corresponds to the [`window/workDoneProgress/create`] request.
144    ///
145    /// [`window/workDoneProgress/create`]: https://microsoft.github.io/language-server-protocol/specification#window_workDoneProgress_create
146    ///
147    /// # Compatibility
148    ///
149    /// This request was introduced in specification version 3.15.0.
150    pub async fn work_done_progress_create(
151        &self,
152        params: WorkDoneProgressCreateParams,
153    ) -> jsonrpc::Result<()> {
154        use lsp_types_max::request::WorkDoneProgressCreate;
155        self.send_request::<WorkDoneProgressCreate>(params).await
156    }
157
158    /// Notifies the client to log a telemetry event.
159    ///
160    /// This corresponds to the [`telemetry/event`] notification.
161    ///
162    /// [`telemetry/event`]: https://microsoft.github.io/language-server-protocol/specification#telemetry_event
163    pub async fn telemetry_event<S: Serialize>(&self, data: S) {
164        use lsp_types_max::notification::TelemetryEvent;
165        match serde_json::to_value(data) {
166            Err(e) => tracing::error!("invalid JSON in `telemetry/event` notification: {}", e),
167            Ok(mut value) => {
168                if !value.is_null() && !value.is_array() && !value.is_object() {
169                    value = Value::Array(vec![value]);
170                }
171                let params = match value {
172                    Value::Object(map) => OneOf::Left(map),
173                    Value::Array(vec) => OneOf::Right(vec),
174                    _ => OneOf::Right(Vec::new()),
175                };
176                self.send_notification_unchecked::<TelemetryEvent>(params)
177                    .await;
178            }
179        }
180    }
181
182    /// Asks the client to refresh the code lenses currently shown in editors. As a result, the
183    /// client should ask the server to recompute the code lenses for these editors.
184    ///
185    /// This is useful if a server detects a configuration change which requires a re-calculation
186    /// of all code lenses.
187    ///
188    /// Note that the client still has the freedom to delay the re-calculation of the code lenses
189    /// if for example an editor is currently not visible.
190    ///
191    /// This corresponds to the [`workspace/codeLens/refresh`] request.
192    ///
193    /// [`workspace/codeLens/refresh`]: https://microsoft.github.io/language-server-protocol/specification#codeLens_refresh
194    ///
195    /// # Initialization
196    ///
197    /// If the request is sent to the client before the server has been initialized, this will
198    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
199    ///
200    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
201    ///
202    /// # Compatibility
203    ///
204    /// This request was introduced in specification version 3.16.0.
205    pub async fn code_lens_refresh(&self) -> jsonrpc::Result<()> {
206        use lsp_types_max::request::CodeLensRefresh;
207        self.send_request::<CodeLensRefresh>(()).await
208    }
209
210    /// Asks the client to refresh the editors for which this server provides semantic tokens. As a
211    /// result, the client should ask the server to recompute the semantic tokens for these
212    /// editors.
213    ///
214    /// This is useful if a server detects a project-wide configuration change which requires a
215    /// re-calculation of all semantic tokens. Note that the client still has the freedom to delay
216    /// the re-calculation of the semantic tokens if for example an editor is currently not visible.
217    ///
218    /// This corresponds to the [`workspace/semanticTokens/refresh`] request.
219    ///
220    /// [`workspace/semanticTokens/refresh`]: https://microsoft.github.io/language-server-protocol/specification#textDocument_semanticTokens
221    ///
222    /// # Initialization
223    ///
224    /// If the request is sent to the client before the server has been initialized, this will
225    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
226    ///
227    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
228    ///
229    /// # Compatibility
230    ///
231    /// This request was introduced in specification version 3.16.0.
232    pub async fn semantic_tokens_refresh(&self) -> jsonrpc::Result<()> {
233        use lsp_types_max::request::SemanticTokensRefresh;
234        self.send_request::<SemanticTokensRefresh>(()).await
235    }
236
237    /// Asks the client to refresh the inline values currently shown in editors. As a result, the
238    /// client should ask the server to recompute the inline values for these editors.
239    ///
240    /// This is useful if a server detects a configuration change which requires a re-calculation
241    /// of all inline values. Note that the client still has the freedom to delay the
242    /// re-calculation of the inline values if for example an editor is currently not visible.
243    ///
244    /// This corresponds to the [`workspace/inlineValue/refresh`] request.
245    ///
246    /// [`workspace/inlineValue/refresh`]: https://microsoft.github.io/language-server-protocol/specification#workspace_inlineValue_refresh
247    ///
248    /// # Initialization
249    ///
250    /// If the request is sent to the client before the server has been initialized, this will
251    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
252    ///
253    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
254    ///
255    /// # Compatibility
256    ///
257    /// This request was introduced in specification version 3.17.0.
258    pub async fn inline_value_refresh(&self) -> jsonrpc::Result<()> {
259        use lsp_types_max::request::InlineValueRefreshRequest;
260        self.send_request::<InlineValueRefreshRequest>(()).await
261    }
262
263    /// Asks the client to refresh the inlay hints currently shown in editors. As a result, the
264    /// client should ask the server to recompute the inlay hints for these editors.
265    ///
266    /// This is useful if a server detects a configuration change which requires a re-calculation
267    /// of all inlay hints. Note that the client still has the freedom to delay the re-calculation
268    /// of the inlay hints if for example an editor is currently not visible.
269    ///
270    /// This corresponds to the [`workspace/inlayHint/refresh`] request.
271    ///
272    /// [`workspace/inlayHint/refresh`]: https://microsoft.github.io/language-server-protocol/specification#workspace_inlayHint_refresh
273    ///
274    /// # Initialization
275    ///
276    /// If the request is sent to the client before the server has been initialized, this will
277    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
278    ///
279    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
280    ///
281    /// # Compatibility
282    ///
283    /// This request was introduced in specification version 3.17.0.
284    pub async fn inlay_hint_refresh(&self) -> jsonrpc::Result<()> {
285        use lsp_types_max::request::InlayHintRefreshRequest;
286        self.send_request::<InlayHintRefreshRequest>(()).await
287    }
288
289    /// Asks the client to refresh all folding ranges.
290    ///
291    /// This corresponds to the [`workspace/foldingRange/refresh`] request.
292    ///
293    /// [`workspace/foldingRange/refresh`]: https://microsoft.github.io/language-server-protocol/specification#workspace_foldingRange_refresh
294    ///
295    /// # Initialization
296    ///
297    /// If the request is sent to the client before the server has been initialized, this will
298    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
299    ///
300    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
301    ///
302    /// # Compatibility
303    ///
304    /// This request was introduced in specification version 3.18.0.
305    pub async fn folding_range_refresh(&self) -> jsonrpc::Result<()> {
306        self.send_request::<super::FoldingRangeRefresh>(()).await
307    }
308
309    /// Asks the client to refresh all needed document and workspace diagnostics.
310    ///
311    /// This is useful if a server detects a project wide configuration change which requires a
312    /// re-calculation of all diagnostics.
313    ///
314    /// This corresponds to the [`workspace/diagnostic/refresh`] request.
315    ///
316    /// [`workspace/diagnostic/refresh`]: https://microsoft.github.io/language-server-protocol/specification#diagnostic_refresh
317    ///
318    /// # Initialization
319    ///
320    /// If the request is sent to the client before the server has been initialized, this will
321    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
322    ///
323    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
324    ///
325    /// # Compatibility
326    ///
327    /// This request was introduced in specification version 3.17.0.
328    pub async fn workspace_diagnostic_refresh(&self) -> jsonrpc::Result<()> {
329        use lsp_types_max::request::WorkspaceDiagnosticRefresh;
330        self.send_request::<WorkspaceDiagnosticRefresh>(()).await
331    }
332
333    /// Asks the client to refresh the content of a text document.
334    ///
335    /// This corresponds to the [`workspace/textDocumentContent/refresh`](lsp_max_protocol::lsp_3_18::TextDocumentContentRefreshRequest) request.
336    pub async fn text_document_content_refresh(
337        &self,
338        params: lsp_max_protocol::lsp_3_18::TextDocumentContentRefreshParams,
339    ) -> jsonrpc::Result<()> {
340        self.send_request::<lsp_max_protocol::lsp_3_18::TextDocumentContentRefreshRequest>(params)
341            .await
342    }
343
344    /// Submits validation diagnostics for an open file with the given URI.
345    ///
346    /// This corresponds to the [`textDocument/publishDiagnostics`] notification.
347    ///
348    /// [`textDocument/publishDiagnostics`]: https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics
349    ///
350    /// # Initialization
351    ///
352    /// This notification will only be sent if the server is initialized.
353    pub async fn publish_diagnostics(
354        &self,
355        uri: Uri,
356        mut diags: Vec<Diagnostic>,
357        version: Option<i32>,
358    ) {
359        use lsp_types_max::notification::PublishDiagnostics;
360
361        let mut missing_push = false;
362
363        // Track the pushes we made in the inner state, or simply assume that
364        // any ERROR diagnostic should be flagged if not generated via Andon event.
365        // For now, if there is a blocking diagnostic but no push was tracked...
366
367        // Let's check if the diagnostic has an ANDON code
368        for diag in &diags {
369            if let Some(severity) = diag.severity {
370                if severity == DiagnosticSeverity::ERROR {
371                    // Check if it's an ANDON diagnostic
372                    if let Some(source) = &diag.source {
373                        if source != "lsp-max-andon" {
374                            missing_push = true;
375                        }
376                    } else {
377                        missing_push = true;
378                    }
379                }
380            }
381        }
382
383        if missing_push {
384            diags.push(Diagnostic {
385                range: Default::default(),
386                severity: Some(DiagnosticSeverity::ERROR),
387                code: Some(lsp_types_max::NumberOrString::String(
388                    "LSPMAX-ANDON-PUSH-MISSING".to_string(),
389                )),
390                source: Some("lsp-max-andon".to_string()),
391                message:
392                    "A blocking diagnostic was emitted without a corresponding ANDON push event."
393                        .to_string(),
394                related_information: None,
395                tags: None,
396                code_description: None,
397                data: None,
398            });
399        }
400
401        self.send_notification_unchecked::<PublishDiagnostics>(PublishDiagnosticsParams::new(
402            uri, diags, version,
403        ))
404        .await;
405    }
406
407    /// `lspMax/andonRaised` notification
408    pub async fn andon_raised(&self, event: crate::andon::andon::AndonEvent) {
409        use crate::andon::lsp::LspMaxAndonRaised;
410        self.send_notification_unchecked::<LspMaxAndonRaised>(event)
411            .await;
412    }
413
414    /// `lspMax/admissionChanged` notification
415    pub async fn admission_changed(&self, status: String) {
416        use crate::andon::lsp::{AdmissionChangedParams, LspMaxAdmissionChanged};
417        self.send_notification_unchecked::<LspMaxAdmissionChanged>(AdmissionChangedParams {
418            status,
419        })
420        .await;
421    }
422
423    /// `lspMax/truthTableChanged` notification
424    pub async fn truth_table_changed(&self, uri: String) {
425        use crate::andon::lsp::{LspMaxTruthTableChanged, TruthTableChangedParams};
426        self.send_notification_unchecked::<LspMaxTruthTableChanged>(TruthTableChangedParams {
427            uri,
428        })
429        .await;
430    }
431
432    /// `lspMax/counterfactualFailed` notification
433    pub async fn counterfactual_failed(&self, invariant_id: String) {
434        use crate::andon::lsp::{CounterfactualFailedParams, LspMaxCounterfactualFailed};
435        self.send_notification_unchecked::<LspMaxCounterfactualFailed>(
436            CounterfactualFailedParams { invariant_id },
437        )
438        .await;
439    }
440
441    /// `lspMax/nextLawfulStepChanged` notification
442    pub async fn next_lawful_step_changed(&self, step: String) {
443        use crate::andon::lsp::{LspMaxNextLawfulStepChanged, NextLawfulStepChangedParams};
444        self.send_notification_unchecked::<LspMaxNextLawfulStepChanged>(
445            NextLawfulStepChangedParams { step },
446        )
447        .await;
448    }
449
450    // Workspace Features
451
452    /// Fetches configuration settings from the client.
453    ///
454    /// The request can fetch several configuration settings in one roundtrip. The order of the
455    /// returned configuration settings correspond to the order of the passed
456    /// [`ConfigurationItem`]s (e.g. the first item in the response is the result for the first
457    /// configuration item in the params).
458    ///
459    /// This corresponds to the [`workspace/configuration`] request.
460    ///
461    /// [`workspace/configuration`]: https://microsoft.github.io/language-server-protocol/specification#workspace_configuration
462    ///
463    /// # Initialization
464    ///
465    /// If the request is sent to the client before the server has been initialized, this will
466    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
467    ///
468    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
469    ///
470    /// # Compatibility
471    ///
472    /// This request was introduced in specification version 3.6.0.
473    pub async fn configuration(
474        &self,
475        items: Vec<ConfigurationItem>,
476    ) -> jsonrpc::Result<Vec<Value>> {
477        use lsp_types_max::request::WorkspaceConfiguration;
478        self.send_request::<WorkspaceConfiguration>(ConfigurationParams { items })
479            .await
480    }
481
482    /// Fetches the current open list of workspace folders.
483    ///
484    /// Returns `None` if only a single file is open in the tool. Returns an empty `Vec` if a
485    /// workspace is open but no folders are configured.
486    ///
487    /// This corresponds to the [`workspace/workspaceFolders`] request.
488    ///
489    /// [`workspace/workspaceFolders`]: https://microsoft.github.io/language-server-protocol/specification#workspace_workspaceFolders
490    ///
491    /// # Initialization
492    ///
493    /// If the request is sent to the client before the server has been initialized, this will
494    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
495    ///
496    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
497    ///
498    /// # Compatibility
499    ///
500    /// This request was introduced in specification version 3.6.0.
501    pub async fn workspace_folders(&self) -> jsonrpc::Result<Option<Vec<WorkspaceFolder>>> {
502        use lsp_types_max::request::WorkspaceFoldersRequest;
503        self.send_request::<WorkspaceFoldersRequest>(()).await
504    }
505
506    /// Requests a workspace resource be edited on the client side and returns whether the edit was
507    /// applied.
508    ///
509    /// This corresponds to the [`workspace/applyEdit`] request.
510    ///
511    /// [`workspace/applyEdit`]: https://microsoft.github.io/language-server-protocol/specification#workspace_applyEdit
512    ///
513    /// # Initialization
514    ///
515    /// If the request is sent to the client before the server has been initialized, this will
516    /// immediately return `Err` with JSON-RPC error code `-32002` ([read more]).
517    ///
518    /// [read more]: https://microsoft.github.io/language-server-protocol/specification#initialize
519    pub async fn apply_edit(
520        &self,
521        edit: WorkspaceEdit,
522    ) -> jsonrpc::Result<ApplyWorkspaceEditResponse> {
523        use lsp_types_max::request::ApplyWorkspaceEdit;
524        self.send_request::<ApplyWorkspaceEdit>(ApplyWorkspaceEditParams { edit, label: None })
525            .await
526    }
527
528    /// Starts a stream of `$/progress` notifications for a client-provided [`ProgressToken`].
529    ///
530    /// This method also takes a `title` argument briefly describing the kind of operation being
531    /// performed, e.g. "Indexing" or "Linking Dependencies".
532    ///
533    /// [`ProgressToken`]: https://docs.rs/lsp-types/latest/lsp_types/type.ProgressToken.html
534    ///
535    /// # Initialization
536    ///
537    /// These notifications will only be sent if the server is initialized.
538    pub fn progress<T>(&self, token: ProgressToken, title: T) -> super::Progress
539    where
540        T: Into<String>,
541    {
542        super::Progress::new(self.clone(), token, title.into())
543    }
544}