react-native-marcus 0.1.0

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.
Files changed (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +227 -0
  3. package/RNMarcus.podspec +78 -0
  4. package/android/build.gradle +220 -0
  5. package/android/proguard-rules.pro +1 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/AndroidManifestNew.xml +2 -0
  8. package/android/src/main/cpp/CMakeLists.txt +41 -0
  9. package/android/src/main/cpp/MarkdownParser.cpp +49 -0
  10. package/android/src/main/cpp/MarkdownParser.h +56 -0
  11. package/android/src/main/cpp/OnLoad.cpp +17 -0
  12. package/android/src/main/java/app/getbullet/marcus/MarcusModule.kt +28 -0
  13. package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +31 -0
  14. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +63 -0
  15. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManager.kt +32 -0
  16. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManagerSpec.kt +21 -0
  17. package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +333 -0
  18. package/android/src/main/java/app/getbullet/marcus/MarkdownParseResult.kt +12 -0
  19. package/android/src/main/java/app/getbullet/marcus/MarkdownParser.kt +89 -0
  20. package/android/src/main/java/app/getbullet/marcus/MarkdownRange.kt +11 -0
  21. package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +81 -0
  22. package/android/src/main/java/app/getbullet/marcus/MarkdownTextWatcher.kt +17 -0
  23. package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +84 -0
  24. package/android/src/main/java/app/getbullet/marcus/ReactLineHeight.java +29 -0
  25. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +6 -0
  26. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +105 -0
  27. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +67 -0
  28. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +6 -0
  29. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontFamilySpan.kt +28 -0
  30. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontSizeSpan.kt +7 -0
  31. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownForegroundColorSpan.kt +6 -0
  32. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +57 -0
  33. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +6 -0
  34. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLineHeightSpan.kt +21 -0
  35. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownSpan.kt +7 -0
  36. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownStrikethroughSpan.kt +5 -0
  37. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownUnderlineSpan.kt +5 -0
  38. package/android/src/main/new_arch/CMakeLists.txt +70 -0
  39. package/android/src/main/new_arch/RNMarcusSpec.cpp +43 -0
  40. package/android/src/main/new_arch/RNMarcusSpec.h +36 -0
  41. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.cpp +218 -0
  42. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.h +54 -0
  43. package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +156 -0
  44. package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +130 -0
  45. package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +205 -0
  46. package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +78 -0
  47. package/android/src/test/resources/render-model.txt +583 -0
  48. package/apple/MarcusModule.h +8 -0
  49. package/apple/MarcusModule.mm +26 -0
  50. package/apple/MarcusRange.h +15 -0
  51. package/apple/MarcusRange.mm +15 -0
  52. package/apple/MarcusTextInputDecoratorComponentView.h +12 -0
  53. package/apple/MarcusTextInputDecoratorComponentView.mm +121 -0
  54. package/apple/MarcusTextInputDecoratorShadowNode.cpp +251 -0
  55. package/apple/MarcusTextInputDecoratorShadowNode.h +65 -0
  56. package/apple/MarcusTextInputDecoratorShadowNode.mm +204 -0
  57. package/apple/MarcusTextInputDecoratorViewManager.h +8 -0
  58. package/apple/MarcusTextInputDecoratorViewManager.mm +11 -0
  59. package/apple/MarkdownAdaptiveImageGlyph.swift +44 -0
  60. package/apple/MarkdownAttributes.h +31 -0
  61. package/apple/MarkdownAttributes.m +9 -0
  62. package/apple/MarkdownBackedTextInputDelegate.swift +117 -0
  63. package/apple/MarkdownDecorator.swift +316 -0
  64. package/apple/MarkdownFonts.swift +21 -0
  65. package/apple/MarkdownFormatter+React.swift +51 -0
  66. package/apple/MarkdownFormatter.swift +509 -0
  67. package/apple/MarkdownLog.h +10 -0
  68. package/apple/MarkdownLog.mm +6 -0
  69. package/apple/MarkdownParser.swift +200 -0
  70. package/apple/MarkdownSwiftInterop.h +23 -0
  71. package/apple/MarkdownTextBackground.swift +17 -0
  72. package/apple/MarkdownTextFieldObserver.swift +90 -0
  73. package/apple/MarkdownTextLayoutFragment.swift +205 -0
  74. package/apple/MarkdownTextLayoutManagerDelegate.swift +84 -0
  75. package/apple/MarkdownTextStorageDelegate.swift +32 -0
  76. package/apple/MarkdownTextViewObserver.swift +30 -0
  77. package/apple/RCTMarcusStyle+Codegen.h +18 -0
  78. package/apple/RCTMarcusStyle+Codegen.mm +64 -0
  79. package/apple/RCTMarcusStyle.h +41 -0
  80. package/apple/RCTMarcusStyle.m +5 -0
  81. package/apple/RCTMarcusUtils.h +26 -0
  82. package/apple/RCTMarcusUtils.mm +26 -0
  83. package/apple/RCTTextInput+AdaptiveImageGlyph.h +16 -0
  84. package/apple/RCTTextInput+AdaptiveImageGlyph.mm +79 -0
  85. package/apple/RCTTextInputComponentView+Marcus.h +11 -0
  86. package/apple/RCTTextInputComponentView+Marcus.mm +79 -0
  87. package/cpp/MarkdownCxx.modulemap +8 -0
  88. package/cpp/MarkdownGlobal.cpp +48 -0
  89. package/cpp/MarkdownGlobal.h +33 -0
  90. package/cpp/MarkdownWorkletParser.cpp +93 -0
  91. package/cpp/MarkdownWorkletParser.h +45 -0
  92. package/cpp/RuntimeDecorator.cpp +39 -0
  93. package/cpp/RuntimeDecorator.h +14 -0
  94. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorState.h +33 -0
  95. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorViewComponentDescriptor.h +17 -0
  96. package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  97. package/lib/commonjs/MarkdownTextInput.js +99 -0
  98. package/lib/commonjs/MarkdownTextInput.js.map +1 -0
  99. package/lib/commonjs/MarkdownTextInput.web.js +618 -0
  100. package/lib/commonjs/MarkdownTextInput.web.js.map +1 -0
  101. package/lib/commonjs/NativeMarcusModule.js +9 -0
  102. package/lib/commonjs/NativeMarcusModule.js.map +1 -0
  103. package/lib/commonjs/commonTypes.js +2 -0
  104. package/lib/commonjs/commonTypes.js.map +1 -0
  105. package/lib/commonjs/global.d.js +2 -0
  106. package/lib/commonjs/global.d.js.map +1 -0
  107. package/lib/commonjs/index.js +27 -0
  108. package/lib/commonjs/index.js.map +1 -0
  109. package/lib/commonjs/package.json +1 -0
  110. package/lib/commonjs/parser/index.js +7030 -0
  111. package/lib/commonjs/parser/index.js.map +7 -0
  112. package/lib/commonjs/rangeUtils.js +71 -0
  113. package/lib/commonjs/rangeUtils.js.map +1 -0
  114. package/lib/commonjs/react-native-web.d.js +2 -0
  115. package/lib/commonjs/react-native-web.d.js.map +1 -0
  116. package/lib/commonjs/styleUtils.js +91 -0
  117. package/lib/commonjs/styleUtils.js.map +1 -0
  118. package/lib/commonjs/web/InputHistory.js +111 -0
  119. package/lib/commonjs/web/InputHistory.js.map +1 -0
  120. package/lib/commonjs/web/MarkdownTextInput.css +72 -0
  121. package/lib/commonjs/web/utils/blockLayout.js +132 -0
  122. package/lib/commonjs/web/utils/blockLayout.js.map +1 -0
  123. package/lib/commonjs/web/utils/blockUtils.js +219 -0
  124. package/lib/commonjs/web/utils/blockUtils.js.map +1 -0
  125. package/lib/commonjs/web/utils/browserUtils.js +40 -0
  126. package/lib/commonjs/web/utils/browserUtils.js.map +1 -0
  127. package/lib/commonjs/web/utils/cursorUtils.js +157 -0
  128. package/lib/commonjs/web/utils/cursorUtils.js.map +1 -0
  129. package/lib/commonjs/web/utils/inputUtils.js +152 -0
  130. package/lib/commonjs/web/utils/inputUtils.js.map +1 -0
  131. package/lib/commonjs/web/utils/measureUtils.js +0 -0
  132. package/lib/commonjs/web/utils/measureUtils.js.map +1 -0
  133. package/lib/commonjs/web/utils/parserUtils.js +552 -0
  134. package/lib/commonjs/web/utils/parserUtils.js.map +1 -0
  135. package/lib/commonjs/web/utils/treeUtils.js +109 -0
  136. package/lib/commonjs/web/utils/treeUtils.js.map +1 -0
  137. package/lib/commonjs/web/utils/webStyleUtils.js +59 -0
  138. package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -0
  139. package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  140. package/lib/module/MarkdownTextInput.js +94 -0
  141. package/lib/module/MarkdownTextInput.js.map +1 -0
  142. package/lib/module/MarkdownTextInput.web.js +612 -0
  143. package/lib/module/MarkdownTextInput.web.js.map +1 -0
  144. package/lib/module/NativeMarcusModule.js +5 -0
  145. package/lib/module/NativeMarcusModule.js.map +1 -0
  146. package/lib/module/commonTypes.js +2 -0
  147. package/lib/module/commonTypes.js.map +1 -0
  148. package/lib/module/global.d.js +2 -0
  149. package/lib/module/global.d.js.map +1 -0
  150. package/lib/module/index.js +5 -0
  151. package/lib/module/index.js.map +1 -0
  152. package/lib/module/package.json +1 -0
  153. package/lib/module/parser/index.js +7029 -0
  154. package/lib/module/parser/index.js.map +7 -0
  155. package/lib/module/rangeUtils.js +66 -0
  156. package/lib/module/rangeUtils.js.map +1 -0
  157. package/lib/module/react-native-web.d.js +2 -0
  158. package/lib/module/react-native-web.d.js.map +1 -0
  159. package/lib/module/styleUtils.js +88 -0
  160. package/lib/module/styleUtils.js.map +1 -0
  161. package/lib/module/web/InputHistory.js +106 -0
  162. package/lib/module/web/InputHistory.js.map +1 -0
  163. package/lib/module/web/MarkdownTextInput.css +72 -0
  164. package/lib/module/web/utils/blockLayout.js +128 -0
  165. package/lib/module/web/utils/blockLayout.js.map +1 -0
  166. package/lib/module/web/utils/blockUtils.js +210 -0
  167. package/lib/module/web/utils/blockUtils.js.map +1 -0
  168. package/lib/module/web/utils/browserUtils.js +36 -0
  169. package/lib/module/web/utils/browserUtils.js.map +1 -0
  170. package/lib/module/web/utils/cursorUtils.js +150 -0
  171. package/lib/module/web/utils/cursorUtils.js.map +1 -0
  172. package/lib/module/web/utils/inputUtils.js +144 -0
  173. package/lib/module/web/utils/inputUtils.js.map +1 -0
  174. package/lib/module/web/utils/measureUtils.js +0 -0
  175. package/lib/module/web/utils/measureUtils.js.map +1 -0
  176. package/lib/module/web/utils/parserUtils.js +547 -0
  177. package/lib/module/web/utils/parserUtils.js.map +1 -0
  178. package/lib/module/web/utils/treeUtils.js +103 -0
  179. package/lib/module/web/utils/treeUtils.js.map +1 -0
  180. package/lib/module/web/utils/webStyleUtils.js +54 -0
  181. package/lib/module/web/utils/webStyleUtils.js.map +1 -0
  182. package/lib/typescript/commonjs/e2e/checks.test.d.ts +2 -0
  183. package/lib/typescript/commonjs/e2e/checks.test.d.ts.map +1 -0
  184. package/lib/typescript/commonjs/e2e/editing.test.d.ts +2 -0
  185. package/lib/typescript/commonjs/e2e/editing.test.d.ts.map +1 -0
  186. package/lib/typescript/commonjs/e2e/helpers.d.ts +23 -0
  187. package/lib/typescript/commonjs/e2e/helpers.d.ts.map +1 -0
  188. package/lib/typescript/commonjs/e2e/smoke.test.d.ts +2 -0
  189. package/lib/typescript/commonjs/e2e/smoke.test.d.ts.map +1 -0
  190. package/lib/typescript/commonjs/package.json +1 -0
  191. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
  192. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +22 -0
  194. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +41 -0
  196. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts +7 -0
  198. package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/src/commonTypes.d.ts +10 -0
  200. package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -0
  201. package/lib/typescript/commonjs/src/index.d.ts +5 -0
  202. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/src/parser/index.d.ts +8 -0
  204. package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts +8 -0
  206. package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -0
  207. package/lib/typescript/commonjs/src/rangeUtils.d.ts +6 -0
  208. package/lib/typescript/commonjs/src/rangeUtils.d.ts.map +1 -0
  209. package/lib/typescript/commonjs/src/styleUtils.d.ts +8 -0
  210. package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -0
  211. package/lib/typescript/commonjs/src/web/InputHistory.d.ts +24 -0
  212. package/lib/typescript/commonjs/src/web/InputHistory.d.ts.map +1 -0
  213. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +41 -0
  214. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -0
  215. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +33 -0
  216. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -0
  217. package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts +7 -0
  218. package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts +12 -0
  220. package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts.map +1 -0
  221. package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts +12 -0
  222. package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts.map +1 -0
  223. package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts +22 -0
  224. package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts.map +1 -0
  225. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +44 -0
  226. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -0
  227. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +25 -0
  228. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -0
  229. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +7 -0
  230. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -0
  231. package/lib/typescript/module/e2e/checks.test.d.ts +2 -0
  232. package/lib/typescript/module/e2e/checks.test.d.ts.map +1 -0
  233. package/lib/typescript/module/e2e/editing.test.d.ts +2 -0
  234. package/lib/typescript/module/e2e/editing.test.d.ts.map +1 -0
  235. package/lib/typescript/module/e2e/helpers.d.ts +23 -0
  236. package/lib/typescript/module/e2e/helpers.d.ts.map +1 -0
  237. package/lib/typescript/module/e2e/smoke.test.d.ts +2 -0
  238. package/lib/typescript/module/e2e/smoke.test.d.ts.map +1 -0
  239. package/lib/typescript/module/package.json +1 -0
  240. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
  241. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
  242. package/lib/typescript/module/src/MarkdownTextInput.d.ts +22 -0
  243. package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -0
  244. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +41 -0
  245. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -0
  246. package/lib/typescript/module/src/NativeMarcusModule.d.ts +7 -0
  247. package/lib/typescript/module/src/NativeMarcusModule.d.ts.map +1 -0
  248. package/lib/typescript/module/src/commonTypes.d.ts +10 -0
  249. package/lib/typescript/module/src/commonTypes.d.ts.map +1 -0
  250. package/lib/typescript/module/src/index.d.ts +5 -0
  251. package/lib/typescript/module/src/index.d.ts.map +1 -0
  252. package/lib/typescript/module/src/parser/index.d.ts +8 -0
  253. package/lib/typescript/module/src/parser/index.d.ts.map +1 -0
  254. package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts +8 -0
  255. package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -0
  256. package/lib/typescript/module/src/rangeUtils.d.ts +6 -0
  257. package/lib/typescript/module/src/rangeUtils.d.ts.map +1 -0
  258. package/lib/typescript/module/src/styleUtils.d.ts +8 -0
  259. package/lib/typescript/module/src/styleUtils.d.ts.map +1 -0
  260. package/lib/typescript/module/src/web/InputHistory.d.ts +24 -0
  261. package/lib/typescript/module/src/web/InputHistory.d.ts.map +1 -0
  262. package/lib/typescript/module/src/web/utils/blockLayout.d.ts +41 -0
  263. package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -0
  264. package/lib/typescript/module/src/web/utils/blockUtils.d.ts +33 -0
  265. package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -0
  266. package/lib/typescript/module/src/web/utils/browserUtils.d.ts +7 -0
  267. package/lib/typescript/module/src/web/utils/browserUtils.d.ts.map +1 -0
  268. package/lib/typescript/module/src/web/utils/cursorUtils.d.ts +12 -0
  269. package/lib/typescript/module/src/web/utils/cursorUtils.d.ts.map +1 -0
  270. package/lib/typescript/module/src/web/utils/inputUtils.d.ts +12 -0
  271. package/lib/typescript/module/src/web/utils/inputUtils.d.ts.map +1 -0
  272. package/lib/typescript/module/src/web/utils/measureUtils.d.ts +22 -0
  273. package/lib/typescript/module/src/web/utils/measureUtils.d.ts.map +1 -0
  274. package/lib/typescript/module/src/web/utils/parserUtils.d.ts +44 -0
  275. package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -0
  276. package/lib/typescript/module/src/web/utils/treeUtils.d.ts +25 -0
  277. package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -0
  278. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +7 -0
  279. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -0
  280. package/package.json +167 -0
  281. package/react-native.config.js +10 -0
  282. package/src/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  283. package/src/MarkdownTextInput.tsx +139 -0
  284. package/src/MarkdownTextInput.web.tsx +958 -0
  285. package/src/NativeMarcusModule.ts +8 -0
  286. package/src/commonTypes.ts +30 -0
  287. package/src/global.d.ts +1 -0
  288. package/src/index.tsx +4 -0
  289. package/src/parser/index.ts +556 -0
  290. package/src/parser/micromark-extension-mentions.ts +82 -0
  291. package/src/rangeUtils.ts +68 -0
  292. package/src/react-native-web.d.ts +1 -0
  293. package/src/styleUtils.ts +100 -0
  294. package/src/web/InputHistory.ts +137 -0
  295. package/src/web/MarkdownTextInput.css +72 -0
  296. package/src/web/utils/blockLayout.ts +163 -0
  297. package/src/web/utils/blockUtils.ts +245 -0
  298. package/src/web/utils/browserUtils.ts +41 -0
  299. package/src/web/utils/cursorUtils.ts +204 -0
  300. package/src/web/utils/inputUtils.ts +206 -0
  301. package/src/web/utils/measureUtils.ts +0 -0
  302. package/src/web/utils/parserUtils.ts +813 -0
  303. package/src/web/utils/treeUtils.ts +149 -0
  304. package/src/web/utils/webStyleUtils.ts +69 -0
@@ -0,0 +1,18 @@
1
+ #import <RNMarcus/RCTMarcusStyle.h>
2
+
3
+ #import <react/renderer/components/RNMarcusSpec/Props.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ // Conversion from the codegen props struct lives in a separate category so that
8
+ // `RCTMarcusStyle.h` itself stays free of C++. Only the component view and
9
+ // the shadow node need this header; everything downstream can import the plain
10
+ // one.
11
+ @interface RCTMarcusStyle (Codegen)
12
+
13
+ - (instancetype)initWithStruct:
14
+ (const facebook::react::MarcusTextInputDecoratorViewMarkdownStyleStruct &)style;
15
+
16
+ @end
17
+
18
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,64 @@
1
+ #import <RNMarcus/RCTMarcusStyle+Codegen.h>
2
+
3
+ #import <React/RCTConversions.h>
4
+
5
+ @implementation RCTMarcusStyle (Codegen)
6
+
7
+ - (instancetype)initWithStruct:
8
+ (const facebook::react::MarcusTextInputDecoratorViewMarkdownStyleStruct &)style {
9
+ if (self = [super init]) {
10
+ self.syntaxColor = RCTUIColorFromSharedColor(style.syntax.color);
11
+
12
+ self.linkColor = RCTUIColorFromSharedColor(style.link.color);
13
+
14
+ self.headingFontSize = style.heading.fontSize;
15
+ self.headingScale = style.heading.scale;
16
+
17
+ self.emojiFontSize = style.emoji.fontSize;
18
+ self.emojiFontFamily = RCTNSStringFromString(style.emoji.fontFamily);
19
+
20
+ self.blockquoteBorderColor =
21
+ RCTUIColorFromSharedColor(style.blockquote.borderColor);
22
+ self.blockquoteBorderWidth = style.blockquote.borderWidth;
23
+ self.blockquoteMarginLeft = style.blockquote.marginLeft;
24
+ self.blockquotePaddingLeft = style.blockquote.paddingLeft;
25
+
26
+ self.orderedListMarginLeft = style.orderedList.marginLeft;
27
+ self.orderedListPaddingLeft = style.orderedList.paddingLeft;
28
+
29
+ self.unorderedListMarginLeft = style.unorderedList.marginLeft;
30
+ self.unorderedListPaddingLeft = style.unorderedList.paddingLeft;
31
+
32
+ self.codeFontFamily = RCTNSStringFromString(style.code.fontFamily);
33
+ self.codeFontSize = style.code.fontSize;
34
+ self.codeColor = RCTUIColorFromSharedColor(style.code.color);
35
+ self.codeBackgroundColor =
36
+ RCTUIColorFromSharedColor(style.code.backgroundColor);
37
+
38
+ self.preFontFamily = RCTNSStringFromString(style.pre.fontFamily);
39
+ self.preFontSize = style.pre.fontSize;
40
+ self.preColor = RCTUIColorFromSharedColor(style.pre.color);
41
+ self.preBackgroundColor =
42
+ RCTUIColorFromSharedColor(style.pre.backgroundColor);
43
+
44
+ self.mentionHereColor = RCTUIColorFromSharedColor(style.mentionHere.color);
45
+ self.mentionHereBackgroundColor =
46
+ RCTUIColorFromSharedColor(style.mentionHere.backgroundColor);
47
+ self.mentionHereBorderRadius = style.mentionHere.borderRadius;
48
+
49
+ self.mentionUserColor = RCTUIColorFromSharedColor(style.mentionUser.color);
50
+ self.mentionUserBackgroundColor =
51
+ RCTUIColorFromSharedColor(style.mentionUser.backgroundColor);
52
+ self.mentionUserBorderRadius = style.mentionUser.borderRadius;
53
+
54
+ self.mentionReportColor =
55
+ RCTUIColorFromSharedColor(style.mentionReport.color);
56
+ self.mentionReportBackgroundColor =
57
+ RCTUIColorFromSharedColor(style.mentionReport.backgroundColor);
58
+ self.mentionReportBorderRadius = style.mentionReport.borderRadius;
59
+ }
60
+
61
+ return self;
62
+ }
63
+
64
+ @end
@@ -0,0 +1,41 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface RCTMarcusStyle : NSObject
6
+
7
+ @property(nonatomic) UIColor *syntaxColor;
8
+ @property(nonatomic) UIColor *linkColor;
9
+ @property(nonatomic) CGFloat headingFontSize;
10
+ @property(nonatomic) CGFloat headingScale;
11
+ @property(nonatomic) CGFloat emojiFontSize;
12
+ @property(nonatomic) NSString *emojiFontFamily;
13
+ @property(nonatomic) UIColor *blockquoteBorderColor;
14
+ @property(nonatomic) CGFloat blockquoteBorderWidth;
15
+ @property(nonatomic) CGFloat blockquoteMarginLeft;
16
+ @property(nonatomic) CGFloat blockquotePaddingLeft;
17
+ @property(nonatomic) CGFloat orderedListMarginLeft;
18
+ @property(nonatomic) CGFloat orderedListPaddingLeft;
19
+ @property(nonatomic) CGFloat unorderedListMarginLeft;
20
+ @property(nonatomic) CGFloat unorderedListPaddingLeft;
21
+ @property(nonatomic) NSString *codeFontFamily;
22
+ @property(nonatomic) CGFloat codeFontSize;
23
+ @property(nonatomic) UIColor *codeColor;
24
+ @property(nonatomic) UIColor *codeBackgroundColor;
25
+ @property(nonatomic) NSString *preFontFamily;
26
+ @property(nonatomic) CGFloat preFontSize;
27
+ @property(nonatomic) UIColor *preColor;
28
+ @property(nonatomic) UIColor *preBackgroundColor;
29
+ @property(nonatomic) UIColor *mentionHereColor;
30
+ @property(nonatomic) UIColor *mentionHereBackgroundColor;
31
+ @property(nonatomic) CGFloat mentionHereBorderRadius;
32
+ @property(nonatomic) UIColor *mentionUserColor;
33
+ @property(nonatomic) UIColor *mentionUserBackgroundColor;
34
+ @property(nonatomic) CGFloat mentionUserBorderRadius;
35
+ @property(nonatomic) UIColor *mentionReportColor;
36
+ @property(nonatomic) UIColor *mentionReportBackgroundColor;
37
+ @property(nonatomic) CGFloat mentionReportBorderRadius;
38
+
39
+ @end
40
+
41
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,5 @@
1
+ #import <RNMarcus/RCTMarcusStyle.h>
2
+
3
+ @implementation RCTMarcusStyle
4
+
5
+ @end
@@ -0,0 +1,26 @@
1
+ #import <RNMarcus/RCTMarcusStyle.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ // Parses and formats in one step for the view layer.
7
+ //
8
+ // Parsing is stateful (it owns the parser's memo cache) so it stays here rather
9
+ // than moving to Swift; formatting itself is a stateless Swift call. One
10
+ // instance is owned per text input and only ever touched on the main thread.
11
+ @interface RCTMarcusUtils : NSObject
12
+
13
+ // Nullable: both are assigned after init (props arrive after the view
14
+ // hierarchy is built), and applyMarkdownFormatting: bails out when either is
15
+ // still nil.
16
+ @property(nonatomic, nullable) RCTMarcusStyle *markdownStyle;
17
+ @property(nonatomic, nullable) NSNumber *parserId;
18
+
19
+ - (void)applyMarkdownFormatting:
20
+ (nonnull NSMutableAttributedString *)attributedString
21
+ withDefaultTextAttributes:
22
+ (nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes;
23
+
24
+ @end
25
+
26
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,26 @@
1
+ #import <RNMarcus/MarkdownSwiftInterop.h>
2
+ #import <RNMarcus/RCTMarcusUtils.h>
3
+
4
+ @implementation RCTMarcusUtils
5
+
6
+ - (void)applyMarkdownFormatting:
7
+ (nonnull NSMutableAttributedString *)attributedString
8
+ withDefaultTextAttributes:
9
+ (nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes {
10
+ // `markdownStyle` and `parserId` may not be set yet: props are applied after
11
+ // the view hierarchy is built.
12
+ if (_markdownStyle == nil || _parserId == nil) {
13
+ return;
14
+ }
15
+
16
+ NSArray<MarcusRange *> *markdownRanges =
17
+ [[MarkdownParser sharedParser] parse:attributedString.string
18
+ withParserId:_parserId];
19
+
20
+ [MarkdownFormatter formatAttributedString:attributedString
21
+ defaultTextAttributes:defaultTextAttributes
22
+ ranges:markdownRanges
23
+ style:_markdownStyle];
24
+ }
25
+
26
+ @end
@@ -0,0 +1,16 @@
1
+ #import <React/RCTUITextField.h>
2
+ #import <React/RCTUITextView.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface RCTUITextField (AdaptiveImageGlyph)
7
+ - (void)marcus_insertAdaptiveImageGlyph:(id)glyph
8
+ replacementRange:(NSRange)replacementRange;
9
+ @end
10
+
11
+ @interface RCTUITextView (AdaptiveImageGlyph)
12
+ - (void)marcus_insertAdaptiveImageGlyph:(id)glyph
13
+ replacementRange:(NSRange)replacementRange;
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,79 @@
1
+ #import <RNMarcus/MarkdownSwiftInterop.h>
2
+ #import <RNMarcus/RCTTextInput+AdaptiveImageGlyph.h>
3
+
4
+ #import <objc/runtime.h>
5
+
6
+ // Kept as .mm rather than .m: plain Objective-C translation units in this pod
7
+ // compile with modules enabled, which makes importing any React header build
8
+ // the React clang module -- and that fails against React Native's prebuilt
9
+ // xcframework. Objective-C++ uses textual includes and avoids it.
10
+
11
+ // Installs `marcus_insertAdaptiveImageGlyph:replacementRange:` in place
12
+ // of UIKit's `insertAdaptiveImageGlyph:replacementRange:`. The handler itself
13
+ // is in Swift; only the runtime plumbing has to live here, because Swift cannot
14
+ // define
15
+ // `+load`.
16
+ static void
17
+ RCTMarcusSwizzleAdaptiveImageGlyph(Class targetClass, SEL swizzledSelector) {
18
+ if (@available(iOS 18.0, *)) {
19
+ SEL originalSelector = @selector(insertAdaptiveImageGlyph:
20
+ replacementRange:);
21
+
22
+ if (![targetClass instancesRespondToSelector:originalSelector]) {
23
+ return;
24
+ }
25
+
26
+ Method originalMethod =
27
+ class_getInstanceMethod(targetClass, originalSelector);
28
+ Method swizzledMethod =
29
+ class_getInstanceMethod(targetClass, swizzledSelector);
30
+ if (!originalMethod || !swizzledMethod) {
31
+ return;
32
+ }
33
+
34
+ BOOL didAddMethod = class_addMethod(
35
+ targetClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)
36
+ );
37
+ if (didAddMethod) {
38
+ class_replaceMethod(targetClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
39
+ } else {
40
+ method_exchangeImplementations(originalMethod, swizzledMethod);
41
+ }
42
+ }
43
+ }
44
+
45
+ @implementation RCTUITextField (AdaptiveImageGlyph)
46
+
47
+ + (void)load {
48
+ static dispatch_once_t onceToken;
49
+ dispatch_once(&onceToken, ^{
50
+ RCTMarcusSwizzleAdaptiveImageGlyph([self class], @selector(marcus_insertAdaptiveImageGlyph:
51
+ replacementRange:));
52
+ });
53
+ }
54
+
55
+ - (void)marcus_insertAdaptiveImageGlyph:(id)glyph
56
+ replacementRange:(NSRange)replacementRange {
57
+ // Deliberately does not call through to the original: the glyph is pasted as
58
+ // a plain image instead of being inserted as an adaptive glyph.
59
+ [MarkdownAdaptiveImageGlyph handlePasteInTextInputView:self glyph:glyph];
60
+ }
61
+
62
+ @end
63
+
64
+ @implementation RCTUITextView (AdaptiveImageGlyph)
65
+
66
+ + (void)load {
67
+ static dispatch_once_t onceToken;
68
+ dispatch_once(&onceToken, ^{
69
+ RCTMarcusSwizzleAdaptiveImageGlyph([self class], @selector(marcus_insertAdaptiveImageGlyph:
70
+ replacementRange:));
71
+ });
72
+ }
73
+
74
+ - (void)marcus_insertAdaptiveImageGlyph:(id)glyph
75
+ replacementRange:(NSRange)replacementRange {
76
+ [MarkdownAdaptiveImageGlyph handlePasteInTextInputView:self glyph:glyph];
77
+ }
78
+
79
+ @end
@@ -0,0 +1,11 @@
1
+ #import <React/RCTTextInputComponentView.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface RCTTextInputComponentView (Marcus)
6
+
7
+ - (BOOL)marcus__textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldText;
8
+
9
+ @end
10
+
11
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,79 @@
1
+ #import <RNMarcus/MarkdownAttributes.h>
2
+ #import <RNMarcus/MarcusTextInputDecoratorComponentView.h>
3
+ #import <RNMarcus/RCTTextInputComponentView+Marcus.h>
4
+ #import <objc/message.h>
5
+
6
+ @implementation RCTTextInputComponentView (Marcus)
7
+
8
+ - (BOOL)marcus__textOf:(NSAttributedString *)newText
9
+ equals:(NSAttributedString *)oldText {
10
+ __block BOOL isMarkdownTextInput = false;
11
+ [oldText enumerateAttribute:RCTMarcusTextAttributeName
12
+ inRange:NSMakeRange(0, oldText.length)
13
+ options:0
14
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
15
+ if (value) {
16
+ isMarkdownTextInput = true;
17
+ *stop = YES;
18
+ }
19
+ }];
20
+ if (isMarkdownTextInput) {
21
+ return [newText.string isEqualToString:oldText.string];
22
+ }
23
+
24
+ return [self marcus__textOf:newText equals:oldText];
25
+ }
26
+
27
+ - (void)marcus_didAddSubview:(UIView *)subview {
28
+ [self marcus_didAddSubview:subview];
29
+
30
+ // React Native swaps `_backedTextInputView` in place when `multiline`
31
+ // changes: it removes the old view from this component view and adds a new
32
+ // one. That never touches the decorator's own subviews, so its didAddSubview:
33
+ // does not fire and its observers would stay bound to the discarded view --
34
+ // keeping it alive and leaving the new, visible one unformatted.
35
+ UIView *parent = self.superview;
36
+ if ([parent isKindOfClass:[MarcusTextInputDecoratorComponentView class]]) {
37
+ [(MarcusTextInputDecoratorComponentView *)
38
+ parent reattachTextInputObservers];
39
+ }
40
+ }
41
+
42
+ // Installs `swizzledSelector` in place of `originalSelector` on `cls`.
43
+ //
44
+ // method_exchangeImplementations alone is only safe when `cls` implements
45
+ // `originalSelector` itself. For an inherited method -- didAddSubview:, for
46
+ // instance -- class_getInstanceMethod returns the *superclass's* method, and
47
+ // exchanging it rewrites UIView for every view in the app. So the
48
+ // implementation is added to this class first; when that succeeds, the
49
+ // "call the original" selector is pointed at the inherited implementation.
50
+ static void
51
+ RCTMarcusSwizzle(Class cls, SEL originalSelector, SEL swizzledSelector) {
52
+ Method originalMethod = class_getInstanceMethod(cls, originalSelector);
53
+ Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
54
+ if (originalMethod == NULL || swizzledMethod == NULL) {
55
+ return;
56
+ }
57
+
58
+ BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
59
+ if (didAddMethod) {
60
+ class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
61
+ } else {
62
+ method_exchangeImplementations(originalMethod, swizzledMethod);
63
+ }
64
+ }
65
+
66
+ + (void)load {
67
+ static dispatch_once_t onceToken;
68
+ dispatch_once(&onceToken, ^{
69
+ Class cls = [self class];
70
+
71
+ // Implemented by this class, so this is a plain exchange.
72
+ RCTMarcusSwizzle(cls, @selector(_textOf:equals:), @selector(marcus__textOf:equals:));
73
+
74
+ // Inherited from UIView, so this must go through class_addMethod.
75
+ RCTMarcusSwizzle(cls, @selector(didAddSubview:), @selector(marcus_didAddSubview:));
76
+ });
77
+ }
78
+
79
+ @end
@@ -0,0 +1,8 @@
1
+ // Exposes the pure-C++ parser to Swift. Kept separate from the pod's generated
2
+ // Objective-C umbrella, which Swift parses in Objective-C mode and therefore
3
+ // cannot contain any C++.
4
+ module MarkdownCxx {
5
+ header "MarkdownWorkletParser.h"
6
+ requires cplusplus
7
+ export *
8
+ }
@@ -0,0 +1,48 @@
1
+ #include "MarkdownGlobal.h"
2
+
3
+ #include <unordered_map>
4
+
5
+ using namespace facebook;
6
+
7
+ namespace bulletpoint {
8
+ namespace marcus {
9
+
10
+ std::shared_ptr<WorkletRuntime> globalMarkdownWorkletRuntime;
11
+
12
+ void
13
+ setMarkdownRuntime(const std::shared_ptr<WorkletRuntime> &markdownWorkletRuntime) {
14
+ globalMarkdownWorkletRuntime = markdownWorkletRuntime;
15
+ }
16
+
17
+ std::shared_ptr<WorkletRuntime>
18
+ getMarkdownRuntime() {
19
+ return globalMarkdownWorkletRuntime;
20
+ }
21
+
22
+ std::unordered_map<int, std::shared_ptr<SerializableWorklet>> globalMarkdownShareableWorklets;
23
+ std::mutex globalMarkdownShareableWorkletsMutex;
24
+ int nextParserId = 1;
25
+
26
+ const int
27
+ registerMarkdownWorklet(const std::shared_ptr<SerializableWorklet> &markdownWorklet) {
28
+ assert(markdownWorklet != nullptr);
29
+ auto parserId = nextParserId++;
30
+ std::unique_lock<std::mutex> lock(globalMarkdownShareableWorkletsMutex);
31
+ globalMarkdownShareableWorklets[parserId] = markdownWorklet;
32
+ return parserId;
33
+ }
34
+
35
+ void
36
+ unregisterMarkdownWorklet(const int parserId) {
37
+ std::unique_lock<std::mutex> lock(globalMarkdownShareableWorkletsMutex);
38
+ globalMarkdownShareableWorklets.erase(parserId);
39
+ }
40
+
41
+ std::shared_ptr<SerializableWorklet>
42
+ getMarkdownWorklet(const int parserId) {
43
+ std::unique_lock<std::mutex> lock(globalMarkdownShareableWorkletsMutex);
44
+ return globalMarkdownShareableWorklets.at(parserId);
45
+ }
46
+
47
+ } // namespace marcus
48
+ } // namespace bulletpoint
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+
5
+ #include <worklets/WorkletRuntime/WorkletRuntime.h>
6
+
7
+ using namespace facebook;
8
+ using namespace worklets;
9
+
10
+ namespace bulletpoint {
11
+ namespace marcus {
12
+
13
+ void
14
+ setMarkdownRuntime(
15
+ const std::shared_ptr<WorkletRuntime> &markdownWorkletRuntime
16
+ );
17
+
18
+ std::shared_ptr<WorkletRuntime>
19
+ getMarkdownRuntime();
20
+
21
+ const int
22
+ registerMarkdownWorklet(
23
+ const std::shared_ptr<SerializableWorklet> &markdownWorklet
24
+ );
25
+
26
+ void
27
+ unregisterMarkdownWorklet(const int parserId);
28
+
29
+ std::shared_ptr<SerializableWorklet>
30
+ getMarkdownWorklet(const int parserId);
31
+
32
+ } // namespace marcus
33
+ } // namespace bulletpoint
@@ -0,0 +1,93 @@
1
+ #include "MarkdownWorkletParser.h"
2
+
3
+ #include "MarkdownGlobal.h"
4
+
5
+ #include <stdexcept>
6
+ #include <string>
7
+ #include <utility>
8
+
9
+ namespace bulletpoint {
10
+ namespace marcus {
11
+
12
+ namespace {
13
+
14
+ bool
15
+ requiresDepth(const std::string &type) {
16
+ return type == "blockquote" || type == "heading" ||
17
+ type == "list-ordered" || type == "list-unordered";
18
+ }
19
+
20
+ constexpr int kMaxDepth = 6;
21
+
22
+ } // namespace
23
+
24
+ ParseResult
25
+ parseMarkdown(const std::string &utf8Text, size_t textLengthUtf16, int parserId) {
26
+ const auto &markdownRuntime = getMarkdownRuntime();
27
+ jsi::Runtime &rt = markdownRuntime->getJSIRuntime();
28
+
29
+ std::shared_ptr<SerializableWorklet> markdownWorklet;
30
+ try {
31
+ markdownWorklet = getMarkdownWorklet(parserId);
32
+ } catch (const std::out_of_range &) {
33
+ // Parser was never registered, or was already unregistered.
34
+ return {};
35
+ }
36
+
37
+ const auto &input = jsi::String::createFromUtf8(rt, utf8Text);
38
+
39
+ jsi::Value output;
40
+ try {
41
+ output = markdownRuntime->runGuarded(markdownWorklet, input);
42
+ } catch (const jsi::JSError &) {
43
+ // Skip formatting; runGuarded will have surfaced the error in LogBox.
44
+ return {};
45
+ }
46
+
47
+ std::vector<MarkdownRange> ranges;
48
+ try {
49
+ const auto &items = output.asObject(rt).asArray(rt);
50
+ const size_t count = items.size(rt);
51
+ ranges.reserve(count);
52
+
53
+ for (size_t i = 0; i < count; ++i) {
54
+ const auto &item = items.getValueAtIndex(rt, i).asObject(rt);
55
+ auto type = item.getProperty(rt, "type").asString(rt).utf8(rt);
56
+ const auto start =
57
+ static_cast<int>(item.getProperty(rt, "start").asNumber());
58
+ const auto length =
59
+ static_cast<int>(item.getProperty(rt, "length").asNumber());
60
+ int depth = 1;
61
+ if (item.hasProperty(rt, "depth")) {
62
+ depth = static_cast<int>(item.getProperty(rt, "depth").asNumber());
63
+
64
+ if (requiresDepth(type) && depth < 1) {
65
+ return {{}, "range of type '" + type + "' has a `depth` of " + std::to_string(depth) + ", which must be at least 1"};
66
+ }
67
+
68
+ if (depth > kMaxDepth) {
69
+ depth = kMaxDepth;
70
+ }
71
+ } else if (requiresDepth(type)) {
72
+ return {{}, "range of type '" + type + "' is missing `depth`"};
73
+ }
74
+
75
+ // `start` is checked explicitly because the offsets come from JS and a
76
+ // negative one would wrap when converted to an unsigned platform range.
77
+ if (length <= 0 || start < 0 ||
78
+ static_cast<size_t>(start) + static_cast<size_t>(length) >
79
+ textLengthUtf16) {
80
+ continue;
81
+ }
82
+
83
+ ranges.push_back(MarkdownRange{std::move(type), start, length, depth});
84
+ }
85
+ } catch (const jsi::JSError &error) {
86
+ return {{}, error.getMessage()};
87
+ }
88
+
89
+ return {std::move(ranges), ""};
90
+ }
91
+
92
+ } // namespace marcus
93
+ } // namespace bulletpoint
@@ -0,0 +1,45 @@
1
+ #pragma once
2
+
3
+ #include <cstddef>
4
+ #include <string>
5
+ #include <vector>
6
+
7
+ namespace bulletpoint {
8
+ namespace marcus {
9
+
10
+ struct MarkdownRange {
11
+ std::string type;
12
+ int start;
13
+ int length;
14
+ int depth;
15
+ };
16
+
17
+ struct ParseResult {
18
+ std::vector<MarkdownRange> ranges;
19
+
20
+ // Non-empty when the worklet returned something that didn't match the
21
+ // expected schema. Reporting is left to the caller so this stays free of any
22
+ // platform logging dependency.
23
+ std::string schemaError;
24
+ };
25
+
26
+ // Runs a registered markdown parser worklet and returns the ranges it produced.
27
+ //
28
+ // Stateless and lock-free on purpose. Running the worklet waits on the markdown
29
+ // runtime, and holding a lock across that wait is what allowed a background
30
+ // parse to block the main thread until iOS killed the app
31
+ // (Expensify/react-native-live-markdown#772). Caching therefore belongs to the
32
+ // caller, which must not hold its cache lock while calling this.
33
+ //
34
+ // `utf8Text` is the text to parse, UTF-8 encoded for the JSI boundary.
35
+ //
36
+ // `textLengthUtf16` is the same text's length in UTF-16 code units. It is
37
+ // passed separately rather than derived from `utf8Text.size()` because the
38
+ // worklet reports range offsets in UTF-16 units, matching JS string indices.
39
+ // For any non-ASCII text the UTF-8 byte count is larger, so validating against
40
+ // it would let out-of-bounds ranges through.
41
+ ParseResult
42
+ parseMarkdown(const std::string &utf8Text, size_t textLengthUtf16, int parserId);
43
+
44
+ } // namespace marcus
45
+ } // namespace bulletpoint
@@ -0,0 +1,39 @@
1
+ #include "RuntimeDecorator.h"
2
+ #include "MarkdownGlobal.h"
3
+
4
+ using namespace facebook;
5
+ using namespace worklets;
6
+
7
+ namespace bulletpoint {
8
+ namespace marcus {
9
+
10
+ void
11
+ injectJSIBindings(jsi::Runtime &rt) {
12
+
13
+ rt.global().setProperty(
14
+ rt, "jsi_setMarcusRuntime", jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "jsi_setMarcusRuntime"), 1, [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
15
+ setMarkdownRuntime(extractWorkletRuntime(rt, args[0]));
16
+ return jsi::Value::undefined();
17
+ })
18
+ );
19
+
20
+ rt.global().setProperty(
21
+ rt, "jsi_registerMarcusWorklet", jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "jsi_registerMarcusWorklet"), 1, [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
22
+ const auto parserId = registerMarkdownWorklet(
23
+ extractSerializableOrThrow<SerializableWorklet>(rt, args[0])
24
+ );
25
+ return jsi::Value(parserId);
26
+ })
27
+ );
28
+
29
+ rt.global().setProperty(
30
+ rt, "jsi_unregisterMarcusWorklet", jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "jsi_unregisterMarcusWorklet"), 1, [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
31
+ auto parserId = static_cast<int>(args[0].asNumber());
32
+ unregisterMarkdownWorklet(parserId);
33
+ return jsi::Value::undefined();
34
+ })
35
+ );
36
+ }
37
+
38
+ } // namespace marcus
39
+ } // namespace bulletpoint
@@ -0,0 +1,14 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+
5
+ using namespace facebook;
6
+
7
+ namespace bulletpoint {
8
+ namespace marcus {
9
+
10
+ void
11
+ injectJSIBindings(jsi::Runtime &rt);
12
+
13
+ } // namespace marcus
14
+ } // namespace bulletpoint