Skip to content

Commit e5369da

Browse files
Remove Problematic CATransaction, Fix Lines Disappearing (#52)
Remove Problematic CATransaction, Assert Overlapping Layout
1 parent 6fa44d6 commit e5369da

File tree

4 files changed

+35
-25
lines changed

4 files changed

+35
-25
lines changed

Package.resolved

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,39 @@
11
{
22
"pins" : [
3-
{
4-
"identity" : "mainoffender",
5-
"kind" : "remoteSourceControl",
6-
"location" : "https://github.com/mattmassicotte/MainOffender",
7-
"state" : {
8-
"revision" : "343cc3797618c29b48b037b4e2beea0664e75315",
9-
"version" : "0.1.0"
10-
}
11-
},
123
{
134
"identity" : "rearrange",
145
"kind" : "remoteSourceControl",
156
"location" : "https://github.com/ChimeHQ/Rearrange",
167
"state" : {
17-
"revision" : "8f97f721d8a08c6e01ab9f7460e53819bef72dfa",
18-
"version" : "1.5.3"
8+
"revision" : "5ff7f3363f7a08f77e0d761e38e6add31c2136e1",
9+
"version" : "1.8.1"
1910
}
2011
},
2112
{
2213
"identity" : "swift-collections",
2314
"kind" : "remoteSourceControl",
2415
"location" : "https://github.com/apple/swift-collections.git",
2516
"state" : {
26-
"revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
27-
"version" : "1.0.4"
17+
"revision" : "9bf03ff58ce34478e66aaee630e491823326fd06",
18+
"version" : "1.1.3"
2819
}
2920
},
3021
{
3122
"identity" : "swiftlintplugin",
3223
"kind" : "remoteSourceControl",
3324
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
3425
"state" : {
35-
"revision" : "f69b412a765396d44dc9f4788a5b79919c1ca9e3",
36-
"version" : "0.2.2"
26+
"revision" : "5a65f4074975f811da666dfe31a19850950b1ea4",
27+
"version" : "0.56.2"
3728
}
3829
},
3930
{
4031
"identity" : "textstory",
4132
"kind" : "remoteSourceControl",
4233
"location" : "https://github.com/ChimeHQ/TextStory",
4334
"state" : {
44-
"revision" : "8883fa739aa213e70e6cb109bfbf0a0b551e4cb5",
45-
"version" : "0.8.0"
35+
"revision" : "8dc9148b46fcf93b08ea9d4ef9bdb5e4f700e008",
36+
"version" : "0.9.0"
4637
}
4738
}
4839
],

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ let package = Package(
1717
// Text mutation, storage helpers
1818
.package(
1919
url: "https://github.com/ChimeHQ/TextStory",
20-
from: "0.8.0"
20+
from: "0.9.0"
2121
),
2222
// Useful data structures
2323
.package(
@@ -27,7 +27,7 @@ let package = Package(
2727
// SwiftLint
2828
.package(
2929
url: "https://github.com/lukepistrol/SwiftLintPlugin",
30-
from: "0.2.2"
30+
from: "0.52.2"
3131
)
3232
],
3333
targets: [

Sources/CodeEditTextView/TextLayoutManager/TextLayoutManager.swift

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ public class TextLayoutManager: NSObject {
7979
public var isInTransaction: Bool {
8080
transactionCounter > 0
8181
}
82+
#if DEBUG
83+
/// Guard variable for an assertion check in debug builds.
84+
/// Ensures that layout calls are not overlapping, potentially causing layout issues.
85+
/// This is used over a lock, as locks in performant code such as this would be detrimental to performance.
86+
/// Also only included in debug builds. DO NOT USE for checking if layout is active or not. That is an anti-pattern.
87+
private var isInLayout: Bool = false
88+
#endif
8289

8390
weak var layoutView: NSView?
8491

@@ -188,15 +195,26 @@ public class TextLayoutManager: NSObject {
188195

189196
// MARK: - Layout
190197

198+
/// Asserts that the caller is not in an active layout pass.
199+
/// See docs on ``isInLayout`` for more details.
200+
private func assertNotInLayout() {
201+
#if DEBUG // This is redundant, but it keeps the flag debug-only too which helps prevent misuse.
202+
assert(!isInLayout, "layoutLines called while already in a layout pass. This is a programmer error.")
203+
#endif
204+
}
205+
191206
/// Lays out all visible lines
192207
func layoutLines(in rect: NSRect? = nil) { // swiftlint:disable:this function_body_length
208+
assertNotInLayout()
193209
guard layoutView?.superview != nil,
194210
let visibleRect = rect ?? delegate?.visibleRect,
195211
!isInTransaction,
196212
let textStorage else {
197213
return
198214
}
199-
CATransaction.begin()
215+
#if DEBUG
216+
isInLayout = true
217+
#endif
200218
let minY = max(visibleRect.minY - verticalLayoutPadding, 0)
201219
let maxY = max(visibleRect.maxY + verticalLayoutPadding, 0)
202220
let originalHeight = lineStorage.height
@@ -237,13 +255,11 @@ public class TextLayoutManager: NSObject {
237255
}
238256
} else {
239257
// Make sure the used fragment views aren't dequeued.
240-
usedFragmentIDs.formUnion(linePosition.data.typesetter.lineFragments.map(\.data.id))
258+
usedFragmentIDs.formUnion(linePosition.data.lineFragments.map(\.data.id))
241259
}
242260
newVisibleLines.insert(linePosition.data.id)
243261
}
244262

245-
CATransaction.commit()
246-
247263
// Enqueue any lines not used in this layout pass.
248264
viewReuseQueue.enqueueViews(notInSet: usedFragmentIDs)
249265

@@ -262,6 +278,9 @@ public class TextLayoutManager: NSObject {
262278
delegate?.layoutManagerYAdjustment(yContentAdjustment)
263279
}
264280

281+
#if DEBUG
282+
isInLayout = false
283+
#endif
265284
needsLayout = false
266285
}
267286

@@ -302,7 +321,7 @@ public class TextLayoutManager: NSObject {
302321
let relativeMinY = max(layoutData.minY - position.yPos, 0)
303322
let relativeMaxY = max(layoutData.maxY - position.yPos, relativeMinY)
304323

305-
for lineFragmentPosition in line.typesetter.lineFragments.linesStartingAt(
324+
for lineFragmentPosition in line.lineFragments.linesStartingAt(
306325
relativeMinY,
307326
until: relativeMaxY
308327
) {

Sources/CodeEditTextView/TextView/TextView+ReplaceCharacters.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ extension TextView {
3838
delegate?.textView(self, didReplaceContentsIn: range, with: string)
3939
}
4040

41-
layoutManager.endTransaction()
4241
textStorage.endEditing()
42+
layoutManager.endTransaction()
4343
selectionManager.notifyAfterEdit()
4444
NotificationCenter.default.post(name: Self.textDidChangeNotification, object: self)
4545
}

0 commit comments

Comments
 (0)