dprint_core/plugins/
plugin_handler.rs1use anyhow::Result;
2use serde::Deserialize;
3use serde::Serialize;
4
5#[cfg(feature = "async_runtime")]
6use crate::async_runtime::FutureExt;
7#[cfg(feature = "async_runtime")]
8use crate::async_runtime::LocalBoxFuture;
9
10use crate::configuration::ConfigKeyMap;
11use crate::configuration::ConfigKeyValue;
12use crate::configuration::ConfigurationDiagnostic;
13use crate::configuration::GlobalConfiguration;
14use crate::plugins::PluginInfo;
15
16use super::FileMatchingInfo;
17
18pub trait CancellationToken: Send + Sync + std::fmt::Debug {
19 fn is_cancelled(&self) -> bool;
20 #[cfg(feature = "async_runtime")]
21 fn wait_cancellation(&self) -> LocalBoxFuture<'static, ()>;
22}
23
24#[cfg(feature = "async_runtime")]
25impl CancellationToken for tokio_util::sync::CancellationToken {
26 fn is_cancelled(&self) -> bool {
27 self.is_cancelled()
28 }
29
30 fn wait_cancellation(&self) -> LocalBoxFuture<'static, ()> {
31 let token = self.clone();
32 async move { token.cancelled().await }.boxed_local()
33 }
34}
35
36#[derive(Debug)]
38pub struct NullCancellationToken;
39
40impl CancellationToken for NullCancellationToken {
41 fn is_cancelled(&self) -> bool {
42 false
43 }
44
45 #[cfg(feature = "async_runtime")]
46 fn wait_cancellation(&self) -> LocalBoxFuture<'static, ()> {
47 Box::pin(std::future::pending())
49 }
50}
51
52pub type FormatRange = Option<std::ops::Range<usize>>;
53
54#[derive(Debug)]
59pub struct CriticalFormatError(pub anyhow::Error);
60
61impl std::fmt::Display for CriticalFormatError {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 self.0.fmt(f)
64 }
65}
66
67impl std::error::Error for CriticalFormatError {
68 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
69 self.0.source()
70 }
71}
72
73#[derive(Debug, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct CheckConfigUpdatesMessage {
76 #[serde(default)]
78 pub old_version: Option<String>,
79 pub config: ConfigKeyMap,
80}
81
82#[cfg(feature = "process")]
83#[derive(Debug)]
84pub struct HostFormatRequest {
85 pub file_path: std::path::PathBuf,
86 pub file_bytes: Vec<u8>,
87 pub range: FormatRange,
89 pub override_config: ConfigKeyMap,
90 pub token: std::sync::Arc<dyn CancellationToken>,
91}
92
93#[cfg(feature = "wasm")]
94#[derive(Debug)]
95pub struct SyncHostFormatRequest<'a> {
96 pub file_path: &'a std::path::Path,
97 pub file_bytes: &'a [u8],
98 pub range: FormatRange,
100 pub override_config: &'a ConfigKeyMap,
101}
102
103pub type FormatResult = Result<Option<Vec<u8>>>;
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct RawFormatConfig {
110 pub plugin: ConfigKeyMap,
111 pub global: GlobalConfiguration,
112}
113
114#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
116pub struct FormatConfigId(u32);
117
118impl std::fmt::Display for FormatConfigId {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 write!(f, "${}", self.0)
121 }
122}
123
124impl FormatConfigId {
125 pub fn from_raw(raw: u32) -> FormatConfigId {
126 FormatConfigId(raw)
127 }
128
129 pub fn uninitialized() -> FormatConfigId {
130 FormatConfigId(0)
131 }
132
133 pub fn as_raw(&self) -> u32 {
134 self.0
135 }
136}
137
138#[cfg(feature = "process")]
139pub struct FormatRequest<TConfiguration> {
140 pub file_path: std::path::PathBuf,
141 pub file_bytes: Vec<u8>,
142 pub config_id: FormatConfigId,
143 pub config: std::sync::Arc<TConfiguration>,
144 pub range: FormatRange,
146 pub token: std::sync::Arc<dyn CancellationToken>,
147}
148
149#[cfg(feature = "wasm")]
150pub struct SyncFormatRequest<'a, TConfiguration> {
151 pub file_path: &'a std::path::Path,
152 pub file_bytes: Vec<u8>,
153 pub config_id: FormatConfigId,
154 pub config: &'a TConfiguration,
155 pub range: FormatRange,
157 pub token: &'a dyn CancellationToken,
158}
159
160#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
161#[serde(untagged)]
162pub enum ConfigChangePathItem {
163 String(String),
165 Number(usize),
167}
168
169impl From<String> for ConfigChangePathItem {
170 fn from(value: String) -> Self {
171 Self::String(value)
172 }
173}
174
175impl From<usize> for ConfigChangePathItem {
176 fn from(value: usize) -> Self {
177 Self::Number(value)
178 }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct ConfigChange {
184 pub path: Vec<ConfigChangePathItem>,
186 #[serde(flatten)]
187 pub kind: ConfigChangeKind,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(tag = "kind", content = "value")]
192pub enum ConfigChangeKind {
193 Add(ConfigKeyValue),
195 Set(ConfigKeyValue),
197 Remove,
199}
200
201#[derive(Clone, Serialize)]
202#[serde(rename_all = "camelCase")]
203pub struct PluginResolveConfigurationResult<T>
204where
205 T: Clone + Serialize,
206{
207 pub file_matching: FileMatchingInfo,
209
210 pub diagnostics: Vec<ConfigurationDiagnostic>,
212
213 pub config: T,
216}
217
218#[cfg(feature = "process")]
220#[crate::async_runtime::async_trait(?Send)]
221pub trait AsyncPluginHandler: 'static {
222 type Configuration: Serialize + Clone + Send + Sync;
223
224 fn plugin_info(&self) -> PluginInfo;
226 fn license_text(&self) -> String;
228 async fn resolve_config(&self, config: ConfigKeyMap, global_config: GlobalConfiguration) -> PluginResolveConfigurationResult<Self::Configuration>;
230 async fn check_config_updates(&self, _message: CheckConfigUpdatesMessage) -> Result<Vec<ConfigChange>> {
233 Ok(Vec::new())
234 }
235 async fn format(
237 &self,
238 request: FormatRequest<Self::Configuration>,
239 format_with_host: impl FnMut(HostFormatRequest) -> LocalBoxFuture<'static, FormatResult> + 'static,
240 ) -> FormatResult;
241}
242
243#[cfg(feature = "wasm")]
245pub trait SyncPluginHandler<TConfiguration: Clone + serde::Serialize> {
246 fn resolve_config(&mut self, config: ConfigKeyMap, global_config: &GlobalConfiguration) -> PluginResolveConfigurationResult<TConfiguration>;
248 fn plugin_info(&mut self) -> PluginInfo;
250 fn license_text(&mut self) -> String;
252 fn check_config_updates(&self, message: CheckConfigUpdatesMessage) -> Result<Vec<ConfigChange>>;
255 fn format(&mut self, request: SyncFormatRequest<TConfiguration>, format_with_host: impl FnMut(SyncHostFormatRequest) -> FormatResult) -> FormatResult;
257}