Skip to main content

things3_cloud/ui/
mod.rs

1pub mod components;
2pub mod views;
3
4use iocraft::prelude::*;
5
6pub fn render_lines(lines: Vec<String>, no_color: bool) -> String {
7    let mut element = element! {
8        View(flex_direction: FlexDirection::Column) {
9            #(lines.into_iter().map(|line| element! { Text(content: line, wrap: TextWrap::NoWrap) }))
10        }
11    };
12
13    render_element_to_string(&mut element, no_color)
14}
15
16pub fn indent_lines(lines: Vec<String>, spaces: usize) -> Vec<String> {
17    let prefix = " ".repeat(spaces);
18    lines
19        .into_iter()
20        .map(|line| {
21            if line.is_empty() {
22                line
23            } else {
24                format!("{}{}", prefix, line)
25            }
26        })
27        .collect()
28}
29
30pub fn render_element_to_string<E: ElementExt>(element: &mut E, no_color: bool) -> String {
31    let canvas = element.render(None);
32    let mut bytes = Vec::new();
33    if no_color {
34        canvas
35            .write(&mut bytes)
36            .expect("writing iocraft canvas should not fail");
37    } else {
38        canvas
39            .write_ansi(&mut bytes)
40            .expect("writing ANSI iocraft canvas should not fail");
41    }
42
43    let s = String::from_utf8(bytes).expect("iocraft output should be UTF-8");
44    let s = s.replace("\u{1b}[K", "");
45    let mut lines = s
46        .split('\n')
47        .map(|line| line.trim_end_matches(' ').to_string())
48        .collect::<Vec<_>>();
49
50    while lines.last().map(|line| line.is_empty()).unwrap_or(false) {
51        lines.pop();
52    }
53
54    lines.join("\n")
55}