- 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
95 lines
2.8 KiB
Swift
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
|
|
}
|
|
}
|
|
}
|