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:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user