Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Hermes instead of JSC on iOS #83

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RNLiveMarkdown.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Pod::Spec.new do |s|

s.resources = "parser/react-native-live-markdown-parser.js"

s.dependency "hermes-engine"

install_modules_dependencies(s)

if ENV['USE_FRAMEWORKS'] && ENV['RCT_NEW_ARCH_ENABLED']
Expand Down
110 changes: 6 additions & 104 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
PODS:
- boost (1.83.0)
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- FBLazyVector (0.73.4)
- FBReactNativeSpec (0.73.4):
Expand All @@ -10,69 +9,12 @@ PODS:
- React-Core (= 0.73.4)
- React-jsi (= 0.73.4)
- ReactCommon/turbomodule/core (= 0.73.4)
- Flipper (0.201.0):
- Flipper-Folly (~> 2.6)
- Flipper-Boost-iOSX (1.76.0.1.11)
- Flipper-DoubleConversion (3.2.0.1)
- Flipper-Fmt (7.1.7)
- Flipper-Folly (2.6.10):
- Flipper-Boost-iOSX
- Flipper-DoubleConversion
- Flipper-Fmt (= 7.1.7)
- Flipper-Glog
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100)
- Flipper-Glog (0.5.0.5)
- Flipper-PeerTalk (0.0.4)
- FlipperKit (0.201.0):
- FlipperKit/Core (= 0.201.0)
- FlipperKit/Core (0.201.0):
- Flipper (~> 0.201.0)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- SocketRocket (~> 0.6.0)
- FlipperKit/CppBridge (0.201.0):
- Flipper (~> 0.201.0)
- FlipperKit/FBCxxFollyDynamicConvert (0.201.0):
- Flipper-Folly (~> 2.6)
- FlipperKit/FBDefines (0.201.0)
- FlipperKit/FKPortForwarding (0.201.0):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- FlipperKit/FlipperKitHighlightOverlay (0.201.0)
- FlipperKit/FlipperKitLayoutHelpers (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- FlipperKit/FlipperKitLayoutIOSDescriptors (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- FlipperKit/FlipperKitLayoutPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- FlipperKit/FlipperKitLayoutIOSDescriptors
- FlipperKit/FlipperKitLayoutTextSearchable
- FlipperKit/FlipperKitLayoutTextSearchable (0.201.0)
- FlipperKit/FlipperKitNetworkPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitReactPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitUserDefaultsPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/SKIOSNetworkPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- fmt (6.2.1)
- glog (0.3.5)
- hermes-engine (0.73.4):
- hermes-engine/Pre-built (= 0.73.4)
- hermes-engine/Pre-built (0.73.4)
- libevent (2.1.12)
- OpenSSL-Universal (1.1.1100)
- RCT-Folly (2022.05.16.00):
- boost
- DoubleConversion
Expand Down Expand Up @@ -1111,13 +1053,15 @@ PODS:
- React-jsi (= 0.73.4)
- React-logger (= 0.73.4)
- React-perflogger (= 0.73.4)
- RNLiveMarkdown (0.1.79):
- RNLiveMarkdown (0.1.92):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
- React-Core
- RNLiveMarkdown/common (= 0.1.79)
- RNLiveMarkdown/common (0.1.79):
- RNLiveMarkdown/common (= 0.1.92)
- RNLiveMarkdown/common (0.1.92):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
- React-Core
- SocketRocket (0.6.1)
Expand All @@ -1128,30 +1072,9 @@ DEPENDENCIES:
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- Flipper (= 0.201.0)
- Flipper-Boost-iOSX (= 1.76.0.1.11)
- Flipper-DoubleConversion (= 3.2.0.1)
- Flipper-Fmt (= 7.1.7)
- Flipper-Folly (= 2.6.10)
- Flipper-Glog (= 0.5.0.5)
- Flipper-PeerTalk (= 0.0.4)
- FlipperKit (= 0.201.0)
- FlipperKit/Core (= 0.201.0)
- FlipperKit/CppBridge (= 0.201.0)
- FlipperKit/FBCxxFollyDynamicConvert (= 0.201.0)
- FlipperKit/FBDefines (= 0.201.0)
- FlipperKit/FKPortForwarding (= 0.201.0)
- FlipperKit/FlipperKitHighlightOverlay (= 0.201.0)
- FlipperKit/FlipperKitLayoutPlugin (= 0.201.0)
- FlipperKit/FlipperKitLayoutTextSearchable (= 0.201.0)
- FlipperKit/FlipperKitNetworkPlugin (= 0.201.0)
- FlipperKit/FlipperKitReactPlugin (= 0.201.0)
- FlipperKit/FlipperKitUserDefaultsPlugin (= 0.201.0)
- FlipperKit/SKIOSNetworkPlugin (= 0.201.0)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.1100)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
Expand All @@ -1160,7 +1083,6 @@ DEPENDENCIES:
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Codegen (from `build/generated/ios`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
Expand Down Expand Up @@ -1201,18 +1123,8 @@ DEPENDENCIES:

SPEC REPOS:
trunk:
- CocoaAsyncSocket
- Flipper
- Flipper-Boost-iOSX
- Flipper-DoubleConversion
- Flipper-Fmt
- Flipper-Folly
- Flipper-Glog
- Flipper-PeerTalk
- FlipperKit
- fmt
- libevent
- OpenSSL-Universal
- SocketRocket

EXTERNAL SOURCES:
Expand Down Expand Up @@ -1318,23 +1230,13 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
boost: d3f49c53809116a5d38da093a8aa78bf551aed09
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953
FBLazyVector: 84f6edbe225f38aebd9deaf1540a4160b1f087d7
FBReactNativeSpec: d0086a479be91c44ce4687a962956a352d2dc697
Flipper: c7a0093234c4bdd456e363f2f19b2e4b27652d44
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: b2669ce35fc4ac14f523b307aff8896799829fe2
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
RCTRequired: ab7f915c15569f04a49669e573e6e319a53f9faa
RCTTypeSafety: 63b97ced7b766865057e7154db0e81ce4ee6cf1e
Expand Down Expand Up @@ -1376,7 +1278,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: ed48e5faac6751e66ee1261c4bd01643b436f112
React-utils: 6e5ad394416482ae21831050928ae27348f83487
ReactCommon: 840a955d37b7f3358554d819446bffcf624b2522
RNLiveMarkdown: a4ddf419a109cd3f916db22ee19f8b8293b4f7e4
RNLiveMarkdown: c04da6410e95af38ccb615b8de8bb4eefc9f6e2c
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Yoga: 64cd2a583ead952b0315d5135bf39e053ae9be70

Expand Down
77 changes: 44 additions & 33 deletions ios/RCTMarkdownUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
#import "react_native_assert.h"
#import <React/RCTAssert.h>
#import <React/RCTFont.h>
#import <JavaScriptCore/JavaScriptCore.h>

#include <jsi/jsi.h>
#include <hermes/hermes.h>

using namespace facebook;

@implementation RCTMarkdownUtils {
NSString *_prevInputString;
Expand All @@ -23,20 +27,26 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA
return _prevAttributedString;
}

static JSContext *ctx = nil;
static JSValue *function = nil;
if (ctx == nil) {
static std::shared_ptr<jsi::Runtime> runtime;
if (runtime == nullptr) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"react-native-live-markdown-parser" ofType:@"js"];
assert(path != nil && "[react-native-live-markdown] Markdown parser bundle not found");
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
assert(content != nil && "[react-native-live-markdown] Markdown parser bundle is empty");
ctx = [[JSContext alloc] init];
[ctx evaluateScript:content];
function = ctx[@"parseExpensiMarkToRanges"];
runtime = facebook::hermes::makeHermesRuntime();
auto codeBuffer = std::make_shared<const jsi::StringBuffer>([content UTF8String]);
runtime->evaluateJavaScript(codeBuffer, "evaluateJavaScript");
}

JSValue *result = [function callWithArguments:@[inputString]];
NSArray *ranges = [result toArray];
jsi::Runtime &rt = *runtime;
auto text = jsi::String::createFromUtf8(rt, [inputString UTF8String]);

auto func = rt.global().getPropertyAsFunction(rt, "parseExpensiMarkToRanges");
auto output = func.call(rt, text);
if (output.isUndefined()) {
return input;
}
const auto &ranges = output.asObject(rt).asArray(rt);

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes];
[attributedString beginEditing];
Expand All @@ -48,42 +58,43 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA

