Skip to content

Commit 80fb884

Browse files
Fix End of Doc Bugs (#112)
### Description Fixes a few end-of-document bugs: - `rectForOffset` had an incorrect `!=` instead of a `<` check for the end of the document. - `mouseDown` needed to be looser on finding content runs for the end of documents. Adds test cases that would have caught both these bugs. ### Related Issues N/A ### Checklist <!--- Add things that are not yet implemented above --> - [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md) - [x] The issues this PR addresses are related to each other - [x] My changes generate no new warnings - [x] My code builds and runs on my machine - [x] My changes are all related to the related issue above - [x] I documented my code ### Screenshots N/A
1 parent 8f02a6b commit 80fb884

File tree

4 files changed

+32
-4
lines changed

4 files changed

+32
-4
lines changed

Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager+Public.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ extension TextLayoutManager {
166166
/// - Parameter offset: The offset to create the rect for.
167167
/// - Returns: The found rect for the given offset.
168168
public func rectForOffset(_ offset: Int) -> CGRect? {
169-
guard offset != lineStorage.length else {
169+
guard offset < lineStorage.length else {
170170
return rectForEndOffset()
171171
}
172172
guard let linePosition = determineVisiblePosition(for: lineStorage.getLine(atOffset: offset))?.position else {

Sources/CodeEditTextView/TextView/TextView+Mouse.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ extension TextView {
1212
// Set cursor
1313
guard isSelectable,
1414
event.type == .leftMouseDown,
15-
let offset = layoutManager.textOffsetAtPoint(self.convert(event.locationInWindow, from: nil)),
16-
let content = layoutManager.contentRun(at: offset) else {
15+
let offset = layoutManager.textOffsetAtPoint(self.convert(event.locationInWindow, from: nil)) else {
1716
super.mouseDown(with: event)
1817
return
1918
}
2019

21-
if case let .attachment(attachment) = content.data, event.clickCount < 3 {
20+
if let content = layoutManager.contentRun(at: offset),
21+
case let .attachment(attachment) = content.data, event.clickCount < 3 {
2222
handleAttachmentClick(event: event, offset: offset, attachment: attachment)
2323
return
2424
}

Tests/CodeEditTextViewTests/LayoutManager/TextLayoutManagerTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,26 @@ struct TextLayoutManagerTests {
228228
let invalidatedLineIds = layoutManager.layoutLines()
229229
#expect(Set(expectedLineIds) == invalidatedLineIds)
230230
}
231+
232+
@Test
233+
func rectForOffsetReturnsValueAfterEndOfDoc() throws {
234+
layoutManager.layoutLines(in: NSRect(x: 0, y: 0, width: 1000, height: 1000))
235+
236+
for idx in 0..<10 {
237+
// This should return something even after the end of the document.
238+
#expect(layoutManager.rectForOffset(idx) != nil, "Failed to find rect for offset: \(idx)")
239+
}
240+
}
241+
242+
@Test
243+
func textOffsetForPointReturnsValuesEverywhere() throws {
244+
layoutManager.layoutLines(in: NSRect(x: 0, y: 0, width: 1000, height: 1000))
245+
246+
// textOffsetAtPoint is valid *everywhere*. It should always return something.
247+
for xPos in 0..<1000 {
248+
for yPos in 0..<1000 {
249+
#expect(layoutManager.textOffsetAtPoint(CGPoint(x: xPos, y: yPos)) != nil)
250+
}
251+
}
252+
}
231253
}

Tests/CodeEditTextViewTests/TextSelectionManagerTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,10 @@ final class TextSelectionManagerTests: XCTestCase {
217217
)
218218
}
219219
}
220+
221+
func test_selectionEndOfDocumentHasXPos() {
222+
let selectionManager = selectionManager("1\n2\n3\n")
223+
selectionManager.setSelectedRange(NSRange(location: 6, length: 0)) // Beyond text.length, end of doc
224+
XCTAssertNotNil(selectionManager.textSelections.first?.suggestedXPos)
225+
}
220226
}

0 commit comments

Comments
 (0)