返回 CodeWhale
output.rs
根目录 / crates / tui / src / tools / shell / output.rs
1 use std::sync::{Arc, Mutex};
2
3 pub(super) fn take_delta_from_buffer(
4 buffer: &Arc<Mutex<Vec<u8>>>,
5 cursor: &mut usize,
6 ) -> (Vec<u8>, usize) {
7 let guard = buffer.lock().unwrap_or_else(|e| e.into_inner());
8 let total = guard.len();
9 let start = (*cursor).min(total);
10 // Clone only the unread portion (the delta), not the entire accumulated buffer.
11 // Long-running processes can produce megabytes of output; cloning the full
12 // buffer on every poll held the ShellManager mutex for O(total_bytes) time.
13 let delta = guard[start..].to_vec();
14 *cursor = total;
15 (delta, total)
16 }
17
18 /// Read only the tail of a byte buffer and return (total_len, tail_string).
19 ///
20 /// Avoids cloning the full buffer when only a trailing excerpt is needed
21 /// (e.g. for the job-panel display). `max_tail_chars` is in Unicode scalar
22 /// values; we read at most `max_tail_chars * 4` bytes from the end to account
23 /// for multi-byte UTF-8 sequences.
24 pub(super) fn tail_from_buffer(
25 buffer: &Arc<Mutex<Vec<u8>>>,
26 max_tail_chars: usize,
27 ) -> (usize, String) {
28 let guard = buffer.lock().unwrap_or_else(|e| e.into_inner());
29 let total = guard.len();
30 // Over-estimate byte count (4 bytes per char worst case for UTF-8).
31 let mut tail_start = total.saturating_sub(max_tail_chars.saturating_mul(4));
32 // Snap forward to the next valid UTF-8 codepoint boundary so we don't
33 // pass a slice beginning with continuation bytes (0x80-0xBF) to
34 // from_utf8_lossy, which would emit a leading U+FFFD replacement char.
35 while tail_start < total && (guard[tail_start] & 0xC0) == 0x80 {
36 tail_start += 1;
37 }
38 let tail_str = String::from_utf8_lossy(&guard[tail_start..]).into_owned();
39 (total, tail_text(&tail_str, max_tail_chars))
40 }
41
42 fn tail_text(text: &str, max_chars: usize) -> String {
43 if text.chars().count() <= max_chars {
44 return text.to_string();
45 }
46 let tail = text
47 .chars()
48 .rev()
49 .take(max_chars)
50 .collect::<Vec<_>>()
51 .into_iter()
52 .rev()
53 .collect::<String>();
54 format!("...{tail}")
55 }
56
56 lines RUST