use std::path::Path;
use ktrs_ast::Ast;
use crate::engine::code::{Code, KtLintException, LintError};
use crate::engine::code_formatter::{AutocorrectHandler, format};
use crate::engine::editor_config_cache::THREAD_SAFE_EDITOR_CONFIG_CACHE;
use crate::engine::editor_config_defaults::{EditorConfigDefaults, EditorConfigOverride};
use crate::engine::editor_config_loader::{EditorConfigLoader, EditorConfigLoaderEc4j};
use crate::engine::rule_execution_context::create_rule_execution_context;
use crate::rule::AutocorrectDecision;
use crate::rule_provider::{RuleV2Provider, property_types};
pub const MAX_FORMAT_RUNS_PER_FILE: usize = 3;
pub const UTF8_BOM: char = '\u{FEFF}';
pub struct KtLintRuleEngine {
pub(crate) rule_providers: Vec<RuleV2Provider>,
editor_config_defaults: EditorConfigDefaults,
editor_config_override: EditorConfigOverride,
editor_config_loader: EditorConfigLoader,
}
impl KtLintRuleEngine {
pub fn new(rule_providers: Vec<RuleV2Provider>) -> KtLintRuleEngine {
KtLintRuleEngine::with_editor_config(
rule_providers,
EditorConfigDefaults::empty(),
EditorConfigOverride::empty(),
)
}
pub fn with_editor_config(
rule_providers: Vec<RuleV2Provider>,
editor_config_defaults: EditorConfigDefaults,
editor_config_override: EditorConfigOverride,
) -> KtLintRuleEngine {
assert!(
!rule_providers.is_empty(),
"IllegalArgumentException: A non-empty set of 'ruleProviders' need to be provided"
);
let editor_config_loader = EditorConfigLoader::new(
EditorConfigLoaderEc4j::new(&property_types(&rule_providers)),
editor_config_defaults.clone(),
editor_config_override.clone(),
);
KtLintRuleEngine {
rule_providers,
editor_config_defaults,
editor_config_override,
editor_config_loader,
}
}
pub(crate) fn editor_config_loader(&self) -> &EditorConfigLoader {
&self.editor_config_loader
}
pub fn rule_providers(&self) -> &[RuleV2Provider] {
&self.rule_providers
}
pub fn editor_config_defaults(&self) -> &EditorConfigDefaults {
&self.editor_config_defaults
}
pub fn editor_config_override(&self) -> &EditorConfigOverride {
&self.editor_config_override
}
pub fn lint(
&self,
code: &Code,
callback: &mut dyn FnMut(&LintError),
) -> Result<(), KtLintException> {
format(
self,
code,
AutocorrectHandler::None,
&mut |e, _| callback(e),
1,
&mut |_| {},
)
.map(drop)
}
pub fn format(
&self,
code: &Code,
callback: &mut dyn FnMut(&LintError) -> AutocorrectDecision,
) -> Result<String, KtLintException> {
self.format_with(code, true, callback)
}
pub fn format_with(
&self,
code: &Code,
rerun_after_autocorrect: bool,
callback: &mut dyn FnMut(&LintError) -> AutocorrectDecision,
) -> Result<String, KtLintException> {
let max_format_runs_per_file = if rerun_after_autocorrect {
MAX_FORMAT_RUNS_PER_FILE
} else {
1
};
let handler = AutocorrectHandler::LintErrorAutocorrectHandler(callback);
format(
self,
code,
handler,
&mut |_, _| {},
max_format_runs_per_file,
&mut |_| {},
)
}
pub fn format_observed(
&self,
code: &Code,
callback: &mut dyn FnMut(&LintError) -> AutocorrectDecision,
after_pass: &mut dyn FnMut(&Ast),
) -> Result<String, KtLintException> {
let handler = AutocorrectHandler::LintErrorAutocorrectHandler(callback);
format(
self,
code,
handler,
&mut |_, _| {},
MAX_FORMAT_RUNS_PER_FILE,
after_pass,
)
}
pub fn transform_to_ast(&self, code: &Code) -> Result<Ast, KtLintException> {
create_rule_execution_context(self, code).map(|context| context.ast)
}
pub fn trim_memory(&self) {
THREAD_SAFE_EDITOR_CONFIG_CACHE.clear();
}
pub fn reload_editor_config_file(
&self,
path: &Path,
) -> Result<(), ktrs_editorconfig::ParseException> {
THREAD_SAFE_EDITOR_CONFIG_CACHE.reload_if_exists(path)
}
}