_blockquoteRangesAndLevels = [NSMutableArray new];

[ranges enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *item = obj;
NSString *type = [item valueForKey:@"type"];
NSInteger location = [[item valueForKey:@"start"] unsignedIntegerValue];
NSInteger length = [[item valueForKey:@"length"] unsignedIntegerValue];
NSInteger depth = [[item valueForKey:@"depth"] unsignedIntegerValue] ?: 1;
for (size_t i = 0, n = ranges.size(rt); i < n; ++i) {
const auto &item = ranges.getValueAtIndex(rt, i).asObject(rt);
const auto &type = item.getProperty(rt, "type").asString(rt).utf8(rt);
const auto &location = static_cast<int>(item.getProperty(rt, "start").asNumber());
const auto &length = static_cast<int>(item.getProperty(rt, "length").asNumber());
const auto &depth = item.hasProperty(rt, "depth") ? static_cast<int>(item.getProperty(rt, "depth").asNumber()) : 1;

NSRange range = NSMakeRange(location, length);

if ([type isEqualToString:@"bold"] || [type isEqualToString:@"italic"] || [type isEqualToString:@"code"] || [type isEqualToString:@"pre"] || [type isEqualToString:@"h1"] || [type isEqualToString:@"emoji"]) {
if (type == "bold" || type == "italic" || type == "code" || type == "pre" || type == "h1" || type == "emoji") {
UIFont *font = [attributedString attribute:NSFontAttributeName atIndex:location effectiveRange:NULL];
if ([type isEqualToString:@"bold"]) {
if (type == "bold") {
font = [RCTFont updateFont:font withWeight:@"bold"];
} else if ([type isEqualToString:@"italic"]) {
} else if (type == "italic") {
font = [RCTFont updateFont:font withStyle:@"italic"];
} else if ([type isEqualToString:@"code"]) {
} else if (type == "code") {
font = [RCTFont updateFont:font withFamily:_markdownStyle.codeFontFamily
size:[NSNumber numberWithFloat:_markdownStyle.codeFontSize]
weight:nil
style:nil
variant:nil
scaleMultiplier:0];
} else if ([type isEqualToString:@"pre"]) {
} else if (type == "pre") {
font = [RCTFont updateFont:font withFamily:_markdownStyle.preFontFamily
size:[NSNumber numberWithFloat:_markdownStyle.preFontSize]
weight:nil
style:nil
variant:nil
scaleMultiplier:0];
} else if ([type isEqualToString:@"h1"]) {
} else if (type == "h1") {
font = [RCTFont updateFont:font withFamily:nil
size:[NSNumber numberWithFloat:_markdownStyle.h1FontSize]
weight:@"bold"
style:nil
variant:nil
scaleMultiplier:0];
} else if ([type isEqualToString:@"emoji"]) {
} else if (type == "emoji") {
font = [RCTFont updateFont:font withFamily:nil
size:[NSNumber numberWithFloat:_markdownStyle.emojiFontSize]
weight:nil
Expand All @@ -94,27 +105,27 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA
[attributedString addAttribute:NSFontAttributeName value:font range:range];
}

if ([type isEqualToString:@"syntax"]) {
if (type == "syntax") {
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.syntaxColor range:range];
} else if ([type isEqualToString:@"strikethrough"]) {
} else if (type == "strikethrough") {
[attributedString addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:range];
} else if ([type isEqualToString:@"code"]) {
} else if (type == "code") {
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.codeColor range:range];
[attributedString addAttribute:NSBackgroundColorAttributeName value:_markdownStyle.codeBackgroundColor range:range];
} else if ([type isEqualToString:@"mention-here"]) {
} else if (type == "mention-here") {
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.mentionHereColor range:range];
[attributedString addAttribute:NSBackgroundColorAttributeName value:_markdownStyle.mentionHereBackgroundColor range:range];
} else if ([type isEqualToString:@"mention-user"]) {
} else if (type == "mention-user") {
// TODO: change mention color when it mentions current user
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.mentionUserColor range:range];
[attributedString addAttribute:NSBackgroundColorAttributeName value:_markdownStyle.mentionUserBackgroundColor range:range];
} else if ([type isEqualToString:@"mention-report"]) {
} else if (type == "mention-report") {
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.mentionReportColor range:range];
[attributedString addAttribute:NSBackgroundColorAttributeName value:_markdownStyle.mentionReportBackgroundColor range:range];
} else if ([type isEqualToString:@"link"]) {
} else if (type == "link") {
[attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:range];
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.linkColor range:range];
} else if ([type isEqualToString:@"blockquote"]) {
} else if (type == "blockquote") {
CGFloat indent = (_markdownStyle.blockquoteMarginLeft + _markdownStyle.blockquoteBorderWidth + _markdownStyle.blockquotePaddingLeft) * depth;
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.firstLineHeadIndent = indent;
Expand All @@ -124,17 +135,17 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withA
@"range": [NSValue valueWithRange:range],
@"depth": @(depth)
}];
} else if ([type isEqualToString:@"pre"]) {
} else if (type == "pre") {
[attributedString addAttribute:NSForegroundColorAttributeName value:_markdownStyle.preColor range:range];
NSRange rangeForBackground = [inputString characterAtIndex:range.location] == '\n' ? NSMakeRange(range.location + 1, range.length - 1) : range;
[attributedString addAttribute:NSBackgroundColorAttributeName value:_markdownStyle.preBackgroundColor range:rangeForBackground];
// TODO: pass background color and ranges to layout manager
} else if ([type isEqualToString:@"h1"]) {
} else if (type == "h1") {
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
NSRange rangeWithHashAndSpace = NSMakeRange(range.location - 2, range.length + 2); // we also need to include prepending "# "
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:rangeWithHashAndSpace];
}
}];
}

RCTApplyBaselineOffset(attributedString);

Expand Down
Loading