refactor: use structured rich text for Notes editing

This commit is contained in:
2026-10-22 13:13:31 +02:00
parent 5803a00944
commit 751f22f6b1
20 changed files with 2155 additions and 2583 deletions
+30 -27
View File
@@ -1,41 +1,44 @@
import AppKit
import ConjureKit
import Testing
@testable import Conjure
@Test @MainActor func numberedMarkersShareTheBodyTextBaseline() throws {
_ = NSApplication.shared
let editor = NotesTextView(frame: NSRect(x: 0, y: 0, width: 400, height: 200))
for source in ["1. 1", "123) 123", " 12. 12"] {
editor.setMarkdownContents(NSAttributedString(string: source))
MarkdownHighlighting.apply(to: editor)
editor.refreshTasks()
editor.drawsBackground = false
let window = NSWindow(contentRect: editor.frame, styleMask: .borderless, backing: .buffered, defer: false)
window.contentView = editor
defer { window.orderOut(nil) }
for source in ["1. 1", "123. 123", " 12. 12"] {
editor.setDocumentContents(NoteDocument.importMarkdown(NSAttributedString(string: source)))
let layout = try #require(editor.layoutManager)
let container = try #require(editor.textContainer)
layout.ensureLayout(for: container)
let text = editor.string as NSString
let marker = text.range(of: "\u{fffc}")
let body = NSRange(location: NSMaxRange(marker) + 1, length: text.length - NSMaxRange(marker) - 1)
var bottoms: [Int] = []
for range in [marker, body] {
let bitmap = try #require(NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: 400, pixelsHigh: 80,
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0))
let bitmapContext = try #require(NSGraphicsContext(bitmapImageRep: bitmap))
bitmapContext.cgContext.translateBy(x: 0, y: 80)
bitmapContext.cgContext.scaleBy(x: 1, y: -1)
let context = NSGraphicsContext(cgContext: bitmapContext.cgContext, flipped: true)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = context
context.cgContext.clear(CGRect(x: 0, y: 0, width: 400, height: 80))
layout.drawGlyphs(forGlyphRange: layout.glyphRange(forCharacterRange: range, actualCharacterRange: nil), at: .zero)
NSGraphicsContext.restoreGraphicsState()
var bottom = -1
for y in 0..<80 {
for x in 0..<400 where (bitmap.colorAt(x: x, y: y)?.alphaComponent ?? 0) > 0.2 { bottom = y }
let glyph = layout.glyphIndexForCharacter(at: 0)
let fragment = layout.lineFragmentRect(forGlyphAt: glyph, effectiveRange: nil)
let bodyX = editor.textContainerOrigin.x + fragment.minX + layout.location(forGlyphAt: glyph).x
let bitmap = try #require(NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: 400, pixelsHigh: 200,
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0))
let bitmapContext = try #require(NSGraphicsContext(bitmapImageRep: bitmap))
bitmapContext.cgContext.translateBy(x: 0, y: 200)
bitmapContext.cgContext.scaleBy(x: 1, y: -1)
let context = NSGraphicsContext(cgContext: bitmapContext.cgContext, flipped: true)
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = context
context.cgContext.clear(CGRect(x: 0, y: 0, width: 400, height: 200))
editor.draw(editor.bounds)
NSGraphicsContext.restoreGraphicsState()
var markerBottom = -1, bodyBottom = -1
for y in 0..<200 {
for x in 0..<400 where (bitmap.colorAt(x: x, y: y)?.alphaComponent ?? 0) > 0.2 {
if CGFloat(x) < bodyX - 1 { markerBottom = y }
else { bodyBottom = y }
}
try #require(bottom >= 0)
bottoms.append(bottom)
}
#expect(abs(bottoms[0] - bottoms[1]) <= 1, "Marker/body ink baseline for \(source)")
try #require(markerBottom >= 0 && bodyBottom >= 0)
#expect(abs(markerBottom - bodyBottom) <= 1, "Marker/body ink baseline for \(source)")
#expect(!editor.string.contains("\u{fffc}"))
}
}