diff --git a/Sources/ContentView.swift b/Sources/ContentView.swift index 82f6c5d6..d6576116 100644 --- a/Sources/ContentView.swift +++ b/Sources/ContentView.swift @@ -236,8 +236,9 @@ struct TabItemView: View { Text(subtitle) .font(.system(size: 10)) .foregroundColor(isSelected ? .white.opacity(0.8) : .secondary) - .lineLimit(1) + .lineLimit(2) .truncationMode(.tail) + .multilineTextAlignment(.leading) } if let directories = directorySummary { diff --git a/Sources/GhosttyTabsApp.swift b/Sources/GhosttyTabsApp.swift index a2b157f7..15b56353 100644 --- a/Sources/GhosttyTabsApp.swift +++ b/Sources/GhosttyTabsApp.swift @@ -44,10 +44,15 @@ struct GhosttyTabsApp: App { // Close tab CommandGroup(after: .newItem) { - Button("Close Tab") { - tabManager.closeCurrentTab() + Button("Close Panel") { + tabManager.closeCurrentPanelWithConfirmation() } .keyboardShortcut("w", modifiers: .command) + + Button("Close Tab") { + tabManager.closeCurrentTabWithConfirmation() + } + .keyboardShortcut("w", modifiers: [.command, .shift]) } // Tab navigation @@ -77,7 +82,11 @@ struct GhosttyTabsApp: App { // Cmd+1 through Cmd+9 for tab selection ForEach(1...9, id: \.self) { number in Button("Tab \(number)") { - tabManager.selectTab(at: number - 1) + if number == 9 { + tabManager.selectLastTab() + } else { + tabManager.selectTab(at: number - 1) + } } .keyboardShortcut(KeyEquivalent(Character("\(number)")), modifiers: .command) } diff --git a/Sources/TabManager.swift b/Sources/TabManager.swift index d8ce1cbd..15886fa3 100644 --- a/Sources/TabManager.swift +++ b/Sources/TabManager.swift @@ -304,10 +304,43 @@ class TabManager: ObservableObject { closeTab(tab) } + func closeCurrentPanelWithConfirmation() { + guard let selectedId = selectedTabId, + let tab = tabs.first(where: { $0.id == selectedId }), + let focusedSurfaceId = tab.focusedSurfaceId else { return } + guard tab.splitTree.isSplit else { return } + guard confirmClose( + title: "Close panel?", + message: "This will close the current split panel in this tab." + ) else { return } + _ = tab.closeSurface(focusedSurfaceId) + } + + func closeCurrentTabWithConfirmation() { + guard tabs.count > 1 else { return } + guard let selectedId = selectedTabId, + let tab = tabs.first(where: { $0.id == selectedId }) else { return } + guard confirmClose( + title: "Close tab?", + message: "This will close the current tab and all of its panels." + ) else { return } + closeTab(tab) + } + func selectTab(_ tab: Tab) { selectedTabId = tab.id } + private func confirmClose(title: String, message: String) -> Bool { + let alert = NSAlert() + alert.messageText = title + alert.informativeText = message + alert.alertStyle = .warning + alert.addButton(withTitle: "Close") + alert.addButton(withTitle: "Cancel") + return alert.runModal() == .alertFirstButtonReturn + } + func titleForTab(_ tabId: UUID) -> String? { tabs.first(where: { $0.id == tabId })?.title } @@ -401,6 +434,11 @@ class TabManager: ObservableObject { selectedTabId = tabs[index].id } + func selectLastTab() { + guard let lastTab = tabs.last else { return } + selectedTabId = lastTab.id + } + func newSplit(tabId: UUID, surfaceId: UUID, direction: SplitTree.NewDirection) -> Bool { guard let tab = tabs.first(where: { $0.id == tabId }) else { return false } return tab.newSplit(from: surfaceId, direction: direction) != nil