Skip to content

feat: ring terminal bell on blocked edge-scroll#9

Merged
rrbe merged 2 commits into
masterfrom
feat/scroll-edge-bell
May 22, 2026
Merged

feat: ring terminal bell on blocked edge-scroll#9
rrbe merged 2 commits into
masterfrom
feat/scroll-edge-bell

Conversation

@rrbe
Copy link
Copy Markdown
Owner

@rrbe rrbe commented May 22, 2026

Summary

  • Vim-style cue: when a scroll keystroke would push the viewport past the document's top or bottom but it's already pinned, termdown emits \x07 to stderr. The terminal emulator decides the visible effect — Ghostty puts a 🔔 in the window title, iTerm2/Terminal.app bounce the dock, audible-bell users get a beep. Explicit jumps (gg/G/]/[) stay silent to match vim's behavior.
  • Detection lives in the dispatcher, not in Viewport: capture viewport.top before/after scroll_by and ring when it didn't move. Keeps Viewport pure (no App/Config/IO coupling) and lets the three scroll-action arms share one perform_scroll helper.
  • Off-switch: bell = false in ~/.termdown/config.toml or --no-bell on the command line (documented in --help).
  • Closes the relevant TODO entry; README / README_CN / CHANGELOG updated.

Test plan

  • make fmt && make check clean (73 unit + 9 CLI + 5 snapshot tests, clippy -D warnings clean)
  • cargo run -- --help lists --no-bell
  • Manual TUI in Ghostty: j past the bottom → BEL fires; Ghostty shows 🔔 in title bar (its default bell-features includes title). gg/G/]/[ at edges stay silent.
  • Reviewer sanity-check in their own terminal — bell behavior depends on emulator's bell-features / "Audible bell" setting.

🤖 Generated with Claude Code

rrbe added 2 commits May 22, 2026 10:48
Vim-style cue: when j/k, d/u, or f/b/Space/PgUp/PgDn would push the
viewport past the top or bottom but it's already pinned, termdown now
emits a `\x07` BEL to stderr. The terminal emulator decides what the
user sees — Ghostty's default `bell-features` puts a 🔔 in the window
title, iTerm2/Terminal.app bounce the dock, audible-bell users get a
beep. Explicit jumps (gg/G/]/[) stay silent to match vim's scope.

Detection lives in the dispatcher, not in `Viewport`: we capture
`viewport.top` before/after `scroll_by` and ring when it didn't move.
This keeps `Viewport` free of `App`/`Config`/IO coupling and means the
three scroll-action arms share one helper (`perform_scroll`).

Off-switch:
- `bell = false` in ~/.termdown/config.toml
- `--no-bell` CLI flag (also documented in --help)

Closes the TODO.md item for top/bottom audio feedback.
- ring_bell now takes &Config instead of &App, documenting the actual
  dependency and making the helper trivially testable without an App.
- Drop the redundant flush() — std::io::Stderr is unbuffered, so the
  BEL byte hits the fd immediately on write_all. Matches the rest of
  the codebase (eprintln! never manually flushes).
- Use io::stderr().write_all(...) instead of fully-qualified
  std::io::Write::write_all(...) now that Write is already in scope at
  the top of the file.
@rrbe rrbe merged commit 57a7004 into master May 22, 2026
5 checks passed
@rrbe rrbe deleted the feat/scroll-edge-bell branch May 22, 2026 02:59
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