sync_lsp/workspace/execute_command.rs
1//! Implementation for the `workspace/executeCommand` request.
2//!
3//! # Usage
4//! Commands can be attached to certain actions on the client side and then be executed on the server side.
5//! This module provides a [`Command`] trait that can be implemented through a macro to define commands that
6//! can be executed by the server via [`Server::on_execute_command`].
7//!
8//! # Example
9//! ```
10//!use sync_lsp::text_document::{Range, Position};
11//!use sync_lsp::text_document::code_lens::CodeLens;
12//!use sync_lsp::{Transport, TypeProvider, Server, UnitType};
13//!use sync_lsp::workspace::execute_command::Command;
14//!use log::info;
15//!
16//!// This enum defines all commands that can be executed by the server.
17//!// It could also be a struct or a tuple struct.
18//!// Even unit structs and enum variants are supported.
19//!#[derive(Clone, Command, Debug)]
20//!enum MyCommand {
21//! #[command(title = "My first command")]
22//! MyCommand,
23//! #[command(title = "My command with arguments")]
24//! MyCommandWithArguments(u32),
25//!}
26//!
27//!// For this example, we don't need any state.
28//!struct MyServerState;
29//!
30//!// This macro provides default implementations for all required types.
31//!#[sync_lsp::type_provider]
32//!impl TypeProvider for MyServerState {
33//! type Command = MyCommand;
34//!}
35//!
36//!fn main() {
37//! let transport = Transport::stdio();
38//! let mut server = Server::new(MyServerState, transport);
39//!
40//! // One example for a way to send commands to the client is the code lens request.
41//! server.on_code_lens(|_, _| {
42//! vec![
43//! CodeLens {
44//! // For this example, we just return a code lens at the beginning of the document.
45//! range: Range {
46//! start: Position { line: 0, character: 0 },
47//! end: Position { line: 0, character: 0 }
48//! },
49//! // This command will be executed when the user clicks on the code lens.
50//! command: Some(MyCommand::MyCommandWithArguments(1)),
51//! // Since we didn't override TypeProvider::CodeLensData, we have to use UnitType here.
52//! data: UnitType
53//! }
54//! ]
55//! });
56//!
57//! server.on_execute_command(|_, command| {
58//! // Instead of executing the command here, we just log it.
59//! info!("Received command: {:?}", command);
60//! });
61//!
62//! server.serve().unwrap();
63//!}
64//! ```
65
66use crate::TypeProvider;
67use crate::{Server, connection::Endpoint};
68use crate::connection::Callback;
69use serde::{Serialize, Serializer, Deserializer, Deserialize};
70pub use sync_lsp_derive::Command;
71
72#[derive(Serialize, Default, Clone)]
73pub(crate) struct ExecuteCommandOptions {
74 commands: Vec<String>
75}
76
77pub(crate) struct CommandContainer<C: Command>(pub C);
78
79/// A unit command is a command that does not take any arguments.
80/// Command arguments are always optional, which is why this type
81/// never needs to be instantiated and is therefore an empty enum.
82#[derive(Debug, Clone, Deserialize)]
83pub enum UnitCommand {}
84
85/// Defines a command that can be executed by this server.
86/// Instead of implementing this trait manually, you can use the `Command` derive macro.
87/// If you do so, you must also derive [`Clone`].
88/// Implementing this trait manually might break the connection if not done properly.
89pub trait Command: Clone {
90 /// Returns a vector of commands that can be executed by this server.
91 fn commands() -> Vec<String>;
92 /// This is beeing forwared to the `serde::Serialize::serialize` implementation.
93 fn serialize<T: Serializer>(&self, serializer: T) -> Result<T::Ok, T::Error>;
94 /// This is beeing forwared to the `serde::Deserialize::deserialize` implementation.
95 fn deserialize<'de, T: Deserializer<'de>>(deserializer: T) -> Result<Self, T::Error> where Self: Sized;
96}
97
98impl ExecuteCommandOptions {
99
100 pub(crate) const METHOD: &'static str = "workspace/executeCommand";
101
102 pub(super) fn endpoint<T: TypeProvider>() -> Endpoint<T, ExecuteCommandOptions> {
103 let mut endpoint = Endpoint::<T, ExecuteCommandOptions>::new(Callback::request(|_, _: CommandContainer<T::Command>| ()));
104 endpoint.options_mut().commands = T::Command::commands();
105 endpoint
106 }
107}
108
109impl<T: TypeProvider> Server<T> {
110
111 /// Sets the callback that will be called to [execute a command](self).
112 ///
113 /// # Argument
114 /// * `callback` - A callback which is called with the following parameters as soon as the corresponding request is received:
115 /// * The server instance receiving the response.
116 /// * The `Command` to be executed.
117
118 pub fn on_execute_command<R: 'static + Serialize>(&mut self, callback: fn(&mut Server<T>, T::Command) -> R) {
119 self.workspace.execute_command.set_callback(Callback::request(move |server, params: CommandContainer<T::Command>| {
120 callback(server, params.0)
121 }))
122 }
123}
124
125pub(crate) fn deserialize_opt_command<'de, D: Deserializer<'de>, C: Command>(deserializer: D) -> Result<Option<C>, D::Error> {
126 Ok(Some(Command::deserialize(deserializer)?))
127}
128
129pub(crate) fn serialize_opt_command<S: Serializer, C: Command>(command: &Option<C>, serializer: S) -> Result<S::Ok, S::Error> {
130 if let Some(command) = command {
131 command.serialize(serializer)
132 } else {
133 serializer.serialize_none()
134 }
135}
136
137impl<C: Command> Serialize for CommandContainer<C> {
138 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
139 self.0.serialize(serializer)
140 }
141}
142
143impl<'de, C:Command> Deserialize<'de> for CommandContainer<C> {
144 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
145 Ok(CommandContainer(C::deserialize(deserializer)?))
146 }
147}
148
149impl Command for UnitCommand {
150 fn commands() -> Vec<String> {
151 vec![]
152 }
153
154 fn serialize<T: Serializer>(&self, _: T) -> Result<T::Ok, T::Error> {
155 match *self {}
156 }
157
158 fn deserialize<'de, T: Deserializer<'de>>(deserializer: T) -> Result<Self, T::Error> where Self: Sized {
159 <Self as Deserialize>::deserialize(deserializer)
160 }
161}