mirror of
https://github.com/BigMarc/grammargem.git
synced 2026-10-13 17:01:55 +02:00
- Added LiveMonitor class to scan text areas in the frontmost window for grammar and spelling issues. - Introduced DetectedField struct to represent text areas with issues, including suggestions for corrections. - Implemented functionality to apply corrections and dismiss suggestions. - Added Permissions class to manage Accessibility permissions required for monitoring. - Created SnippetStore for managing text-expansion snippets, including persistence to UserDefaults. - Developed TextCapture class to read and write text from the frontmost application using Accessibility API and clipboard fallback. - Implemented TextFieldScanner to traverse the Accessibility tree and collect editable text elements. - Added TextReplacementCoordinator to orchestrate the text correction process. - Integrated UpdaterManager for handling application updates using Sparkle. - Created comprehensive unit tests for various components, including grammar corrections and entitlement checks.
52 lines
1.5 KiB
Swift
52 lines
1.5 KiB
Swift
import Foundation
|
|
|
|
/// A text-expansion snippet: type a short trigger, get a longer expansion.
|
|
struct Snippet: Codable, Identifiable, Equatable {
|
|
var id = UUID()
|
|
var trigger: String
|
|
var expansion: String
|
|
}
|
|
|
|
/// Local store for text-expansion snippets (a paid feature). Persisted to disk;
|
|
/// snippet contents never leave the device.
|
|
@MainActor
|
|
final class SnippetStore: ObservableObject {
|
|
@Published private(set) var snippets: [Snippet]
|
|
|
|
private let key = "GrammaGem.snippets"
|
|
private let d = UserDefaults.standard
|
|
|
|
init() {
|
|
if let raw = d.data(forKey: key),
|
|
let decoded = try? JSONDecoder().decode([Snippet].self, from: raw) {
|
|
snippets = decoded
|
|
} else {
|
|
snippets = []
|
|
}
|
|
}
|
|
|
|
func add(trigger: String, expansion: String) {
|
|
let t = trigger.trimmingCharacters(in: .whitespaces)
|
|
let e = expansion.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard !t.isEmpty, !e.isEmpty else { return }
|
|
snippets.append(Snippet(trigger: t, expansion: e))
|
|
persist()
|
|
}
|
|
|
|
func remove(_ snippet: Snippet) {
|
|
snippets.removeAll { $0.id == snippet.id }
|
|
persist()
|
|
}
|
|
|
|
/// Resolve a trigger to its expansion (used by the snippet hotkey path).
|
|
func expansion(for trigger: String) -> String? {
|
|
snippets.first { $0.trigger == trigger }?.expansion
|
|
}
|
|
|
|
private func persist() {
|
|
if let raw = try? JSONEncoder().encode(snippets) {
|
|
d.set(raw, forKey: key)
|
|
}
|
|
}
|
|
}
|