aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMroik <mroik@delayed.space>2025-01-30 03:16:50 +0100
committerMroik <mroik@delayed.space>2025-02-01 19:34:41 +0100
commit20dad637b5485f706f905a777232c11a5cc2efc6 (patch)
tree2761f939fbd7aee91489b0d16a133667746a7aaf
parent4e6e1c21d5bd0776d79b437700373cc7e4c010ae (diff)
Give better feedback if program errors
-rw-r--r--src/app.rs38
-rw-r--r--src/error.rs31
2 files changed, 51 insertions, 18 deletions
diff --git a/src/app.rs b/src/app.rs
index 81eb9e1..81db4d0 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -21,7 +21,7 @@ use tokio::{
};
use crate::{
- error::WordTooLongError,
+ error::{TerminalTooSmallError, TyperError, WordTooLongError},
event::{handle_input, Event},
state::State,
};
@@ -45,6 +45,7 @@ pub struct App<'a> {
mistake_count: u32,
mistakes: HashSet<(usize, usize)>,
raw_quote: &'a str,
+ error: Option<TyperError>,
}
impl App<'_> {
@@ -63,10 +64,11 @@ impl App<'_> {
completed: false,
mistake_count: 0,
mistakes: HashSet::new(),
+ error: None,
}
}
- async fn format_quote(quote: &str, row_len: u16) -> Result<Vec<Vec<&str>>, Box<dyn Error>> {
+ async fn format_quote(quote: &str, row_len: u16) -> Result<Vec<Vec<&str>>, WordTooLongError> {
let max = if row_len - (MIN_MARGIN * 2) < MAX_QUOTE_LINE {
row_len - (MIN_MARGIN * 2)
} else {
@@ -78,7 +80,7 @@ impl App<'_> {
for w in quote.trim().split_whitespace().filter(|s| !s.is_empty()) {
let w_len = w.chars().count();
if w_len > max as usize {
- return Err(Box::new(WordTooLongError::new(w)));
+ return Err(WordTooLongError::new(w));
}
if w_len + counter > max as usize {
@@ -132,22 +134,19 @@ impl App<'_> {
}
pub async fn start(&mut self) -> Result<(), Box<dyn Error>> {
- let (col, row) = size()?;
- if col < MIN_TERM_COL || row < MIN_TERM_ROW {
- println!("Terminal is too small! Minimum size is 65 columns and 15 rows");
- return Ok(());
- }
-
let (wpm, accuracy, history) = self.run().await?;
if self.completed {
println!(
- "Mistake history:\n{}\n\nYour stats\nWPM: {}\nAccuracy: {}\nMistakes: {}",
+ "Mistake history:\n{}\n\nYour stats\nWPM: {}\nAccuracy: {}%\nMistakes: {}",
history,
wpm.round(),
accuracy.round(),
self.mistake_count
);
}
+ if self.error.is_some() {
+ println!("{}", self.error.as_ref().unwrap());
+ }
return Ok(());
}
@@ -189,11 +188,6 @@ impl App<'_> {
Event::Backspace => self.handle_backspace().await,
Event::Render => self.render().await?,
Event::ForceRender => {
- let (col, row) = size()?;
- if col < MIN_TERM_COL || row < MIN_TERM_ROW {
- self.running = false;
- return Ok(());
- }
self.should_render = true;
self.render().await?;
}
@@ -249,7 +243,19 @@ impl App<'_> {
}
let (cols, rows) = size()?;
- let lines = App::format_quote(self.raw_quote, cols).await?;
+ if cols < MIN_TERM_COL || rows < MIN_TERM_ROW {
+ self.error = Some(TyperError::TerminalTooSmallError(TerminalTooSmallError));
+ self.running = false;
+ return Ok(());
+ }
+ let lines = match App::format_quote(self.raw_quote, cols).await {
+ Ok(v) => v,
+ Err(e) => {
+ self.error = Some(TyperError::WordTooLongError(e));
+ self.running = false;
+ return Ok(());
+ }
+ };
let margin =
(cols - lines.iter().map(|line| line.join(" ").len()).max().unwrap() as u16) / 2;
let current_line = lines
diff --git a/src/error.rs b/src/error.rs
index 0da2cf7..9474203 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,6 +1,6 @@
use std::{error::Error, fmt::Display};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct WordTooLongError {
word: String,
}
@@ -14,10 +14,37 @@ impl WordTooLongError {
impl Display for WordTooLongError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!(
- "The word \"{}\" is too long for the current terminal size",
+ "The word \"{}\" is too long for the current terminal size or longer than 80 characters.",
self.word
))
}
}
impl Error for WordTooLongError {}
+
+#[derive(Debug)]
+pub struct TerminalTooSmallError;
+
+impl Display for TerminalTooSmallError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(
+ "The terminal size is too small. Min column count is 65 and minimum row count is 15.",
+ )
+ }
+}
+
+#[derive(Debug)]
+pub enum TyperError {
+ TerminalTooSmallError(TerminalTooSmallError),
+ WordTooLongError(WordTooLongError),
+}
+
+impl Display for TyperError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let text = match self {
+ TyperError::TerminalTooSmallError(e) => e.to_string(),
+ TyperError::WordTooLongError(e) => e.to_string(),
+ };
+ f.write_str(&text)
+ }
+}
XMR address: 854DmXNrxULU3ZFJVs4Wc8PFhbq29RhqHhY8W6cdWrtFN3qmooKyyeYPcDzZTNRxphhJ5UzASQfAdEMwSteVqymk28aLhqj