docker_stats/
escape.rs

1/// Handles cleaning and processing of ANSI escape sequences from Docker output
2pub struct EscapeSequenceCleaner {
3    partial_line: String
4}
5
6impl Default for EscapeSequenceCleaner {
7    fn default() -> Self { Self::new() }
8}
9
10impl EscapeSequenceCleaner {
11    pub fn new() -> Self {
12        Self {
13            partial_line: String::new()
14        }
15    }
16
17    /// Processes a line and returns cleaned JSON if available
18    pub fn process_line(&mut self, mut line: String) -> Option<String> {
19        // Handle screen clearing sequences - these indicate we should print current stats
20        if line.starts_with("\u{1b}[J\u{1b}[H") {
21            line = line.replace("\u{1b}[J\u{1b}[H", "");
22            if line.is_empty() {
23                return None;
24            }
25        }
26
27        // Handle cursor positioning sequences
28        if line.starts_with("\u{1b}[H") {
29            line = line.replace("\u{1b}[H", "");
30            if line.is_empty() {
31                return None;
32            }
33        }
34
35        // Remove trailing escape sequences
36        if line.ends_with("\u{1b}[K") {
37            line = line.replace("\u{1b}[K", "").trim().to_string();
38        }
39
40        // Skip lines that are just whitespace or escape sequences
41        if line.trim().is_empty() {
42            return None;
43        }
44
45        // Handle partial JSON lines
46        if !line.starts_with('{') && !self.partial_line.is_empty() {
47            self.partial_line.push_str(&line);
48            line = self.partial_line.clone();
49            self.partial_line.clear();
50        } else if line.starts_with('{') && !line.ends_with('}') {
51            // This is the start of JSON but incomplete
52            self.partial_line = line;
53            return None;
54        } else if !self.partial_line.is_empty() {
55            // We have a partial line from before, complete it
56            self.partial_line.push_str(&line);
57            line = self.partial_line.clone();
58            self.partial_line.clear();
59        }
60
61        // Skip lines that don't look like JSON
62        if !line.starts_with('{') || !line.ends_with('}') {
63            return None;
64        }
65
66        Some(line)
67    }
68
69    /// Check if the line indicates a screen clear event
70    pub fn is_screen_clear_event(line: &str) -> bool { line.starts_with("\u{1b}[J\u{1b}[H") }
71}