From 69acd78d6d59dcc3f0d421acf764262077dc8e48 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 5 Dec 2024 17:12:16 +0100 Subject: [PATCH 1/2] Obtain blockquotes ranges and levels from `markdownRanges` on iOS --- apple/RCTMarkdownUtils.mm | 17 +++++++++++------ example/ios/Podfile.lock | 8 ++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apple/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm index 57d90774..857e3860 100644 --- a/apple/RCTMarkdownUtils.mm +++ b/apple/RCTMarkdownUtils.mm @@ -38,6 +38,17 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA NSArray *markdownRanges = [_markdownParser parse:inputString withParserId:_parserId]; + // TODO: use custom attribute to store blockquote depth instead + _blockquoteRangesAndLevels = [NSMutableArray new]; + for (MarkdownRange *markdownRange in markdownRanges) { + if ([markdownRange.type isEqualToString:@"blockquote"]) { + [_blockquoteRangesAndLevels addObject:@{ + @"range": [NSValue valueWithRange:markdownRange.range], + @"depth": @(markdownRange.depth) + }]; + } + } + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes]; [attributedString beginEditing]; @@ -46,8 +57,6 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem. [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)]; - _blockquoteRangesAndLevels = [NSMutableArray new]; - for (MarkdownRange *markdownRange in markdownRanges) { [self applyRangeToAttributedString:attributedString type:std::string([markdownRange.type UTF8String]) @@ -134,10 +143,6 @@ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedStri paragraphStyle.firstLineHeadIndent = indent; paragraphStyle.headIndent = indent; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range]; - [_blockquoteRangesAndLevels addObject:@{ - @"range": [NSValue valueWithRange:range], - @"depth": @(depth) - }]; } else if (type == "pre") { [attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.preColor range:range]; NSRange rangeForBackground = [[attributedString string] characterAtIndex:range.location] == '\n' ? NSMakeRange(range.location + 1, range.length - 1) : range; diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d9e49e6f..2a4b70a6 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1497,7 +1497,7 @@ PODS: - React-logger (= 0.75.3) - React-perflogger (= 0.75.3) - React-utils (= 0.75.3) - - RNLiveMarkdown (0.1.190): + - RNLiveMarkdown (0.1.195): - DoubleConversion - glog - hermes-engine @@ -1517,10 +1517,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNLiveMarkdown/newarch (= 0.1.190) + - RNLiveMarkdown/newarch (= 0.1.195) - RNReanimated/worklets - Yoga - - RNLiveMarkdown/newarch (0.1.190): + - RNLiveMarkdown/newarch (0.1.195): - DoubleConversion - glog - hermes-engine @@ -1897,7 +1897,7 @@ SPEC CHECKSUMS: React-utils: f2afa6acd905ca2ce7bb8ffb4a22f7f8a12534e8 ReactCodegen: e35c23cdd36922f6d2990c6c1f1b022ade7ad74d ReactCommon: 289214026502e6a93484f4a46bcc0efa4f3f2864 - RNLiveMarkdown: a210cbb45b6cb9db0b28ef09aafdc9c77424dd38 + RNLiveMarkdown: 18b4dec85110bc61b02f53501cd9e7aa08066b7f RNReanimated: ab6c33a61e90c4cbe5dbcbe65bd6c7cb3be167e6 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d Yoga: 1354c027ab07c7736f99a3bef16172d6f1b12b47 From e79a9a443060ab7aeeb598f10f72a52cc2a2d83d Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 5 Dec 2024 22:27:33 +0100 Subject: [PATCH 2/2] Use custom attribute to store blockquote depth --- apple/MarkdownLayoutManager.mm | 45 ++++++++++++++-------------------- apple/RCTMarkdownUtils.h | 3 ++- apple/RCTMarkdownUtils.mm | 12 +-------- 3 files changed, 22 insertions(+), 38 deletions(-) diff --git a/apple/MarkdownLayoutManager.mm b/apple/MarkdownLayoutManager.mm index 3974ba98..4ea7da64 100644 --- a/apple/MarkdownLayoutManager.mm +++ b/apple/MarkdownLayoutManager.mm @@ -5,34 +5,27 @@ @implementation MarkdownLayoutManager - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin { [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin]; + NSTextStorage *textStorage = self.textStorage; + [self enumerateLineFragmentsForGlyphRange:glyphsToShow usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { - __block BOOL isBlockquote = NO; - __block int currentDepth = 0; + NSNumber *depth = [textStorage attribute:RCTLiveMarkdownBlockquoteDepthAttributeName atIndex:glyphRange.location effectiveRange:nil]; + if (depth == nil) { + return; // not a blockquote + } + RCTMarkdownUtils *markdownUtils = [self valueForKey:@"markdownUtils"]; - [markdownUtils.blockquoteRangesAndLevels enumerateObjectsUsingBlock:^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) { - NSRange range = [[item valueForKey:@"range"] rangeValue]; - currentDepth = [[item valueForKey:@"depth"] unsignedIntegerValue]; - NSUInteger start = range.location; - NSUInteger end = start + range.length; - NSUInteger location = glyphRange.location; - if (location >= start && location < end) { - isBlockquote = YES; - *stop = YES; - } - }]; - if (isBlockquote) { - CGFloat paddingLeft = origin.x; - CGFloat paddingTop = origin.y; - CGFloat y = paddingTop + rect.origin.y; - CGFloat width = markdownUtils.markdownStyle.blockquoteBorderWidth; - CGFloat height = rect.size.height; - CGFloat shift = markdownUtils.markdownStyle.blockquoteMarginLeft + markdownUtils.markdownStyle.blockquoteBorderWidth + markdownUtils.markdownStyle.blockquotePaddingLeft; - for (int level = 0; level < currentDepth; level++) { - CGFloat x = paddingLeft + (level * shift) + markdownUtils.markdownStyle.blockquoteMarginLeft; - CGRect lineRect = CGRectMake(x, y, width, height); - [markdownUtils.markdownStyle.blockquoteBorderColor setFill]; - UIRectFill(lineRect); - } + CGFloat paddingLeft = origin.x; + CGFloat paddingTop = origin.y; + CGFloat y = paddingTop + rect.origin.y; + CGFloat width = markdownUtils.markdownStyle.blockquoteBorderWidth; + CGFloat height = rect.size.height; + CGFloat shift = markdownUtils.markdownStyle.blockquoteMarginLeft + markdownUtils.markdownStyle.blockquoteBorderWidth + markdownUtils.markdownStyle.blockquotePaddingLeft; + + for (NSUInteger level = 0; level < [depth unsignedIntValue]; level++) { + CGFloat x = paddingLeft + (level * shift) + markdownUtils.markdownStyle.blockquoteMarginLeft; + CGRect lineRect = CGRectMake(x, y, width, height); + [markdownUtils.markdownStyle.blockquoteBorderColor setFill]; + UIRectFill(lineRect); } }]; } diff --git a/apple/RCTMarkdownUtils.h b/apple/RCTMarkdownUtils.h index e942139d..7b76d438 100644 --- a/apple/RCTMarkdownUtils.h +++ b/apple/RCTMarkdownUtils.h @@ -3,11 +3,12 @@ NS_ASSUME_NONNULL_BEGIN +const NSAttributedStringKey RCTLiveMarkdownBlockquoteDepthAttributeName = @"RCTLiveMarkdownBlockquoteDepth"; + @interface RCTMarkdownUtils : NSObject @property (nonatomic) RCTMarkdownStyle *markdownStyle; @property (nonatomic) NSNumber *parserId; -@property (nonatomic) NSMutableArray *blockquoteRangesAndLevels; - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary*)attributes; diff --git a/apple/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm index 857e3860..8a5ee447 100644 --- a/apple/RCTMarkdownUtils.mm +++ b/apple/RCTMarkdownUtils.mm @@ -38,17 +38,6 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA NSArray *markdownRanges = [_markdownParser parse:inputString withParserId:_parserId]; - // TODO: use custom attribute to store blockquote depth instead - _blockquoteRangesAndLevels = [NSMutableArray new]; - for (MarkdownRange *markdownRange in markdownRanges) { - if ([markdownRange.type isEqualToString:@"blockquote"]) { - [_blockquoteRangesAndLevels addObject:@{ - @"range": [NSValue valueWithRange:markdownRange.range], - @"depth": @(markdownRange.depth) - }]; - } - } - NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes]; [attributedString beginEditing]; @@ -143,6 +132,7 @@ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedStri paragraphStyle.firstLineHeadIndent = indent; paragraphStyle.headIndent = indent; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range]; + [attributedString addAttribute:RCTLiveMarkdownBlockquoteDepthAttributeName value:@(depth) range:range]; } else if (type == "pre") { [attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.preColor range:range]; NSRange rangeForBackground = [[attributedString string] characterAtIndex:range.location] == '\n' ? NSMakeRange(range.location + 1, range.length - 1) : range;