fix: batch note formatting to prevent typing flashes

This commit is contained in:
Valdemar Lorenzen
2026-10-20 12:41:55 +02:00
parent f6d9d04b74
commit 3dfd9f58a4
5 changed files with 63 additions and 10 deletions
+51 -2
View File
@@ -41,6 +41,57 @@ func noteFormattingHidesSyntaxButPreservesMarkdownAndLiteralCode() throws {
#expect(reloaded.contents.string == source)
}
private final class NotesLayoutProbe: NSLayoutManager {
var observeFormatting: ((NSTextStorage) -> Void)?
override func processEditing(for textStorage: NSTextStorage, edited editMask: NSTextStorageEditActions,
range newCharRange: NSRange, changeInLength delta: Int,
invalidatedRange invalidatedCharRange: NSRange) {
observeFormatting?(textStorage)
super.processEditing(for: textStorage, edited: editMask, range: newCharRange,
changeInLength: delta, invalidatedRange: invalidatedCharRange)
}
}
@Test @MainActor
func typingDoesNotExposeUnformattedExistingTextToLayout() throws {
_ = NSApplication.shared
let suite = "NotesFlashing.\(UUID().uuidString)"
let defaults = try #require(UserDefaults(suiteName: suite))
let directory = FileManager.default.temporaryDirectory.appendingPathComponent(suite)
defer {
defaults.removePersistentDomain(forName: suite)
try? FileManager.default.removeItem(at: directory)
}
let store = try NotesStore(directory: directory)
let id = try store.create()
try store.update(id: id, contents: NSAttributedString(string: "# Heading\n- [ ] Task\nPlain"))
defaults.set(id.uuidString, forKey: "selectedNote")
let controller = NotesController(defaults: defaults, directory: directory)
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 570, height: 404),
styleMask: .borderless, backing: .buffered, defer: false)
window.contentViewController = controller
defer { _ = controller.close(); window.orderOut(nil) }
func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) }
let editor = try #require(descendants(controller.view).compactMap { $0 as? NotesTextView }.first)
let layout = NotesLayoutProbe()
try #require(editor.textContainer).replaceLayoutManager(layout)
editor.refreshTasks()
window.makeFirstResponder(editor)
layout.observeFormatting = { storage in
let text = storage.string as NSString
let heading = text.range(of: "Heading")
let task = text.range(of: "Task")
#expect((storage.attribute(.font, at: heading.location, effectiveRange: nil) as? NSFont)?.pointSize == 26)
#expect((storage.attribute(.paragraphStyle, at: task.location, effectiveRange: nil) as? NSParagraphStyle)?.headIndent == 22)
#expect(storage.attribute(MarkdownHighlighting.hiddenMarkup, at: 0, effectiveRange: nil) as? Bool == true)
}
defer { layout.observeFormatting = nil }
editor.insertText("!", replacementRange: NSRange(location: editor.string.utf16.count, length: 0))
#expect(editor.markdownString == "# Heading\n- [ ] Task\nPlain!")
#expect(try NotesStore(directory: directory).notes.first?.contents.string == editor.markdownString)
}
@Test @MainActor
func noteImagesRenderRoundedWithoutChangingSavedImageData() throws {
_ = NSApplication.shared
@@ -196,8 +247,6 @@ func notesFormattingShortcutsToggleCombinedStylesAndRespectPopupFocus() throws {
#expect(try shortcut("b"))
#expect(editor.markdownString == "fox 🦊")
let hide = try #require(descendants(content).compactMap { $0 as? NSButton }.first { $0.toolTip == "Hide formatting" })
hide.performClick(nil)
#expect(try shortcut("x", shift: true))
#expect(editor.markdownString == "~~fox 🦊~~")
#expect(try shortcut("x", shift: true))