Skip to content

The finale: Block Party (Ctrl-v) + The Macro Forge (q/@) + The Archivist — curriculum complete#11

Merged
StrangeNoob merged 2 commits into
mainfrom
feature/act4-finale
Jul 3, 2026
Merged

The finale: Block Party (Ctrl-v) + The Macro Forge (q/@) + The Archivist — curriculum complete#11
StrangeNoob merged 2 commits into
mainfrom
feature/act4-finale

Conversation

@StrangeNoob

@StrangeNoob StrangeNoob commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

The last two lessons and the final boss. The curriculum is complete: all 29 lessons across four acts are shipped, and clearing The Archivist triggers the game's mastery finale.

New lessons (29/29)

Act Lesson Teaches
IV · 28 Block Party Ctrl-v visual block + column I/A
IV · 29 The Macro Forge · boss: The Archivist q{reg}…q record, @{reg} replay, @@

Engine

  • Visual block (ctrl+v): rectangle reshaped by h/j/k/l/0/$; d/x cut the columns; I prefixes and A suffixes every row of the block when the insert closes on esc (the typed text replicates down the column, like Vim). Not dot-repeatable
  • Macros: q{reg} records the raw keystroke stream (the stopping q excluded), @{reg} replays it through the real Press path so it obeys allowedKeys, @@ repeats the last. A depth guard bounds self-invoking macros. Macros live in a store separate from the yank registers — a deliberate simplification, noted in the gap analysis
  • 14 new engine test cases; the Archivist's three boss steps were separately verified solvable through the engine (boss steps aren't covered by the solvable-at-par test)

UI

  • -- VISUAL BLOCK -- mode line, rectangular reverse-video highlight, and a red ● REC indicator while recording

Finale

Clearing the final boss now sets resGameComplete and shows the mastery screen (TestFinaleOnFinalBoss); a mid-game boss does not (TestMidGameBossIsNotTheFinale).

Test plan

  • go test ./... green (29 lessons solvable at par; boss steps verified)
  • go vet, gofmt -l clean
  • Binary builds; version smoke run

Summary by CodeRabbit

  • New Features

    • Added two new lessons covering block editing and macros.
    • Visual block selection is now shown in the editor, including HUD status for block mode and recording.
    • Macro recording and replay are now available during gameplay.
  • Bug Fixes

    • Improved handling for exiting block insert mode and replaying recorded actions safely.
    • Finale completion now triggers only on the true final boss.
  • Documentation

    • Updated lesson and curriculum docs to show the full 29-lesson roadmap as complete.

… Archivist

The curriculum is complete: all 29 lessons across four acts shipped, and
clearing The Archivist re-arms the game finale.

Engine:
- Visual block (ctrl+v): a rectangular selection reshaped by h/j/k/l/0/$;
  d/x cut its columns; I inserts a prefix and A appends a suffix on every
  row of the block when Insert closes on esc. Not dot-repeatable
- Macros: q{reg}…q records a keystroke stream (the closing q excluded);
  @{reg} replays it through the real key path; @@ repeats the last macro.
  A depth guard bounds self-invoking macros. Macros use a store separate
  from the yank registers (documented)

UI:
- -- VISUAL BLOCK -- HUD, rectangular reverse-video highlight, and a
  "● REC" indicator while a macro records

Content:
- Block Party (act4-28): column prefix (I) and suffix (A) edits
- The Macro Forge (act4-29): record/replay and @@, carrying the boss
  The Archivist (dip → block-I → macro capstone). Boss steps verified
  solvable through the engine
- Finale reachable again: clearing the final boss shows the mastery
  screen; a mid-game boss does not (both asserted)

Docs: LESSONS.md / lessons.csv / README / gap analysis all mark the
curriculum complete — 29/29, no consensus gaps remain.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@StrangeNoob, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3fb2f4c5-af74-41fc-b621-9fb68333a0af

📥 Commits

Reviewing files that changed from the base of the PR and between 874300f and e64c4f5.

📒 Files selected for processing (3)
  • internal/engine/engine.go
  • internal/engine/macro_test.go
  • internal/ui/app_test.go
📝 Walkthrough

Walkthrough

