Conversation
Replaces hardcoded keyboard handling with plugin-style action system. Addresses GitHub issue #11 for extensible terminal actions. ## Changes ### New Files - **TerminalAction.kt**: Core action framework with KeyStroke and TerminalAction classes - Platform-aware keystroke matching (macOS Cmd vs Windows/Linux Ctrl) - Support for multiple keystrokes per action - Enable/disable predicates for context-sensitive actions - **ActionRegistry.kt**: Thread-safe action registry - ConcurrentHashMap-based storage - Registration, lookup, and execution methods - Support for finding actions by KeyEvent - **BuiltinActions.kt**: Factory for all built-in actions - Copy (Cmd/Ctrl+C) - only when selection exists - Paste (Cmd/Ctrl+V) - fixed with dynamic processHandle access - Search (Cmd/Ctrl+F) - toggles search bar - ClearSelection (Escape) - clears text selection - ToggleIME (Ctrl+Space) - for CJK input - SelectAll (Cmd/Ctrl+A) - selects all content ### Modified Files - **ProperTerminal.kt**: Refactored to use ActionRegistry - Removed 118 lines of hardcoded keyboard handling - Created action registry with platform detection - Simplified onKeyEvent and onPreviewKeyEvent handlers ## Bug Fixes - **Paste fix**: Changed from passing processHandle value to lambda { processHandle } - Ensures paste action accesses current processHandle, not captured null value - Fixes Cmd/Ctrl+V not working after terminal connection ## Architecture - Clean separation of action definition and handling - Thread-safe for concurrent access - Platform-agnostic with runtime OS detection - Extensible: users can register custom actions ## Testing ✅ All keyboard shortcuts tested and working: - Copy (with/without selection) - Paste (fixed) - Search toggle - Clear selection - Select all⚠️ IME toggle (Ctrl+Space) works but only for CJK users 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…work (#11) Added ActionRegistryTest.kt with 16 unit tests covering: - KeyStroke properties and creation - TerminalAction properties and enabled states - ActionRegistry operations (register, unregister, get, clear) - Platform-specific registry creation - Duplicate action handling Note: KeyEvent matching tests excluded due to internal Compose UI API constraints. Manual integration testing confirmed all shortcuts working correctly. Updated CLAUDE.md with comprehensive action framework documentation: - Architecture overview with all components explained - Key files and line references - Usage examples for custom and platform-specific actions - Critical lambda capture pattern for dynamic resource access - Platform awareness details - Testing approach and verification results - Benefits and future enhancement ideas All changes committed as part of extensible terminal actions framework implementation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Pull Request Review: Extensible Terminal Actions FrameworkOverviewThis is an excellent refactoring that replaces hardcoded keyboard handling with a clean, extensible plugin-style architecture. The implementation demonstrates strong software engineering principles and significantly improves code maintainability. 🎯 StrengthsArchitecture & Design
Code Quality
Testing
📝 Suggestions for Improvement1. KeyStroke Matching Logic (TerminalAction.kt:20-46)The platform-aware matching logic is solid, but there's a subtle potential issue: Current code: val primaryModifier = if (isMacOS) meta else ctrl
val primaryEventModifier = if (isMacOS) eventMeta else eventCtrl
if (primaryModifier != primaryEventModifier) return falseIssue: When a Example scenario: KeyStroke(key = Key.C, ctrl = true) // Windows/Linux shortcutOn macOS, this will check:
This works correctly, but the secondary modifier check (lines 39-43) might be overly strict. Consider if you want to allow "Ctrl+C on macOS" to work even when the action defines only Recommendation: The current behavior is probably correct (strict platform matching), but add a comment explaining this design decision to prevent future confusion. 2. MutableState Wrapper Boilerplate (ProperTerminal.kt:342-362)The manual selectionStart = object : androidx.compose.runtime.MutableState<Pair<Int, Int>?> {
override var value: Pair<Int, Int>?
get() = selectionStart
set(value) { selectionStart = value }
override fun component1() = value
override fun component2(): (Pair<Int, Int>?) -> Unit = { selectionStart = it }
},Recommendation: Extract this into a helper function: private fun <T> wrapAsMutableState(
getter: () -> T,
setter: (T) -> Unit
): MutableState<T> {
return object : MutableState<T> {
override var value: T
get() = getter()
set(value) = setter(value)
override fun component1() = value
override fun component2(): (T) -> Unit = setter
}
}
// Usage:
selectionStart = wrapAsMutableState({ selectionStart }, { selectionStart = it }),This would reduce code duplication and make the intent clearer. However, I notice these variables are already using Compose's 3. extractSelectedText Function Complexity (BuiltinActions.kt:179-232)The val (minCol, maxCol) = if (startRow == endRow) {
// Same row - compare columns
if (startCol < endCol) startCol to endCol else endCol to startCol
} else {
// Different rows - use natural order
if (startRow < endRow) startCol to endCol else endCol to startCol
}Issue: The "different rows" case comment says "use natural order" but still depends on row comparison. Recommendation: Add a detailed comment explaining the selection model: // Selection model:
// - For same-row selections: normalize columns regardless of drag direction
// - For multi-row selections: columns follow the row order
// (if dragged backwards, startCol is at higher row, endCol at lower row)Or consider simplifying by always converting to a normalized 4. Action Registry Thread Safety (ActionRegistry.kt)While Risk: Low (terminal keyboard events are typically single-threaded) /**
* Thread-safe registry for terminal actions.
* Individual operations (register, unregister, find) are atomic.
* Bulk operations (registerAll, clear) are not atomic but safe for
* typical single-threaded keyboard event handling.
*/5. toDisplayString Method (TerminalAction.kt:51-72)Minor issue - the string formatting for Windows/Linux could be cleaner: Current: modifiers.joinToString(if (isMacOS) "" else "+") + (if (isMacOS) "" else "+") + keyNameCleaner: if (isMacOS) {
modifiers.joinToString("") + keyName
} else {
(modifiers + keyName).joinToString("+")
}6. Test CoverageThe test suite is good, but consider adding:
🔒 Security ConsiderationsNo security concerns identified. The framework properly:
⚡ Performance Considerations
Current performance: ✅ Excellent for typical use (6-50 actions) 📊 Test Coverage Assessment
Overall test coverage: Strong (estimated 85-90% of critical paths) 🎨 Code Style & Consistency
📦 Impact AssessmentLines changed: +938 / -46 (net +892) ✅ Recommendation: APPROVE WITH MINOR SUGGESTIONSThis PR represents high-quality engineering work that significantly improves the codebase. The suggestions above are all minor refinements - none are blocking issues. The implementation is solid, well-tested, and ready to merge. Before Merge:
After Merge:
Great work on this refactoring! 🚀 The extensible architecture will make future keyboard shortcut additions much cleaner. Reviewed by: Claude Code |
feat: Implement extensible terminal actions framework (#11)
- Add AI Assistant Installation API section to embedding.md - Add AI Assistant Installation API section to tabbed-terminal.md - Add feature #15 (AI Assistant Integration) to CLAUDE.md - Update Recent Changes with detailed implementation notes - Document all API methods, usage examples, and supported assistants 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Implements a plugin-style extensible actions framework to replace hardcoded keyboard handling with a maintainable, testable system.
Changes
Core Implementation
Built-in Actions (6 total)
Key Features
Testing & Documentation
Testing Performed
✅ All 6 built-in shortcuts manually tested and working
✅ Platform-aware shortcuts verified (macOS Cmd handling)
✅ Unit tests created for core framework components
✅ Integration testing with existing features (search, context menu, IME)
Closes #11
🤖 Generated with Claude Code