Skip to content

Commit b7e3bad

Browse files
committed
Fixed issue related to hang encountered when editing some lists
1 parent 486b674 commit b7e3bad

File tree

6 files changed

+55
-24
lines changed

6 files changed

+55
-24
lines changed

Diff for: Proton/Sources/Swift/Core/LayoutManager.swift

-20
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,6 @@ class LayoutManager: NSLayoutManager {
8888
counters = [:]
8989
}
9090

91-
var levelToSet = 0
92-
textStorage.enumerateAttribute(.paragraphStyle, in: listRange, options: []) { value, range, _ in
93-
levelToSet = 0
94-
if let paraStyle = (value as? NSParagraphStyle)?.mutableParagraphStyle {
95-
let previousLevel = Int(prevStyle?.firstLineHeadIndent ?? 0)/Int(listIndent)
96-
let currentLevel = Int(paraStyle.firstLineHeadIndent)/Int(listIndent)
97-
98-
if currentLevel - previousLevel > 1 {
99-
levelToSet = previousLevel + 1
100-
let indentation = CGFloat(levelToSet) * listIndent
101-
paraStyle.firstLineHeadIndent = indentation
102-
paraStyle.headIndent = indentation
103-
textStorage.addAttribute(.paragraphStyle, value: paraStyle, range: range)
104-
prevStyle = paraStyle
105-
} else {
106-
prevStyle = value as? NSParagraphStyle
107-
}
108-
}
109-
}
110-
11191
let listGlyphRange = glyphRange(forCharacterRange: listRange, actualCharacterRange: nil)
11292
previousLevel = 0
11393
enumerateLineFragments(forGlyphRange: listGlyphRange) { [weak self] (rect, usedRect, textContainer, glyphRange, stop) in

Diff for: Proton/Sources/Swift/EditorCommand/Commands/List/ListCommand.swift

+31
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public class ListCommand: EditorCommand {
104104
], at: selectedRange)
105105
editor.removeAttribute(.listItem, at: selectedRange)
106106
editor.typingAttributes[.listItem] = nil
107+
cleanupIfNeeded(editor: editor)
107108
return
108109
}
109110

@@ -132,4 +133,34 @@ public class ListCommand: EditorCommand {
132133
self.attributeValue = attributeValue
133134
execute(on: editor)
134135
}
136+
137+
// Cleanup any dangling lists after the parent of this is removed as being a list item
138+
private func cleanupIfNeeded(editor: EditorView) {
139+
guard let nextContentLine = editor.nextContentLine(from: editor.selectedRange.endLocation),
140+
nextContentLine.text.attributeOrNil(.listItem, at: 0) != nil,
141+
let listToUpdateRange = editor.attributedText.rangeOf(attribute: .listItem, startingLocation: editor.selectedRange.endLocation) else { return }
142+
143+
let listIndent = editor.listLineFormatting.indentation
144+
145+
var levelToSet = 0
146+
var prevStyle: NSParagraphStyle?
147+
editor.attributedText.enumerateAttribute(.paragraphStyle, in: listToUpdateRange) { value, range, stop in
148+
levelToSet = 0
149+
if let paraStyle = (value as? NSParagraphStyle)?.mutableParagraphStyle {
150+
let previousLevel = Int(prevStyle?.firstLineHeadIndent ?? 0)/Int(listIndent)
151+
let currentLevel = Int(paraStyle.firstLineHeadIndent)/Int(listIndent)
152+
153+
if currentLevel - previousLevel > 1 {
154+
levelToSet = previousLevel + 1
155+
let indentation = CGFloat(levelToSet) * listIndent
156+
paraStyle.firstLineHeadIndent = indentation
157+
paraStyle.headIndent = indentation
158+
editor.addAttribute(.paragraphStyle, value: paraStyle, at: range)
159+
prevStyle = paraStyle
160+
} else {
161+
prevStyle = value as? NSParagraphStyle
162+
}
163+
}
164+
}
165+
}
135166
}

Diff for: Proton/Sources/Swift/Helpers/NSAttributedString+Range.swift

+24
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,28 @@ public extension NSAttributedString {
173173
let range = NSRange(location: searchTextRange.location, length: searchText.count)
174174
return range
175175
}
176+
177+
func attributedSubstringOrClamped(from range: NSRange) -> NSAttributedString {
178+
let clamped = range.clamped(upperBound: length)
179+
return attributedSubstring(from: clamped)
180+
}
181+
182+
func substringOrClamped(from range: NSRange) -> String {
183+
let clamped = range.clamped(upperBound: length)
184+
return (string as NSString).substring(with: clamped)
185+
}
186+
187+
func attributeOrNil(_ key: NSAttributedString.Key, at location: Int) -> Any? {
188+
return attributesOrEmpty(at: location)[key]
189+
}
190+
191+
func attributesOrEmpty(at location: Int) -> [NSAttributedString.Key: Any] {
192+
guard self.length != 0, location >= 0, location < length else { return [:] }
193+
return attributes(at: location, effectiveRange: nil)
194+
}
195+
196+
func containsAttribute(_ key: NSAttributedString.Key, at location: Int) -> Bool {
197+
attributesOrEmpty(at: location).keys.contains(key)
198+
}
199+
176200
}

Diff for: Proton/Tests/Editor/EditorListsSnapshotTests.swift

-4
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,6 @@ class EditorListsSnapshotTests: SnapshotTestCase {
594594

595595
viewController.render(size: CGSize(width: 300, height: 225))
596596
assertSnapshot(matching: viewController.view, as: .image, record: recordMode)
597-
598-
// For some reason, a re-render is required in tests
599-
viewController.render(size: CGSize(width: 300, height: 225))
600-
assertSnapshot(matching: viewController.view, as: .image, record: recordMode)
601597
}
602598

603599
func testRendersListWithDifferentAttributeValues() {
Loading
Binary file not shown.

0 commit comments

Comments
 (0)