use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Result;
use dprint_core::configuration::ConfigKeyMap;
use dprint_core::configuration::ConfigKeyValue;
use dprint_core::configuration::ConfigurationDiagnostic;
use dprint_core::configuration::GlobalConfiguration;
use dprint_core::plugins::CancellationToken;
use dprint_core::plugins::FormatRange;
use dprint_core::plugins::FormatResult;
use futures::future::BoxFuture;
use crate::configuration::RawPluginConfig;
pub trait Plugin: Send + Sync {
fn name(&self) -> &str;
fn version(&self) -> &str;
fn config_key(&self) -> &str;
fn file_extensions(&self) -> &Vec<String>;
fn file_names(&self) -> &Vec<String>;
fn help_url(&self) -> &str;
fn config_schema_url(&self) -> &str;
fn update_url(&self) -> Option<&str>;
fn set_config(&mut self, plugin_config: RawPluginConfig, global_config: GlobalConfiguration);
fn initialize(&self) -> BoxFuture<'static, Result<Arc<dyn InitializedPlugin>>>;
fn get_config(&self) -> &(RawPluginConfig, GlobalConfiguration);
fn get_hash(&self) -> u64 {
let config = self.get_config();
let mut hash_str = String::new();
hash_str.push_str(self.name());
hash_str.push_str(self.version());
let sorted_config: std::collections::BTreeMap<&String, &ConfigKeyValue> = config.0.properties.iter().collect();
hash_str.push_str(&serde_json::to_string(&sorted_config).unwrap());
hash_str.push_str(&serde_json::to_string(&config.0.associations).unwrap());
hash_str.push_str(&serde_json::to_string(&config.1).unwrap());
crate::utils::get_bytes_hash(hash_str.as_bytes())
}
}
pub struct InitializedPluginFormatRequest {
pub file_path: PathBuf,
pub file_text: String,
pub range: FormatRange,
pub override_config: ConfigKeyMap,
pub token: Arc<dyn CancellationToken>,
}
pub trait InitializedPlugin: Send + Sync {
fn license_text(&self) -> BoxFuture<'static, Result<String>>;
fn resolved_config(&self) -> BoxFuture<'static, Result<String>>;
fn config_diagnostics(&self) -> BoxFuture<'static, Result<Vec<ConfigurationDiagnostic>>>;
fn format_text(&self, format_request: InitializedPluginFormatRequest) -> BoxFuture<'static, FormatResult>;
}
#[cfg(test)]
pub struct TestPlugin {
name: &'static str,
config_key: String,
file_extensions: Vec<String>,
file_names: Vec<String>,
initialized_test_plugin: Option<InitializedTestPlugin>,
config: (RawPluginConfig, GlobalConfiguration),
}
#[cfg(test)]
impl TestPlugin {
pub fn new(name: &'static str, config_key: &'static str, file_extensions: Vec<&'static str>, file_names: Vec<&'static str>) -> TestPlugin {
TestPlugin {
name,
config_key: String::from(config_key),
file_extensions: file_extensions.into_iter().map(String::from).collect(),
file_names: file_names.into_iter().map(String::from).collect(),
initialized_test_plugin: Some(InitializedTestPlugin::new()),
config: (
Default::default(),
GlobalConfiguration {
line_width: None,
use_tabs: None,
indent_width: None,
new_line_kind: None,
},
),
}
}
}
#[cfg(test)]
impl Plugin for TestPlugin {
fn name(&self) -> &str {
&self.name
}
fn version(&self) -> &str {
"1.0.0"
}
fn help_url(&self) -> &str {
"https://dprint.dev/plugins/test"
}
fn config_schema_url(&self) -> &str {
"https://plugins.dprint.dev/schemas/test.json"
}
fn update_url(&self) -> Option<&str> {
None
}
fn config_key(&self) -> &str {
&self.config_key
}
fn file_extensions(&self) -> &Vec<String> {
&self.file_extensions
}
fn file_names(&self) -> &Vec<String> {
&self.file_names
}
fn set_config(&mut self, _: RawPluginConfig, _: GlobalConfiguration) {}
fn get_config(&self) -> &(RawPluginConfig, GlobalConfiguration) {
&self.config
}
fn initialize(&self) -> BoxFuture<'static, Result<Arc<dyn InitializedPlugin>>> {
use futures::FutureExt;
let test_plugin = Arc::new(self.initialized_test_plugin.clone().unwrap());
async move {
let result: Arc<dyn InitializedPlugin> = test_plugin;
Ok(result)
}
.boxed()
}
}
#[cfg(test)]
#[derive(Clone)]
pub struct InitializedTestPlugin {}
#[cfg(test)]
impl InitializedTestPlugin {
pub fn new() -> InitializedTestPlugin {
InitializedTestPlugin {}
}
}
#[cfg(test)]
impl InitializedPlugin for InitializedTestPlugin {
fn license_text(&self) -> BoxFuture<'static, Result<String>> {
use futures::FutureExt;
async move { Ok(String::from("License Text")) }.boxed()
}
fn resolved_config(&self) -> BoxFuture<'static, Result<String>> {
use futures::FutureExt;
async move { Ok(String::from("{}")) }.boxed()
}
fn config_diagnostics(&self) -> BoxFuture<'static, Result<Vec<ConfigurationDiagnostic>>> {
use futures::FutureExt;
async move { Ok(vec![]) }.boxed()
}
fn format_text(&self, format_request: InitializedPluginFormatRequest) -> BoxFuture<'static, FormatResult> {
use futures::FutureExt;
async move { Ok(Some(format!("{}_formatted", format_request.file_text))) }.boxed()
}
}