prettyping_rs/render/
mod.rs1pub mod palette;
2pub mod plain;
3pub mod terminal;
4
5use crate::config::Config;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct RenderConfig {
9 pub color: bool,
10 pub multicolor: bool,
11 pub unicode: bool,
12 pub legend: bool,
13 pub globalstats: bool,
14 pub recentstats: bool,
15 pub last: u32,
16 pub columns: Option<u16>,
17 pub lines: Option<u16>,
18 pub rttmin: Option<u32>,
19 pub rttmax: Option<u32>,
20}
21
22impl From<&Config> for RenderConfig {
23 fn from(value: &Config) -> Self {
24 Self {
25 color: value.color,
26 multicolor: value.multicolor,
27 unicode: value.unicode,
28 legend: value.legend,
29 globalstats: value.globalstats,
30 recentstats: value.recentstats,
31 last: value.last,
32 columns: value.columns,
33 lines: value.lines,
34 rttmin: value.rttmin,
35 rttmax: value.rttmax,
36 }
37 }
38}
39
40pub(crate) fn format_global_stats_line_terminal(
41 snapshot: &crate::stats::GlobalStatsSnapshot,
42) -> String {
43 format!(
44 "{:>2}/{:>3} ({:>2}%) lost; {:>4}/{:>4}/{:>4}ms; last: {:>4}ms",
45 snapshot.loss.lost,
46 snapshot.loss.total,
47 snapshot.loss.percent,
48 snapshot.rtt.min_ms,
49 snapshot.rtt.avg_ms,
50 snapshot.rtt.max_ms,
51 snapshot.last_rtt_ms
52 )
53}
54
55pub(crate) fn format_global_stats_line_plain(
56 snapshot: &crate::stats::GlobalStatsSnapshot,
57) -> String {
58 format!(
59 "{:>2}/{:>3} ({:>2}%) lost; {:>4}/{:>4}/{:>4}ms",
60 snapshot.loss.lost,
61 snapshot.loss.total,
62 snapshot.loss.percent,
63 snapshot.rtt.min_ms,
64 snapshot.rtt.avg_ms,
65 snapshot.rtt.max_ms
66 )
67}
68
69pub(crate) fn format_recent_stats_line(snapshot: &crate::stats::RecentStatsSnapshot) -> String {
70 format!(
71 "{:>2}/{:>3} ({:>2}%) lost; {:>4}/{:>4}/{:>4}/{:>4}ms stddev (last {})",
72 snapshot.loss.lost,
73 snapshot.loss.total,
74 snapshot.loss.percent,
75 snapshot.rtt.min_ms,
76 snapshot.rtt.avg_ms,
77 snapshot.rtt.max_ms,
78 snapshot.rtt.stddev_ms,
79 snapshot.rtt.count
80 )
81}
82
83pub(crate) fn trim_to_width(line: &str, width: usize) -> String {
84 if width == 0 {
85 return String::new();
86 }
87
88 line.chars().take(width).collect()
89}
90
91pub(crate) fn trim_ansi_to_width(input: &str, width: usize) -> String {
97 if width == 0 || input.is_empty() {
98 return String::new();
99 }
100
101 let bytes = input.as_bytes();
102 let mut out = String::new();
103 let mut idx = 0usize;
104 let mut visible = 0usize;
105 let mut saw_escape = false;
106
107 while idx < bytes.len() {
108 if bytes[idx] == b'\x1b' {
109 saw_escape = true;
110
111 if idx + 1 < bytes.len() && bytes[idx + 1] == b'[' {
113 let mut j = idx + 2;
114 while j < bytes.len() {
115 let b = bytes[j];
116 if (0x40..=0x7E).contains(&b) {
118 j += 1;
119 break;
120 }
121 j += 1;
122 }
123
124 out.push_str(&input[idx..j.min(bytes.len())]);
125 idx = j.min(bytes.len());
126 continue;
127 }
128
129 if idx + 1 < bytes.len() {
131 out.push_str(&input[idx..idx + 2]);
132 idx += 2;
133 continue;
134 }
135
136 out.push('\x1b');
138 break;
139 }
140
141 let ch = input[idx..].chars().next().unwrap();
142 if visible >= width {
143 break;
144 }
145
146 out.push(ch);
147 visible += 1;
148 idx += ch.len_utf8();
149 }
150
151 if saw_escape && idx < bytes.len() {
153 out.push_str("\x1b[0m");
154 }
155
156 out
157}