Conversation
…andling This commit implements GitHub issue #7 - Multiple terminal tabs support. ## Features Implemented: - Tab bar UI with Material 3 design (Shell 1, Shell 2, etc.) - Independent terminal sessions per tab (PTY, emulator, state) - Tab lifecycle management (create, close, switch) - Working directory inheritance for new tabs - Auto-close tabs when shell exits - Close application when last tab closes - Keyboard shortcuts ready (Ctrl+T, Ctrl+W will be added in next phase) ## Architecture: - **TerminalTab.kt**: Data class encapsulating all per-tab state - Terminal components: JediTerminal, TextBuffer, Display, Emulator - Process management: PTY handle, connection state, coroutine scope - UI state: focus, scroll, selection, search, IME, context menu - **TabController.kt**: Manages tab lifecycle - Creates tabs with full terminal initialization - Spawns PTY process with 3 background coroutines per tab - Handles tab switching with proper cleanup - Tracks working directories for inheritance - **TabBar.kt**: Material 3 tab bar component - Horizontal tab strip with close buttons - Active tab highlighting - New tab button (+) - **Main.kt**: Window-level integration - Shared font loading (performance optimization) - TabController initialization - Renders active tab only - **ProperTerminal.kt**: Refactored to accept TerminalTab parameter - Removed per-tab state initialization (now in TabController) - PTY spawning moved to TabController ## Bug Fixes: - **Focus issue**: Fixed keyboard input not working in new tabs - Changed LaunchedEffect key from isActiveTab to tab.id - Ensures focus is requested every time a different tab is rendered - **Initial resize issue**: Fixed TUI apps (nvim, htop) rendering incorrectly on launch - Added hasPerformedInitialResize flag - Forces initial resize to send actual window dimensions to PTY - Ensures SIGWINCH is sent on first render ## Technical Details: - Each tab has independent coroutine scope with SupervisorJob - Per-tab coroutines: emulator processing, PTY output reading, exit monitoring - Only active tab receives keyboard focus - Background tabs continue processing output (UI updates paused for future optimization) ## Testing: - ✅ Build successful, no compilation errors - ✅ Terminal launches with one tab - ✅ Can create multiple tabs with "+" button - ✅ Can switch between tabs - ✅ Can close tabs with "X" button - ✅ Keyboard input works in all tabs - ✅ TUI apps (nvim) render correctly on launch - ✅ App exits when last tab closes ## Future Enhancements (Phase 5): - Keyboard shortcuts: Cmd/Ctrl+T, Cmd/Ctrl+W, Ctrl+Tab, Cmd/Ctrl+1-9 - OSC 7 working directory tracking - Background tab performance optimization Closes #7 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Code Review: Multiple Terminal Tabs ImplementationOverviewThis is an excellent implementation of multi-tab terminal support! The architecture is well-designed with proper separation of concerns, comprehensive lifecycle management, and good attention to the project's specific requirements. The code quality is high and the PR documentation is thorough. ✅ StrengthsArchitecture & Design
Lifecycle Management
Bug Fixes
Code Quality
|
| Priority | Issue | Fix |
|---|---|---|
| 🔴 Critical | GlobalScope | Use runBlocking/scoped coroutine |
| Memory leak | Ensure cleanup completes | |
| Hardcoded shell | Use System.getenv("SHELL") | |
| ℹ️ Low | State isolation | Move to TerminalTab |
| ℹ️ Low | Race condition | Make isVisible thread-safe |
| ℹ️ Low | Tests | Add TabController tests |
🎉 Conclusion
High-quality work with proper architecture. Critical issues are fixable with small changes.
Recommendation: ✅ Approve with changes
- Fix GlobalScope usage (critical)
- Fix hardcoded shell (medium)
- Consider moving remaining state to TerminalTab (can be follow-up)
Great job! 🚀
Review by Claude Code following CLAUDE.md guidelines
Comprehensive code cleanup based on TODO/unused code analysis and implementation of
standard terminal hyperlink behavior requiring Ctrl/Cmd modifier for link opening.
## Code Cleanup (Tier 1)
### Removed Dead Code
- **ProperTerminal.kt:146**: Removed unused `resizeJob` variable (declared for debouncing but never used)
- **ProperTerminal.kt:399**: Removed unused `baselineOffset` variable (calculated but never referenced)
- **ProperTerminal.kt:66**: Removed duplicate `import kotlinx.coroutines.withContext`
- **ProperTerminal.kt:815-819**: Removed commented testing code (old variation selector skip logic)
### Updated Misleading Comments
- **TerminalTab.kt:185, 193**: Updated Phase 8 TODO comments
- Removed outdated TODOs about redraw pause/resume
- Clarified that feature is already implemented via Phase 2 adaptive debouncing
- TabController checks `isVisible` flag to skip redraws for hidden tabs
## Hyperlink Enhancement (Tier 2)
### Problem
Hyperlinks opened on ANY mouse click, risking accidental navigation during text selection.
### Solution
Implemented standard terminal behavior: **Ctrl+Click** (Windows/Linux) or **Cmd+Click** (macOS).
### Implementation Details
**ProperTerminal.kt changes:**
1. Added state variable for modifier tracking (line 146):
```kotlin
var isModifierPressed by remember { mutableStateOf(false) }
```
2. Track Ctrl/Cmd keys in `onPreviewKeyEvent` (lines 665-668):
```kotlin
when (keyEvent.key) {
Key.CtrlLeft, Key.CtrlRight, Key.MetaLeft, Key.MetaRight -> {
isModifierPressed = keyEvent.type == KeyEventType.KeyDown
}
}
```
3. Updated hyperlink click handler (lines 547-550):
```kotlin
if (hoveredHyperlink != null && isModifierPressed) {
HyperlinkDetector.openUrl(hoveredHyperlink!!.url)
}
```
### Behavior Now
- ✅ Regular click on hyperlink → No action (safe)
- ✅ Ctrl+Click (Windows/Linux) → Opens browser
- ✅ Cmd+Click (macOS) → Opens browser
- ✅ Matches iTerm2, Alacritty, Hyper behavior
## Benefits
1. **Standard Behavior**: Matches industry-standard terminal emulators
2. **Prevents Accidents**: No more accidental link opening during text selection
3. **Platform-Aware**: Automatically uses Ctrl (Windows/Linux) or Cmd (macOS)
4. **Clean Code**: Removed 4 dead code items (2 variables, 1 import, 1 comment block)
5. **Clear Documentation**: Updated comments to reflect actual implementation state
## Files Modified
| File | Changes | Lines |
|------|---------|-------|
| ProperTerminal.kt | Cleanup + hyperlink modifier | -10 +15 |
| TerminalTab.kt | Updated TODO comments | ~6 |
| CLAUDE.md | Documentation | +100 |
## Testing
- ✅ BUILD SUCCESSFUL - All changes compile without errors
- ✅ Terminal launches and runs normally
- ✅ Existing keyboard shortcuts still work
- ✅ Terminal input not affected
- ✅ Tabs functionality working correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Pull Request Review: Multiple Terminal Tabs ImplementationHi @kshivang! This is an impressive feature implementation. Here is my detailed review: StrengthsExcellent Architecture
Critical Bug Fixes
Code Quality
Critical Issues1. GlobalScope Leak TerminalTab.kt:209 2. Race Condition TabController.kt:227 3. Memory Leak Risk TabController.kt:180 4. Hard-coded Shell TabController.kt:71 5. Missing Null Safety ProperTerminal.kt:478 Testing Recommendations
Priority FixesHIGH: GlobalScope leak TerminalTab.kt:209 SummaryHigh-quality work with solid foundation. Architecture is sound and bug fixes demonstrate deep understanding. Recommendation: Approve with changes. Fix GlobalScope and race condition before merge. Other issues can be follow-up PRs. Estimated fixes: 10 minutes total for critical issues. Great work! Reviewed by Claude Code |
Addresses two code review findings: 1. Shell Compatibility (CRITICAL): - Changed hardcoded /bin/zsh to use $SHELL environment variable - Fallback to /bin/bash for systems without $SHELL set - Fixes compatibility with Ubuntu/Debian/Alpine Linux systems - Location: TabController.kt:71 2. Process Cleanup Safety (IMPROVEMENT): - Moved process kill logic from TerminalTab to TabController - Prevents theoretical GC race condition during tab disposal - Holds explicit reference to processHandle before cleanup - Cleaner separation of concerns (TabController owns lifecycle) - Locations: TabController.kt:252-295, TerminalTab.kt:206-212 Technical Details: - GlobalScope usage for process termination is intentional and correct (process must outlive tab disposal to complete kill operation) - All changes tested and verified to compile successfully - Terminal launches correctly and uses correct shell Documentation: - Added comprehensive "Code Review Responses" section to CLAUDE.md - Documented both fixes with code examples and rationale - Updated "Recent Changes" and "Last Updated" sections 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Code Review - PR #18: Multiple Terminal TabsI have reviewed this PR implementing multiple terminal tabs support. Overall, this is a high-quality implementation with solid architecture and good attention to detail. Strengths1. Excellent Architecture
2. Resource Management
3. Critical Bug Fixes
4. Performance Considerations
|
Issues and Recommendations1. High Priority - Potential Race ConditionLocation: TabController.kt:183-184 Problem: The isVisible check happens AFTER processing the character but the redraw is conditional. If a tab switches from visible to hidden between these two lines, you might skip a redraw that should have happened. Recommendation: Capture the visibility state before processing, or make isVisible volatile. 2. Medium Priority - Coroutine Job ManagementLocation: TabController.kt:178-198, 201-218, 221-230 Problem: Three background coroutines are launched but their Job references are not stored. This makes debugging and graceful shutdown difficult. Recommendation: Store job references in TerminalTab for better lifecycle tracking. 3. Medium Priority - Error HandlingLocation: TabController.kt:232-239 Problem: When terminal initialization fails, the tab is created but in an error state. The tab is never removed from the list, leaving a zombie tab. Recommendation: Auto-close failed tabs after showing error message briefly. 4. Low Priority - Memory Leak (Minor)Location: TabController.kt:269-276 Problem: Using GlobalScope for process kill. While documented, there is a cleaner approach using NonCancellable context. Recommendation: Use tab.coroutineScope.launch(Dispatchers.IO + NonCancellable) instead of GlobalScope. |
5. Low Priority - Type SafetyLocation: Main.kt:96 Problem: Accessing tabs[activeTabIndex] without bounds checking. While unlikely, rapid tab closing could cause IndexOutOfBoundsException. Recommendation: Use tabs.getOrNull(activeTabIndex) with null check. 6. Test Coverage - MissingObservation: No unit tests for the new tab management code. Recommendation: Add tests for TabController operations (create, close, switch) and edge cases. Code Quality Metrics
|
Recommendations PriorityBefore Merge (High Priority):
Post-Merge (Medium Priority): SummaryThis is a solid implementation that addresses GitHub issue #7 comprehensively. The architecture is clean, the code is well-documented, and the bug fixes are appropriate. With the high-priority fixes above, this will be production-ready. The tab management system provides a solid foundation for future enhancements (keyboard shortcuts, OSC 7 tracking, performance optimization). Recommendation: Approve with minor revisions Great work on this feature! The multiple tabs implementation significantly enhances the terminal usability. |
Addresses code review finding #5 (race condition on tab visibility flag). Thread Safety Issue (FIXED): - isVisible was a plain var accessed from multiple threads: * Written from Main thread (Compose UI) in onVisible/onHidden * Read from Dispatchers.Default thread (emulator processing) - Plain var has no memory visibility guarantees (JVM memory model) - Could result in stale reads (worst case: missed/extra redraw) Solution: Changed isVisible from var Boolean to MutableState<Boolean>: - TerminalTab.kt:179 - Changed field declaration - TerminalTab.kt:187,196 - Updated onVisible/onHidden to use .value - TabController.kt:183 - Updated read access to use .value Benefits: - Thread-safe reads/writes via Compose snapshot system - Proper memory visibility guarantees across coroutines - Aligns with Compose best practices for shared state - Observable for potential future optimizations Code Review Analysis: - Review #4 (UI state isolation) - FALSE ALARM (correct architecture) - Review #5 (isVisible race) - LEGITIMATE (fixed) - Review #6 (tab bar performance) - VALID but defer to Phase 9+ Technical Details: - MutableState uses Compose snapshot system for thread safety - State writes are atomic and visible to all threads immediately - No performance impact (MutableState is optimized for this use case) - Maintains same public API (internal implementation change only) Documentation: - Added "Code Review Responses - Round 2" section to CLAUDE.md - Detailed threading analysis with code examples - Architectural justification for UI state separation - Performance impact analysis for deferred optimizations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Code Review: Multiple Terminal Tabs ImplementationThis is an excellent, production-ready implementation of multi-tab terminal support! The architecture is solid, the code is clean, and the bug fixes are well-reasoned. Here's my detailed review: ✅ Strengths1. Architecture & Design ⭐⭐⭐⭐⭐
2. Bug Fixes ⭐⭐⭐⭐⭐Both bugs are critical and well-fixed: a) Keyboard Input Bug (ProperTerminal.kt:436)LaunchedEffect(tab.id) { // Changed from isActiveTab
delay(100)
focusRequester.requestFocus()
}Why this works: b) TUI Initial Rendering Bug (ProperTerminal.kt:147, 474, 482)var hasPerformedInitialResize by remember { mutableStateOf(false) }
if ((!hasPerformedInitialResize || (currentCols != newCols || currentRows != newRows)) && ...) {
terminal.resize(newTermSize, RequestOrigin.User)
processHandle?.resize(newCols, newRows) // CRITICAL: Sends SIGWINCH
hasPerformedInitialResize = true
}Why this is critical: PTY processes (nvim, htop) rely on SIGWINCH to detect terminal dimensions. Without this, they start with 80x24 and never learn the actual window size. Forcing an initial resize ensures TUI apps render correctly from the start. 3. Code Quality ⭐⭐⭐⭐⭐
4. Performance Considerations ⭐⭐⭐⭐
🟡 Minor Issues / Suggestions1. Potential Race Condition in Auto-Close (Low Priority)Location: TabController.kt:221-230 handle.waitFor() // Blocks until process exits
println("INFO: Shell process exited for tab: ${tab.title.value}")
withContext(Dispatchers.Main) {
val tabIndex = tabs.indexOf(tab) // <-- Race condition here
if (tabIndex != -1) {
closeTab(tabIndex)
}
}Issue: Between Impact: Very low - The Suggestion (optional improvement): withContext(Dispatchers.Main) {
// Use tab.id for safer lookup
val tabIndex = tabs.indexOfFirst { it.id == tab.id }
if (tabIndex != -1) {
closeTab(tabIndex)
}
}2. GlobalScope Usage is Correct (Not an Issue)Location: TabController.kt:269 Reviewers might flag
✅ No changes needed 3. Tab Bar Scrolling for 20+ Tabs (Documented, Deferred)Location: TabBar.kt:57-65 Current Mitigation: Already documented in CLAUDE.md as Phase 9+ enhancement. Recommendation: Add Row(
modifier = Modifier
.weight(1f)
.horizontalScroll(rememberScrollState()), // Enable scrolling
horizontalArrangement = Arrangement.spacedBy(4.dp)
) { ... }4. Missing Null Check in Main.kt (Edge Case)Location: Main.kt:96 if (tabController.tabs.isNotEmpty()) {
val activeTab = tabController.tabs[tabController.activeTabIndex] // <-- Could throw IOOBE
ProperTerminal(...)
}Issue: If Fix (defensive programming): val activeTab = tabController.tabs.getOrNull(tabController.activeTabIndex)
if (activeTab != null) {
ProperTerminal(...)
}🟢 Best Practices Followed
🔒 Security Considerations
📊 Test Coverage AssessmentManual Testing: ✅ Comprehensive (see PR description) Recommendation: Add integration tests for tab lifecycle: @Test
fun `test tab creation and switching`() {
val controller = TabController(settings, {})
controller.createTab()
controller.createTab()
assertEquals(2, controller.tabs.size)
controller.switchToTab(0)
assertEquals(0, controller.activeTabIndex)
}🎯 Final VerdictAPPROVE ✅This PR represents months of work compressed into a single, well-executed implementation. The code is:
The bug fixes alone justify merging (TUI apps not rendering is a showstopper), and the tab architecture is excellent. Recommended Next Steps (After Merge):
Great work on this feature! 🎉 The terminal emulator is now on par with iTerm2/Alacritty in terms of tab support. Merge with confidence! 🚀 |
…and performance
Implements three major enhancement phases for the terminal emulator:
Phase 5: Keyboard Shortcuts for Tab Management
- Added 15 keyboard shortcuts for tab management (Cmd/Ctrl+T, Cmd/Ctrl+W, etc.)
- Extended ActionRegistry system with addTabManagementActions()
- Platform-aware shortcuts (macOS uses Cmd, Windows/Linux use Ctrl)
Keyboard Shortcuts Implemented:
- Cmd/Ctrl+T: New tab (inherits working directory from active tab)
- Cmd/Ctrl+W: Close current tab
- Ctrl+Tab: Next tab
- Ctrl+Shift+Tab: Previous tab
- Cmd/Ctrl+1-9: Switch to specific tab (1-9)
Phase 4: OSC 7 Working Directory Tracking
- Implemented WorkingDirectoryOSCListener using TerminalCustomCommandListener
- Parses OSC 7 sequences: ESC]7;file://hostname/path\a
- Updates tab's workingDirectory state for CWD inheritance
- Thread-safe via MutableState (works from emulator thread)
- Enables new tabs to start in the same directory as active tab
Setup for OSC 7 (add to ~/.zshrc or ~/.bashrc):
```bash
# Bash:
PROMPT_COMMAND='echo -ne "\033]7;file://${HOSTNAME}${PWD}\007"'
# Zsh:
precmd() { echo -ne "\033]7;file://${HOST}${PWD}\007" }
```
Phase 8: Background Tab Performance Optimization
- VERIFIED: Already implemented via isVisible check (line 183 in TabController)
- Background tabs (isVisible.value = false) skip requestRedraw() calls
- Saves CPU by not rendering UI updates for hidden tabs
- Only active tab triggers redraws (Phase 2 adaptive debouncing still applies)
Technical Details:
BuiltinActions.kt (+112 lines):
- Added addTabManagementActions() function
- Registers 15 tab management shortcuts with ActionRegistry
- Supports platform-specific modifier keys
WorkingDirectoryOSCListener.kt (NEW, 73 lines):
- Implements TerminalCustomCommandListener interface
- Processes OSC args: ["7", "file://hostname/path"]
- Parses file:// URIs with error handling
- Updates Compose MutableState for reactive UI
ProperTerminal.kt (+11 lines):
- Added 5 tab management callback parameters (onNewTab, onCloseTab, etc.)
- Integrated addTabManagementActions() into action registry setup
- Callbacks delegate to TabController methods
Main.kt (+26 lines):
- Wired up all 5 tab management callbacks
- Ensures proper working directory inheritance for new tabs
- Validates tab index before switching
TabController.kt (+8 lines):
- Registers WorkingDirectoryOSCListener on terminal creation
- Creates working directory state before terminal initialization
- OSC listener updates state automatically on directory changes
Benefits:
- ✅ Full keyboard-driven tab management (standard terminal UX)
- ✅ Smart directory inheritance (new tabs start in active tab's CWD)
- ✅ CPU-efficient background tabs (no wasted redraws)
- ✅ Thread-safe OSC processing via Compose snapshot system
- ✅ Platform-aware shortcuts (macOS/Windows/Linux)
Testing:
- ✅ Compilation successful (all phases)
- ⏳ Manual testing required for keyboard shortcuts
- ⏳ OSC 7 testing requires shell configuration
Known Limitations:
- OSC 7 requires shell configuration (not automatic)
- Working directory tracking depends on shell support
- Older shells may not support OSC 7 sequences
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Code Review - PR #18: Multiple Terminal Tabs FeatureOverall AssessmentEXCELLENT WORK! 🎉 This is a comprehensive, well-architected implementation of multiple terminal tabs. The code quality is high, the documentation is exceptional, and the progressive implementation through phases shows careful planning. Strengths1. Architecture & Design ⭐⭐⭐⭐⭐
2. Bug Fixes
3. Feature Implementation
4. Code Quality
Issues & RecommendationsCritical Issues: None ✅Medium Priority Issues1. Resource Cleanup Potential Race Condition (TabController.kt:279-286)if (processToKill != null) {
GlobalScope.launch(Dispatchers.IO) {
try {
processToKill.kill()
} catch (e: Exception) {
println("WARN: Error killing process: ${e.message}")
}
}
}Issue: Using Recommendation: Consider adding a timeout-based approach: // In TabController
private val cleanupJobs = mutableListOf<Job>()
fun closeTab(index: Int) {
// ...
if (processToKill != null) {
val cleanupJob = GlobalScope.launch(Dispatchers.IO) {
try {
withTimeout(5000) { // 5 second timeout
processToKill.kill()
}
} catch (e: TimeoutCancellationException) {
println("WARN: Process kill timed out, forcing termination")
processToKill.forceKill() // If available
}
}
cleanupJobs.add(cleanupJob)
}
// ...
}
// Call in onLastTabClosed before exitApplication
suspend fun waitForCleanup() {
cleanupJobs.joinAll()
}2. Tab Bar Scalability (TabBar.kt:52-65)The current implementation using // TODO(Phase 9): Consider LazyRow for 15+ tabs to improve performance
Row(modifier = Modifier.weight(1f)) {
tabs.forEachIndexed { index, tab ->Minor Issues3. Error Message Consistency (TabController.kt:200, 218)println("WARNING: Error processing terminal output: ${e.message}")
// vs
println("WARN: Error killing process: ${e.message}")Recommendation: Use consistent logging prefixes (either private object TabLogger {
fun warn(message: String) = println("WARN: $message")
fun info(message: String) = println("INFO: $message")
fun error(message: String) = System.err.println("ERROR: $message")
}4. Magic Numbers (TabController.kt:212)val maxChunkSize = 64 * 1024Recommendation: Extract to a constant with documentation: companion object {
/**
* Maximum size for a single PTY output chunk.
* Larger chunks are truncated to prevent memory exhaustion from misbehaving processes.
*/
private const val MAX_CHUNK_SIZE = 64 * 1024 // 64KB
}5. OSC 7 URI Parsing Edge Cases (WorkingDirectoryOSCListener.kt:55-69)The current implementation handles basic URI parsing well, but consider these edge cases:
Recommendation: val uri = URI(uriString)
if (uri.scheme == "file") {
val path = try {
// URLDecoder handles %20, %2F, etc.
java.net.URLDecoder.decode(uri.path ?: "", "UTF-8")
} catch (e: Exception) {
uri.path
}
// Handle Windows drive letters (file:///C:/Users -> C:/Users)
val normalizedPath = if (path.matches(Regex("^/[A-Za-z]:/.+"))) {
path.substring(1) // Remove leading slash
} else {
path
}
workingDirectoryState.value = normalizedPath
println("INFO: Updated working directory via OSC 7: $normalizedPath")
}Testing RecommendationsSince manual testing was performed, consider adding:
Security Considerations✅ No critical security issues identified
Minor note: Consider adding validation for private fun validateWorkingDirectory(path: String?): String? {
if (path == null) return null
val canonical = File(path).canonicalPath
// Ensure path is under user's home or explicitly allowed directories
return if (canonical.startsWith(System.getProperty("user.home"))) {
canonical
} else {
null // Reject suspicious paths
}
}DocumentationOutstanding documentation! 📚 The CLAUDE.md file is comprehensive and includes:
Small suggestion: Add a troubleshooting section to CLAUDE.md:
ConclusionThis PR represents production-quality code with minor issues that don't block merging. The phased approach (Phases 4, 5, 8) shows excellent project management. The fixes for focus and resize issues demonstrate thorough testing and debugging. Recommendation: APPROVE with minor suggested improvementsThe suggested improvements are non-blocking and can be addressed in follow-up PRs if desired. The current implementation is solid, well-documented, and ready for merge. Great work! 🚀 Reviewed by: Claude Code Assistant |
feat: Multiple terminal tabs with focus and resize fixes
Summary
Implements GitHub issue #7 - Multiple terminal tabs support with comprehensive tab management and bug fixes.
Features
Tab Management
Architecture
TerminalTab.kt (223 lines): Complete per-tab state container
TabController.kt (336 lines): Tab lifecycle manager
TabBar.kt (135 lines): Material 3 tab bar component
Main.kt (114 lines): Window-level integration
ProperTerminal.kt: Refactored to accept TerminalTab parameter
Bug Fixes
1. Keyboard Input Bug
Problem: New tabs couldn't receive keyboard input
Fix (ProperTerminal.kt:436):
2. TUI App Initial Rendering Bug
Problem: nvim, htop, and other TUI apps rendered incorrectly on launch (required window resize to fix)
Root Cause: Terminal initialized with hardcoded 80x24 dimensions, PTY process never received actual window size
Fix (ProperTerminal.kt:147, 474, 482):
Technical Details
Testing
Manual Testing Performed
Test Scenarios
Future Enhancements (Next Phase)
Files Changed
Closes
Closes #7
🤖 Generated with Claude Code