Add comprehensive features: snippets, export/import, tab renaming, session persistence, and enhanced auto-suggestions

- Snippets: Start empty, add via right-click context menu on selected text
- Export/Import: Save and load snippets as JSON files with merge/replace options
- Tab Renaming: Double-click tabs to rename them
- Session Persistence: Tabs and their names are saved and restored on app restart
- Delete Snippets: Remove unwanted snippets from the panel
- Auto-suggestions: Comprehensive command database with 400+ commands
  - Includes Git, Docker, Kubernetes, NPM, Python, Ruby, Rust, Go, and more
  - Suggestions from command history, common commands, and system PATH
  - Updates in real-time as you type
  - Press Tab to accept suggestions
- Fixed tab content persistence when switching between tabs
- Fixed tab bar layout and positioning
- All features fully functional and tested
This commit is contained in:
2026-01-31 23:17:02 +00:00
parent 5874b31464
commit 8573e09563
7 changed files with 611 additions and 48 deletions

View File

@@ -26,7 +26,9 @@ class MainWindowController: NSWindowController {
setupUI()
setupPanels()
setupNotifications()
addNewTab()
// Restore previous session or create new tab
restoreSession()
// Force window to show
window.makeKeyAndOrderFront(nil)
@@ -38,6 +40,28 @@ class MainWindowController: NSWindowController {
NSLog("Window content view: \(window.contentView?.frame ?? .zero)")
}
private func restoreSession() {
let savedSessions = tabManager.loadSession()
if savedSessions.isEmpty {
// No saved session, create default tab
addNewTab()
} else {
// Restore saved tabs
for sessionData in savedSessions {
let session = tabManager.addTab(title: sessionData.title)
session.title = sessionData.title // Override the auto-generated title
session.setupTextView(frame: contentView.bounds)
session.startShell()
}
// Restore current tab index
let savedIndex = tabManager.getSavedCurrentIndex()
updateTabBar()
switchToTab(index: min(savedIndex, tabManager.tabs.count - 1))
}
}
private func setupUI() {
guard let window = window else { return }
@@ -203,7 +227,7 @@ class MainWindowController: NSWindowController {
tabBar.arrangedSubviews.forEach { $0.removeFromSuperview() }
// Add tab buttons
for (index, _) in tabManager.tabs.enumerated() {
for (index, session) in tabManager.tabs.enumerated() {
// Create container for tab button and close button
let tabContainer = NSView()
tabContainer.wantsLayer = true
@@ -211,7 +235,7 @@ class MainWindowController: NSWindowController {
// Tab button
let tabButton = NSButton()
tabButton.title = "Tab \(index + 1)"
tabButton.title = session.title
tabButton.bezelStyle = .rounded
tabButton.tag = index
tabButton.target = self
@@ -219,6 +243,11 @@ class MainWindowController: NSWindowController {
tabButton.font = NSFont.systemFont(ofSize: 11)
tabButton.translatesAutoresizingMaskIntoConstraints = false
// Add double-click for rename
let doubleClickGesture = NSClickGestureRecognizer(target: self, action: #selector(tabDoubleClicked(_:)))
doubleClickGesture.numberOfClicksRequired = 2
tabButton.addGestureRecognizer(doubleClickGesture)
// Highlight current tab
if index == tabManager.currentIndex {
tabButton.contentTintColor = .systemBlue
@@ -321,6 +350,34 @@ class MainWindowController: NSWindowController {
switchToTab(index: sender.tag)
}
@objc func tabDoubleClicked(_ sender: NSClickGestureRecognizer) {
guard let button = sender.view as? NSButton else { return }
let index = button.tag
let alert = NSAlert()
alert.messageText = "Rename Tab"
alert.informativeText = "Enter a new name for this tab:"
let textField = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
textField.stringValue = tabManager.tabs[index].title
textField.placeholderString = "Tab name"
alert.accessoryView = textField
alert.addButton(withTitle: "Rename")
alert.addButton(withTitle: "Cancel")
alert.window.initialFirstResponder = textField
if alert.runModal() == .alertFirstButtonReturn {
let newName = textField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
if !newName.isEmpty {
tabManager.tabs[index].title = newName
updateTabBar()
tabManager.saveSession()
}
}
}
private func switchToTab(index: Int) {
guard index < tabManager.tabs.count else { return }
@@ -329,6 +386,7 @@ class MainWindowController: NSWindowController {
// Select the new tab
tabManager.selectTab(at: index)
tabManager.saveSession()
// Add the selected tab's scroll view to content view
if let session = tabManager.getCurrentSession() {