Skip to content

Commit 442308e

Browse files
committed
tests for the caret fix
1 parent 73be292 commit 442308e

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import AppKit
2+
import Testing
3+
4+
@testable import Spotlight
5+
6+
@MainActor
7+
@Suite("Multiline editor vim logical line motions")
8+
struct MultilineEditorVimLogicalLineMotionTests {
9+
@Test("j steps one logical line at a time over checklist markers")
10+
func downOverChecklistMarkers() {
11+
let textView = makeVimMotionTextView(text: "plain\n☐ one\n☐ two\n☑ three\nafter")
12+
textView.setSelectedRange(NSRange(location: 0, length: 0))
13+
14+
textView.executeMotion(.down(1))
15+
#expect(textView.selectedRange.location == ("plain\n" as NSString).length)
16+
17+
textView.executeMotion(.down(1))
18+
#expect(textView.selectedRange.location == ("plain\n☐ one\n" as NSString).length)
19+
}
20+
21+
@Test("j and k step through fenced code block lines")
22+
func verticalMotionsOverFencedCodeBlock() {
23+
let textView = makeVimMotionTextView(text: "before\n```swift\nlet x = 1\nlet y = 2\n```\nafter")
24+
textView.setSelectedRange(NSRange(location: 0, length: 0))
25+
26+
textView.executeMotion(.down(3))
27+
#expect(textView.selectedRange.location == ("before\n```swift\nlet x = 1\n" as NSString).length)
28+
29+
textView.executeMotion(.up(1))
30+
#expect(textView.selectedRange.location == ("before\n```swift\n" as NSString).length)
31+
}
32+
33+
@Test("normal mode caret at code block line start uses that line fragment")
34+
func lineStartCaretRectInsideCodeBlock() {
35+
let textView = makeVimMotionTextView(text: "before\n```cpp\nint x;\nint y;\n```\nafter")
36+
let lineStart = ("before\n```cpp\n" as NSString).length
37+
textView.setSelectedRange(NSRange(location: lineStart, length: 0))
38+
39+
let rect = textView.normalizedInsertionPointRect(
40+
NSRect(x: 0, y: 0, width: 1, height: EditorMetrics.lineHeight)
41+
)
42+
43+
#expect(rect.origin.y == EditorMetrics.lineHeight * 2)
44+
}
45+
46+
@Test("insert caret at closing fence end keeps the fence column")
47+
func closingFenceEndCaretRectKeepsXPosition() {
48+
let textView = makeVimMotionTextView(text: "before\n```cpp\nint x;\n```\nafter")
49+
let fenceEnd = ("before\n```cpp\nint x;\n```" as NSString).length
50+
textView.setSelectedRange(NSRange(location: fenceEnd, length: 0))
51+
52+
let rect = textView.normalizedInsertionPointRect(
53+
NSRect(x: 0, y: 0, width: 1, height: EditorMetrics.lineHeight)
54+
)
55+
56+
#expect(rect.origin.y == EditorMetrics.lineHeight * 3)
57+
#expect(rect.origin.x > 1)
58+
}
59+
60+
@Test("trailing newline caret still uses the extra line fragment")
61+
func trailingNewlineCaretRectUsesExtraLineFragment() {
62+
let textView = makeVimMotionTextView(text: "before\n")
63+
textView.setSelectedRange(NSRange(location: ("before\n" as NSString).length, length: 0))
64+
65+
let rect = textView.normalizedInsertionPointRect(
66+
NSRect(x: 0, y: 0, width: 1, height: EditorMetrics.lineHeight)
67+
)
68+
69+
#expect(rect.origin.y == EditorMetrics.lineHeight)
70+
}
71+
72+
private func makeVimMotionTextView(text: String) -> PlaceholderTextView {
73+
let textView = PlaceholderTextView(frame: NSRect(x: 0, y: 0, width: EditorMetrics.panelWidth, height: 240))
74+
textView.font = .systemFont(ofSize: EditorMetrics.fontSize)
75+
textView.string = text
76+
textView.textContainer?.lineFragmentPadding = 0
77+
textView.textContainer?.widthTracksTextView = true
78+
guard let storage = textView.textStorage,
79+
let container = textView.textContainer
80+
else { return textView }
81+
let fixed = FixedLineHeightLayoutManager()
82+
fixed.fixedLineHeight = EditorMetrics.lineHeight
83+
fixed.editorFont = textView.font ?? .systemFont(ofSize: EditorMetrics.fontSize)
84+
if let existing = storage.layoutManagers.first {
85+
storage.removeLayoutManager(existing)
86+
}
87+
storage.addLayoutManager(fixed)
88+
fixed.addTextContainer(container)
89+
CodeStyler.apply(to: textView, theme: ThemeCatalog.obsidian)
90+
return textView
91+
}
92+
}

0 commit comments

Comments
 (0)