Adds Visual Block (ctrl-v) editing mode and macro recording/replay (q/@) to the editing engine, integrates them into UI rendering and HUD, adds two new lessons ("Block Party" and "The Macro Forge" with boss "The Archivist"), and updates curriculum docs and tests to reflect a completed 29-lesson curriculum.

Changes

Visual Block & Macro Engine Feature

Layer / File(s) Summary
Engine mode/state and dispatch wiring
internal/engine/engine.go
Adds ModeVisualBlock constant, BlockAnchor and macro-arming/block-insert state fields, dispatch routing for the new mode, Recording() helper, and tape-reset handling.
Visual block selection, deletion, and block insert
internal/engine/visual.go, internal/engine/edit.go, internal/engine/visual_block_test.go
Implements pressVisualBlock, BlockSelection/blockBounds, deleteBlock, startBlockInsert/finishBlockInsert, insert-mode esc handling for block insert, and corresponding tests.
Macro recording and replay
internal/engine/engine.go, internal/engine/macro_test.go
Adds stopsMacro, pendingQ/pendingAt arming for q/@, runMacro with recursion guard, and tests covering recording, replay, @@, and bounded recursion.
UI rendering and HUD updates
internal/ui/room.go, internal/ui/cmdline_hud_test.go
Renders reverse-video block selections via renderBlockSelected, shows "-- VISUAL BLOCK --" and "● REC" HUD indicators, and adds HUD integration test.
New lessons and curriculum docs
assets/lessons/act4-28-block-party.json, assets/lessons/act4-29-the-macro-forge.json, docs/LESSONS.md, docs/LESSON-GAP-ANALYSIS.md, README.md, internal/content/loader_test.go, internal/content/solvable_test.go, internal/ui/app_test.go
Adds "Block Party" and "The Macro Forge" (with boss "The Archivist") lesson definitions, updates docs to reflect all 29 lessons shipped, updates lesson-count/solvability tests, and revises finale tests for final vs mid-game boss.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Simulator
  participant Room as UI/room.go

  User->>Simulator: ctrl+v
  Simulator->>Simulator: enter ModeVisualBlock, set BlockAnchor
  Room->>Simulator: BlockSelection()
  Room->>Room: renderBlockSelected (reverse-video rectangle)
  User->>Simulator: I / d / x
  Simulator->>Simulator: startBlockInsert or deleteBlock
  User->>Simulator: type text, esc
  Simulator->>Simulator: finishBlockInsert replicates across rows
  Room->>Room: renderHUD shows "-- VISUAL BLOCK --"
Loading
sequenceDiagram
  participant User
  participant Simulator
  participant Room as UI/room.go

  User->>Simulator: q, a
  Simulator->>Simulator: arm pendingQ, start recording register a
  Room->>Room: renderHUD shows "● REC"
  User->>Simulator: keystrokes, q
  Simulator->>Simulator: store macroKeys into macros[a]
  User->>Simulator: @, a
  Simulator->>Simulator: runMacro replays keys via Press, guarded by macroDepth
Loading

