cargo hollywood
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use super::ls::SList;
use crate::cargo::TestEvent;
use crate::test::TestState;
use ratatui::{
    layout::{Constraint::Percentage, Direction::Horizontal},
    prelude::*,
    style::Stylize,
    widgets::{Block, Borders, List, ListItem},
    Frame,
};
use std::time::Duration;
#[derive(Default)]
pub struct TestList {
    a: SList,
    b: SList,
    c: SList,
}

trait RExt<'a> {
    fn pl(&mut self, list: impl Into<Line<'a>>);
}

impl<'a> RExt<'a> for Vec<ListItem<'a>> {
    fn pl(&mut self, list: impl Into<Line<'a>>) {
        self.push(ListItem::new(list.into()));
    }
}

impl TestList {
    fn has(&mut self, n: usize) {
        self.all().map(|a| a.has(n));
    }

    fn all(&mut self) -> [&mut SList; 3] {
        [&mut self.a, &mut self.b, &mut self.c]
    }

    pub fn next(&mut self) {
        self.all().map(SList::next);
    }

    pub fn prev(&mut self) {
        self.all().map(SList::prev);
    }

    pub fn selects<'a>(&'a self, state: &'a TestState) -> Option<&TestEvent> {
        state.tests.get(self.a.state.selected()?)
    }

    pub fn stdout<'a>(&'a self, state: &'a TestState) -> Option<&str> {
        self.selects(state)?.stdout()
    }
}

pub fn test_list<B: Backend>(f: &mut Frame<B>, state: &mut TestState, chunk: Rect) {
    let mut tests = Vec::<ListItem>::new();
    let mut test_side1 = Vec::<ListItem>::new();
    let mut test_side2 = Vec::<ListItem>::new();
    fn time<'v>(secs: f32) -> Line<'v> {
        let dur = Duration::from_secs_f32(secs);
        let time = humantime::format_duration(dur).to_string();
        match (secs / 16.).round() as usize {
            0 => Line::styled(time, Style::default().green()),
            1 => Line::styled(time, Style::default().yellow()),
            _ => Line::styled(time, Style::default().red()),
        }
    }
    for test in &state.tests {
        match test {
            TestEvent::Started { name } => {
                tests.pl(name.bold().yellow());
                test_side1.pl("in progress".yellow().italic());
                test_side2.pl("");
            }
            TestEvent::Ok {
                name, exec_time, ..
            } => {
                tests.pl(name.bold().green());
                test_side1.pl("passed".green().italic());
                test_side2.pl(time(*exec_time));
            }
            TestEvent::Failed {
                name, exec_time, ..
            } => {
                tests.pl(name.bold().red());
                test_side1.pl("failed".red().bold().italic());
                test_side2.pl(time(*exec_time));
            }
            TestEvent::Timeout { name } => {
                tests.pl(name.bold().red());
                test_side1.pl("timed out".red().bold().italic());
                test_side2.pl("");
            }
            TestEvent::Ignored { name } => {
                tests.pl(name.bold().yellow());
                test_side1.pl("ignored".yellow().italic());
                test_side2.pl("");
            }
        }
    }
    let sides = Layout::default()
        .direction(Horizontal)
        .constraints([Percentage(80), Percentage(10), Percentage(10)])
        .split(chunk);
    let hl = Style::default().on_light_green().italic();
    state.test_list.has(tests.len());
    f.render_stateful_widget(
        List::new(tests)
            .highlight_style(hl)
            .highlight_symbol("> ")
            .block(Block::default().borders(Borders::LEFT | Borders::TOP | Borders::BOTTOM)),
        sides[0],
        &mut state.test_list.a.state,
    );
    f.render_stateful_widget(
        List::new(test_side1)
            .highlight_style(hl)
            .block(Block::default().borders(Borders::TOP | Borders::BOTTOM)),
        sides[1],
        &mut state.test_list.b.state,
    );
    f.render_stateful_widget(
        List::new(test_side2)
            .highlight_style(hl)
            .block(Block::default().borders(Borders::TOP | Borders::BOTTOM | Borders::RIGHT)),
        sides[2],
        &mut state.test_list.c.state,
    );
}