use forge::signal::compactor;
use once_cell::sync::Lazy;
use regex::Regex;
static REFRESH_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^[^\n]*: Refreshing state\.\.\.[^\n]*\n?").unwrap());
static DOTS_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^\.\.\.\n?").unwrap());
static DOWNLOAD_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^- (Finding|Installing|Downloading)[^\n]+\n?").unwrap());
pub fn compress_plan(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = REFRESH_RE.replace_all(&cleaned, "");
let s = DOTS_RE.replace_all(&s, "");
compactor::collapse_blanks(&s)
}
pub fn compress_apply(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = REFRESH_RE.replace_all(&cleaned, "");
let out: Vec<&str> = s
.lines()
.filter(|l| {
!l.contains(": Still ")
&& !l.contains(": Creating...")
&& !l.contains(": Destroying...")
})
.collect();
compactor::collapse_blanks(&out.join("\n"))
}
pub fn compress_init(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let s = DOWNLOAD_RE.replace_all(&cleaned, "");
compactor::collapse_blanks(&s)
}
pub fn compress_validate(raw: &str) -> String {
compactor::normalise(raw)
}
pub fn compress_show(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().collect();
if lines.len() <= 60 {
return cleaned;
}
format!(
"{}\n... [{} more lines — full state omitted] ...",
lines[..60].join("\n"),
lines.len() - 60
)
}
pub fn compress_output(raw: &str) -> String {
compactor::normalise(raw)
}
pub fn compress_state(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= 40 {
return lines.join("\n");
}
format!(
"{}\n... [{} more resources] ...",
lines[..40].join("\n"),
lines.len() - 40
)
}
pub fn compress_terraform(subcmd: &str, raw: &str) -> String {
let sub = subcmd.trim();
if sub.starts_with("plan") {
return compress_plan(raw);
}
if sub.starts_with("apply") {
return compress_apply(raw);
}
if sub.starts_with("destroy") {
return compress_apply(raw);
}
if sub.starts_with("init") {
return compress_init(raw);
}
if sub.starts_with("validate") || sub.starts_with("fmt") {
return compress_validate(raw);
}
if sub.starts_with("show") {
return compress_show(raw);
}
if sub.starts_with("output") {
return compress_output(raw);
}
if sub.starts_with("state") {
return compress_state(raw);
}
if sub.starts_with("workspace") {
return compress_workspace(raw);
}
if sub.starts_with("providers") {
return compress_providers(raw);
}
compactor::normalise(raw)
}
pub fn compress_workspace(raw: &str) -> String {
compactor::normalise(raw)
}
pub fn compress_providers(raw: &str) -> String {
let cleaned = compactor::normalise(raw);
let lines: Vec<&str> = cleaned.lines().filter(|l| !l.trim().is_empty()).collect();
if lines.len() <= 30 {
return lines.join("\n");
}
format!(
"{}\n... [{} more providers] ...",
lines[..30].join("\n"),
lines.len() - 30
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plan_strips_refreshing() {
let raw = "aws_instance.foo: Refreshing state... [id=i-abc]\nPlan: 1 to add, 0 to change, 0 to destroy.\n";
let out = compress_plan(raw);
assert!(!out.contains("Refreshing state"), "{out}");
assert!(out.contains("Plan: 1 to add"));
}
#[test]
fn apply_strips_still_creating() {
let raw = "aws_instance.foo: Creating...\naws_instance.foo: Still creating... [10s elapsed]\naws_instance.foo: Creation complete\n";
let out = compress_apply(raw);
assert!(!out.contains("Still creating"), "{out}");
assert!(out.contains("Creation complete"));
}
#[test]
fn init_strips_download_lines() {
let raw = "Initializing the backend...\n- Finding hashicorp/aws versions matching \"~> 4.0\"...\n- Installing hashicorp/aws v4.67.0...\nTerraform has been successfully initialized!\n";
let out = compress_init(raw);
assert!(!out.contains("Finding hashicorp"), "{out}");
assert!(out.contains("successfully initialized"));
}
}