use serde::Deserialize;
use std::path::Path;
#[derive(Debug, Deserialize, Clone)]
pub struct Plugin {
pub name: String,
pub bin: String,
pub args: Option<Vec<String>>,
pub filter_mode: Option<String>,
pub drop_prefixes: Option<Vec<String>>,
pub keep_prefixes: Option<Vec<String>>,
}
#[derive(Debug, Deserialize, Clone, Default)]
pub struct PluginsConfig {
pub plugins: Vec<Plugin>,
}
pub fn load_plugins() -> PluginsConfig {
let mut config = PluginsConfig::default();
if let Some(home) = std::env::var_os("USERPROFILE").or_else(|| std::env::var_os("HOME")) {
let global_path = Path::new(&home).join(".config/rtk/plugins.toml");
if let Ok(content) = std::fs::read_to_string(&global_path) {
if let Ok(c) = toml::from_str::<PluginsConfig>(&content) {
config.plugins.extend(c.plugins);
}
}
}
let local_path = Path::new("plugins.toml");
if let Ok(content) = std::fs::read_to_string(local_path) {
if let Ok(c) = toml::from_str::<PluginsConfig>(&content) {
for p in c.plugins {
if let Some(pos) = config.plugins.iter().position(|x| x.name == p.name) {
config.plugins[pos] = p; } else {
config.plugins.push(p); }
}
}
}
config
}
pub fn filter_plugin(input: &str, plugin: &Plugin) -> String {
let mut out = String::with_capacity(input.len());
for line in input.lines() {
let mut keep = true;
if let Some(ref drop) = plugin.drop_prefixes {
if drop
.iter()
.any(|prefix| line.trim_start().starts_with(prefix))
{
keep = false;
}
}
if let Some(ref k_pref) = plugin.keep_prefixes {
let matches_keep = k_pref
.iter()
.any(|prefix| line.trim_start().starts_with(prefix));
let has_error = line.to_lowercase().contains("error")
|| line.to_lowercase().contains("warning")
|| line.to_lowercase().contains("failed");
if !matches_keep && !has_error {
keep = false;
}
}
if keep {
out.push_str(line);
out.push('\n');
}
}
if out.trim().is_empty() {
input.to_string()
} else {
out
}
}