1use std::{collections::VecDeque, time::Duration};
4
5use crate::{Event, RecordError, RecordInput, TerminalKind};
6
7pub fn make_binary_description(hash: &str, num_bytes: u64) -> String {
9    format!("{} ({} bytes)", hash, num_bytes)
10}
11
12pub struct CrosstermInput;
17
18impl RecordInput for CrosstermInput {
19    fn terminal_kind(&self) -> TerminalKind {
20        TerminalKind::Crossterm
21    }
22
23    fn next_events(&mut self) -> Result<Vec<Event>, RecordError> {
24        let first_event = crossterm::event::read().map_err(RecordError::ReadInput)?;
26        let mut events = vec![first_event.into()];
27        while crossterm::event::poll(Duration::ZERO).map_err(RecordError::ReadInput)? {
31            let event = crossterm::event::read().map_err(RecordError::ReadInput)?;
32            events.push(event.into());
33        }
34        Ok(events)
35    }
36
37    fn edit_commit_message(&mut self, message: &str) -> Result<String, RecordError> {
38        Ok(message.to_owned())
39    }
40}
41
42pub struct TestingInput {
44    pub width: usize,
46
47    pub height: usize,
49
50    pub events: Box<dyn Iterator<Item = Event>>,
52
53    pub commit_messages: VecDeque<String>,
55}
56
57impl TestingInput {
58    pub fn new(
60        width: usize,
61        height: usize,
62        events: impl IntoIterator<Item = Event> + 'static,
63    ) -> Self {
64        Self {
65            width,
66            height,
67            events: Box::new(events.into_iter()),
68            commit_messages: Default::default(),
69        }
70    }
71}
72
73impl RecordInput for TestingInput {
74    fn terminal_kind(&self) -> TerminalKind {
75        let Self {
76            width,
77            height,
78            events: _,
79            commit_messages: _,
80        } = self;
81        TerminalKind::Testing {
82            width: *width,
83            height: *height,
84        }
85    }
86
87    fn next_events(&mut self) -> Result<Vec<Event>, RecordError> {
88        Ok(vec![self.events.next().unwrap_or(Event::None)])
89    }
90
91    fn edit_commit_message(&mut self, _message: &str) -> Result<String, RecordError> {
92        self.commit_messages
93            .pop_front()
94            .ok_or_else(|| RecordError::Other("No more commit messages available".to_string()))
95    }
96}