Skip to content

Commit 1175c57

Browse files
committed
refactor: ios optimalization
1 parent 8fef696 commit 1175c57

2 files changed

Lines changed: 83 additions & 48 deletions

File tree

ios/inputAttributesManager/InputAttributesManager.mm

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,27 @@ - (void)clearRemovedTypingAttributes {
6666
}
6767

6868
- (void)handleDirtyRangesStyling {
69-
// snapshot edited ranges (including 0-length ones) before filtering, so
70-
// we can use them when recalculating adjacent ordered lists
71-
NSArray<NSValue *> *editedRangesForListRecalc = [_dirtyRanges copy];
72-
73-
// Filter out 0 length ranges for styling.
74-
NSPredicate *predicate = [NSPredicate
75-
predicateWithBlock:^BOOL(NSValue *evaluatedObject, NSDictionary *_) {
76-
return [evaluatedObject rangeValue].length > 0;
77-
}];
78-
[_dirtyRanges filterUsingPredicate:predicate];
69+
OrderedListStyle *orderedListStyle =
70+
(OrderedListStyle *)_input->stylesDict[@([OrderedListStyle getType])];
7971

8072
for (NSValue *rangeObj in _dirtyRanges) {
8173
NSRange dirtyRange = [rangeObj rangeValue];
8274

75+
// deletion (0-length dirtyRange) means we need to refresh the ordered
76+
// list margins. If the ordered list style is not present itself,
77+
// it might mean that we have just deleted a list element and need
78+
// to recalculate the potentially split list (current adjacent lists)
79+
if (dirtyRange.length == 0) {
80+
if (orderedListStyle != nil) {
81+
if ([orderedListStyle detect:dirtyRange]) {
82+
[orderedListStyle applyStyling:dirtyRange];
83+
} else {
84+
[orderedListStyle recalculateListsAroundEditedRange:dirtyRange];
85+
}
86+
}
87+
continue;
88+
}
89+
8390
// dirty range can sometimes be wrong because of apple doing some changes
8491
// behind the scenes
8592
if (dirtyRange.location + dirtyRange.length >
@@ -94,6 +101,13 @@ - (void)handleDirtyRangesStyling {
94101
presentStyles[@([[style class] getType])] = [style all:dirtyRange];
95102
}
96103

104+
// it's possible that ordered list style has just got removed,
105+
// so we have to refresh adjacent ordered lists
106+
if (orderedListStyle != nil &&
107+
[presentStyles[@([OrderedListStyle getType])] count] == 0) {
108+
[orderedListStyle recalculateListsAroundEditedRange:dirtyRange];
109+
}
110+
97111
// now reset the attributes to default ones
98112
[_input->textView.textStorage setAttributes:_input->defaultTypingAttributes
99113
range:dirtyRange];
@@ -126,15 +140,6 @@ - (void)handleDirtyRangesStyling {
126140
}
127141
}
128142
}
129-
// refresh ordered lists adjacent to any edit
130-
OrderedListStyle *orderedListStyle =
131-
(OrderedListStyle *)_input->stylesDict[@([OrderedListStyle getType])];
132-
if (orderedListStyle != nil) {
133-
for (NSValue *rangeObj in editedRangesForListRecalc) {
134-
[orderedListStyle
135-
recalculateListsAroundEditedRange:[rangeObj rangeValue]];
136-
}
137-
}
138143

139144
// do the typing attributes management, with no selection
140145
[self manageTypingAttributesWithOnlySelection:NO];

ios/styles/OrderedListStyle.mm

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -182,48 +182,78 @@ - (NSRange)contiguousOrderedListRangeContaining:(NSRange)range
182182
return NSMakeRange(range.location, 0);
183183
}
184184

185+
NSTextStorage *textStorage = self.host.textView.textStorage;
186+
NSRange fullRange = NSMakeRange(0, length);
185187
NSUInteger seedLocation = MIN(range.location, length - 1);
186-
NSRange initialParagraph =
187-
[fullText paragraphRangeForRange:NSMakeRange(seedLocation, 0)];
188-
NSRange firstParagraph = initialParagraph;
189188

