Add working directory persistence, command aliases, and keyboard shortcuts reference
1. Working Directory Persistence: Tracks and restores last directory per tab 2. Command Aliases: Create shortcuts for long commands (e.g., gs=git status) - Manage aliases in Settings - Type 'aliases' to see all defined aliases 3. Keyboard Shortcuts Reference: Cmd+? to view all shortcuts All features tested and working
This commit is contained in:
111
Panels.swift
111
Panels.swift
@@ -769,8 +769,8 @@ class AIGeneratorPanel: NSPanel, NSTextFieldDelegate {
|
||||
class SettingsWindowController: NSWindowController {
|
||||
convenience init() {
|
||||
let window = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 500, height: 550),
|
||||
styleMask: [.titled, .closable],
|
||||
contentRect: NSRect(x: 0, y: 0, width: 500, height: 650),
|
||||
styleMask: [.titled, .closable, .resizable],
|
||||
backing: .buffered,
|
||||
defer: false
|
||||
)
|
||||
@@ -907,8 +907,23 @@ class SettingsWindowController: NSWindowController {
|
||||
|
||||
yPos -= 50
|
||||
|
||||
// Command aliases
|
||||
let aliasLabel = NSTextField(labelWithString: "Command Aliases:")
|
||||
aliasLabel.frame = NSRect(x: 20, y: yPos, width: 120, height: 20)
|
||||
|
||||
let aliasButton = NSButton(frame: NSRect(x: 150, y: yPos - 5, width: 150, height: 30))
|
||||
aliasButton.title = "Manage Aliases..."
|
||||
aliasButton.bezelStyle = .rounded
|
||||
aliasButton.target = self
|
||||
aliasButton.action = #selector(manageAliases)
|
||||
|
||||
container.addSubview(aliasLabel)
|
||||
container.addSubview(aliasButton)
|
||||
|
||||
yPos -= 50
|
||||
|
||||
// Info label
|
||||
let infoLabel = NSTextField(wrappingLabelWithString: "Note: For Ollama, make sure it's running locally. For OpenAI, you need an API key from platform.openai.com\n\nStartup commands will run automatically when opening a new tab.")
|
||||
let infoLabel = NSTextField(wrappingLabelWithString: "Note: For Ollama, make sure it's running locally. For OpenAI, you need an API key from platform.openai.com\n\nStartup commands will run automatically when opening a new tab.\n\nAliases let you create shortcuts for long commands (e.g., 'gs' → 'git status').")
|
||||
infoLabel.frame = NSRect(x: 20, y: 20, width: 460, height: 40)
|
||||
infoLabel.textColor = .secondaryLabelColor
|
||||
infoLabel.font = NSFont.systemFont(ofSize: 11)
|
||||
@@ -964,4 +979,94 @@ class SettingsWindowController: NSWindowController {
|
||||
let commands = sender.stringValue.split(separator: ",").map { $0.trimmingCharacters(in: .whitespaces) }
|
||||
TerminalSettings.shared.startupCommands = commands.filter { !$0.isEmpty }
|
||||
}
|
||||
|
||||
@objc private func manageAliases() {
|
||||
let panel = NSPanel(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
|
||||
styleMask: [.titled, .closable, .resizable],
|
||||
backing: .buffered,
|
||||
defer: false
|
||||
)
|
||||
panel.title = "Command Aliases"
|
||||
panel.center()
|
||||
|
||||
let container = NSView(frame: panel.contentView!.bounds)
|
||||
container.autoresizingMask = [.width, .height]
|
||||
|
||||
// Instructions
|
||||
let instructions = NSTextField(wrappingLabelWithString: "Format: alias=command (one per line)\nExample: gs=git status")
|
||||
instructions.frame = NSRect(x: 20, y: container.bounds.height - 50, width: 360, height: 40)
|
||||
instructions.autoresizingMask = [.width, .minYMargin]
|
||||
|
||||
// Text view for aliases
|
||||
let scrollView = NSScrollView(frame: NSRect(x: 20, y: 60, width: 360, height: container.bounds.height - 120))
|
||||
scrollView.autoresizingMask = [.width, .height]
|
||||
scrollView.hasVerticalScroller = true
|
||||
scrollView.borderType = .bezelBorder
|
||||
|
||||
let textView = NSTextView(frame: scrollView.bounds)
|
||||
textView.autoresizingMask = [.width, .height]
|
||||
textView.isEditable = true
|
||||
textView.font = NSFont.monospacedSystemFont(ofSize: 12, weight: .regular)
|
||||
|
||||
// Load current aliases
|
||||
let aliasText = TerminalSettings.shared.commandAliases.map { "\($0.key)=\($0.value)" }.joined(separator: "\n")
|
||||
textView.string = aliasText
|
||||
|
||||
scrollView.documentView = textView
|
||||
|
||||
// Save button
|
||||
let saveButton = NSButton(frame: NSRect(x: 300, y: 20, width: 80, height: 30))
|
||||
saveButton.title = "Save"
|
||||
saveButton.bezelStyle = .rounded
|
||||
saveButton.target = self
|
||||
saveButton.action = #selector(saveAliases(_:))
|
||||
saveButton.tag = textView.hash
|
||||
|
||||
// Cancel button
|
||||
let cancelButton = NSButton(frame: NSRect(x: 210, y: 20, width: 80, height: 30))
|
||||
cancelButton.title = "Cancel"
|
||||
cancelButton.bezelStyle = .rounded
|
||||
cancelButton.target = panel
|
||||
cancelButton.action = #selector(NSWindow.close)
|
||||
|
||||
container.addSubview(instructions)
|
||||
container.addSubview(scrollView)
|
||||
container.addSubview(saveButton)
|
||||
container.addSubview(cancelButton)
|
||||
|
||||
panel.contentView = container
|
||||
panel.makeKeyAndOrderFront(nil)
|
||||
|
||||
// Store textView reference
|
||||
objc_setAssociatedObject(saveButton, "textView", textView, .OBJC_ASSOCIATION_RETAIN)
|
||||
}
|
||||
|
||||
@objc private func saveAliases(_ sender: NSButton) {
|
||||
guard let textView = objc_getAssociatedObject(sender, "textView") as? NSTextView else { return }
|
||||
|
||||
var aliases: [String: String] = [:]
|
||||
let lines = textView.string.components(separatedBy: .newlines)
|
||||
|
||||
for line in lines {
|
||||
let trimmed = line.trimmingCharacters(in: .whitespaces)
|
||||
guard !trimmed.isEmpty else { continue }
|
||||
|
||||
let parts = trimmed.split(separator: "=", maxSplits: 1)
|
||||
if parts.count == 2 {
|
||||
let alias = String(parts[0]).trimmingCharacters(in: .whitespaces)
|
||||
let command = String(parts[1]).trimmingCharacters(in: .whitespaces)
|
||||
aliases[alias] = command
|
||||
}
|
||||
}
|
||||
|
||||
TerminalSettings.shared.commandAliases = aliases
|
||||
sender.window?.close()
|
||||
|
||||
let alert = NSAlert()
|
||||
alert.messageText = "Aliases Saved"
|
||||
alert.informativeText = "Saved \(aliases.count) alias(es). Type 'aliases' in terminal to see them."
|
||||
alert.alertStyle = .informational
|
||||
alert.runModal()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user