Add an in-TUI editor, solution diff, and lesson-first flow - #1
Merged
Merged
Conversation
A second change arriving within the 300ms window set `last_event` and returned false; the block meant to fire it later had an empty body, so the save was recorded and then dropped. Verification never ran for it. Replaced with a single trailing-edge path: any event restarts the window and reports nothing, and a quiet poll fires once the window elapses. The leading edge is deliberately gone — editors emit truncate and write as separate events, which could straddle a poll and verify twice.
Adds `solution_viewed` per exercise and a `preferences` block holding the editor layout, both behind `#[serde(default)]` so a v2 file parses before the migration runs. Fills the v2 -> v3 slot the v1 -> v2 work left marked. `clear_solution_viewed` exists because the two resets differ: the CLI one forfeits XP via `forget_exercise`, the TUI one only restores the file. The record follows the file, not the XP. The migration test asserts every prior exercise, module and lesson entry survives — a schema bump that silently drops progress would look exactly like a corrupt state file.
Watch mode becomes an editable split: edtui above, compiler output beside or below it. Ctrl+S saves and the existing watcher drives verification, so no second terminal is needed. Ctrl+D compares your code against the reference solution; Ctrl+J switches the split; an unread module lesson opens before its exercises and Esc skips it for the session. Notes on choices that are not obvious from the diff: - edtui's EditorState defaults to Normal mode, where its modeless keymap binds nothing at all. Both construction sites set Insert explicitly or the editor renders perfectly and ignores every keystroke. - Saving is atomic (temp file plus rename). A partial write would fire the watcher and, under disk-wins, reload the truncated file over the buffer. - Our own writes are fingerprinted so they still verify but never trigger a reload, which would discard anything typed during the compile. - Ctrl+I and Ctrl+M arrive as Tab and Enter; Ctrl+H is how some terminals send Backspace; Ctrl+Q/T/W/Z are claimed by the terminal emulator. All are left unbound — a binding taken upstream never reaches us. - Search moved to Ctrl+F. edtui registers Ctrl+S in two modes, so both had to move or repeat-search would silently stop working. - render_editor refuses to draw below a size floor: edtui's line wrapper spins forever at zero content width, and a hang defeats the panic hook.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Learning Rust in this tool meant keeping two terminals open: the game in one,
your editor in the other. That split is where the friction was — every fix
needed a window change, and the compiler output you were fixing lived in the
window you had just left.
It also fixes the problem that started the project. Hitting
printlnwithoutthe
!on exercise one and having nowhere to turn is exactly what the lessongating is for: the module's lesson now arrives before its exercises rather than
sitting behind a marker you can ignore.
What
Three commits, ordered so each builds and tests on its own.
d48514d— fix: fire a save that lands inside the debounce windowA pre-existing bug found while building the rest. A second save arriving within
300ms of another was recorded and then dropped: the block meant to fire it later
had an empty body. Its regression test fails against the old logic and passes
against the new one.
9bb2fc4— feat: track layout and viewed solutions in state v3Schema bump for the two new pieces of persisted state. Both fields carry
#[serde(default)]so a v2 file parses before migration runs. The migrationtest asserts every prior exercise, module and lesson entry survives — a schema
bump that quietly drops progress is indistinguishable from a corrupt file.
ba2f80c— feat: add an in-TUI editor with lesson gating and diffWatch mode becomes an editable split.
Ctrl+Ssaves and the existing watcherdrives verification.
Ctrl+Dshows your code beside the reference solution withdiffering lines highlighted, recorded but never penalised.
Ctrl+Jswitchesbetween side-by-side and stacked. An unread lesson opens before its exercises;
Escskips it for the session.Things worth knowing when reading the diff
EditorStatedefaults toNormalmode, where its modeless keymapbinds nothing. Both construction sites set
Insertexplicitly — without itthe editor renders perfectly and ignores every keystroke.
watcher and, under disk-wins, reload the truncated file over the live buffer.
reload, which would discard anything typed while the compile ran.
Ctrl+I/Ctrl+Marrive as Tab and Enter,Ctrl+His how some terminals sendBackspace, and
Ctrl+Q/T/W/Zare claimed by the terminal emulator. All areleft unbound — a binding taken upstream never reaches the application.
Ctrl+FbecauseCtrl+Sis now save. edtui registersCtrl+Sin two modes, so both had to move or repeat-search would silentlystop working.
spins forever at zero content width, and a hang defeats the panic hook that
would otherwise restore the terminal.
Verification
cargo clippy --all-targets -- -D warnings— cleancargo test— 182 passing, 0 failing (was 150)cargo test --test solution_verification_test -- --ignored— 64/64 solutions