190-
NSInteger precedingCount = 0;
189+
NSRange seedRun;
190+
[textStorage attribute:NSParagraphStyleAttributeName
191+
atIndex:seedLocation
192+
longestEffectiveRange:&seedRun
193+
inRange:fullRange];
191194

192-
// seek backward over preceding ordered-list paragraphs, counting items
193-
while (firstParagraph.location > 0) {
194-
NSRange previous = [fullText
195-
paragraphRangeForRange:NSMakeRange(firstParagraph.location - 1, 0)];
196-
if (![self detect:NSMakeRange(previous.location, 0)]) {
195+
NSUInteger firstParagraphStart = seedRun.location;
196+
NSUInteger lastParagraphEnd = NSMaxRange(seedRun);
197+
198+
// seek backward over preceding ordered-list runs
199+
while (firstParagraphStart > 0) {
200+
if (![self detect:NSMakeRange(firstParagraphStart - 1, 0)]) {
197201
break;
198202
}
199-
firstParagraph = previous;
200-
precedingCount += 1;
203+
NSRange previousRun;
204+
[textStorage attribute:NSParagraphStyleAttributeName
205+
atIndex:firstParagraphStart - 1
206+
longestEffectiveRange:&previousRun
207+
inRange:fullRange];
208+
firstParagraphStart = previousRun.location;
201209
}
202210

203-
// seek forward over following ordered-list paragraphs, counting items
204-
NSInteger followingCount = 0;
205-
NSRange lastParagraph = initialParagraph;
206-
NSRange cursor = initialParagraph;
207-
while (true) {
208-
lastParagraph = cursor;
209-
NSUInteger nextLocation = NSMaxRange(cursor);
210-
if (nextLocation >= length) {
211-
break;
212-
}
213-
NSRange next =
214-
[fullText paragraphRangeForRange:NSMakeRange(nextLocation, 0)];
215-
if (![self detect:NSMakeRange(next.location, 0)]) {
211+
// seek forward over following ordered-list runs
212+
while (lastParagraphEnd < length) {
213+
if (![self detect:NSMakeRange(lastParagraphEnd, 0)]) {
216214
break;
217215
}
218-
cursor = next;
219-
followingCount += 1;
216+
NSRange nextRun;
217+
[textStorage attribute:NSParagraphStyleAttributeName
218+
atIndex:lastParagraphEnd
219+
longestEffectiveRange:&nextRun
220+
inRange:fullRange];
221+
lastParagraphEnd = NSMaxRange(nextRun);
220222
}
221223

224+
NSRange listRange =
225+
NSMakeRange(firstParagraphStart, lastParagraphEnd - firstParagraphStart);
226+
222227
if (outCount != nullptr) {
223-
*outCount = precedingCount + followingCount + 1;
228+
*outCount =
229+
[self countParagraphsInRange:listRange
230+
inText:self.host.textView.textStorage.string];
224231
}
225-
return NSMakeRange(firstParagraph.location,
226-
NSMaxRange(lastParagraph) - firstParagraph.location);
232+
return listRange;
233+
}
234+
235+
// counts paragraphs (newline-delimited) within a range that is already known
236+
// to start and end exactly on paragraph boundaries
237+
- (NSInteger)countParagraphsInRange:(NSRange)listRange inText:(NSString *)text {
238+
if (listRange.length == 0) {
239+
return 0;
240+
}
241+
242+
NSCharacterSet *newlineSet = [NSCharacterSet newlineCharacterSet];
243+
NSUInteger rangeEnd = NSMaxRange(listRange);
244+
NSUInteger cursor = listRange.location;
245+
NSInteger count = 0;
246+
247+
while (cursor < rangeEnd) {
248+
count += 1;
249+
NSRange newline =
250+
[text rangeOfCharacterFromSet:newlineSet
251+
options:0
252+
range:NSMakeRange(cursor, rangeEnd - cursor)];
253+
cursor = newline.location != NSNotFound ? NSMaxRange(newline) : rangeEnd;
254+
}
255+
256+
return count;
227257
}
228258

229259
@end

0 commit comments

Comments
 (0)