diff --git a/src/ui.rs b/src/ui.rs index c06f801..da70a88 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -104,52 +104,95 @@ impl ThemedWidget for &Test { let words = iter::empty::>() // already typed words .chain(self.words[..self.current_word].iter().map(|w| { - vec![Span::styled( - w.text.clone() + " ", - if w.progress == w.text { - theme.prompt_correct + let text = &mut w.text.chars(); + let prog = &mut w.progress.chars(); + let mut display = vec![]; + 'checking: loop { + if let Some(t) = text.next() { + if let Some(p) = prog.next() { + display.push( + Span::styled( + t.to_string(), + if t == p { + theme.prompt_correct + } else { + theme.prompt_incorrect + } + ), + ); + } else { + display.push( + Span::styled(t.to_string(), theme.prompt_untyped), + ); + } } else { - theme.prompt_incorrect - }, - )] + if let Some(p) = prog.next() { + display.push( + Span::styled(p.to_string(), theme.prompt_incorrect), + ); + } else { + display.push( + Span::styled(" ", theme.prompt_untyped), + ); + break 'checking; + } + } + } + display })) // current word .chain({ - let progress_ind = self.words[self.current_word] - .progress - .len() - .min(self.words[self.current_word].text.len()); - - let correct = self.words[self.current_word] - .text - .starts_with(&self.words[self.current_word].progress[..]); - - let (typed, untyped) = - self.words[self.current_word] - .text - .split_at(ceil_char_boundary( - &self.words[self.current_word].text, - progress_ind, - )); - - let mut remaining = untyped.chars().chain(iter::once(' ')); - let cursor = remaining.next().unwrap(); - - iter::once(vec![ - Span::styled( - typed, - if correct { - theme.prompt_current_correct + let text = &mut self.words[self.current_word].text.chars(); + let prog = &mut self.words[self.current_word].progress.chars(); + let mut display = vec![]; + let mut cursor_showed = false; + 'checking: loop { + if let Some(t) = text.next() { + if let Some(p) = prog.next() { + display.push( + Span::styled( + t.to_string(), + if t == p { + theme.prompt_current_correct + } else { + theme.prompt_current_incorrect + } + ), + ); + } else { + display.push( + Span::styled( + t.to_string(), + if cursor_showed { + theme.prompt_current_untyped + } else { + cursor_showed = true; + theme.prompt_current_untyped.patch(theme.prompt_cursor) + } + ), + ); + } + } else { + if let Some(p) = prog.next() { + display.push( + Span::styled(p.to_string(), theme.prompt_current_incorrect), + ); } else { - theme.prompt_current_incorrect - }, - ), - Span::styled( - cursor.to_string(), - theme.prompt_current_untyped.patch(theme.prompt_cursor), - ), - Span::styled(remaining.collect::(), theme.prompt_current_untyped), - ]) + display.push( + Span::styled( + " ", + if cursor_showed { + theme.prompt_current_untyped + } else { + theme.prompt_current_untyped.patch(theme.prompt_cursor) + } + ), + ); + break 'checking; + } + } + }; + iter::once(display) }) // remaining words .chain( @@ -328,12 +371,3 @@ impl ThemedWidget for &results::Results { wpm_chart.render(res_chunks[1], buf); } } - -// FIXME: replace with `str::ceil_char_boundary` when stable -fn ceil_char_boundary(string: &str, index: usize) -> usize { - if string.is_char_boundary(index) { - index - } else { - ceil_char_boundary(string, index + 1) - } -}