Insert new tabs after current and inherit cwd

This commit is contained in:
Lawrence Chen 2026-01-29 03:30:22 -08:00
parent 004a353fe5
commit 357eeb3585
2 changed files with 67 additions and 13 deletions

View file

@ -594,15 +594,22 @@ class TerminalSurface: Identifiable {
let tabId: UUID
private let surfaceContext: ghostty_surface_context_e
private let configTemplate: ghostty_surface_config_s?
private let workingDirectory: String?
let hostedView: GhosttySurfaceScrollView
private let surfaceView: GhosttyNSView
private var ownsDisplayLink = false
init(tabId: UUID, context: ghostty_surface_context_e, configTemplate: ghostty_surface_config_s?) {
init(
tabId: UUID,
context: ghostty_surface_context_e,
configTemplate: ghostty_surface_config_s?,
workingDirectory: String? = nil
) {
self.id = UUID()
self.tabId = tabId
self.surfaceContext = context
self.configTemplate = configTemplate
self.workingDirectory = workingDirectory?.trimmingCharacters(in: .whitespacesAndNewlines)
let view = GhosttyNSView(frame: .zero)
self.surfaceView = view
self.hostedView = GhosttySurfaceScrollView(surfaceView: view)
@ -692,15 +699,26 @@ class TerminalSurface: Identifiable {
}
}
if !envVars.isEmpty {
let envVarsCount = envVars.count
envVars.withUnsafeMutableBufferPointer { buffer in
surfaceConfig.env_vars = buffer.baseAddress
surfaceConfig.env_var_count = envVarsCount
surface = ghostty_surface_new(app, &surfaceConfig)
let createSurface = { [self] in
if !envVars.isEmpty {
let envVarsCount = envVars.count
envVars.withUnsafeMutableBufferPointer { buffer in
surfaceConfig.env_vars = buffer.baseAddress
surfaceConfig.env_var_count = envVarsCount
self.surface = ghostty_surface_new(app, &surfaceConfig)
}
} else {
self.surface = ghostty_surface_new(app, &surfaceConfig)
}
}
if let workingDirectory, !workingDirectory.isEmpty {
workingDirectory.withCString { cWorkingDir in
surfaceConfig.working_directory = cWorkingDir
createSurface()
}
} else {
surface = ghostty_surface_new(app, &surfaceConfig)
createSurface()
}
if surface == nil {

View file

@ -16,11 +16,20 @@ class Tab: Identifiable, ObservableObject {
@Published var surfaceDirectories: [UUID: String] = [:]
var splitViewSize: CGSize = .zero
init(title: String = "Terminal") {
init(title: String = "Terminal", workingDirectory: String? = nil) {
self.id = UUID()
self.title = title
self.currentDirectory = FileManager.default.homeDirectoryForCurrentUser.path
let surface = TerminalSurface(tabId: id, context: GHOSTTY_SURFACE_CONTEXT_TAB, configTemplate: nil)
let trimmedWorkingDirectory = workingDirectory?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
let hasWorkingDirectory = !trimmedWorkingDirectory.isEmpty
self.currentDirectory = hasWorkingDirectory
? trimmedWorkingDirectory
: FileManager.default.homeDirectoryForCurrentUser.path
let surface = TerminalSurface(
tabId: id,
context: GHOSTTY_SURFACE_CONTEXT_TAB,
configTemplate: nil,
workingDirectory: hasWorkingDirectory ? trimmedWorkingDirectory : nil
)
self.splitTree = SplitTree(view: surface)
self.focusedSurfaceId = surface.id
}
@ -302,8 +311,14 @@ class TabManager: ObservableObject {
@discardableResult
func addTab() -> Tab {
let newTab = Tab(title: "Terminal \(tabs.count + 1)")
tabs.append(newTab)
let workingDirectory = preferredWorkingDirectoryForNewTab()
let newTab = Tab(title: "Terminal \(tabs.count + 1)", workingDirectory: workingDirectory)
let insertIndex = newTabInsertIndex()
if insertIndex >= 0 && insertIndex <= tabs.count {
tabs.insert(newTab, at: insertIndex)
} else {
tabs.append(newTab)
}
selectedTabId = newTab.id
NotificationCenter.default.post(
name: .ghosttyDidFocusTab,
@ -313,6 +328,27 @@ class TabManager: ObservableObject {
return newTab
}
private func newTabInsertIndex() -> Int {
guard let selectedTabId,
let index = tabs.firstIndex(where: { $0.id == selectedTabId }) else {
return tabs.count
}
return min(index + 1, tabs.count)
}
private func preferredWorkingDirectoryForNewTab() -> String? {
guard let selectedTabId,
let tab = tabs.first(where: { $0.id == selectedTabId }) else {
return nil
}
let focusedDirectory = tab.focusedSurfaceId
.flatMap { tab.surfaceDirectories[$0] }
let candidate = focusedDirectory ?? tab.currentDirectory
let normalized = normalizeDirectory(candidate)
let trimmed = normalized.trimmingCharacters(in: .whitespacesAndNewlines)
return trimmed.isEmpty ? nil : normalized
}
func moveTabToTop(_ tabId: UUID) {
guard let index = tabs.firstIndex(where: { $0.id == tabId }) else { return }
guard index != 0 else { return }