Skip to content

Commit be4be7f

Browse files
committed
Register Content Reloads with UndoManager
1 parent c3ad843 commit be4be7f

1 file changed

Lines changed: 29 additions & 8 deletions

File tree

CodeEdit/Features/Documents/CodeFileDocument/CodeFileDocument.swift

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import CodeEditTextView
1414
import CodeEditLanguages
1515
import Combine
1616
import OSLog
17+
import TextStory
1718

1819
enum CodeFileError: Error {
1920
case failedToDecode
@@ -161,18 +162,38 @@ final class CodeFileDocument: NSDocument, ObservableObject {
161162
convertedString: &nsString,
162163
usedLossyConversion: nil
163164
)
164-
if let validEncoding = FileEncoding(rawEncoding), let nsString {
165-
self.sourceEncoding = validEncoding
166-
if let content {
167-
content.mutableString.setString(nsString as String)
168-
} else {
169-
self.content = NSTextStorage(string: nsString as String)
170-
}
171-
} else {
165+
guard let validEncoding = FileEncoding(rawEncoding), let nsString else {
172166
Self.logger.error("Failed to read file from data using encoding: \(rawEncoding)")
167+
return
168+
}
169+
self.sourceEncoding = validEncoding
170+
if let content {
171+
registerContentChangeUndo(fileURL: fileURL, nsString: nsString, content: content)
172+
content.mutableString.setString(nsString as String)
173+
} else {
174+
self.content = NSTextStorage(string: nsString as String)
173175
}
174176
NotificationCenter.default.post(name: Self.didOpenNotification, object: self)
175177
}
178+
179+
/// If this file is already open and being tracked by an undo manager, we register an undo mutation
180+
/// of the entire contents. This allows the user to undo changes that occurred outside of CodeEdit
181+
/// while the file was displayed in CodeEdit.
182+
///
183+
/// - Note: This is inefficient memory-wise. We could do a diff of the file and only register the
184+
/// mutations that would recreate the diff. However, that would instead be CPU intensive.
185+
/// Tradeoffs.
186+
private func registerContentChangeUndo(fileURL: URL?, nsString: NSString, content: NSTextStorage) {
187+
guard let fileURL else { return }
188+
// If there's an undo manager, register a mutation replacing the entire contents.
189+
let mutation = TextMutation(
190+
string: nsString as String,
191+
range: NSRange(location: 0, length: content.length),
192+
limit: content.length
193+
)
194+
let undoManager = self.findWorkspace()?.undoRegistration.managerIfExists(forFile: fileURL)
195+
undoManager?.registerMutation(mutation)
196+
}
176197

177198
// MARK: - Autosave
178199

0 commit comments

Comments
 (0)