Skip to content

Commit fb70a58

Browse files
committed
Fix Lint Errors, Clean Up Calculator
1 parent aa89ce2 commit fb70a58

File tree

5 files changed

+121
-85
lines changed

5 files changed

+121
-85
lines changed

Sources/CodeEditSourceEditor/Extensions/NSBezierPath+RoundedCorners.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ extension NSBezierPath {
2424
public static let bottomRight = Corners(rawValue: 1 << 3)
2525
}
2626

27+
// swiftlint:disable:next function_body_length
2728
convenience init(rect: CGRect, roundedCorners corners: Corners, cornerRadius: CGFloat) {
2829
self.init()
2930

@@ -95,7 +96,6 @@ extension NSBezierPath {
9596
close()
9697
}
9798

98-
9999
convenience init(roundingRect: CGRect, capTop: Bool, capBottom: Bool, cornerRadius radius: CGFloat) {
100100
switch (capTop, capBottom) {
101101
case (true, true):

Sources/CodeEditSourceEditor/LineFolding/Model/LineFoldCalculator.swift

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,13 @@ actor LineFoldCalculator {
5656
// Depth: Open range
5757
var openFolds: [Int: LineFoldStorage.RawFold] = [:]
5858
var currentDepth: Int = 0
59-
var iterator = await controller.textView.layoutManager.lineStorage.makeIterator()
60-
61-
var lines = await self.getMoreLines(
59+
var lineIterator = await ChunkedLineIterator(
6260
controller: controller,
63-
iterator: &iterator,
64-
previousDepth: currentDepth,
65-
foldProvider: foldProvider
61+
foldProvider: foldProvider,
62+
textIterator: await controller.textView.layoutManager.lineStorage.makeIterator()
6663
)
67-
while let lineChunk = lines {
64+
65+
for await lineChunk in lineIterator {
6866
for lineInfo in lineChunk {
6967
// Start a new fold, going deeper to a new depth.
7068
if lineInfo.depth > currentDepth {
@@ -88,12 +86,6 @@ actor LineFoldCalculator {
8886

8987
currentDepth = lineInfo.depth
9088
}
91-
lines = await self.getMoreLines(
92-
controller: controller,
93-
iterator: &iterator,
94-
previousDepth: currentDepth,
95-
foldProvider: foldProvider
96-
)
9789
}
9890

9991
// Clean up any hanging folds.
@@ -106,6 +98,14 @@ actor LineFoldCalculator {
10698
)
10799
}
108100

101+
await yieldNewStorage(newFolds: foldCache, controller: controller, documentRange: documentRange)
102+
}
103+
104+
private func yieldNewStorage(
105+
newFolds: [LineFoldStorage.RawFold],
106+
controller: TextViewController,
107+
documentRange: NSRange
108+
) async {
109109
let attachments = await controller.textView.layoutManager.attachments
110110
.getAttachmentsOverlapping(documentRange)
111111
.compactMap { attachmentBox -> LineFoldStorage.DepthStartPair? in
@@ -116,39 +116,55 @@ actor LineFoldCalculator {
116116
}
117117

118118
let storage = LineFoldStorage(
119-
documentLength: foldCache.max(
119+
documentLength: newFolds.max(
120120
by: { $0.range.upperBound < $1.range.upperBound }
121121
)?.range.upperBound ?? documentRange.length,
122-
folds: foldCache.sorted(by: { $0.range.lowerBound < $1.range.lowerBound }),
122+
folds: newFolds.sorted(by: { $0.range.lowerBound < $1.range.lowerBound }),
123123
collapsedRanges: Set(attachments)
124124
)
125125
valueStreamContinuation.yield(storage)
126126
}
127127

128128
@MainActor
129-
private func getMoreLines(
130-
controller: TextViewController,
131-
iterator: inout TextLineStorage<TextLine>.TextLineStorageIterator,
132-
previousDepth: Int,
133-
foldProvider: LineFoldProvider
134-
) -> [LineFoldProviderLineInfo]? {
135-
var results: [LineFoldProviderLineInfo] = []
136-
var count = 0
137-
var previousDepth: Int = previousDepth
138-
while count < 50, let linePosition = iterator.next() {
139-
let foldInfo = foldProvider.foldLevelAtLine(
140-
lineNumber: linePosition.index,
141-
lineRange: linePosition.range,
142-
previousDepth: previousDepth,
143-
controller: controller
144-
)
145-
results.append(contentsOf: foldInfo)
146-
count += 1
147-
previousDepth = foldInfo.max(by: { $0.depth < $1.depth })?.depth ?? previousDepth
129+
struct ChunkedLineIterator: AsyncSequence, AsyncIteratorProtocol {
130+
var controller: TextViewController
131+
var foldProvider: LineFoldProvider
132+
private var previousDepth: Int = 0
133+
var textIterator: TextLineStorage<TextLine>.TextLineStorageIterator
134+
135+
init(
136+
controller: TextViewController,
137+
foldProvider: LineFoldProvider,
138+
textIterator: TextLineStorage<TextLine>.TextLineStorageIterator
139+
) {
140+
self.controller = controller
141+
self.foldProvider = foldProvider
142+
self.textIterator = textIterator
143+
}
144+
145+
nonisolated func makeAsyncIterator() -> ChunkedLineIterator {
146+
self
148147
}
149-
if results.isEmpty && count == 0 {
150-
return nil
148+
149+
mutating func next() async -> [LineFoldProviderLineInfo]? {
150+
var results: [LineFoldProviderLineInfo] = []
151+
var count = 0
152+
var previousDepth: Int = previousDepth
153+
while count < 50, let linePosition = textIterator.next() {
154+
let foldInfo = foldProvider.foldLevelAtLine(
155+
lineNumber: linePosition.index,
156+
lineRange: linePosition.range,
157+
previousDepth: previousDepth,
158+
controller: controller
159+
)
160+
results.append(contentsOf: foldInfo)
161+
count += 1
162+
previousDepth = foldInfo.max(by: { $0.depth < $1.depth })?.depth ?? previousDepth
163+
}
164+
if results.isEmpty && count == 0 {
165+
return nil
166+
}
167+
return results
151168
}
152-
return results
153169
}
154170
}

Sources/CodeEditSourceEditor/LineFolding/View/FoldingRibbonView+Draw.swift

Lines changed: 16 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,6 @@ import AppKit
99
import CodeEditTextView
1010

1111
extension FoldingRibbonView {
12-
struct FoldCapInfo {
13-
let startIndices: Set<Int>
14-
let endIndices: Set<Int>
15-
16-
init(_ folds: [DrawingFoldInfo]) {
17-
self.startIndices = folds.reduce(into: Set<Int>(), { $0.insert($1.startLine.index) })
18-
self.endIndices = folds.reduce(into: Set<Int>(), { $0.insert($1.endLine.index) })
19-
}
20-
21-
func foldNeedsTopCap(_ fold: DrawingFoldInfo) -> Bool {
22-
endIndices.contains(fold.startLine.index)
23-
}
24-
25-
func foldNeedsBottomCap(_ fold: DrawingFoldInfo) -> Bool {
26-
startIndices.contains(fold.endLine.index)
27-
}
28-
29-
func adjustFoldRect(
30-
using fold: DrawingFoldInfo,
31-
rect: NSRect
32-
) -> NSRect {
33-
let capTop = foldNeedsTopCap(fold)
34-
let capBottom = foldNeedsBottomCap(fold)
35-
let yDelta = capTop ? fold.startLine.height / 2.0 : 0.0
36-
let heightDelta: CGFloat = if capTop && capBottom {
37-
-fold.startLine.height
38-
} else if capTop || capBottom {
39-
-(fold.startLine.height / 2.0)
40-
} else {
41-
0.0
42-
}
43-
return NSRect(
44-
x: rect.origin.x,
45-
y: rect.origin.y + yDelta,
46-
width: rect.size.width,
47-
height: rect.size.height + heightDelta
48-
)
49-
}
50-
}
51-
5212
struct DrawingFoldInfo {
5313
let fold: FoldRange
5414
let startLine: TextLineStorage<TextLine>.TextLinePosition
@@ -273,8 +233,7 @@ extension FoldingRibbonView {
273233
foldInfo: foldInfo,
274234
foldCaps: foldCaps,
275235
originalPath: roundedRect.cgPathFallback,
276-
minYPosition: minYPosition,
277-
maxYPosition: maxYPosition,
236+
yPosition: minYPosition...maxYPosition,
278237
in: context
279238
)
280239
}
@@ -295,15 +254,19 @@ extension FoldingRibbonView {
295254
foldInfo: DrawingFoldInfo,
296255
foldCaps: FoldCapInfo,
297256
originalPath: CGPath,
298-
minYPosition: CGFloat,
299-
maxYPosition: CGFloat,
257+
yPosition: ClosedRange<CGFloat>,
300258
in context: CGContext
301259
) {
302260
context.saveGState()
303261

304262
let plainRect = foldCaps.adjustFoldRect(
305263
using: foldInfo,
306-
rect: NSRect(x: -0.5, y: minYPosition, width: frame.width + 1.0, height: maxYPosition - minYPosition)
264+
rect: NSRect(
265+
x: -0.5,
266+
y: yPosition.lowerBound,
267+
width: frame.width + 1.0,
268+
height: yPosition.upperBound - yPosition.lowerBound
269+
)
307270
)
308271
let radius = plainRect.width / 2.0
309272
let roundedRect = NSBezierPath(
@@ -318,7 +281,14 @@ extension FoldingRibbonView {
318281
combined.addPath(roundedRect.cgPathFallback)
319282
combined.addPath(originalPath)
320283

321-
context.clip(to: CGRect(x: 0, y: minYPosition, width: 7, height: maxYPosition - minYPosition))
284+
context.clip(
285+
to: CGRect(
286+
x: 0,
287+
y: yPosition.lowerBound,
288+
width: 7,
289+
height: yPosition.upperBound - yPosition.lowerBound
290+
)
291+
)
322292
context.addPath(combined)
323293
context.setFillColor(markerBorderColor)
324294
context.drawPath(using: .eoFill)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// FoldCapInfo.swift
3+
// CodeEditSourceEditor
4+
//
5+
// Created by Khan Winter on 6/3/25.
6+
//
7+
8+
import AppKit
9+
10+
extension FoldingRibbonView {
11+
struct FoldCapInfo {
12+
let startIndices: Set<Int>
13+
let endIndices: Set<Int>
14+
15+
init(_ folds: [DrawingFoldInfo]) {
16+
self.startIndices = folds.reduce(into: Set<Int>(), { $0.insert($1.startLine.index) })
17+
self.endIndices = folds.reduce(into: Set<Int>(), { $0.insert($1.endLine.index) })
18+
}
19+
20+
func foldNeedsTopCap(_ fold: DrawingFoldInfo) -> Bool {
21+
endIndices.contains(fold.startLine.index)
22+
}
23+
24+
func foldNeedsBottomCap(_ fold: DrawingFoldInfo) -> Bool {
25+
startIndices.contains(fold.endLine.index)
26+
}
27+
28+
func adjustFoldRect(
29+
using fold: DrawingFoldInfo,
30+
rect: NSRect
31+
) -> NSRect {
32+
let capTop = foldNeedsTopCap(fold)
33+
let capBottom = foldNeedsBottomCap(fold)
34+
let yDelta = capTop ? fold.startLine.height / 2.0 : 0.0
35+
let heightDelta: CGFloat = if capTop && capBottom {
36+
-fold.startLine.height
37+
} else if capTop || capBottom {
38+
-(fold.startLine.height / 2.0)
39+
} else {
40+
0.0
41+
}
42+
return NSRect(
43+
x: rect.origin.x,
44+
y: rect.origin.y + yDelta,
45+
width: rect.size.width,
46+
height: rect.size.height + heightDelta
47+
)
48+
}
49+
}
50+
}

Sources/CodeEditSourceEditor/RangeStore/RangeStore+FindIndex.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extension RangeStore {
1212
func findIndex(at offset: Int) -> (index: Index, remaining: Int) {
1313
_guts.find(at: offset, in: OffsetMetric(), preferEnd: false)
1414
}
15-
15+
1616
/// Finds the value stored at a given string offset.
1717
/// - Parameter offset: The offset to query for.
1818
/// - Returns: The element stored, if any.

0 commit comments

Comments
 (0)