Possibly related PRs

  • StrangeNoob/nvim-quest#2: Updates internal/ui/app_test.go finale-related tests (final-boss mastery vs mid-game boss), overlapping with the same test functions modified here.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding the last lessons and boss to complete the curriculum.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/act4-finale

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/engine/engine.go`:
- Around line 157-165: The macro recording path in Press is currently appending
keystrokes even when they are being replayed by runMacro, which causes nested or
replayed macro input to be captured into macroKeys and duplicated on later runs.
Update the recording guard around the s.macroKeys append in Press to skip
appending while playback is active, using the existing s.replaying or
s.macroDepth state. Keep the normal s.record and dispatch flow intact, but
ensure only user-entered keys are recorded when recordingMacro is true.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fac19598-ed7b-429f-a812-05756eb98fc9

📥 Commits

Reviewing files that changed from the base of the PR and between e0bc9ba and 874300f.

⛔ Files ignored due to path filters (1)
  • docs/lessons.csv is excluded by !**/*.csv
📒 Files selected for processing (15)
  • README.md
  • assets/lessons/act4-28-block-party.json
  • assets/lessons/act4-29-the-macro-forge.json
  • docs/LESSON-GAP-ANALYSIS.md
  • docs/LESSONS.md
  • internal/content/loader_test.go
  • internal/content/solvable_test.go
  • internal/engine/edit.go
  • internal/engine/engine.go
  • internal/engine/macro_test.go
  • internal/engine/visual.go
  • internal/engine/visual_block_test.go
  • internal/ui/app_test.go
  • internal/ui/cmdline_hud_test.go
  • internal/ui/room.go

Comment thread internal/engine/engine.go
Comment on lines +157 to 165
// Macro recording captures every key except the q that ends it.
if s.recordingMacro && !s.stopsMacro(key) {
s.macroKeys = append(s.macroKeys, key)
}
s.record(key)
ev := s.dispatch(key)
s.finishRecord(key, ev)
return ev
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm there is no replay/depth guard on the macroKeys append and that `.`
# is handled before the append.
rg -nP -C4 'macroKeys\s*=\s*append' internal/engine/engine.go
rg -nP -C2 'repeatLastChange|s\.replaying' internal/engine/engine.go

Repository: StrangeNoob/nvim-quest

Length of output: 1542


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the relevant sections around Press, record/replay, and macro playback.
sed -n '140,260p' internal/engine/engine.go
printf '\n----\n'
sed -n '520,570p' internal/engine/engine.go

Repository: StrangeNoob/nvim-quest

Length of output: 4771


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the q/@ handling and macro state transitions.
rg -n -C4 'recordingMacro|lastMacroReg|pendingQ|pendingAt|runMacro|stopsMacro|macroKeys|macros\[|@' internal/engine/engine.go

Repository: StrangeNoob/nvim-quest

Length of output: 4172


Skip replayed keystrokes while recording macros. runMacro re-enters Press while recordingMacro is still enabled, so recording @b inside another macro appends b’s expansion to macroKeys and makes later replays duplicate it. Guard the append during playback, for example with s.replaying or s.macroDepth > 0.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/engine/engine.go` around lines 157 - 165, The macro recording path
in Press is currently appending keystrokes even when they are being replayed by
runMacro, which causes nested or replayed macro input to be captured into
macroKeys and duplicated on later runs. Update the recording guard around the
s.macroKeys append in Press to skip appending while playback is active, using
the existing s.replaying or s.macroDepth state. Keep the normal s.record and
dispatch flow intact, but ensure only user-entered keys are recorded when
recordingMacro is true.

- Pending() now reports pendingQ/pendingAt so the HUD shows a macro
  register prompt, consistent with the other pending-key states
- TestMidGameBossIsNotTheFinale also asserts the act-complete unlock,
  covering the positive path alongside the not-finale assertion
@StrangeNoob

Copy link
Copy Markdown
Owner Author

CodeRabbit CLI review disposition (4 minor findings)

The CLI review is incremental — the first run surfaced all 4, and re-runs on the same commit dedupe to 0. Addressed by file:

  • engine.go — Pending() omits armed q/@ (real): fixed with a failing test first. Same class as PR Act IV part 2: The Echo Rite (.) + Waypoints (marks) + The Registers #10's pending-state finding; the macro register prompt now shows in the HUD.
  • app_test.go — new finale tests (test completeness): fixed. TestMidGameBossIsNotTheFinale now also asserts the next-act unlock, not just the negative.
  • visual.go ×2 (minor): intentionally skipped, documented. (1) block delete doesn't fill the paste register — no delete in this engine does, only y (the simplification recorded in the gap analysis since PR The operators pack: The Severing (D/C/ce/yw) + The Gatekeeper (%) #7); doing it for block alone would be inconsistent. (2) block column ops index by byte offset — the entire engine models Cursor.Col as a byte offset (insert, x, dw all do), and all lesson buffers are ASCII; rune-ifying only the block paths would diverge from the rest. The UI-layer block highlighter is rune-safe.

Full suite green; go vet and gofmt clean.

@StrangeNoob StrangeNoob merged commit 2e57a26 into main Jul 3, 2026
2 checks passed
@StrangeNoob StrangeNoob deleted the feature/act4-finale branch July 3, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant