diff --git a/src/config.rs b/src/config.rs index ee44a40..1b2d8a4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -48,6 +48,9 @@ pub struct Theme { #[serde(deserialize_with = "deserialize_style")] pub prompt_current_untyped: Style, + #[serde(deserialize_with = "deserialize_style")] + pub prompt_cursor: Style, + // results widget #[serde(deserialize_with = "deserialize_style")] pub results_overview: Style, @@ -94,6 +97,8 @@ impl Default for Theme { .fg(Color::Blue) .add_modifier(Modifier::BOLD), + prompt_cursor: Style::default().add_modifier(Modifier::UNDERLINED), + results_overview: Style::default() .fg(Color::Cyan) .add_modifier(Modifier::BOLD), diff --git a/src/main.rs b/src/main.rs index da305e6..176c1bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,8 +78,7 @@ impl Opt { .language_file .as_ref() .map(fs::read) - .map(Result::ok) - .flatten() + .and_then(Result::ok) .or_else(|| fs::read(self.language_dir().join(&lang_name)).ok()) .or_else(|| { Resources::get(&format!("language/{}", &lang_name)) diff --git a/src/ui.rs b/src/ui.rs index d506731..a7f7f44 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -101,11 +101,8 @@ impl ThemedWidget for &Test { input.render(buf); let target_lines: Vec = { - let progress_ind = self.words[self.current_word] - .progress - .len() - .min(self.words[self.current_word].text.len()); let words = iter::empty::>() + // already typed words .chain(self.words[..self.current_word].iter().map(|w| { vec![Span::styled( w.text.clone() + " ", @@ -116,32 +113,43 @@ impl ThemedWidget for &Test { }, )] })) - .chain(iter::once(vec![ - Span::styled( - self.words[self.current_word] - .text - .chars() - .take(progress_ind) - .collect::(), - if self.words[self.current_word] - .text - .starts_with(&self.words[self.current_word].progress[..]) - { - theme.prompt_current_correct - } else { - theme.prompt_current_incorrect - }, - ), - Span::styled( - self.words[self.current_word] - .text - .chars() - .skip(progress_ind) - .collect::() - + " ", - theme.prompt_current_untyped, - ), - ])) + // 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(progress_ind); + + let untyped_formatted = format!("{} ", untyped); + let (cursor, remaining) = untyped_formatted.split_at(1); + + iter::once(vec![ + Span::styled( + typed, + if correct { + theme.prompt_current_correct + } else { + theme.prompt_current_incorrect + }, + ), + Span::styled( + cursor.to_owned(), + theme.prompt_current_untyped.patch(theme.prompt_cursor), + ), + Span::styled( + remaining.to_owned(), + theme.prompt_current_untyped, + ), + ]) + }) + // remaining words .chain( self.words[self.current_word + 1..] .iter()