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,205 @@
1
+ package app.getbullet.marcus
2
+
3
+ import android.text.SpannableStringBuilder
4
+ import android.text.TextPaint
5
+ import com.facebook.react.bridge.JavaOnlyMap
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.facebook.react.uimanager.DisplayMetricsHolder
8
+ import java.io.File
9
+ import org.json.JSONArray
10
+ import org.json.JSONObject
11
+ import org.junit.Assert.assertEquals
12
+ import org.junit.Before
13
+ import org.junit.Test
14
+ import org.junit.runner.RunWith
15
+ import org.robolectric.RobolectricTestRunner
16
+ import org.robolectric.RuntimeEnvironment
17
+ import org.robolectric.annotation.Config
18
+
19
+ /**
20
+ * The Android render model, driven by the same corpus every other layer uses.
21
+ *
22
+ * Ranges come from `ranges.json`, produced by the JS parser: a formatter takes
23
+ * ranges rather than markdown, so this suite needs no JS runtime and no device.
24
+ *
25
+ * The whole corpus is dumped into one baseline rather than one file per case,
26
+ * so the Android and iOS outputs stay diffable against each other in a single
27
+ * comparison. Regenerate with `-Dmarcus.updateBaselines=true`.
28
+ */
29
+ @RunWith(RobolectricTestRunner::class)
30
+ @Config(sdk = [34])
31
+ class MarkdownFormatterTest {
32
+
33
+ private lateinit var style: MarkdownStyle
34
+ private lateinit var formatter: MarkdownFormatter
35
+
36
+ @Before
37
+ fun setUp() {
38
+ val context = RuntimeEnvironment.getApplication()
39
+ // `PixelUtil.toPixelFromDIP` reads these; without them every gutter is NaN.
40
+ DisplayMetricsHolder.initDisplayMetrics(context)
41
+
42
+ style = MarkdownStyle(styleMap(), context)
43
+ formatter = MarkdownFormatter(context.assets)
44
+ }
45
+
46
+ @Test
47
+ fun `formats every fixture into the shared render model`() {
48
+ val cases = JSONArray(resource("cases.json"))
49
+ val ranges = JSONObject(resource("ranges.json"))
50
+
51
+ val dump = buildString {
52
+ for (i in 0 until cases.length()) {
53
+ val entry = cases.getJSONObject(i)
54
+ val id = entry.getString("id")
55
+ val markdown = entry.getString("markdown")
56
+
57
+ val ssb = SpannableStringBuilder(markdown)
58
+ formatter.format(ssb, rangesOf(ranges.getJSONArray(id)), style, textPaint())
59
+
60
+ append(id).append('\n')
61
+ append(RenderModel.dump(markdown, ssb).prependIndent(" ")).append('\n')
62
+ }
63
+ }
64
+
65
+ val baseline = File("src/test/resources/render-model.txt")
66
+
67
+ if (System.getProperty("marcus.updateBaselines") == "true" || !baseline.exists()) {
68
+ baseline.parentFile.mkdirs()
69
+ baseline.writeText(dump)
70
+ println("Wrote baseline to ${baseline.absolutePath}")
71
+ return
72
+ }
73
+
74
+ if (baseline.readText() != dump) {
75
+ val actual = File("build/render-model-actual.txt")
76
+ actual.parentFile.mkdirs()
77
+ actual.writeText(dump)
78
+ }
79
+
80
+ assertEquals(baseline.readText(), dump)
81
+ }
82
+
83
+ @Test
84
+ fun `applies bold across the whole emphasis span`() {
85
+ val ssb = SpannableStringBuilder("**bold**")
86
+ formatter.format(
87
+ ssb,
88
+ listOf(
89
+ MarkdownRange("bold", 0, 8, 0),
90
+ MarkdownRange("syntax", 0, 2, 0),
91
+ MarkdownRange("syntax", 6, 2, 0),
92
+ ),
93
+ style,
94
+ textPaint(),
95
+ )
96
+
97
+ assertEquals(
98
+ """
99
+ 0..8 bold
100
+ 0..2 color(#808080)
101
+ 6..8 color(#808080)
102
+ """.trimIndent(),
103
+ RenderModel.dump("**bold**", ssb).trimIndent(),
104
+ )
105
+ }
106
+
107
+ @Test
108
+ fun `leaves plain text unspanned`() {
109
+ val ssb = SpannableStringBuilder("no markdown here")
110
+ formatter.format(ssb, emptyList(), style, textPaint())
111
+
112
+ assertEquals("(no spans)", RenderModel.dump("no markdown here", ssb))
113
+ }
114
+
115
+ private fun textPaint() = TextPaint().apply { textSize = 16f }
116
+
117
+ private fun rangesOf(array: JSONArray): List<MarkdownRange> =
118
+ (0 until array.length()).map { i ->
119
+ val range = array.getJSONObject(i)
120
+ MarkdownRange(
121
+ range.getString("type"),
122
+ range.getInt("start"),
123
+ range.getInt("length"),
124
+ range.optInt("depth", 0),
125
+ )
126
+ }
127
+
128
+ private fun resource(name: String): String =
129
+ requireNotNull(javaClass.classLoader?.getResourceAsStream(name)) {
130
+ "$name is not on the test classpath -- is sourceSets.test.resources pointing at src/__fixtures__?"
131
+ }.bufferedReader().readText()
132
+
133
+ /** The same style the web harness pins, so the dumps are comparable. */
134
+ private fun styleMap(): ReadableMap {
135
+ fun group(vararg entries: Pair<String, Any>): JavaOnlyMap = JavaOnlyMap().apply {
136
+ entries.forEach { (key, value) ->
137
+ when (value) {
138
+ is Int -> putInt(key, value)
139
+ is Double -> putDouble(key, value)
140
+ is String -> putString(key, value)
141
+ }
142
+ }
143
+ }
144
+
145
+ return JavaOnlyMap().apply {
146
+ putMap("syntax", group("color" to 0xFF808080.toInt()))
147
+ putMap("link", group("color" to 0xFF0000FF.toInt()))
148
+ putMap("heading", group("fontSize" to 38.0, "scale" to 0.85))
149
+ putMap("emoji", group("fontSize" to 16.0, "fontFamily" to "System"))
150
+ putMap(
151
+ "blockquote",
152
+ group(
153
+ "borderColor" to 0xFF808080.toInt(),
154
+ "borderWidth" to 6.0,
155
+ "marginLeft" to 6.0,
156
+ "paddingLeft" to 6.0,
157
+ ),
158
+ )
159
+ putMap("orderedList", group("marginLeft" to 6.0, "paddingLeft" to 18.0))
160
+ putMap("unorderedList", group("marginLeft" to 6.0, "paddingLeft" to 18.0))
161
+ putMap(
162
+ "code",
163
+ group(
164
+ "fontFamily" to "monospace",
165
+ "fontSize" to 16.0,
166
+ "color" to 0xFF000000.toInt(),
167
+ "backgroundColor" to 0xFFD3D3D3.toInt(),
168
+ ),
169
+ )
170
+ putMap(
171
+ "pre",
172
+ group(
173
+ "fontFamily" to "monospace",
174
+ "fontSize" to 16.0,
175
+ "color" to 0xFF000000.toInt(),
176
+ "backgroundColor" to 0xFFD3D3D3.toInt(),
177
+ ),
178
+ )
179
+ putMap(
180
+ "mentionHere",
181
+ group(
182
+ "color" to 0xFF008000.toInt(),
183
+ "backgroundColor" to 0xFF00FF00.toInt(),
184
+ "borderRadius" to 5.0,
185
+ ),
186
+ )
187
+ putMap(
188
+ "mentionUser",
189
+ group(
190
+ "color" to 0xFF0000FF.toInt(),
191
+ "backgroundColor" to 0xFF00FFFF.toInt(),
192
+ "borderRadius" to 5.0,
193
+ ),
194
+ )
195
+ putMap(
196
+ "mentionReport",
197
+ group(
198
+ "color" to 0xFFFF0000.toInt(),
199
+ "backgroundColor" to 0xFFFFC0CB.toInt(),
200
+ "borderRadius" to 5.0,
201
+ ),
202
+ )
203
+ }
204
+ }
205
+ }
@@ -0,0 +1,78 @@
1
+ package app.getbullet.marcus
2
+
3
+ import android.graphics.Color
4
+ import android.text.Spanned
5
+ import android.text.style.AbsoluteSizeSpan
6
+ import android.text.style.BackgroundColorSpan
7
+ import android.text.style.ForegroundColorSpan
8
+ import android.text.style.LeadingMarginSpan
9
+ import app.getbullet.marcus.spans.MarkdownBackgroundSpan
10
+ import app.getbullet.marcus.spans.MarkdownBoldSpan
11
+ import app.getbullet.marcus.spans.MarkdownFontFamilySpan
12
+ import app.getbullet.marcus.spans.MarkdownGapSpan
13
+ import app.getbullet.marcus.spans.MarkdownItalicSpan
14
+ import app.getbullet.marcus.spans.MarkdownLineHeightSpan
15
+ import app.getbullet.marcus.spans.MarkdownStrikethroughSpan
16
+ import app.getbullet.marcus.spans.MarkdownUnderlineSpan
17
+
18
+ /**
19
+ * Serializes the spans a formatted string carries into the shared render model.
20
+ *
21
+ * One line per span, `start..end attribute`, sorted so the output does not
22
+ * depend on the order the formatter happened to apply things in. The attribute
23
+ * vocabulary is deliberately platform neutral -- `bold`, `color(#RRGGBB)`,
24
+ * `indent(first,rest)` -- so an Android dump and an iOS dump of the same case
25
+ * can be diffed against each other directly.
26
+ *
27
+ * Only public API is read. Making span fields visible purely so a test could
28
+ * assert on them would be the test changing the thing it measures.
29
+ */
30
+ object RenderModel {
31
+
32
+ fun dump(text: CharSequence, spanned: Spanned): String {
33
+ val lines = spanned.getSpans(0, spanned.length, Any::class.java)
34
+ .mapNotNull { span ->
35
+ val attribute = describe(span) ?: return@mapNotNull null
36
+ val start = spanned.getSpanStart(span)
37
+ val end = spanned.getSpanEnd(span)
38
+ Triple(start, end, attribute)
39
+ }
40
+ .sortedWith(compareBy({ it.first }, { -it.second }, { it.third }))
41
+ .map { (start, end, attribute) ->
42
+ "%4d..%-4d %s".format(start, end, attribute)
43
+ }
44
+
45
+ if (lines.isEmpty()) {
46
+ return "(no spans)"
47
+ }
48
+
49
+ return lines.joinToString("\n")
50
+ }
51
+
52
+ /** The shared attribute name for a span, or null for spans we do not model. */
53
+ private fun describe(span: Any): String? = when (span) {
54
+ is MarkdownBoldSpan -> "bold"
55
+ is MarkdownItalicSpan -> "italic"
56
+ is MarkdownStrikethroughSpan -> "strikethrough"
57
+ is MarkdownUnderlineSpan -> "underline"
58
+ is MarkdownFontFamilySpan -> "font-family"
59
+ is MarkdownLineHeightSpan -> "line-height"
60
+ // The rounded rectangle drawn behind a mention, not a plain background
61
+ // colour -- iOS models the same thing as `MarkdownTextBackground`.
62
+ is MarkdownBackgroundSpan -> "background-shape"
63
+ // The space held open after a marker so the next container's gutter lands
64
+ // between the two.
65
+ is MarkdownGapSpan -> "gap"
66
+ is ForegroundColorSpan -> "color(${hex(span.foregroundColor)})"
67
+ is BackgroundColorSpan -> "background(${hex(span.backgroundColor)})"
68
+ is AbsoluteSizeSpan -> "font-size(${span.size})"
69
+ is LeadingMarginSpan ->
70
+ "indent(${span.getLeadingMargin(true)},${span.getLeadingMargin(false)})"
71
+ // Anything still unnamed is flagged rather than dropped: a span the model
72
+ // has no word for is exactly what a reviewer needs to see.
73
+ else -> "?${span.javaClass.simpleName.removePrefix("Markdown").removeSuffix("Span")}"
74
+ }
75
+
76
+ private fun hex(color: Int): String =
77
+ "#%02X%02X%02X".format(Color.red(color), Color.green(color), Color.blue(color))
78
+ }