@expensify/react-native-live-markdown 0.1.197 → 0.1.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
8
8
 
9
9
  import com.expensify.livemarkdown.spans.*;
10
10
  import com.facebook.react.views.text.internal.span.CustomLineHeightSpan;
11
+ import com.facebook.systrace.Systrace;
11
12
 
12
13
  import java.util.List;
13
14
  import java.util.Objects;
@@ -20,22 +21,37 @@ public class MarkdownFormatter {
20
21
  }
21
22
 
22
23
  public void format(SpannableStringBuilder ssb, List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
23
- Objects.requireNonNull(markdownStyle, "mMarkdownStyle is null");
24
- removeSpans(ssb);
25
- applyRanges(ssb, markdownRanges, markdownStyle);
24
+ try {
25
+ Systrace.beginSection(0, "format");
26
+ Objects.requireNonNull(markdownStyle, "mMarkdownStyle is null");
27
+ removeSpans(ssb);
28
+ applyRanges(ssb, markdownRanges, markdownStyle);
29
+ } finally {
30
+ Systrace.endSection(0);
31
+ }
26
32
  }
27
33
 
28
34
  private void removeSpans(SpannableStringBuilder ssb) {
29
- // We shouldn't use `removeSpans()` because it also removes SpellcheckSpan, SuggestionSpan etc.
30
- MarkdownSpan[] spans = ssb.getSpans(0, ssb.length(), MarkdownSpan.class);
31
- for (MarkdownSpan span : spans) {
32
- ssb.removeSpan(span);
35
+ try {
36
+ Systrace.beginSection(0, "removeSpans");
37
+ // We shouldn't use `removeSpans()` because it also removes SpellcheckSpan, SuggestionSpan etc.
38
+ MarkdownSpan[] spans = ssb.getSpans(0, ssb.length(), MarkdownSpan.class);
39
+ for (MarkdownSpan span : spans) {
40
+ ssb.removeSpan(span);
41
+ }
42
+ } finally {
43
+ Systrace.endSection(0);
33
44
  }
34
45
  }
35
46
 
36
47
  private void applyRanges(SpannableStringBuilder ssb, List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
37
- for (MarkdownRange markdownRange : markdownRanges) {
38
- applyRange(ssb, markdownRange, markdownStyle);
48
+ try {
49
+ Systrace.beginSection(0, "applyRanges");
50
+ for (MarkdownRange markdownRange : markdownRanges) {
51
+ applyRange(ssb, markdownRange, markdownStyle);
52
+ }
53
+ } finally {
54
+ Systrace.endSection(0);
39
55
  }
40
56
  }
41
57
 
@@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
5
5
  import com.facebook.react.bridge.ReactContext;
6
6
  import com.facebook.react.util.RNLog;
7
7
  import com.facebook.soloader.SoLoader;
8
+ import com.facebook.systrace.Systrace;
8
9
 
9
10
  import org.json.JSONArray;
10
11
  import org.json.JSONException;
@@ -31,46 +32,58 @@ public class MarkdownParser {
31
32
  private native String nativeParse(String text, int parserId);
32
33
 
33
34
  public synchronized List<MarkdownRange> parse(String text, int parserId) {
34
- if (text.equals(mPrevText) && parserId == mPrevParserId) {
35
- return mPrevMarkdownRanges;
36
- }
37
-
38
- String json;
39
35
  try {
40
- json = nativeParse(text, parserId);
41
- } catch (Exception e) {
42
- // Skip formatting, runGuarded will show the error in LogBox
43
- mPrevText = text;
44
- mPrevParserId = parserId;
45
- mPrevMarkdownRanges = Collections.emptyList();
46
- return mPrevMarkdownRanges;
47
- }
36
+ Systrace.beginSection(0, "parse");
48
37
 
49
- List<MarkdownRange> markdownRanges = new LinkedList<>();
50
- try {
51
- JSONArray ranges = new JSONArray(json);
52
- for (int i = 0; i < ranges.length(); i++) {
53
- JSONObject range = ranges.getJSONObject(i);
54
- String type = range.getString("type");
55
- int start = range.getInt("start");
56
- int length = range.getInt("length");
57
- int depth = range.optInt("depth", 1);
58
- if (length == 0 || start + length > text.length()) {
59
- continue;
38
+ if (text.equals(mPrevText) && parserId == mPrevParserId) {
39
+ return mPrevMarkdownRanges;
40
+ }
41
+
42
+ String json;
43
+ try {
44
+ Systrace.beginSection(0, "nativeParse");
45
+ json = nativeParse(text, parserId);
46
+ } catch (Exception e) {
47
+ // Skip formatting, runGuarded will show the error in LogBox
48
+ mPrevText = text;
49
+ mPrevParserId = parserId;
50
+ mPrevMarkdownRanges = Collections.emptyList();
51
+ return mPrevMarkdownRanges;
52
+ } finally {
53
+ Systrace.endSection(0);
54
+ }
55
+
56
+ List<MarkdownRange> markdownRanges = new LinkedList<>();
57
+ try {
58
+ Systrace.beginSection(0, "markdownRanges");
59
+ JSONArray ranges = new JSONArray(json);
60
+ for (int i = 0; i < ranges.length(); i++) {
61
+ JSONObject range = ranges.getJSONObject(i);
62
+ String type = range.getString("type");
63
+ int start = range.getInt("start");
64
+ int length = range.getInt("length");
65
+ int depth = range.optInt("depth", 1);
66
+ if (length == 0 || start + length > text.length()) {
67
+ continue;
68
+ }
69
+ markdownRanges.add(new MarkdownRange(type, start, length, depth));
60
70
  }
61
- markdownRanges.add(new MarkdownRange(type, start, length, depth));
71
+ } catch (JSONException e) {
72
+ RNLog.w(mReactContext, "[react-native-live-markdown] Incorrect schema of worklet parser output: " + e.getMessage());
73
+ mPrevText = text;
74
+ mPrevParserId = parserId;
75
+ mPrevMarkdownRanges = Collections.emptyList();
76
+ return mPrevMarkdownRanges;
77
+ } finally {
78
+ Systrace.endSection(0);
62
79
  }
63
- } catch (JSONException e) {
64
- RNLog.w(mReactContext, "[react-native-live-markdown] Incorrect schema of worklet parser output: " + e.getMessage());
80
+
65
81
  mPrevText = text;
66
82
  mPrevParserId = parserId;
67
- mPrevMarkdownRanges = Collections.emptyList();
83
+ mPrevMarkdownRanges = markdownRanges;
68
84
  return mPrevMarkdownRanges;
85
+ } finally {
86
+ Systrace.endSection(0);
69
87
  }
70
-
71
- mPrevText = text;
72
- mPrevParserId = parserId;
73
- mPrevMarkdownRanges = markdownRanges;
74
- return mPrevMarkdownRanges;
75
88
  }
76
89
  }
@@ -5,6 +5,7 @@ import android.text.SpannableStringBuilder;
5
5
  import androidx.annotation.NonNull;
6
6
 
7
7
  import com.facebook.react.bridge.ReactContext;
8
+ import com.facebook.systrace.Systrace;
8
9
 
9
10
  import java.util.List;
10
11
 
@@ -29,8 +30,13 @@ public class MarkdownUtils {
29
30
  }
30
31
 
31
32
  public void applyMarkdownFormatting(SpannableStringBuilder ssb) {
32
- String text = ssb.toString();
33
- List<MarkdownRange> markdownRanges = mMarkdownParser.parse(text, mParserId);
34
- mMarkdownFormatter.format(ssb, markdownRanges, mMarkdownStyle);
33
+ try {
34
+ Systrace.beginSection(0, "applyMarkdownFormatting");
35
+ String text = ssb.toString();
36
+ List<MarkdownRange> markdownRanges = mMarkdownParser.parse(text, mParserId);
37
+ mMarkdownFormatter.format(ssb, markdownRanges, mMarkdownStyle);
38
+ } finally {
39
+ Systrace.endSection(0);
40
+ }
35
41
  }
36
42
  }
@@ -5,34 +5,27 @@
5
5
  - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin {
6
6
  [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin];
7
7
 
8
+ NSTextStorage *textStorage = self.textStorage;
9
+
8
10
  [self enumerateLineFragmentsForGlyphRange:glyphsToShow usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
9
- __block BOOL isBlockquote = NO;
10
- __block int currentDepth = 0;
11
+ NSNumber *depth = [textStorage attribute:RCTLiveMarkdownBlockquoteDepthAttributeName atIndex:glyphRange.location effectiveRange:nil];
12
+ if (depth == nil) {
13
+ return; // not a blockquote
14
+ }
15
+
11
16
  RCTMarkdownUtils *markdownUtils = [self valueForKey:@"markdownUtils"];
12
- [markdownUtils.blockquoteRangesAndLevels enumerateObjectsUsingBlock:^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) {
13
- NSRange range = [[item valueForKey:@"range"] rangeValue];
14
- currentDepth = [[item valueForKey:@"depth"] unsignedIntegerValue];
15
- NSUInteger start = range.location;
16
- NSUInteger end = start + range.length;
17
- NSUInteger location = glyphRange.location;
18
- if (location >= start && location < end) {
19
- isBlockquote = YES;
20
- *stop = YES;
21
- }
22
- }];
23
- if (isBlockquote) {
24
- CGFloat paddingLeft = origin.x;
25
- CGFloat paddingTop = origin.y;
26
- CGFloat y = paddingTop + rect.origin.y;
27
- CGFloat width = markdownUtils.markdownStyle.blockquoteBorderWidth;
28
- CGFloat height = rect.size.height;
29
- CGFloat shift = markdownUtils.markdownStyle.blockquoteMarginLeft + markdownUtils.markdownStyle.blockquoteBorderWidth + markdownUtils.markdownStyle.blockquotePaddingLeft;
30
- for (int level = 0; level < currentDepth; level++) {
31
- CGFloat x = paddingLeft + (level * shift) + markdownUtils.markdownStyle.blockquoteMarginLeft;
32
- CGRect lineRect = CGRectMake(x, y, width, height);
33
- [markdownUtils.markdownStyle.blockquoteBorderColor setFill];
34
- UIRectFill(lineRect);
35
- }
17
+ CGFloat paddingLeft = origin.x;
18
+ CGFloat paddingTop = origin.y;
19
+ CGFloat y = paddingTop + rect.origin.y;
20
+ CGFloat width = markdownUtils.markdownStyle.blockquoteBorderWidth;
21
+ CGFloat height = rect.size.height;
22
+ CGFloat shift = markdownUtils.markdownStyle.blockquoteMarginLeft + markdownUtils.markdownStyle.blockquoteBorderWidth + markdownUtils.markdownStyle.blockquotePaddingLeft;
23
+
24
+ for (NSUInteger level = 0; level < [depth unsignedIntValue]; level++) {
25
+ CGFloat x = paddingLeft + (level * shift) + markdownUtils.markdownStyle.blockquoteMarginLeft;
26
+ CGRect lineRect = CGRectMake(x, y, width, height);
27
+ [markdownUtils.markdownStyle.blockquoteBorderColor setFill];
28
+ UIRectFill(lineRect);
36
29
  }
37
30
  }];
38
31
  }
@@ -3,11 +3,12 @@
3
3
 
4
4
  NS_ASSUME_NONNULL_BEGIN
5
5
 
6
+ const NSAttributedStringKey RCTLiveMarkdownBlockquoteDepthAttributeName = @"RCTLiveMarkdownBlockquoteDepth";
7
+
6
8
  @interface RCTMarkdownUtils : NSObject
7
9
 
8
10
  @property (nonatomic) RCTMarkdownStyle *markdownStyle;
9
11
  @property (nonatomic) NSNumber *parserId;
10
- @property (nonatomic) NSMutableArray<NSDictionary *> *blockquoteRangesAndLevels;
11
12
 
12
13
  - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary<NSAttributedStringKey, id>*)attributes;
13
14
 
@@ -46,8 +46,6 @@
46
46
  // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem.
47
47
  [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)];
48
48
 
49
- _blockquoteRangesAndLevels = [NSMutableArray new];
50
-
51
49
  for (MarkdownRange *markdownRange in markdownRanges) {
52
50
  [self applyRangeToAttributedString:attributedString
53
51
  type:std::string([markdownRange.type UTF8String])
@@ -134,10 +132,7 @@
134
132
  paragraphStyle.firstLineHeadIndent = indent;
135
133
  paragraphStyle.headIndent = indent;
136
134
  [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];
137
- [_blockquoteRangesAndLevels addObject:@{
138
- @"range": [NSValue valueWithRange:range],
139
- @"depth": @(depth)
140
- }];
135
+ [attributedString addAttribute:RCTLiveMarkdownBlockquoteDepthAttributeName value:@(depth) range:range];
141
136
  } else if (type == "pre") {
142
137
  [attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.preColor range:range];
143
138
  NSRange rangeForBackground = [[attributedString string] characterAtIndex:range.location] == '\n' ? NSMakeRange(range.location + 1, range.length - 1) : range;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expensify/react-native-live-markdown",
3
- "version": "0.1.197",
3
+ "version": "0.1.199",
4
4
  "description": "Drop-in replacement for React Native's TextInput component with Markdown formatting.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",