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
//! A module for handling key events

use std::io;

#[cfg(feature = "crossterm")]
mod crossterm;
#[cfg(feature = "termion")]
mod termion;

#[cfg(feature = "crossterm")]
pub use self::crossterm::CrosstermEvents;

#[cfg(feature = "termion")]
pub use self::termion::TermionEvents;

mod keys;
mod movement;

pub use keys::{KeyCode, KeyEvent, KeyModifiers};
pub use movement::Movement;

/// Gets the default [`EventIterator`] based on the features enabled.
#[cfg(any(feature = "crossterm", feature = "termion"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "crossterm", feature = "termion"))))]
pub fn get_events() -> impl EventIterator {
    #[cfg(feature = "crossterm")]
    return CrosstermEvents::new();

    // XXX: Only works when crossterm and termion are the only two available backends
    //
    // Instead of directly checking for termion, we check for not crossterm so that compiling
    // (documentation) with both features enabled will not error
    #[cfg(not(feature = "crossterm"))]
    return TermionEvents::new();
}

/// A trait to represent a source of [`KeyEvent`]s.
pub trait EventIterator {
    /// Get the next event
    fn next_event(&mut self) -> io::Result<KeyEvent>;
}

/// A simple wrapper around a [`KeyEvent`] iterator that can be used in tests.
///
/// Even though [`EventIterator`] expects the iterator to be infinite, only having enough events to
/// complete the test is necessary.
///
/// It will also check that the internal iterator is fully exhausted on [`Drop`].
///
/// # Panics
///
/// It will panic if the events run out [`next_event`] is called, or if there are events remaining
/// when dropped.
///
/// [`next_event`]: TestEvents::next_event
#[derive(Debug, Clone)]
pub struct TestEvents<E: Iterator<Item = KeyEvent>> {
    events: E,
}

impl<E: Iterator<Item = KeyEvent>> TestEvents<E> {
    /// Create a new `TestEvents`
    pub fn new<I: IntoIterator<IntoIter = E, Item = KeyEvent>>(iter: I) -> Self {
        Self {
            events: iter.into_iter(),
        }
    }
}

impl TestEvents<std::iter::Empty<KeyEvent>> {
    /// Create a new `TestEvents` which yields no events
    pub fn empty() -> Self {
        Self {
            events: std::iter::empty(),
        }
    }
}

impl<E: Iterator<Item = KeyEvent>> EventIterator for TestEvents<E> {
    fn next_event(&mut self) -> io::Result<KeyEvent> {
        Ok(self
            .events
            .next()
            .expect("Events ran out, but another one was requested"))
    }
}

impl<E: Iterator<Item = KeyEvent>> Drop for TestEvents<E> {
    fn drop(&mut self) {
        let mut count = 0;

        while self.events.next().is_some() {
            count += 1
        }

        assert_eq!(
            count, 0,
            "Events did not fully run out, {} events have not been consumed",
            count
        );
    }
}