1use crate::protocol::{Envelope, MessageKind, SENTINEL};
4
5pub 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 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
41pub 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}