Added support for comma-separated words for word replacement.

This commit is contained in:
Beingpax 2025-09-12 11:21:00 +05:45
parent 8334f75360
commit f1fb2168c2
3 changed files with 46 additions and 20 deletions

View File

@ -15,12 +15,10 @@ class WordReplacementService {
// Apply replacements (case-insensitive)
for (original, replacement) in replacements {
let isPhrase = original.contains(" ") || original.trimmingCharacters(in: .whitespacesAndNewlines) != original
let usesBoundaries = usesWordBoundaries(for: original)
if isPhrase || !usesWordBoundaries(for: original) {
modifiedText = modifiedText.replacingOccurrences(of: original, with: replacement, options: .caseInsensitive)
} else {
// Use word boundaries for spaced languages
if usesBoundaries {
// Word-boundary regex for full original string
let pattern = "\\b\(NSRegularExpression.escapedPattern(for: original))\\b"
if let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) {
let range = NSRange(modifiedText.startIndex..., in: modifiedText)
@ -31,6 +29,9 @@ class WordReplacementService {
withTemplate: replacement
)
}
} else {
// Fallback substring replace for non-spaced scripts
modifiedText = modifiedText.replacingOccurrences(of: original, with: replacement, options: .caseInsensitive)
}
}

View File

@ -1,8 +1,5 @@
import SwiftUI
/// A reusable sheet for editing an existing word replacement entry.
/// Mirrors the UI of `AddReplacementSheet` for consistency while pre-populating
/// the fields with the existing values.
// Edit existing word replacement entry
struct EditReplacementSheet: View {
@ObservedObject var manager: WordReplacementManager
let originalKey: String
@ -84,8 +81,9 @@ struct EditReplacementSheet: View {
.font(.caption)
.foregroundColor(.secondary)
}
TextField("Enter word or phrase to replace", text: $originalWord)
TextField("Enter word or phrase to replace (use commas for multiple)", text: $originalWord)
.textFieldStyle(.roundedBorder)
}
.padding(.horizontal)
@ -117,7 +115,12 @@ struct EditReplacementSheet: View {
private func saveChanges() {
let newOriginal = originalWord.trimmingCharacters(in: .whitespacesAndNewlines)
let newReplacement = replacementWord.trimmingCharacters(in: .whitespacesAndNewlines)
guard !newOriginal.isEmpty, !newReplacement.isEmpty else { return }
// Ensure at least one non-empty token
let tokens = newOriginal
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
guard !tokens.isEmpty, !newReplacement.isEmpty else { return }
manager.updateReplacement(oldOriginal: originalKey, newOriginal: newOriginal, newReplacement: newReplacement)
dismiss()

View File

@ -23,7 +23,15 @@ class WordReplacementManager: ObservableObject {
}
func addReplacement(original: String, replacement: String) {
replacements[original] = replacement
// Support comma-separated originals mapping to the same replacement
let tokens = original
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
guard !tokens.isEmpty else { return }
for token in tokens {
replacements[token] = replacement
}
}
func removeReplacement(original: String) {
@ -31,12 +39,18 @@ class WordReplacementManager: ObservableObject {
}
func updateReplacement(oldOriginal: String, newOriginal: String, newReplacement: String) {
// Remove the old key if the original text has changed
if oldOriginal != newOriginal {
replacements.removeValue(forKey: oldOriginal)
// Always remove the old key being edited
replacements.removeValue(forKey: oldOriginal)
// Add one or more new keys (comma-separated) pointing to the same replacement
let tokens = newOriginal
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
guard !tokens.isEmpty else { return }
for token in tokens {
replacements[token] = newReplacement
}
// Update (or insert) the new key/value pair
replacements[newOriginal] = newReplacement
}
}
@ -142,7 +156,7 @@ struct EmptyStateView: View {
Text("No Replacements")
.font(.headline)
Text("Add word replacements to automatically replace text during AI enhancement.")
Text("Add word replacements to automatically replace text.")
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
@ -221,9 +235,12 @@ struct AddReplacementSheet: View {
.foregroundColor(.secondary)
}
TextField("Enter word or phrase to replace", text: $originalWord)
TextField("Enter word or phrase to replace (use commas for multiple)", text: $originalWord)
.textFieldStyle(.roundedBorder)
.font(.body)
Text("Separate multiple originals with commas, e.g. Voicing, Voice ink, Voiceing")
.font(.caption)
.foregroundColor(.secondary)
}
.padding(.horizontal)
@ -297,7 +314,12 @@ struct AddReplacementSheet: View {
let original = originalWord
let replacement = replacementWord
guard !original.isEmpty && !replacement.isEmpty else { return }
// Validate that at least one non-empty token exists
let tokens = original
.split(separator: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
guard !tokens.isEmpty && !replacement.isEmpty else { return }
manager.addReplacement(original: original, replacement: replacement)
dismiss()