Files
EnhancedTerminal/SnippetManager.swift
Paul Bailey 8573e09563 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
2026-01-31 23:17:02 +00:00

95 lines
2.8 KiB
Swift

import Foundation
// MARK: - Command Snippet Manager
class SnippetManager {
static let shared = SnippetManager()
private var snippets: [Snippet] = []
struct Snippet: Codable {
let id: UUID
var name: String
var command: String
var description: String
var tags: [String]
var category: String
init(name: String, command: String, description: String = "", tags: [String] = [], category: String = "General") {
self.id = UUID()
self.name = name
self.command = command
self.description = description
self.tags = tags
self.category = category
}
}
init() {
loadSnippets()
// Start with empty snippets - user will add via right-click
}
func addSnippet(_ snippet: Snippet) {
snippets.append(snippet)
saveSnippets()
}
func removeSnippet(_ id: UUID) {
snippets.removeAll { $0.id == id }
saveSnippets()
}
func searchSnippets(_ query: String) -> [Snippet] {
if query.isEmpty { return snippets }
return snippets.filter {
$0.name.localizedCaseInsensitiveContains(query) ||
$0.command.localizedCaseInsensitiveContains(query) ||
$0.category.localizedCaseInsensitiveContains(query) ||
$0.tags.contains { $0.localizedCaseInsensitiveContains(query) }
}
}
func getAllSnippets() -> [Snippet] {
return snippets
}
func exportSnippets() -> Data? {
return try? JSONEncoder().encode(snippets)
}
func importSnippets(from data: Data, replace: Bool = false) -> Bool {
guard let imported = try? JSONDecoder().decode([Snippet].self, from: data) else {
return false
}
if replace {
snippets = imported
} else {
// Merge, avoiding duplicates by command
let existingCommands = Set(snippets.map { $0.command })
let newSnippets = imported.filter { !existingCommands.contains($0.command) }
snippets.append(contentsOf: newSnippets)
}
saveSnippets()
return true
}
private func addDefaultSnippets() {
// Removed - snippets now start empty
// Users can add snippets via right-click context menu
}
private func saveSnippets() {
if let data = try? JSONEncoder().encode(snippets) {
UserDefaults.standard.set(data, forKey: "terminal_snippets")
}
}
private func loadSnippets() {
if let data = UserDefaults.standard.data(forKey: "terminal_snippets"),
let loaded = try? JSONDecoder().decode([Snippet].self, from: data) {
snippets = loaded
}
}
}