Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: print error message when terminal size is less the number of lines #28

Merged
merged 12 commits into from
Apr 25, 2022
13 changes: 12 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ pub struct Toipe {
}

/// Represents any error caught in Toipe.
#[derive(Debug)]
pub struct ToipeError {
pub msg: String,
}
Expand All @@ -57,6 +56,18 @@ impl From<std::io::Error> for ToipeError {
}
}

impl From<String> for ToipeError {
fn from(error: String) -> Self {
ToipeError { msg: error }
}
}

impl std::fmt::Debug for ToipeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(format!("ToipeError: {}", self.msg).as_str())
}
}

impl<'a> Toipe {
/// Initializes a new typing test on the standard output.
///
Expand Down
8 changes: 5 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ use clap::StructOpt;
use std::io::stdin;
use toipe::config::ToipeConfig;
use toipe::Toipe;
use toipe::ToipeError;

fn main() {
fn main() -> Result<(), ToipeError> {
let config = ToipeConfig::parse();

let mut toipe = Toipe::new(config).unwrap();
let mut toipe = Toipe::new(config)?;

let stdin = stdin();

notjedi marked this conversation as resolved.
Show resolved Hide resolved
loop {
let stdin = stdin.lock();
if let Ok((true, _)) = toipe.test(stdin) {
toipe.restart().unwrap();
toipe.restart()?;
} else {
break;
}
}
Ok(())
}
29 changes: 26 additions & 3 deletions src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use termion::{

use crate::ToipeError;

const MIN_LINE_WIDTH: usize = 50;

/// Describes something that has a printable length.
///
/// For example, a string containing color characters has a different
Expand Down Expand Up @@ -223,6 +225,7 @@ pub struct ToipeTui {
stdout: RawTerminal<Stdout>,
cursor_pos: CursorPos,
track_lines: bool,
bottom_lines_len: usize,
}

type MaybeError<T = ()> = Result<T, ToipeError>;
Expand All @@ -236,6 +239,7 @@ impl ToipeTui {
stdout: stdout().into_raw_mode().unwrap(),
cursor_pos: CursorPos::new(),
track_lines: false,
bottom_lines_len: 0,
}
}

Expand Down Expand Up @@ -353,6 +357,7 @@ impl ToipeTui {
let (sizex, sizey) = terminal_size()?;

let line_offset = lines.len() as u16;
self.bottom_lines_len = lines.len();

for (line_no, line) in lines.iter().enumerate() {
write!(
Expand All @@ -371,15 +376,17 @@ impl ToipeTui {
pub fn display_words(&mut self, words: &[String]) -> MaybeError<Vec<Text>> {
self.reset();
let mut current_len = 0;
let mut max_word_len = 0;
let mut line = Vec::new();
let mut lines = Vec::new();
let (terminal_width, _) = terminal_size()?;
let (terminal_width, terminal_height) = terminal_size()?;
// 40% of terminal width
let max_width = terminal_width * 2 / 5;
const MAX_WORDS_PER_LINE: usize = 10;
// eprintln!("max width is {}", max_width);

for word in words {
max_word_len = std::cmp::max(max_word_len, word.len() + 1);
notjedi marked this conversation as resolved.
Show resolved Hide resolved
let new_len = current_len + word.len() as u16 + 1;
if line.len() < MAX_WORDS_PER_LINE && new_len <= max_width {
// add to line
Expand All @@ -392,8 +399,8 @@ impl ToipeTui {
lines.push(Text::from(line.join(" ") + " ").with_faint());

// clear line
line = Vec::new();
current_len = 0;
line = vec![word.clone()];
current_len = word.len() as u16 + 1;
}
}

Expand All @@ -403,6 +410,20 @@ impl ToipeTui {
// - won't hang there waiting for user to type space
lines.push(Text::from(line.join(" ")).with_faint());

max_word_len = std::cmp::max(max_word_len + 1, MIN_LINE_WIDTH);
if lines.len() + self.bottom_lines_len + 2 > terminal_height as usize {
return Err(ToipeError::from(format!(
"Terminal height is too short! Toipe requires at least {} lines, got {} lines",
lines.len() + self.bottom_lines_len + 2,
terminal_height,
)));
} else if max_word_len > max_width as usize {
return Err(ToipeError::from(format!(
notjedi marked this conversation as resolved.
Show resolved Hide resolved
"Terminal width is too low! Toipe requires at least {} columns, got {} columns",
notjedi marked this conversation as resolved.
Show resolved Hide resolved
max_word_len, max_width,
)));
}

self.track_lines = true;
self.display_lines(
lines
Expand Down Expand Up @@ -504,6 +525,8 @@ impl Drop for ToipeTui {
/// Clears screen and sets the cursor to a non-blinking block.
///
/// TODO: reset cursor to whatever it was before Toipe was started.
/// TODO: print error message when terminal height/width is too small.
/// Take a look at https://github.com/Samyak2/toipe/pull/28#discussion_r851784291 for more info.
fn drop(&mut self) {
write!(
self.stdout,
Expand Down