8000 feat(ui): steady death screen and retry-key lockout after a test ends by jrnxf · Pull Request #42 · jrnxf/thokr · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn bench_key_and_frame() {
terminal.draw(|frame| app.draw(frame)).unwrap();
let start = Instant::now();
for c in PROMPT.chars().take(keys) {
app.thok.write(c);
app.thok.write(c, Instant::now());
terminal.draw(|frame| app.draw(frame)).unwrap();
}
samples.push(start.elapsed().as_nanos() as f64 / keys as f64);
Expand All @@ -50,7 +50,7 @@ fn bench_key_and_frame() {
);

// finish the test, then redraw the results screen
app.thok.write('e');
app.thok.write('e', Instant::now());
app.thok.calc_results();
let mut samples = Vec::new();
for _ in 0..RUNS {
Expand Down
107 changes: 91 additions & 16 deletions src/main.rs
10BC8
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ impl App {
fn draw(&mut self, frame: &mut ratatui::Frame) {
// a timed test streams words to fill the lines the screen shows
self.thok.set_line_width(ui::line_width(frame.area()));
ui::draw(frame, &self.thok);
ui::draw(frame, &self.thok, Instant::now());
}

fn on_key(&mut self, key: KeyEvent) -> ControlFlow<()> {
Expand All @@ -136,12 +136,16 @@ impl App {
KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
return ControlFlow::Break(());
}
// a test that just ended ignores these, dropped rather than held
KeyCode::Left | KeyCode::Right | KeyCode::Char('r' | 'n')
if !self.thok.restart_keys_live_at(Instant::now()) => {}
KeyCode::Left => self.restart(),
KeyCode::Right => self.new_test(),
KeyCode::Backspace if !finished => self.thok.backspace(),
KeyCode::Char(c) if !finished => {
self.thok.write(c);
self.save_if_finished();
if self.thok.write(c, Instant::now()) {
self.save_results();
}
}
KeyCode::Char('r') => self.restart(),
KeyCode::Char('n') => self.new_test(),
Expand All @@ -151,20 +155,19 @@ impl App {
}

fn on_tick(&mut self) {
self.thok.on_tick();
self.save_if_finished();
if self.thok.on_tick(Instant::now()) {
self.save_results();
}
}

/// Call after anything that can end the test: a key press or a tick.
fn save_if_finished(&mut self) {
if self.thok.has_finished() {
self.thok.calc_results();
if self.thok.died() {
return;
}
if let Err(error) = history::append(&self.thok) {
self.save_error.get_or_insert(error);
}
/// Call once, when a key press or a tick has ended the test.
fn save_results(&mut self) {
self.thok.calc_results();
if self.thok.died() {
return;
}
if let Err(error) = history::append(&self.thok) {
self.save_error.get_or_insert(error);
}
}
}
Expand Down Expand Up @@ -239,7 +242,7 @@ fn run(terminal: &mut DefaultTerminal, app: &mut App) -> io::Result<()> {
loop {
terminal.draw(|frame| app.draw(frame))?;

match next_input(app.thok.next_tick())? {
match next_input(app.thok.next_tick(Instant::now()))? {
Input::Key(key) => {
if app.on_key(key).is_break() {
return Ok(());
Expand Down Expand Up @@ -274,3 +277,75 @@ fn next_input(tick_at: Option<Instant>) -> io::Result<Input> {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::thok::END_LOCKOUT;
use std::time::Duration;

/// An app on a finished test that ended `ended_ago` ago.
fn finished_app(ended_ago: Duration) -> App {
let mut app = App::new(Cli::parse_from(["thokr", "-p", "ab"]));
app.thok = Thok::typed("ab", "ab", None, &[]);
app.thok.ended_at = Some(Instant::now() - ended_ago);
app
}

fn press(app: &mut App, code: KeyCode) -> ControlFlow<()> {
app.on_key(KeyEvent::new(code, KeyModifiers::NONE))
}

#[test]
fn retry_and_new_are_ignored_just_after_the_end() {
for code in [
KeyCode::Char('r'),
KeyCode::Char('n'),
KeyCode::Left,
KeyCode::Right,
] {
let mut app = finished_app(Duration::ZERO);
assert!(press(&mut app, code).is_continue());
assert_eq!(app.thok.input.len(), 2, "{code:?} left the end screen");
}
}

#[test]
fn a_dropped_key_is_not_replayed_when_the_lockout_ends() {
let mut app = finished_app(Duration::ZERO);
let _ = press(&mut app, KeyCode::Char('r'));
app.thok.ended_at = Some(Instant::now() - END_LOCKOUT);
assert_eq!(app.thok.input.len(), 2, "nothing was buffered");
}

#[test]
fn retry_and_new_work_once_the_lockout_has_passed() {
for code in [
KeyCode::Char('r'),
KeyCode::Char('n'),
KeyCode::Left,
KeyCode::Right,
] {
let mut app = finished_app(END_LOCKOUT);
assert!(press(&mut app, code).is_continue());
assert!(app.thok.input.is_empty(), "{code:?} started a new test");
assert!(app.thok.ended_at.is_none());
}
}

#[test]
fn escape_and_ctrl_c_quit_inside_the_lockout() {
let mut app = finished_app(Duration::ZERO);
assert!(press(&mut app, KeyCode::Esc).is_break());
let ctrl_c = KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL);
assert!(app.on_key(ctrl_c).is_break());
}

#[test]
fn a_running_test_is_never_locked_out() {
let mut app = App::new(Cli::parse_from(["thokr", "-p", "ab"]));
let _ = press(&mut app, KeyCode::Char('a'));
assert!(press(&mut app, KeyCode::Left).is_continue());
assert!(app.thok.input.is_empty(), "left restarted the running test");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ expression: "draw(&died_in_death_mode(\"the quick brx\"), 80, 24)"



💀

expected 'o', pressed 'x'

the quick brown fox jumps over the lazy dog

Expand All @@ -23,7 +22,8 @@ expression: "draw(&died_in_death_mode(\"the quick brx\"), 80, 24)"



(r)etry / (n)ew / (esc)ape

(r)etry / (n)ew



Expand All @@ -35,29 +35,26 @@ expression: "draw(&died_in_death_mode(\"the quick brx\"), 80, 24)"
................................................................................
................................................................................
................................................................................
.......................................a........................................
................................................................................
............................bbbbbbbbbbbbbbbbbbbbbbbbb...........................
................................................................................
...................ccccccccccddeffgggggggggggggggggggggggggggg..................
................................................................................
.............................ggggggggggggggggggggggg............................
...................aaaaaaaaaaaabcccccccccccccccccccccccccccccc..................
................................................................................
.............................ddddddddddddddddddddddd............................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
................................................................................
.....hhhhhhhhhhhhhhhhhhhhhhhhhh.................................................
.....eeeeeeeeeeeeeee............................................................
................................................................................
................................................................................

a = fg Red, BOLD
b = fg Reset, BOLD
c = fg Green, BOLD
d = fg Green, BOLD | UNDERLINED
e = fg Red, BOLD | UNDERLINED | REVERSED
f = fg Reset, BOLD | DIM | UNDERLINED
g = fg Reset, BOLD | DIM
h = fg Reset, ITALIC
a = fg Reset, BOLD
b = fg Red, BOLD | REVERSED
c = fg DarkGray, BOLD | DIM
d = fg Red, BOLD
e = fg Reset, ITALIC
cursor = None
4 changes: 2 additions & 2 deletions src/snapshots/thokr__ui__tests__results_screen.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ expression: "draw(&finished(), 80, 24)"
sec 1 2 3 4 5 6
36 wpm 95% acc 1.02 sd

(r)etry / (n)ew / (esc)ape
(r)etry / (n)ew



Expand All @@ -48,7 +48,7 @@ expression: "draw(&finished(), 80, 24)"
.....bbb........................................................................
...........................cccccccccccccccccccccccccc...........................
................................................................................
.....dddddddddddddddddddddddddd.................................................
.....ddddddddddddddd............................................................
................................................................................
................................................................................

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ expression: "draw(&thok, 80, 24)"
sec 0.5 1
0 wpm 0% acc 0.00 sd

(r)etry / (n)ew / (esc)ape
(r)etry / (n)ew



Expand All @@ -48,7 +48,7 @@ expression: "draw(&thok, 80, 24)"
.....aaa........................................................................
............................bbbbbbbbbbbbbbbbbbbbbbbb............................
................................................................................
.....cccccccccccccccccccccccccc.................................................
.....ccccccccccccccc............................................................
................................................................................
................................................................................

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ expression: "draw(&finished(), 30, 14)"
sec 5
36 wpm 95% acc 1

(r)etry / (n)ew / (e
(r)etry / (n)ew



Expand All @@ -28,7 +28,7 @@ expression: "draw(&finished(), 30, 14)"
.....bbb......................
.....cccccccccccccccccccc.....
..............................
.....dddddddddddddddddddd.....
.....ddddddddddddddd..........
..............................
..............................

Expand Down
Loading
Loading
0