Skip to main content

rz_cli/
log.rs

1//! Helpers for extracting and formatting protocol messages from scrollback.
2
3use crate::protocol::{Envelope, MessageKind, SENTINEL};
4
5/// Scan scrollback text for `@@RZ:` lines and parse each into an [`Envelope`].
6///
7/// Handles terminal line-wrapping by joining continuation lines until the
8/// JSON parses successfully (up to 20 lines lookahead).
9pub fn extract_messages(scrollback: &str) -> Vec<Envelope> {
10    let lines: Vec<&str> = scrollback.lines().collect();
11    let mut result = Vec::new();
12    let mut i = 0;
13
14    while i < lines.len() {
15        if let Some(idx) = lines[i].find(SENTINEL) {
16            let mut candidate = lines[i][idx..].to_string();
17            if let Ok(env) = Envelope::decode(&candidate) {
18                result.push(env);
19                i += 1;
20                continue;
21            }
22            // Try joining wrapped continuation lines.
23            for j in 1..20 {
24                if i + j >= lines.len() {
25                    break;
26                }
27                candidate.push_str(lines[i + j]);
28                if let Ok(env) = Envelope::decode(&candidate) {
29                    result.push(env);
30                    i += j;
31                    break;
32                }
33            }
34        }
35        i += 1;
36    }
37
38    result
39}
40
41/// Format an envelope as a human-readable one-liner: `[HH:MM:SS] from_id> text`
42pub fn format_message(envelope: &Envelope) -> String {
43    let secs = envelope.ts / 1000;
44    let h = (secs / 3600) % 24;
45    let m = (secs % 3600) / 60;
46    let s = secs % 60;
47
48    let text = match &envelope.kind {
49        MessageKind::Chat { text } => text.as_str(),
50        MessageKind::Hello { name, pane_id } => {
51            return format!("[{h:02}:{m:02}:{s:02}] {}> hello ({name}, {pane_id})", envelope.from);
52        }
53        MessageKind::Ping => "ping",
54        MessageKind::Pong => "pong",
55        MessageKind::Error { message } => {
56            return format!("[{h:02}:{m:02}:{s:02}] {}> error: {message}", envelope.from);
57        }
58        MessageKind::Timer { label } => {
59            return format!("[{h:02}:{m:02}:{s:02}] {}> timer: {label}", envelope.from);
60        }
61    };
62
63    format!("[{h:02}:{m:02}:{s:02}] {}> {text}", envelope.from)
64}