use super::ansi_codes::{RESET_CODE, is_end_code, is_intensity_code};
use super::types::AnsiToken;
pub fn reduce_ansi_codes(codes: &[AnsiToken]) -> Vec<AnsiToken> {
reduce_ansi_codes_incremental(&[], codes)
}
pub fn reduce_ansi_codes_incremental(
codes: &[AnsiToken],
new_codes: &[AnsiToken],
) -> Vec<AnsiToken> {
let mut ret: Vec<AnsiToken> = codes.to_vec();
reduce_ansi_codes_in_place(&mut ret, new_codes);
ret
}
pub(crate) fn reduce_ansi_codes_in_place(ret: &mut Vec<AnsiToken>, new_codes: &[AnsiToken]) {
for code in new_codes {
if code.code == RESET_CODE {
ret.clear();
} else if is_end_code(&code.code) {
ret.retain(|c| c.end_code != code.code);
} else {
if is_intensity_code(code) {
let already = ret
.iter()
.any(|c| c.code == code.code && c.end_code == code.end_code);
if !already {
ret.push(code.clone());
}
} else {
ret.retain(|c| c.end_code != code.end_code);
ret.push(code.clone());
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::text::ansi_tokenize::ansi_codes::get_end_code;
fn tok(code: &str) -> AnsiToken {
AnsiToken {
end_code: get_end_code(code),
code: code.into(),
}
}
#[test]
fn reduce_handles_reset() {
let codes = vec![tok("\x1B[31m"), tok("\x1B[1m")];
let result = reduce_ansi_codes_incremental(&codes, &[tok("\x1B[0m")]);
assert!(result.is_empty(), "reset should clear all codes");
}
#[test]
fn reduce_handles_override() {
let codes = vec![tok("\x1B[31m")];
let result = reduce_ansi_codes_incremental(&codes, &[tok("\x1B[34m")]);
assert_eq!(result.len(), 1);
assert_eq!(result[0].code, "\x1B[34m");
}
#[test]
fn reduce_intensity_coexistence() {
let result = reduce_ansi_codes(&[tok("\x1B[1m"), tok("\x1B[2m")]);
assert_eq!(result.len(), 2);
assert!(result.iter().any(|c| c.code == "\x1B[1m"));
assert!(result.iter().any(|c| c.code == "\x1B[2m"));
}
#[test]
fn reduce_intensity_no_duplicate() {
let result = reduce_ansi_codes(&[tok("\x1B[1m"), tok("\x1B[1m")]);
assert_eq!(result.len(), 1);
}
#[test]
fn reduce_end_code_removes_start() {
let codes = vec![tok("\x1B[31m")];
let result = reduce_ansi_codes_incremental(&codes, &[tok("\x1B[39m")]);
assert!(result.is_empty());
}
}