Skip to content

Commit

Permalink
Merge branch 'main' into @Skalakid/fix-emoji-formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
Skalakid committed Dec 9, 2024
2 parents bb101a9 + c35696d commit cb4f160
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 240 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import com.expensify.livemarkdown.spans.*;
import com.facebook.react.views.text.internal.span.CustomLineHeightSpan;
import com.facebook.systrace.Systrace;

import java.util.List;
import java.util.Objects;
Expand All @@ -19,30 +20,45 @@ public MarkdownFormatter(@NonNull AssetManager assetManager) {
mAssetManager = assetManager;
}

public void format(SpannableStringBuilder ssb, List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
Objects.requireNonNull(markdownStyle, "mMarkdownStyle is null");
removeSpans(ssb);
applyRanges(ssb, markdownRanges, markdownStyle);
public void format(@NonNull SpannableStringBuilder ssb, @NonNull List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
try {
Systrace.beginSection(0, "format");
Objects.requireNonNull(markdownStyle, "mMarkdownStyle is null");
removeSpans(ssb);
applyRanges(ssb, markdownRanges, markdownStyle);
} finally {
Systrace.endSection(0);
}
}

private void removeSpans(SpannableStringBuilder ssb) {
// We shouldn't use `removeSpans()` because it also removes SpellcheckSpan, SuggestionSpan etc.
MarkdownSpan[] spans = ssb.getSpans(0, ssb.length(), MarkdownSpan.class);
for (MarkdownSpan span : spans) {
ssb.removeSpan(span);
private void removeSpans(@NonNull SpannableStringBuilder ssb) {
try {
Systrace.beginSection(0, "removeSpans");
// We shouldn't use `removeSpans()` because it also removes SpellcheckSpan, SuggestionSpan etc.
MarkdownSpan[] spans = ssb.getSpans(0, ssb.length(), MarkdownSpan.class);
for (MarkdownSpan span : spans) {
ssb.removeSpan(span);
}
} finally {
Systrace.endSection(0);
}
}

private void applyRanges(SpannableStringBuilder ssb, List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
for (MarkdownRange markdownRange : markdownRanges) {
applyRange(ssb, markdownRange, markdownStyle);
private void applyRanges(@NonNull SpannableStringBuilder ssb, @NonNull List<MarkdownRange> markdownRanges, @NonNull MarkdownStyle markdownStyle) {
try {
Systrace.beginSection(0, "applyRanges");
for (MarkdownRange markdownRange : markdownRanges) {
applyRange(ssb, markdownRange, markdownStyle);
}
} finally {
Systrace.endSection(0);
}
}

private void applyRange(SpannableStringBuilder ssb, MarkdownRange markdownRange, MarkdownStyle markdownStyle) {
private void applyRange(@NonNull SpannableStringBuilder ssb, @NonNull MarkdownRange markdownRange, @NonNull MarkdownStyle markdownStyle) {
String type = markdownRange.getType();
int start = markdownRange.getStart();
int end = start + markdownRange.getLength();
int end = markdownRange.getEnd();
switch (type) {
case "bold":
setSpan(ssb, new MarkdownBoldSpan(), start, end);
Expand Down Expand Up @@ -110,7 +126,7 @@ private void applyRange(SpannableStringBuilder ssb, MarkdownRange markdownRange,
}
}

private void setSpan(SpannableStringBuilder ssb, MarkdownSpan span, int start, int end) {
private void setSpan(@NonNull SpannableStringBuilder ssb, @NonNull MarkdownSpan span, int start, int end) {
ssb.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.util.RNLog;
import com.facebook.soloader.SoLoader;
import com.facebook.systrace.Systrace;

import org.json.JSONArray;
import org.json.JSONException;
Expand All @@ -29,9 +30,9 @@ public MarkdownParser(@NonNull ReactContext reactContext) {
mReactContext = reactContext;
}

private native String nativeParse(String text, int parserId);
private native String nativeParse(@NonNull String text, int parserId);

private void splitRangesOnEmojis(List<MarkdownRange> markdownRanges, String type) {
private void splitRangesOnEmojis(List<MarkdownRange> markdownRanges, String type) {
List<MarkdownRange> emojiRanges = new ArrayList<>();
for (MarkdownRange range : markdownRanges) {
if (range.getType().equals("emoji")) {
Expand Down Expand Up @@ -87,28 +88,37 @@ private List<MarkdownRange> parseRanges(String rangesJSON, String innerText) {
splitRangesOnEmojis(markdownRanges, "strikethrough");
return markdownRanges;
}
public synchronized List<MarkdownRange> parse(@NonNull String text, int parserId) {
try {
Systrace.beginSection(0, "parse");

public synchronized List<MarkdownRange> parse(String text, int parserId) {
if (text.equals(mPrevText) && parserId == mPrevParserId) {
return mPrevMarkdownRanges;
}
if (text.equals(mPrevText) && parserId == mPrevParserId) {
return mPrevMarkdownRanges;
}

String json;
try {
Systrace.beginSection(0, "nativeParse");
json = nativeParse(text, parserId);
} catch (Exception e) {
// Skip formatting, runGuarded will show the error in LogBox
mPrevText = text;
mPrevParserId = parserId;
mPrevMarkdownRanges = Collections.emptyList();
return mPrevMarkdownRanges;
} finally {
Systrace.endSection(0);
}

List<MarkdownRange> markdownRanges = parseRanges(json, text);
Systrace.endSection(0);

String json;
try {
json = nativeParse(text, parserId);
} catch (Exception e) {
// Skip formatting, runGuarded will show the error in LogBox
mPrevText = text;
mPrevParserId = parserId;
mPrevMarkdownRanges = Collections.emptyList();
mPrevMarkdownRanges = markdownRanges;
return mPrevMarkdownRanges;
} finally {
Systrace.endSection(0);
}

List<MarkdownRange> markdownRanges = parseRanges(json, text);

mPrevText = text;
mPrevParserId = parserId;
mPrevMarkdownRanges = markdownRanges;
return mPrevMarkdownRanges;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.expensify.livemarkdown;

import androidx.annotation.NonNull;

public class MarkdownRange {
private final String mType;
private final @NonNull String mType;
private final int mStart;
private final int mEnd;
private final int mLength;
private final int mDepth;

public MarkdownRange(String type, int start, int length, int depth) {
public MarkdownRange(@NonNull String type, int start, int length, int depth) {
mType = type;
mStart = start;
mLength = length;
mEnd = start + length;
mLength = length;
mDepth = depth;
}

Expand All @@ -23,14 +25,14 @@ public int getStart() {
return mStart;
}

public int getLength() {
return mLength;
}

public int getEnd() {
return mEnd;
}

public int getLength() {
return mLength;
}

public int getDepth() {
return mDepth;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class MarkdownStyle {

private final float mBlockquotePaddingLeft;

@NonNull
private final String mCodeFontFamily;

private final float mCodeFontSize;
Expand All @@ -42,6 +43,7 @@ public class MarkdownStyle {
@ColorInt
private final int mCodeBackgroundColor;

@NonNull
private final String mPreFontFamily;

private final float mPreFontSize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import androidx.annotation.NonNull;

public class MarkdownTextWatcher implements TextWatcher {
private final MarkdownUtils mMarkdownUtils;
private final @NonNull MarkdownUtils mMarkdownUtils;

public MarkdownTextWatcher(@NonNull MarkdownUtils markdownUtils) {
mMarkdownUtils = markdownUtils;
Expand All @@ -25,8 +25,8 @@ public void onTextChanged(CharSequence s, int start, int before, int count) {

@Override
public void afterTextChanged(Editable editable) {
if (editable instanceof SpannableStringBuilder) {
mMarkdownUtils.applyMarkdownFormatting((SpannableStringBuilder) editable);
if (editable instanceof SpannableStringBuilder ssb) {
mMarkdownUtils.applyMarkdownFormatting(ssb);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import androidx.annotation.NonNull;

import com.facebook.react.bridge.ReactContext;
import com.facebook.systrace.Systrace;

import java.util.List;

Expand All @@ -29,8 +30,13 @@ public void setParserId(int parserId) {
}

public void applyMarkdownFormatting(SpannableStringBuilder ssb) {
String text = ssb.toString();
List<MarkdownRange> markdownRanges = mMarkdownParser.parse(text, mParserId);
mMarkdownFormatter.format(ssb, markdownRanges, mMarkdownStyle);
try {
Systrace.beginSection(0, "applyMarkdownFormatting");
String text = ssb.toString();
List<MarkdownRange> markdownRanges = mMarkdownParser.parse(text, mParserId);
mMarkdownFormatter.format(ssb, markdownRanges, mMarkdownStyle);
} finally {
Systrace.endSection(0);
}
}
}
18 changes: 18 additions & 0 deletions apple/MarkdownFormatter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#import <RNLiveMarkdown/MarkdownRange.h>
#import <RNLiveMarkdown/RCTMarkdownStyle.h>

NS_ASSUME_NONNULL_BEGIN

const NSAttributedStringKey RCTLiveMarkdownBlockquoteDepthAttributeName = @"RCTLiveMarkdownBlockquoteDepth";

@interface MarkdownFormatter : NSObject

- (nonnull NSAttributedString *)format:(nonnull NSString *)text
withAttributes:(nullable NSDictionary<NSAttributedStringKey, id>*)attributes
withMarkdownRanges:(nonnull NSArray<MarkdownRange *> *)markdownRanges
withMarkdownStyle:(nonnull RCTMarkdownStyle *)markdownStyle;

NS_ASSUME_NONNULL_END

@end
Loading

0 comments on commit cb4f160

Please sign in to comment.