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

scrolling #7

Closed
wants to merge 15 commits into from
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<p align="center">
<img width="300" src="assets/thokr.svg">
</p>
<p align="center" style="font-size: 1.2rem;">a sleek typing tui written in rust</p>
<hr >
# thokr
✨ sleek typing tui written in rust

[![GitHub Build Workflow](https://github.com/coloradocolby/thokr/actions/workflows/build.yml/badge.svg)](https://github.com/coloradocolby/thokr/actions/workflows/build.yml)
[![GitHub Deploy Workflow](https://github.com/coloradocolby/thokr/actions/workflows/deploy.yml/badge.svg)](https://github.com/coloradocolby/thokr/actions/workflows/deploy.yml)
Expand Down
22 changes: 15 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use tui::{
backend::{Backend, CrosstermBackend},
Frame, Terminal,
};
use ui::HORIZONTAL_MARGIN;
use webbrowser::Browser;

const TICK_RATE_MS: u64 = 100;
Expand All @@ -31,7 +32,7 @@ const TICK_RATE_MS: u64 = 100;
#[clap(version, about, long_about= None)]
pub struct Cli {
/// number of words to use in test
#[clap(short = 'w', long, default_value_t = 15)]
#[clap(short = 'w', long, default_value_t = 2000)]
number_of_words: usize,

/// number of sentences to use in test
Expand Down Expand Up @@ -176,8 +177,7 @@ fn start_tui<B: Backend>(

loop {
let mut exit_type: ExitType = ExitType::Quit;
terminal.draw(|f| ui(app, f))?;

terminal.draw(|f| ui(app, f, false))?;
loop {
let app = &mut app;

Expand All @@ -189,13 +189,14 @@ fn start_tui<B: Backend>(
if app.thok.has_finished() {
app.thok.calc_results();
}
terminal.draw(|f| ui(app, f))?;
terminal.draw(|f| ui(app, f, false))?;
}
}
ThokEvent::Resize => {
terminal.draw(|f| ui(app, f))?;
terminal.draw(|f| ui(app, f, false))?;
}
ThokEvent::Key(key) => {
let mut is_space = false;
match key.code {
KeyCode::Esc => {
break;
Expand Down Expand Up @@ -223,6 +224,9 @@ fn start_tui<B: Backend>(

match app.thok.has_finished() {
false => {
if c == ' ' {
is_space = true;
}
app.thok.write(c);
if app.thok.has_finished() {
app.thok.calc_results();
Expand All @@ -249,7 +253,7 @@ fn start_tui<B: Backend>(
}
_ => {}
}
terminal.draw(|f| ui(app, f))?;
terminal.draw(|f| ui(app, f, is_space))?;
}
}
}
Expand Down Expand Up @@ -306,6 +310,10 @@ fn get_thok_events(should_tick: bool) -> mpsc::Receiver<ThokEvent> {
rx
}

fn ui<B: Backend>(app: &mut App, f: &mut Frame<B>) {
fn ui<B: Backend>(app: &mut App, f: &mut Frame<B>, is_space: bool) {
if is_space {
app.thok
.get_skip_count((f.size().width - HORIZONTAL_MARGIN * 2).into());
}
f.render_widget(&app.thok, f.size());
}
41 changes: 39 additions & 2 deletions src/thok.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::util::std_dev;
use crate::TICK_RATE_MS;
use chrono::prelude::*;
use directories::ProjectDirs;
use itertools::Itertools;
use itertools::{any, Itertools};
use std::collections::VecDeque;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::{char, collections::HashMap, time::SystemTime};
Expand Down Expand Up @@ -35,6 +36,9 @@ pub struct Thok {
pub wpm: f64,
pub accuracy: f64,
pub std_dev: f64,
pub line_lengths: VecDeque<usize>,
pub total_line_length: usize,
pub skip_curr: usize,
}

impl Thok {
Expand All @@ -52,6 +56,9 @@ impl Thok {
wpm: 0.0,
accuracy: 0.0,
std_dev: 0.0,
line_lengths: VecDeque::new(),
total_line_length: 0,
skip_curr: 0,
}
}

Expand Down Expand Up @@ -151,7 +158,7 @@ impl Thok {
}

pub fn backspace(&mut self) {
if self.cursor_pos > 0 {
if self.cursor_pos > 0 && self.cursor_pos > self.total_line_length {
self.input.remove(self.cursor_pos - 1);
self.decrement_cursor();
}
Expand Down Expand Up @@ -234,4 +241,34 @@ impl Thok {

Ok(())
}

pub fn get_skip_count(&mut self, max_width: usize) {
if any(&self.input[self.total_line_length..], |x| {
x.outcome == Outcome::Incorrect
}) {
return;
}
let count = self.cursor_pos - self.total_line_length;
if count == 0 {
self.line_lengths.push_back(max_width);
if self.line_lengths.len() >= 2 {
self.skip_curr += self.line_lengths.pop_front().unwrap();
}
self.total_line_length += max_width;
return;
}
let rest = &self.prompt[self.cursor_pos..];
let index = rest.find(' ');
if let Some(index) = index {
let next_word = &rest[..index];
let next_word_len = next_word.len();
if count + next_word_len > max_width {
self.line_lengths.push_back(count);
self.total_line_length += count;
}
if self.line_lengths.len() >= 2 {
self.skip_curr += self.line_lengths.pop_front().unwrap();
}
}
}
}
10 changes: 4 additions & 6 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use webbrowser::Browser;

use crate::thok::{Outcome, Thok};

const HORIZONTAL_MARGIN: u16 = 5;
pub const HORIZONTAL_MARGIN: u16 = 5;
const VERTICAL_MARGIN: u16 = 2;

impl Widget for &Thok {
Expand Down Expand Up @@ -40,11 +40,9 @@ impl Widget for &Thok {
((self.prompt.width() as f64 / max_chars_per_line as f64).ceil() + 1.0) as u16;

let time_left_lines = if self.number_of_secs.is_some() { 2 } else { 0 };

if self.prompt.width() <= max_chars_per_line as usize {
prompt_occupied_lines = 1;
}

let chunks = Layout::default()
.direction(Direction::Vertical)
.horizontal_margin(HORIZONTAL_MARGIN)
Expand All @@ -54,22 +52,22 @@ impl Widget for &Thok {
((area.height as f64 - prompt_occupied_lines as f64) / 2.0) as u16,
),
Constraint::Length(time_left_lines),
Constraint::Length(prompt_occupied_lines),
Constraint::Length(3),
Constraint::Length(
((area.height as f64 - prompt_occupied_lines as f64) / 2.0) as u16,
),
]
.as_ref(),
)
.split(area);

let mut spans = self
.input
.iter()
.skip(self.skip_curr)
.enumerate()
.map(|(idx, input)| {
Span::styled(
self.get_expected_char(idx).to_string(),
self.get_expected_char(self.skip_curr + idx).to_string(),
match input.outcome {
Outcome::Correct => green_bold_style,
Outcome::Incorrect => red_bold_style,
Expand Down