From 09422a8b9586022db6047474678d42bc9eeaf268 Mon Sep 17 00:00:00 2001 From: chris-moller Date: Wed, 18 Mar 2026 21:07:59 +0000 Subject: [PATCH 1/2] chore: add implementation plan Co-Authored-By: Claude Opus 4.6 --- PLAN.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tasks.json | 6 +++++ 2 files changed, 72 insertions(+) create mode 100644 PLAN.md create mode 100644 tasks.json diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..30f775d --- /dev/null +++ b/PLAN.md @@ -0,0 +1,66 @@ +# Implementation Plan: BEL Control Code Event Emission + +## Summary + +Wire up BEL (0x07) handling in the Terminal class (`src/terminal.js`) to emit a callback event, and add a default visual bell handler in the Renderer (`src/renderer.js`). This is a small, well-scoped feature that touches 4 files. + +## Architecture Analysis + +The codebase has two layers relevant to this task: + +1. **Terminal engine** (`src/terminal.js`) — Pure state machine. Parser callbacks (`onPrint`, `onExecute`, `onCsiDispatch`, etc.) drive state changes. The `_execute()` method already has a `case 0x07: // BEL` stub that does nothing. + +2. **Renderer** (`src/renderer.js`) — DOM renderer that reads terminal state and renders it. Currently has no event subscription — it just reads `terminal.getState()`. + +The codebase uses a simple **callback property** pattern for events (e.g., `parser.onPrint`, `parser.onExecute`). Following this pattern, the Terminal class should expose an `onBell` callback property. + +## Research + +xterm.js added `onBell` in v4.12.0 ([Issue #3014](https://github.com/xtermjs/xterm.js/issues/3014)). Their approach: the terminal emits a bell event, and the UI layer subscribes to it independently. The bell event carries no data (it's a `void` callback). This matches our acceptance criteria for full decoupling. + +## Changes + +### 1. `src/terminal.js` — Add `onBell` callback + +- Add `this.onBell = null;` in the constructor (following the pattern of other state like `this.title`). +- In `_execute()`, change `case 0x07` from a bare `break` to `this.onBell?.(); break;`. The optional chaining (`?.`) ensures no error if no handler is registered (AC #5). +- In `reset()`, set `this.onBell` back to `null` is NOT needed — the callback is external configuration, not terminal state. The `title` callback pattern shows that external registrations persist across resets. + +### 2. `src/renderer.js` — Add visual bell handler + +- Add a `_setupBellHandler()` method called from the constructor that subscribes to `terminal.onBell`. +- The handler adds a CSS class (`mogterm-visual-bell`) to the container for a brief flash, then removes it after the animation completes. +- The flash uses a CSS animation (opacity pulse or border flash) defined inline or via a `