Skip to main content

ansiq_core/
history.rs

1use crate::Style;
2use unicode_width::UnicodeWidthChar;
3
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct HistoryRun {
6    pub text: String,
7    pub style: Style,
8}
9
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct HistoryLine {
12    pub runs: Vec<HistoryRun>,
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct HistoryBlock {
17    pub lines: Vec<HistoryLine>,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub enum HistoryEntry {
22    Text(String),
23    Block(HistoryBlock),
24}
25
26pub fn history_block_from_text(content: &str, width: u16) -> HistoryBlock {
27    if width == 0 {
28        return HistoryBlock { lines: Vec::new() };
29    }
30
31    let mut lines = Vec::new();
32
33    for raw_line in content.split('\n') {
34        if raw_line.is_empty() {
35            lines.push(HistoryLine { runs: Vec::new() });
36            continue;
37        }
38
39        let mut current = String::new();
40        let mut current_width = 0u16;
41
42        for ch in raw_line.chars() {
43            let char_width = UnicodeWidthChar::width(ch).unwrap_or(0) as u16;
44            let char_width = char_width.max(1);
45            if current_width.saturating_add(char_width) > width && !current.is_empty() {
46                lines.push(HistoryLine {
47                    runs: vec![HistoryRun {
48                        text: std::mem::take(&mut current),
49                        style: Style::default(),
50                    }],
51                });
52                current_width = 0;
53            }
54
55            current.push(ch);
56            current_width = current_width.saturating_add(char_width);
57        }
58
59        lines.push(HistoryLine {
60            runs: vec![HistoryRun {
61                text: current,
62                style: Style::default(),
63            }],
64        });
65    }
66
67    if lines.is_empty() {
68        lines.push(HistoryLine { runs: Vec::new() });
69    }
70
71    HistoryBlock { lines }
72}