feat: add note formatting keyboard shortcuts

This commit is contained in:
2026-10-19 20:28:44 +02:00
parent 04bfd785e7
commit c53ad3515a
4 changed files with 126 additions and 11 deletions
+74 -1
View File
@@ -80,7 +80,7 @@ func hiddenNoteMarkupKeepsTypingDeletionFormattingAndUndoAtVisibleBoundaries() t
editor.moveRight(nil)
#expect(editor.selectedRange().location == editor.string.utf16.count)
editor.setSelectedRange(NSRange(location: word.location, length: 0))
let italic = try #require(descendants(controller.view).compactMap { $0 as? NSButton }.first { $0.toolTip == "Italic" })
let italic = try #require(descendants(controller.view).compactMap { $0 as? NSButton }.first { $0.accessibilityLabel() == "Italic" })
// Selecting the body and toggling formatting must remove its hidden delimiters.
editor.setSelectedRange(word)
italic.performClick(nil)
@@ -88,3 +88,76 @@ func hiddenNoteMarkupKeepsTypingDeletionFormattingAndUndoAtVisibleBoundaries() t
#expect(controller.save())
#expect(try NotesStore(directory: directory).notes.first?.contents.string == "# ATitle\nword")
}
@Test @MainActor
func notesFormattingShortcutsToggleCombinedStylesAndRespectPopupFocus() throws {
_ = NSApplication.shared
let suite = "NotesFormattingKeys.\(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 launcher = LauncherWindowController(
history: LaunchHistory(defaults: defaults, now: { Date(timeIntervalSinceReferenceDate: 12_000) }),
defaults: defaults, notesDirectory: directory)
let window = try #require(launcher.window)
defer { launcher.dismiss(restoringFocus: false) }
launcher.present(command: .notes)
let content = try #require(window.contentView)
func descendants(_ view: NSView) -> [NSView] { [view] + view.subviews.flatMap(descendants) }
let editor = try #require(descendants(content).compactMap { $0 as? NotesTextView }.first)
let controller = try #require(editor.delegate as? NotesController)
func shortcut(_ key: String, shift: Bool = false, option: Bool = false) throws -> Bool {
var flags: NSEvent.ModifierFlags = .command
if shift { flags.insert(.shift) }
if option { flags.insert(.option) }
let event = try #require(NSEvent.keyEvent(with: .keyDown, location: .zero, modifierFlags: flags,
timestamp: 1, windowNumber: window.windowNumber, context: nil,
characters: shift ? key.uppercased() : key, charactersIgnoringModifiers: shift ? key.uppercased() : key,
isARepeat: false, keyCode: 0))
return window.performKeyEquivalent(with: event)
}
editor.insertText("fox 🦊", replacementRange: editor.selectedRange())
editor.setSelectedRange(NSRange(location: 0, length: editor.string.utf16.count))
#expect(try shortcut("b"))
#expect(editor.markdownString == "**fox 🦊**")
#expect(try shortcut("i"))
#expect(editor.markdownString == "***fox 🦊***")
let font = try #require(editor.textStorage?.attribute(.font, at: editor.selectedRange().location,
effectiveRange: nil) as? NSFont)
let traits = NSFontManager.shared.traits(of: font)
#expect(traits.contains(.boldFontMask) && traits.contains(.italicFontMask))
#expect(try shortcut("i"))
#expect(editor.markdownString == "**fox 🦊**")
#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))
#expect(editor.markdownString == "fox 🦊")
#expect(!(try shortcut("b", option: true)))
#expect(editor.markdownString == "fox 🦊")
editor.breakUndoCoalescing()
editor.undoManager?.removeAllActions()
editor.undoManager?.beginUndoGrouping()
#expect(try shortcut("e"))
editor.undoManager?.endUndoGrouping()
#expect(editor.markdownString == "`fox 🦊`")
editor.undoManager?.undo()
#expect(editor.markdownString == "fox 🦊")
#expect(try shortcut("k"))
let search = try #require(descendants(content).compactMap { $0 as? NSSearchField }.first { $0.accessibilityLabel() == "Search notes actions" })
#expect(window.firstResponder !== editor)
_ = try shortcut("b")
#expect(editor.markdownString == "fox 🦊")
#expect(search.stringValue.isEmpty)
#expect(controller.handle(#selector(NSResponder.cancelOperation(_:))))
#expect(controller.save())
#expect(try NotesStore(directory: directory).notes.first?.contents.string == "fox 🦊")
}