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}