From bdfd46a915e4b0fb6ac53d4ecfbcc08aecf245f4 Mon Sep 17 00:00:00 2001 From: Helmut Januschka Date: Sat, 28 Jun 2025 02:15:50 +0200 Subject: [PATCH] Add keyboard shortcut highlighter to terminal (#114) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add keyboard shortcut highlighter to terminal - Create keyboard-shortcut-highlighter.ts with comprehensive pattern matching - Integrate highlighter into terminal component alongside URL highlighting - Support clickable shortcuts like "Ctrl+R", "Ctrl+A", "esc to interrupt" - Style shortcuts with greyish color and dotted underlines (not blue links) - Send actual key sequences when shortcuts are clicked - Handle overlapping matches and avoid double-processing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix keyboard shortcut input handling - add missing event listener The keyboard shortcut highlighter was dispatching 'terminal-input' events but the session-view component wasn't listening for them. Added: - @terminal-input event listener on vibe-terminal component - handleTerminalInput method that forwards to inputManager.sendInputText() Now clicked shortcuts like 'Ctrl+R' properly send input to the terminal. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Add Claude Code interactive prompt support to keyboard shortcut highlighter Make numbered options in Claude Code prompts clickable: - Pattern: '❯ 1. Yes' or ' 2. Yes, and don't ask again' - Clicking sends the number (1, 2, 3, etc.) to terminal - Handles both selected (❯) and unselected options - Uses multiline regex matching for line-start patterns Now users can click numbered options instead of typing numbers. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix Claude Code prompt patterns to handle indented options Previous patterns required line-start anchors which failed for indented options within bordered terminal output. Updated patterns: - Remove restrictive line-start anchors (^) - Add whitespace-flexible patterns for indented options - Support both cursor-selected (❯) and plain numbered options - Handle 'Yes, proceed' and 'No, exit' style options Now correctly matches: '❯ 1. Yes, proceed' and ' 2. No, exit' patterns. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Simplify Claude Code prompt patterns to be fully generic Replace keyword-specific patterns with generic numbered option matching: - ❯ 1. (cursor-selected options) - 1. xxxxx (any numbered option with text) Now matches any numbered list item regardless of content: '1. Yes, proceed', '2. No, exit', '3. Maybe later', etc. Much cleaner and more flexible than keyword-based matching. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * Fix Claude Code prompt patterns to highlight full option lines Changed from matching only first word to matching entire lines: - /❯\s*(\d+)\.\s+.*/ - highlights complete cursor-selected option - /(\d+)\.\s+.*/ - highlights complete numbered option Now '1. Yes, proceed' and '2. No, exit' are fully underlined instead of just '1. Yes' and '2. No'. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --------- Co-authored-by: Claude --- web/src/client/components/session-view.ts | 8 + web/src/client/components/terminal.ts | 14 + .../utils/keyboard-shortcut-highlighter.ts | 370 ++++++++++++++++++ 3 files changed, 392 insertions(+) create mode 100644 web/src/client/utils/keyboard-shortcut-highlighter.ts diff --git a/web/src/client/components/session-view.ts b/web/src/client/components/session-view.ts index f676a5c9..409a39b0 100644 --- a/web/src/client/components/session-view.ts +++ b/web/src/client/components/session-view.ts @@ -729,6 +729,13 @@ export class SessionView extends LitElement { } } + private async handleTerminalInput(e: CustomEvent) { + const { text } = e.detail; + if (this.inputManager && text) { + await this.inputManager.sendInputText(text); + } + } + private updateTerminalTransform(): void { // Calculate height reduction for keyboard and quick keys let heightReduction = 0; @@ -895,6 +902,7 @@ export class SessionView extends LitElement { .hideScrollButton=${this.showQuickKeys} class="w-full h-full p-0 m-0" @click=${this.handleTerminalClick} + @terminal-input=${this.handleTerminalInput} > diff --git a/web/src/client/components/terminal.ts b/web/src/client/components/terminal.ts index 778fb463..042308f3 100644 --- a/web/src/client/components/terminal.ts +++ b/web/src/client/components/terminal.ts @@ -13,6 +13,7 @@ import { type IBufferCell, type IBufferLine, Terminal as XtermTerminal } from '@xterm/headless'; import { html, LitElement, type PropertyValues } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; +import { processKeyboardShortcuts } from '../utils/keyboard-shortcut-highlighter.js'; import { createLogger } from '../utils/logger.js'; import { UrlHighlighter } from '../utils/url-highlighter'; @@ -731,6 +732,9 @@ export class Terminal extends LitElement { // Process links after rendering UrlHighlighter.processLinks(this.container); + // Process keyboard shortcuts after rendering + processKeyboardShortcuts(this.container, this.handleShortcutClick); + // Track render performance in debug mode if (this.debugMode) { const endTime = performance.now(); @@ -1239,6 +1243,16 @@ export class Terminal extends LitElement { } }; + private handleShortcutClick = (keySequence: string) => { + // Dispatch a custom event with the keyboard shortcut + this.dispatchEvent( + new CustomEvent('terminal-input', { + detail: { text: keySequence }, + bubbles: true, + }) + ); + }; + render() { return html`