use std::fmt;
use std::sync::Arc;
use ktrs_editorconfig::AnyPropertyType;
use crate::editorconfig::{KtlintVersion, PropertyRef};
use crate::rule::{RuleId, RuleV2, RunAfterRuleMode, VisitorModifier};
#[derive(Clone)]
pub struct RuleV2Provider {
provider: Arc<dyn Fn() -> Box<dyn RuleV2> + Send + Sync>,
rule_id: RuleId,
uses_editor_config_properties: Vec<PropertyRef>,
visitor_modifiers: &'static [VisitorModifier],
only_in: Option<KtlintVersion>,
}
impl RuleV2Provider {
pub fn new(provider: impl Fn() -> Box<dyn RuleV2> + Send + Sync + 'static) -> RuleV2Provider {
let rule = provider();
RuleV2Provider {
rule_id: rule.rule_id(),
uses_editor_config_properties: rule.uses_editor_config_properties(),
visitor_modifiers: rule.visitor_modifiers(),
provider: Arc::new(provider),
only_in: None,
}
}
pub fn only_in(self, version: KtlintVersion) -> RuleV2Provider {
RuleV2Provider { only_in: Some(version), ..self }
}
pub fn runs_in(&self, version: KtlintVersion) -> bool {
self.only_in.is_none_or(|v| v == version)
}
pub fn create_new_rule_instance(&self) -> Box<dyn RuleV2> {
(self.provider)()
}
pub fn rule_id(&self) -> RuleId {
self.rule_id
}
pub fn uses_editor_config_properties(&self) -> &[PropertyRef] {
&self.uses_editor_config_properties
}
pub fn run_after_rules(&self) -> impl Iterator<Item = (RuleId, RunAfterRuleMode)> + '_ {
self.visitor_modifiers.iter().filter_map(|m| match *m {
VisitorModifier::RunAfterRule(rule_id, mode) => Some((rule_id, mode)),
VisitorModifier::RunAsLateAsPossible => None,
})
}
pub fn run_as_late_as_possible(&self) -> bool {
self.visitor_modifiers.contains(&VisitorModifier::RunAsLateAsPossible)
}
}
impl fmt::Debug for RuleV2Provider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RuleV2Provider({})", self.rule_id)
}
}
pub fn rule_providers_in(rule_providers: &[RuleV2Provider], version: KtlintVersion) -> Vec<RuleV2Provider> {
rule_providers.iter().filter(|p| p.runs_in(version)).cloned().collect()
}
pub fn property_types(rule_providers: &[RuleV2Provider]) -> Vec<&'static dyn AnyPropertyType> {
let mut types: Vec<&'static dyn AnyPropertyType> = Vec::new();
for t in rule_providers.iter().flat_map(|p| {
p.uses_editor_config_properties
.iter()
.map(|u| u.property_type())
}) {
if !types.iter().any(|e| e.name() == t.name()) {
types.push(t);
}
}
types
}