Skip to main content

cli_denoiser/filters/
mod.rs

1pub mod ansi;
2pub mod cargo;
3pub mod dedup;
4pub mod docker;
5pub mod generic;
6pub mod git;
7pub mod kubectl;
8pub mod npm;
9pub mod progress;
10
11/// Result of filtering a single line.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum FilterResult {
14    /// Keep the line as-is.
15    Keep,
16    /// Replace the line with a new string.
17    Replace(String),
18    /// Drop the line entirely (confirmed noise).
19    Drop,
20    /// Filter is uncertain -- line passes through unchanged.
21    /// This is the zero-false-positive guarantee.
22    Uncertain,
23}
24
25/// Trait that all filters implement.
26pub trait Filter: Send + Sync {
27    /// Human-readable name for logging and stats.
28    fn name(&self) -> &'static str;
29
30    /// Filter a single line. Return `Uncertain` when unsure.
31    fn filter_line(&self, line: &str) -> FilterResult;
32
33    /// Filter at block level (multi-line patterns).
34    /// Default: return lines unchanged.
35    fn filter_block(&self, lines: &[String]) -> Vec<String> {
36        lines.to_vec()
37    }
38}
39
40/// Detect which command is being run from the command string.
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum CommandKind {
43    Git,
44    Npm,
45    Cargo,
46    Docker,
47    Kubectl,
48    Unknown,
49}
50
51impl CommandKind {
52    #[must_use]
53    pub fn detect(command: &str) -> Self {
54        let cmd = command.split_whitespace().next().unwrap_or("");
55        // Strip path prefix (e.g., /usr/bin/git -> git)
56        let base = cmd.rsplit('/').next().unwrap_or(cmd);
57        match base {
58            "git" => Self::Git,
59            "npm" | "npx" | "yarn" | "pnpm" | "bun" => Self::Npm,
60            "cargo" | "rustc" | "rustup" => Self::Cargo,
61            "docker" | "docker-compose" | "podman" => Self::Docker,
62            "kubectl" | "k9s" | "helm" => Self::Kubectl,
63            _ => Self::Unknown,
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn detect_git() {
74        assert_eq!(CommandKind::detect("git status"), CommandKind::Git);
75        assert_eq!(CommandKind::detect("/usr/bin/git log"), CommandKind::Git);
76    }
77
78    #[test]
79    fn detect_npm_variants() {
80        assert_eq!(CommandKind::detect("npm install"), CommandKind::Npm);
81        assert_eq!(CommandKind::detect("pnpm dev"), CommandKind::Npm);
82        assert_eq!(CommandKind::detect("bun run test"), CommandKind::Npm);
83    }
84
85    #[test]
86    fn detect_unknown() {
87        assert_eq!(CommandKind::detect("ls -la"), CommandKind::Unknown);
88        assert_eq!(CommandKind::detect(""), CommandKind::Unknown);
89    }
90}