Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/skills/typerush-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ with a throwaway `HOME` — never the real `~/.typerush` — following
- Every mouse action has a keyboard equivalent; clicks fire on release.
- `config.toml` is only written through `config::edit` (comments kept,
values checked by the loader's rules); a new setting needs a `KEYS`
entry. New modes need a label `Mode::from_label` reads back (replay).
entry, and a typing option the steps in ARCHITECTURE's "When you add a
typing option". New modes need a label `Mode::from_label` reads back (replay).
- Footer hints must fit 80 columns, and the menu and help overlay must fit
80×24 — tests check both; count the cells before adding one.
- Anything added up over the history or the whole run (XP, the profile,
Expand Down
61 changes: 60 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,63 @@ _No unreleased changes yet._

---

## [0.7.0] — practice modes

More ways to practise: drill your mistakes, make every error count, race
your best, type blind — and make TypeRush look the way you want.

### Added

- **Practise missed words:** every session keeps the words you got wrong
(even ones you fixed). The `missed` menu row (or `--missed`) builds a run
from your most-missed recent words.
- **Repeat a run:** `F6` on Results types the same words again, as a
replay compared with the run you just finished.
- **Quick restart on `Tab`** while typing (like `F5` / `Ctrl+R`).
- **A `[typing]` section** in `config.toml`, all of it also on the Settings
screen and in `typerush config`:
- `live_wpm` — hide WPM and accuracy while typing;
- `blind` — no right/wrong colors while typing, numbers only at the end
(`--blind`);
- `stop_on_error` — `letter` (a wrong key doesn't move the cursor) or
`word` (a word with a mistake can't be left until it's fixed)
(`--stop-on-error`);
- `cursor` — `underline`, `block` or `bar`;
- `sound` — the terminal's bell on mistakes or on every key;
- `pace` — a second cursor moving at your best for the mode (on a
replay, the original run) or at a target WPM (`--pace`);
- `idle_limit` — a run with that many seconds without a key (10 by
default) isn't saved, and Results says why.
- **Custom themes:** a TOML file in `~/.typerush/themes/` is a theme named
after the file, on top of a built-in; pick it like any other.
`--list-themes` lists them and notes hard-to-read colors.
- `missed` can be the start mode (`mode = "missed"`).

### Changed

- The typing footer says `Tab / F5 restart`; the Results footer gains
`F6 repeat` (`Ctrl+C` still quits there, as everywhere).
- On a short terminal the Settings list scrolls with the selection.
- The blank line under the menu's last option gives way before the banner
on a terminal too short for both.
- The help overlay lists `Tab` and `F6`.
- The Settings typing rows show the values in use, so `--blind`,
`--stop-on-error` and `--pace` show there for the launch they're given on.
- **The Results chart is labelled on round numbers:** at least four labels
on each axis and as many as fit, every label on its value.
- **The Stats WPM trend shows as many sessions as the box is wide** (it
was the last 20), and says how many; a ★ under a bar marks a session
holding its mode's best, as in the sessions list.
- **Nothing is drawn against a box's side any more** ([#20]): the chart,
the WPM trend and the Stats tables are inset like the text in every other
box, the help box is wide enough for its longest line, and Settings shows
the selected row by its label and value rather than a marker in the
border's first cell.
- **The help box has a blank line above and below its text** (two
two-line entries became one line each, so it still fits 80×24 whole).

---

## [0.6.0] — profile and deeper results

See more of every run, and of all of them: a chart and new figures on
Expand Down Expand Up @@ -572,7 +629,8 @@ keyboard alternates** for accessibility.
dedicated docs.
- Demo GIF uses absolute GitHub raw URL for correct display on crates.io.

[Unreleased]: https://github.com/withrvr/typerush/compare/v0.6.0...HEAD
[Unreleased]: https://github.com/withrvr/typerush/compare/v0.7.0...HEAD
[0.7.0]: https://github.com/withrvr/typerush/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/withrvr/typerush/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/withrvr/typerush/compare/v0.4.1...v0.5.0
[0.4.1]: https://github.com/withrvr/typerush/compare/v0.4.0...v0.4.1
Expand All @@ -583,3 +641,4 @@ keyboard alternates** for accessibility.
[0.1.1]: https://github.com/withrvr/typerush/releases/tag/v0.1.1
[#8]: https://github.com/withrvr/typerush/issues/8
[#4]: https://github.com/withrvr/typerush/issues/4
[#20]: https://github.com/withrvr/typerush/issues/20
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ The TL;DR:
- `src/app.rs` — application state machine
- `src/settings.rs` — the Settings screen's state and actions
- `src/progress.rs` — levels, XP and the Profile screen's summary
- `src/options.rs` — the `[typing]` settings (blind, stop on error, cursor, pace, …)
- `src/game.rs` — character matcher
- `src/storage.rs` — JSON stats persistence
- `src/state.rs` — `state.json` (the last custom file)
- `src/text.rs` — safe display of user-supplied names and text
- `src/config/*.rs` — `config.toml` loading, CLI overrides, and editing it in
place (`edit.rs`, for `typerush config` and Settings)
- `src/theme/*.rs` — built-in themes and colour parsing
- `src/theme/*.rs` — built-in themes, custom theme files, colour parsing
- `src/ui/*.rs` — one file per screen
- `src/words/*.rs` — word sources (pools, quotes, code, symbols, snippets)

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "typerush"
version = "0.6.0"
version = "0.7.0"
edition = "2021"
rust-version = "1.88"
description = "In your terminal — a fast, cross-platform WPM typing trainer built with Rust"
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ with a quote — TypeRush meets you where you already work: the command line.
- ⏸ **Pause** — `Ctrl+P` / `F2` stops the clock and hides the text
- 📊 **A chart of every run** — WPM, raw speed and mistakes second by second, plus raw WPM, consistency and a correct / incorrect / missed breakdown
- 🏅 **Levels, XP and a profile** — earn XP for time typed, see your bests side by side and a year of practice on an activity calendar
- 🎯 **Practice your way** — practise the words you got wrong, stop on errors, blind mode, a pace cursor racing your best, cursor styles
- 🖌 **Your own themes** — drop a small TOML file in `~/.typerush/themes/`
- 🔤 **Seven code languages** — Rust, Python, JavaScript, Go, Java, SQL, Shell
- 📚 **10k-word pool & punctuation/number drills** — toggle them with `b` / `p` / `n` in the menu when you want a tougher session
- 🗂 **Personal snippet library** — drop `.txt` files in `~/.typerush/snippets/`, each with its own personal best
Expand Down Expand Up @@ -88,6 +90,7 @@ typerush --quote # one programming quote
typerush --code rust # rust | python | js | go | java | sql | shell
typerush --symbols 25 # programming-punctuation drill
typerush --daily # today's daily challenge
typerush --missed # practise the words you've got wrong lately
typerush --replay # type your last session again, word for word
typerush --zen # zen mode — no timer, no pressure
typerush --file my_text.txt # type anything you want
Expand Down Expand Up @@ -132,7 +135,8 @@ typerush --init-config # write a starter ~/.typerush/config.toml
| --------------- | ------------------------------- |
| `Enter` | start / restart a session |
| `Esc` | back to menu / end session |
| `Ctrl+R` / `F5` | restart the current mode |
| `Tab` / `F5` | restart the current mode |
| `F6` | the same words again (Results) |
| `Ctrl+P` / `F2` | pause / resume while typing |
| `Tab` | jump to your stats history |
| `c` | settings (from the menu) |
Expand Down
22 changes: 20 additions & 2 deletions config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

# -----------------------------------------------------------------------------
# Theme — pick one of the built-in palettes by name.
# Available names: dark, light, monokai, dracula
# Available names: dark, light, monokai, dracula — and your own: a TOML file
# in ~/.typerush/themes/ (ocean.toml is "ocean") with `base = "dark"` (or
# another built-in) and any of the color slots listed under [colors] below.
# Run `typerush --list-themes` to see what's currently shipped.
# -----------------------------------------------------------------------------
theme = "dark"
Expand All @@ -26,7 +28,7 @@ theme = "dark"
# -----------------------------------------------------------------------------
[defaults]
# Which menu row to pre-select:
# "time" | "words" | "quote" | "code" | "zen" | "symbols" | "daily"
# "time" | "words" | "quote" | "code" | "zen" | "symbols" | "daily" | "missed"
mode = "time"
# Used when mode = "time". Standard menu rows: 15 / 30 / 60 / 120.
time_seconds = 15
Expand All @@ -50,6 +52,22 @@ symbol_count = 25
# punctuation = false # attach commas, periods, quotes, etc. to ~25% of words
# numbers = false # mix in random 1–4 digit number tokens (~12% of slots)

# -----------------------------------------------------------------------------
# Typing — how a run behaves and looks while you type. The Settings screen
# changes these too; `--blind`, `--stop-on-error` and `--pace` set them for
# one launch.
# -----------------------------------------------------------------------------
# [typing]
# live_wpm = true # show WPM and accuracy while typing
# blind = false # no right/wrong colors while typing; numbers at the end
# stop_on_error = "off" # "off" | "letter" (a wrong key doesn't move the cursor)
# # | "word" (a word with a mistake can't be left)
# cursor = "underline" # "underline" | "block" | "bar"
# sound = "off" # "off" | "errors" | "keys" — the terminal's bell
# pace = "off" # "off" | "best" (your best for the mode) | a WPM, e.g. 60
# idle_limit = 10 # a run with this many seconds without a key isn't saved;
# # 0 = never

# -----------------------------------------------------------------------------
# Color overrides — applied ON TOP of the chosen theme.
# Any slot omitted here keeps the theme's value. (The values below are
Expand Down
73 changes: 69 additions & 4 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ The `Screen` enum in `src/app.rs` is the application's high-level state:
```mermaid
stateDiagram-v2
[*] --> Menu
[*] --> Typing: mode flag (--time, --words, --quote, --code, --zen, --symbols, --daily, --replay, --file)
[*] --> Typing: mode flag (--time, --words, --quote, --code, --zen, --symbols, --daily, --missed, --replay, --file)
Menu --> Typing: Enter / Space / click an option
Typing --> Typing: Ctrl+R / F5 restart, Ctrl+P / F2 pause and resume
Typing --> Typing: Tab / F5 / Ctrl+R restart, Ctrl+P / F2 pause and resume
Typing --> Results: mode finishes / Esc
Results --> Typing: Enter / F5 / Ctrl+R restart
Results --> Typing: Enter / F5 / Ctrl+R restart, F6 the same words
Results --> Menu: Esc
Results --> Stats: Tab
Menu --> Stats: Tab / s
Expand Down Expand Up @@ -115,6 +115,9 @@ flowchart LR
src --> settings["settings.rs
Settings screen state (SettingsView) and actions:
change, save through config::edit, apply at once"]
src --> options["options.rs
TypingOptions: live WPM, blind, stop on error,
cursor style, key sound, pace, idle limit"]
src --> progress["progress.rs
XP and levels (Level::of), Profile: totals,
days typed, streaks, standard bests, calendar day"]
Expand Down Expand Up @@ -151,7 +154,10 @@ flowchart LR
(new theme = one row in ALL)"]
theme --> color["color.rs
#RRGGBB and 16 ANSI color names: parse_color,
color_name (the other way)"]
color_name (the other way), contrast (WCAG)"]
theme --> custom["custom.rs
~/.typerush/themes/*.toml: discover_in, parse,
install (by_name / names see them)"]
src --> config["config/"]
config --> config_mod["mod.rs
Config / Defaults / Colors / Words from config.toml (serde)"]
Expand Down Expand Up @@ -417,6 +423,51 @@ The calendar (`ui::profile::render_calendar`) draws as many weeks as fit
share of the busiest day shown in quarters, as glyphs that get denser; each
day cell is a `ClickAction::Select(days_back)` target.

### Practice options (v0.7.0)

`options::TypingOptions` is the resolved `[typing]` section (and the
`--blind`, `--stop-on-error`, `--pace` overrides), kept in `App::options`
and changed live by Settings. Each named setting has `NAMES` / `name` /
`from_name`; the loader resolves them through one `named` helper (unknown
name: a warning and the default), and `config::edit` checks them with
`Kind::Choice(&NAMES)` — so a new choice is one enum and one key.

- **Stop on error** is decided in `handle_char` before anything moves: a
*blocked* key is tallied as a mistake, sets `App::rejected_key` (the
cursor turns the mistake color) and returns. `word` also holds the end of
the last word until it's right.
- **Blind** is a parameter of `style_for_char` (typed text neutral) and of
the header (`show_live_numbers`).
- **Cursor**: underline and block are styles on the character; the bar is
the terminal's cursor (`Frame::set_cursor_position` on the character, its
shape set by the main loop when the option changes and reset on exit and
in the panic hook).
- **Sound** sets `App::bell` in `handle_char`; the main loop writes BEL to
the terminal and clears it — no audio library.
- **Pace**: `App::pace_wpm` is worked out when a run begins (`best` reads
the history through `App::history`, which loads `stats_file` once if no
screen has), and `pace_position` turns elapsed time into a character
index in the text read as one stream; the typing renderer keeps each
word's offset in that stream while laying out.
- **Idle**: `longest_idle` walks the per-second timeline; `too_idle` stops
the save and gives Results its reason.
- **Missed words**: `Word::had_error` is set by any wrong key in the word
or on its space; records keep `mistyped` (≤ 200). `missed_words_run`
counts them over the last 100 sessions and builds the `Mode::Missed` run.
- **Repeat** (`F6`) builds a `Replay` from the current run
(`App::repeat_run`) and restarts it.

### Custom themes (v0.7.0)

`theme::custom::discover_in` reads `~/.typerush/themes/*.toml` at start
(through `config::load::read_config`, the same limits), parses each with
`parse` — a `base` built-in plus a `Colors` table applied with the config's
own `apply_color_overrides` — and `install` puts them in a process-wide
`OnceLock`. `builtin::by_name` and `names` look there after the built-ins,
so the config, `--theme`, `typerush config`, Settings and `--list-themes`
all see them without being passed anything. Tests never install, so they
only see the built-ins; the parsing and discovery are tested directly.

### Config loading

`config::load::load_from(path, cli)` never fails: a missing file means
Expand Down Expand Up @@ -477,6 +528,20 @@ round-trips every menu mode), and if it can be a start mode, a name in
`config::load::MODE_NAMES`, `resolve_default_mode` and
`settings::start_settings`.

## When you add a typing option

1. A field (and, for a choice, an enum with `NAMES` / `name` /
`from_name`) in `options::TypingOptions`, its default in `Default`.
2. The `Typing` field in `config/mod.rs`, resolved in
`load::resolve_typing` (a choice through `named`), and a CLI override in
`CliOverrides` if it gets a flag.
3. A `Key` in `config::edit::KEYS` (`Kind::Choice(&NAMES)` for a choice)
with its `file_value` / `default_value` arms.
4. A `settings::Row`, its arm in `settings_change` and its label and value
in `ui::settings::row_line`.
5. The commented default in `config.example.toml`, and USAGE's typing
options.

## When you add a setting

1. Add the field to the `Config` structs in `src/config/mod.rs` and resolve
Expand Down
Loading
Loading