feat(mouse): #304 PR 4f — mouse_links module wiring#367
Merged
Conversation
Wires the path detector from PR 4e (#366) into a full module: - onOutput captures terminal output into a per-process ring of rows (SGR + OSC stripped; CR / BS / \n line discipline) - onMouseClick maps screen (row,col) → captured row → path_detect.find → POSIX-shell-safe injection command - pollShellInput surfaces `\x15<editor> +LINE 'path'\n` to pty.master so the shell runs the editor via normal readline Command formatting (`mouse_links/inject.zig`) single-quotes the path with `'\''` escape — handles `*`, `?`, `;`, `$`, backtick, embedded newlines. Editor resolution checks `Config.editor`, `$EDITOR`, `$VISUAL`; falls back to silent no-op if none set. Click → row mapping uses a monotonic write counter; visible window = `current_row - term_rows + 1 .. current_row`. Streaming- line model only — TUIs in alt-screen bypass the intercept (shell owns input → atty's mouse intercept is gated off). Statusbar reserve rows are excluded from clickable area. A second click is silently passthrough while a prior injection is still queued — prevents click-spam from overwriting the pending command. 25 integration tests + 11 inject tests = 36 new tests. - 1050/1050 unit tests pass - ReleaseSafe build verified Wires `atty.Mouse` re-export through resolver + root so user configs can write `pub const mouse: atty.Mouse = .{ .enabled = true }`. URL detection + atty-guard security gate lands in PR 4g. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sserts Subagent flagged a real bug in the output-ring high-water-mark accounting: a shorter rewrite after CR (\r) would leave stale tail bytes from the previous content. Path detection then sees garbage past the new write. Fix: `line_lens[idx] = new_col` unconditionally on every printable write (overwrite semantics replaces high-water-mark). Lock the new behaviour with a paired test that fails with the old code — `wrongabcdef\rsrc/y.zig\n` must produce `'src/y.zig'`, not `'src/y.zigef'`. Also: - Comptime asserts `ring_rows > 0` and `row_bytes > 0` — prevents divide-by-zero panic if a user copies the example without uncommenting the defaults. - WHY-only comment on the `inject_len = 0` reset in pollShellInput. - Trim the file header — narrative WHAT was redundant with the hook names; keep only the WHY (streaming-line model + $EDITOR trust posture). 1051/1051 tests pass (+1 new for the bug repro). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Wires the path detector from PR 4e (#366) into a full module that turns mouse clicks on file paths in terminal output into editor launches.
Pipeline
onOutput— captures terminal output into a per-process ring of rows (default 256 × 1024 bytes). SGR + OSC sequences are stripped;\n/\r/ BS are honoured.onMouseClick— left-press only. Maps screen(row, col)→ captured row via a monotonic write counter, then runspath_detect.findfrom PR 4e. On hit, formats a POSIX-shell-safe injection command.pollShellInput— surfaces\x15<editor> +LINE 'path'\ntopty.master. The shell receives it as if the user typed it; the leading Ctrl+U (\x15) clears any half-typed prompt first.Command format
mouse_links/inject.zigsingle-quotes the path with the standard'\''escape — paths can contain*,?,;,$, backtick, even embedded newlines without breaking the shell parser.`+LINE` is the lowest-common-denominator jump syntax: vim, nvim, vi, emacs, nano all honour it. Column is dropped (no portable convention across editors).
Editor resolution
`Config.editor` → `$EDITOR` → `$VISUAL` → silent no-op.
Click → row mapping
Streaming-line model: each
\\nincrementscurrent_row. Visible window =current_row - term_rows + 1 .. current_row. Reserved bottom rows (statusbar) are excluded from the clickable area. Whenctx.terminal_rows == null(non-TTY) clicks pass through.TUIs in the alt-screen are not affected — atty's mouse intercept (PR 4c) is already gated on
!shell_owns_input, so vim/htop see their own clicks normally.Click coalescing
A second click while an injection is still queued is silently passthrough — prevents click-spam from overwriting a pending command before the proxy's next tick drains it.
Wiring
Mousetype re-export inconfig_resolver.zig+root.zigso user configs can spell\pub const mouse: atty.Mouse = .{ .enabled = true }``\atty.modules.mouse_links``src/config.def.zigRoadmap (#304)
mouse_linksmodule: capture + click + injectmouse_urlsmodule: URL detection + atty-guardUrlsAllowsecurity gateTest plan
🤖 Generated with Claude Code