react-native-enriched-markdown-scaffold 0.7.4-scaffold.9 → 1.0.2-scaffold.2

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 (469) hide show
  1. package/README.md +54 -8
  2. package/ReactNativeEnrichedMarkdown.podspec +82 -73
  3. package/android/build.gradle +186 -1
  4. package/android/consumer-rules.pro +1 -1
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +9 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +24 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +8 -0
  9. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +9 -0
  10. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +886 -23
  15. package/android/src/main/baseline-prof.txt +1 -1
  16. package/android/src/main/cpp/jni-adapter.cpp +74 -0
  17. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +189 -13
  18. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +17 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +50 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -1
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +10 -1
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +42 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +82 -4
  24. package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyPressEvent.kt +24 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +54 -4
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +901 -462
  27. package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +101 -7
  34. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
  36. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
  65. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
  68. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
  69. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
  70. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
  72. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
  73. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
  74. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
  75. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
  77. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
  79. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
  80. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
  81. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
  82. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
  83. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
  84. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
  88. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
  89. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
  90. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
  93. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
  94. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
  95. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
  96. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
  97. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
  100. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
  101. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
  102. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
  103. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
  104. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
  105. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
  106. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
  107. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
  108. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
  109. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
  110. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
  111. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
  112. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
  114. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
  115. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
  116. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +49 -15
  117. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +45 -0
  118. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +396 -0
  119. package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
  120. package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
  121. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +36 -9
  122. package/android/src/main/jni/CMakeLists.txt +53 -0
  123. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
  124. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
  125. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
  126. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
  127. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  128. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
  129. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
  130. package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
  131. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +7 -2
  132. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  133. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +6 -4
  134. package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
  135. package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
  136. package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
  137. package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
  138. package/cpp/highlight/HighlightGrammars.hpp +28 -0
  139. package/cpp/highlight/code_highlight_podspec.rb +211 -0
  140. package/cpp/highlight/gen-registry.mjs +155 -0
  141. package/cpp/highlight/grammar-versions.json +159 -0
  142. package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
  143. package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
  144. package/cpp/parser/MD4CParser.cpp +173 -61
  145. package/cpp/parser/MD4CParser.hpp +1 -0
  146. package/cpp/parser/MarkdownASTNode.hpp +2 -1
  147. package/cpp/wasm/ASTSerializer.cpp +2 -0
  148. package/cpp/wasm/build.sh +1 -0
  149. package/cpp/wasm/md4c_wasm.cpp +3 -1
  150. package/docs/ACCESSIBILITY.md +14 -2
  151. package/docs/API_REFERENCE.md +234 -12
  152. package/docs/BREAKING_CHANGES.md +129 -0
  153. package/docs/CODE_HIGHLIGHT.md +133 -0
  154. package/docs/COPY_OPTIONS.md +47 -3
  155. package/docs/ELEMENTS_STRUCTURE.md +52 -4
  156. package/docs/IMAGE_CACHING.md +30 -0
  157. package/docs/INPUT.md +108 -11
  158. package/docs/LATEX_MATH.md +87 -45
  159. package/docs/MACOS.md +1 -1
  160. package/docs/MARKDOWN_STREAMING.md +27 -1
  161. package/docs/NATIVE_ASSETS.md +127 -0
  162. package/docs/RTL.md +1 -1
  163. package/docs/STYLES.md +46 -6
  164. package/docs/TESTING.md +112 -0
  165. package/docs/TEXT.md +16 -6
  166. package/docs/WEB.md +3 -1
  167. package/ios/EnrichedMarkdown.h +7 -0
  168. package/ios/EnrichedMarkdown.mm +284 -75
  169. package/ios/EnrichedMarkdownText.h +7 -0
  170. package/ios/EnrichedMarkdownText.mm +101 -73
  171. package/ios/attachments/ENRMImageAttachment.h +9 -0
  172. package/ios/attachments/ENRMImageAttachment.m +143 -40
  173. package/ios/attachments/ENRMMathInlineAttachment.h +2 -0
  174. package/ios/attachments/ENRMMathInlineAttachment.m +48 -81
  175. package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
  176. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  177. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  178. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  179. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +886 -23
  180. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +131 -0
  181. package/ios/input/ENRMAutoLinkDetector.h +2 -1
  182. package/ios/input/ENRMAutoLinkDetector.mm +79 -41
  183. package/ios/input/ENRMBlockEditCoordinator.h +71 -0
  184. package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
  185. package/ios/input/ENRMBlockRange.h +28 -0
  186. package/ios/input/ENRMBlockRange.mm +30 -0
  187. package/ios/input/ENRMBlockStore.h +56 -0
  188. package/ios/input/ENRMBlockStore.mm +275 -0
  189. package/ios/input/ENRMClipboardCoordinator.h +45 -0
  190. package/ios/input/ENRMClipboardCoordinator.mm +120 -0
  191. package/ios/input/ENRMDetectorPipeline.h +2 -1
  192. package/ios/input/ENRMEditPipeline.h +76 -0
  193. package/ios/input/ENRMEditPipeline.mm +228 -0
  194. package/ios/input/ENRMEditSession.h +36 -0
  195. package/ios/input/ENRMEditSession.mm +63 -0
  196. package/ios/input/ENRMFormattingStore.h +17 -0
  197. package/ios/input/ENRMFormattingStore.mm +95 -105
  198. package/ios/input/ENRMInputBlockType.h +91 -0
  199. package/ios/input/ENRMInputBlockType.mm +5 -0
  200. package/ios/input/ENRMInputDecorationDrawer.h +18 -0
  201. package/ios/input/ENRMInputEventEmitter.h +56 -0
  202. package/ios/input/ENRMInputEventEmitter.mm +308 -0
  203. package/ios/input/ENRMInputFormatter.h +29 -69
  204. package/ios/input/ENRMInputFormatter.mm +216 -124
  205. package/ios/input/ENRMInputFormatterStyle.h +99 -0
  206. package/ios/input/ENRMInputFormatterStyle.mm +188 -0
  207. package/ios/input/ENRMInputLayoutManager.h +9 -0
  208. package/ios/input/ENRMInputLayoutManager.mm +30 -0
  209. package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
  210. package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
  211. package/ios/input/ENRMInputParser.h +5 -6
  212. package/ios/input/ENRMInputParser.mm +461 -178
  213. package/ios/input/ENRMInputRemend.mm +2 -2
  214. package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
  215. package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
  216. package/ios/input/ENRMInputTextView.mm +103 -8
  217. package/ios/input/ENRMInputTypingAttributesController.h +42 -0
  218. package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
  219. package/ios/input/ENRMLinkCoordinator.h +41 -0
  220. package/ios/input/ENRMLinkCoordinator.mm +89 -0
  221. package/ios/input/ENRMMarkdownSerializer.h +29 -5
  222. package/ios/input/ENRMMarkdownSerializer.mm +170 -48
  223. package/ios/input/ENRMMathAtom.h +26 -0
  224. package/ios/input/ENRMMathAtom.mm +12 -0
  225. package/ios/input/ENRMMentionCoordinator.h +45 -0
  226. package/ios/input/ENRMMentionCoordinator.mm +167 -0
  227. package/ios/input/ENRMRangeEditAdjustment.h +38 -0
  228. package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
  229. package/ios/input/ENRMRangeStoreUtils.h +39 -0
  230. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
  231. package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
  232. package/ios/input/EnrichedMarkdownTextInput.h +7 -1
  233. package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
  234. package/ios/input/InputStylePropsUtils.h +109 -68
  235. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
  236. package/ios/input/styles/ENRMBlockHandler.h +46 -0
  237. package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
  238. package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
  239. package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
  240. package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
  241. package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
  242. package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
  243. package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
  244. package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
  245. package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
  246. package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
  247. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
  248. package/ios/internals/MeasurementCache.h +33 -7
  249. package/ios/internals/ShadowMeasurementUtils.h +63 -58
  250. package/ios/math/ENRMMathChipController.h +74 -0
  251. package/ios/math/ENRMMathChipController.mm +476 -0
  252. package/ios/math/ENRMRaTeXBridge.swift +4 -1
  253. package/ios/parser/ENRMMarkdownParser.h +1 -8
  254. package/ios/parser/ENRMMarkdownParser.mm +2 -11
  255. package/ios/parser/MarkdownASTNode.h +2 -1
  256. package/ios/parser/MarkdownParserBridge.mm +4 -0
  257. package/ios/renderer/AttributedRenderer.m +20 -2
  258. package/ios/renderer/BaseRenderer.h +17 -2
  259. package/ios/renderer/BaseRenderer.m +30 -0
  260. package/ios/renderer/BlockquoteRenderer.h +1 -1
  261. package/ios/renderer/BlockquoteRenderer.m +144 -35
  262. package/ios/renderer/CodeBlockRenderer.h +1 -1
  263. package/ios/renderer/CodeBlockRenderer.m +27 -23
  264. package/ios/renderer/CodeRenderer.h +1 -1
  265. package/ios/renderer/CodeRenderer.m +3 -1
  266. package/ios/renderer/ENRMImageRenderer.h +1 -1
  267. package/ios/renderer/ENRMImageRenderer.m +5 -1
  268. package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
  269. package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
  270. package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
  271. package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
  272. package/ios/renderer/EmphasisRenderer.h +1 -1
  273. package/ios/renderer/EmphasisRenderer.m +3 -1
  274. package/ios/renderer/HeadingRenderer.h +1 -1
  275. package/ios/renderer/HeadingRenderer.m +13 -6
  276. package/ios/renderer/HighlightRenderer.h +1 -1
  277. package/ios/renderer/HighlightRenderer.m +3 -1
  278. package/ios/renderer/LinkRenderer.h +1 -1
  279. package/ios/renderer/LinkRenderer.m +3 -1
  280. package/ios/renderer/ListItemRenderer.h +13 -1
  281. package/ios/renderer/ListItemRenderer.m +102 -44
  282. package/ios/renderer/ListRenderer.h +2 -2
  283. package/ios/renderer/ListRenderer.m +63 -25
  284. package/ios/renderer/ParagraphRenderer.h +1 -1
  285. package/ios/renderer/ParagraphRenderer.m +16 -8
  286. package/ios/renderer/RenderContext.h +10 -0
  287. package/ios/renderer/RenderContext.m +44 -0
  288. package/ios/renderer/RendererFactory.m +14 -0
  289. package/ios/renderer/StrikethroughRenderer.h +1 -1
  290. package/ios/renderer/StrikethroughRenderer.m +3 -1
  291. package/ios/renderer/StrongRenderer.h +1 -1
  292. package/ios/renderer/StrongRenderer.m +3 -1
  293. package/ios/renderer/SubscriptRenderer.h +1 -1
  294. package/ios/renderer/SubscriptRenderer.m +3 -1
  295. package/ios/renderer/SuperscriptRenderer.h +1 -1
  296. package/ios/renderer/SuperscriptRenderer.m +3 -1
  297. package/ios/renderer/TextRenderer.h +2 -2
  298. package/ios/renderer/TextRenderer.m +3 -1
  299. package/ios/renderer/ThematicBreakRenderer.h +1 -1
  300. package/ios/renderer/ThematicBreakRenderer.m +3 -1
  301. package/ios/renderer/UnderlineRenderer.h +1 -1
  302. package/ios/renderer/UnderlineRenderer.m +3 -1
  303. package/ios/styles/StyleConfig.h +22 -0
  304. package/ios/styles/StyleConfig.mm +132 -0
  305. package/ios/utils/BlockquoteBorder.h +6 -0
  306. package/ios/utils/BlockquoteBorder.m +249 -52
  307. package/ios/utils/CodeBlockBackground.m +16 -2
  308. package/ios/utils/ENRMAtomicSize.h +65 -0
  309. package/ios/utils/ENRMBlockMenu.h +57 -0
  310. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  311. package/ios/utils/ENRMCodeBlockContent.mm +79 -0
  312. package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
  313. package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
  314. package/ios/utils/ENRMFeatureFlags.h +7 -0
  315. package/ios/utils/ENRMImageDownloader.h +11 -1
  316. package/ios/utils/ENRMImageDownloader.m +60 -16
  317. package/ios/utils/ENRMLocalImageLoader.h +31 -0
  318. package/ios/utils/ENRMLocalImageLoader.m +68 -0
  319. package/ios/utils/ENRMMathFallback.h +26 -0
  320. package/ios/utils/ENRMMathFallback.m +18 -0
  321. package/ios/utils/ENRMTextViewSetup.h +35 -17
  322. package/ios/utils/EditMenuUtils.h +22 -5
  323. package/ios/utils/EditMenuUtils.m +53 -9
  324. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  325. package/ios/utils/LastElementUtils.h +1 -0
  326. package/ios/utils/ListMarkerDrawer.m +29 -42
  327. package/ios/utils/MarkdownASTSerializer.m +4 -0
  328. package/ios/utils/ParagraphStyleUtils.h +5 -0
  329. package/ios/utils/ParagraphStyleUtils.m +77 -17
  330. package/ios/utils/RenderedMarkdownSegment.h +13 -1
  331. package/ios/utils/RenderedMarkdownSegment.m +20 -0
  332. package/ios/utils/SegmentRenderer.m +17 -4
  333. package/ios/utils/StreamingMarkdownFilter.h +11 -1
  334. package/ios/utils/StreamingMarkdownFilter.m +98 -2
  335. package/ios/utils/StylePropsUtils.h +63 -0
  336. package/ios/utils/TaskListTapUtils.m +24 -0
  337. package/ios/views/ENRMCodeBlockContainerView.h +53 -0
  338. package/ios/views/ENRMCodeBlockContainerView.m +559 -0
  339. package/ios/views/ENRMMathContainerView.h +16 -0
  340. package/ios/views/ENRMMathContainerView.m +74 -19
  341. package/ios/views/TableContainerView.h +22 -0
  342. package/ios/views/TableContainerView.m +261 -175
  343. package/jest.d.ts +1 -0
  344. package/jest.js +5 -0
  345. package/lib/module/EnrichedMarkdownNativeComponent.ts +73 -0
  346. package/lib/module/EnrichedMarkdownTextInput.js +84 -5
  347. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  348. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  349. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +74 -0
  350. package/lib/module/headingDefaults.js +34 -0
  351. package/lib/module/headingDefaults.js.map +1 -0
  352. package/lib/module/index.js.map +1 -1
  353. package/lib/module/jest/index.js +191 -0
  354. package/lib/module/jest/index.js.map +1 -0
  355. package/lib/module/native/EnrichedMarkdownText.js +37 -5
  356. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  357. package/lib/module/normalizeMarkdownStyle.js +81 -19
  358. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  359. package/lib/module/normalizeMarkdownStyle.web.js +56 -18
  360. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  361. package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
  362. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  363. package/lib/module/normalizeMenuItem.js +1 -1
  364. package/lib/module/utils/textInputState.js +26 -0
  365. package/lib/module/utils/textInputState.js.map +1 -0
  366. package/lib/module/web/EnrichedMarkdownText.js +9 -5
  367. package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
  368. package/lib/module/web/parseMarkdown.js +4 -3
  369. package/lib/module/web/parseMarkdown.js.map +1 -1
  370. package/lib/module/web/renderers/InlineRenderers.js +6 -0
  371. package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
  372. package/lib/module/web/renderers/ListRenderers.js +7 -2
  373. package/lib/module/web/renderers/ListRenderers.js.map +1 -1
  374. package/lib/module/web/renderers/index.js +7 -4
  375. package/lib/module/web/renderers/index.js.map +1 -1
  376. package/lib/module/web/styles.js +83 -6
  377. package/lib/module/web/styles.js.map +1 -1
  378. package/lib/module/web/utils.js +1 -0
  379. package/lib/module/web/utils.js.map +1 -1
  380. package/lib/module/web/wasm/md4c.js +0 -0
  381. package/lib/module/web/wasm/md4c.js.map +1 -1
  382. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +66 -0
  383. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  384. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
  385. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  386. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
  387. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  388. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +66 -0
  389. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  390. package/lib/typescript/src/headingDefaults.d.ts +9 -0
  391. package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
  392. package/lib/typescript/src/index.d.ts +2 -2
  393. package/lib/typescript/src/index.d.ts.map +1 -1
  394. package/lib/typescript/src/index.web.d.ts +1 -1
  395. package/lib/typescript/src/index.web.d.ts.map +1 -1
  396. package/lib/typescript/src/jest/index.d.ts +6 -0
  397. package/lib/typescript/src/jest/index.d.ts.map +1 -0
  398. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
  399. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  400. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  401. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  402. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
  403. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  404. package/lib/typescript/src/types/MarkdownStyle.d.ts +72 -0
  405. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  406. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +27 -0
  407. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  408. package/lib/typescript/src/types/MarkdownTextProps.d.ts +104 -9
  409. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  410. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +19 -0
  411. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
  412. package/lib/typescript/src/types/events.d.ts +19 -0
  413. package/lib/typescript/src/types/events.d.ts.map +1 -1
  414. package/lib/typescript/src/utils/textInputState.d.ts +24 -0
  415. package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
  416. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
  417. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
  418. package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
  419. package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
  420. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
  421. package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
  422. package/lib/typescript/src/web/renderers/index.d.ts +2 -1
  423. package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
  424. package/lib/typescript/src/web/styles.d.ts +2 -1
  425. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  426. package/lib/typescript/src/web/types.d.ts +6 -2
  427. package/lib/typescript/src/web/types.d.ts.map +1 -1
  428. package/lib/typescript/src/web/utils.d.ts.map +1 -1
  429. package/package.json +36 -9
  430. package/postinstall.mjs +131 -0
  431. package/ratex-version.json +21 -0
  432. package/src/EnrichedMarkdownNativeComponent.ts +73 -0
  433. package/src/EnrichedMarkdownTextInput.tsx +159 -8
  434. package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  435. package/src/EnrichedMarkdownTextNativeComponent.ts +74 -0
  436. package/src/headingDefaults.ts +21 -0
  437. package/src/index.tsx +9 -0
  438. package/src/index.web.tsx +1 -0
  439. package/src/jest/index.tsx +215 -0
  440. package/src/native/EnrichedMarkdownText.tsx +53 -2
  441. package/src/normalizeMarkdownStyle.ts +102 -16
  442. package/src/normalizeMarkdownStyle.web.ts +63 -15
  443. package/src/normalizeMarkdownTextInputStyle.ts +110 -35
  444. package/src/normalizeMenuItem.ts +1 -1
  445. package/src/types/MarkdownStyle.ts +74 -0
  446. package/src/types/MarkdownStyleInternal.ts +39 -0
  447. package/src/types/MarkdownTextProps.ts +101 -9
  448. package/src/types/MarkdownTextProps.web.ts +19 -0
  449. package/src/types/events.ts +21 -0
  450. package/src/utils/textInputState.ts +35 -0
  451. package/src/web/EnrichedMarkdownText.tsx +16 -2
  452. package/src/web/parseMarkdown.ts +6 -2
  453. package/src/web/renderers/InlineRenderers.tsx +5 -0
  454. package/src/web/renderers/ListRenderers.tsx +14 -2
  455. package/src/web/renderers/index.tsx +6 -2
  456. package/src/web/styles.ts +89 -5
  457. package/src/web/types.ts +6 -1
  458. package/src/web/utils.ts +1 -0
  459. package/src/web/wasm/md4c.js +0 -0
  460. package/vendor-grammars.mjs +511 -0
  461. package/vendor-ratex.mjs +173 -0
  462. package/app.plugin.js +0 -2
  463. package/plugin/build/withAndroidMath.js +0 -19
  464. package/plugin/build/withIosMath.js +0 -28
  465. package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
  466. package/plugin/src/withAndroidMath.ts +0 -24
  467. package/plugin/src/withIosMath.ts +0 -35
  468. package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
  469. package/plugin/tsconfig.build.json +0 -16
@@ -1,6 +1,8 @@
1
1
  #pragma once
2
2
 
3
+ #import "ENRMBlockRange.h"
3
4
  #import "ENRMFormattingRange.h"
5
+ #import "ENRMMathAtom.h"
4
6
 
5
7
  NS_ASSUME_NONNULL_BEGIN
6
8
 
@@ -8,11 +10,33 @@ NS_ASSUME_NONNULL_BEGIN
8
10
 
9
11
  + (NSString *)serializePlainText:(NSString *)text ranges:(NSArray<ENRMFormattingRange *> *)ranges;
10
12
 
11
- /// Serializes an attributed string, expanding any `ENRMMathInlineAttachment`
12
- /// at U+FFFC positions back into `$latex$` or `$$latex$$` markdown. The
13
- /// `ranges` are formatting ranges over `attr.string` positions; they are
14
- /// shifted internally to account for the expansion.
15
- + (NSString *)serializeAttributedString:(NSAttributedString *)attr ranges:(NSArray<ENRMFormattingRange *> *)ranges;
13
+ /// Block-aware serialization: serializes inline styles exactly as the inline-only
14
+ /// overload, then prepends each line's block prefix. `prefixProvider` is asked,
15
+ /// per block range, for the markdown line marker (e.g. @"# ", @"- "); returning
16
+ /// @"" or nil leaves the line unprefixed. With empty `blockRanges` the output is
17
+ /// identical to the inline-only overload.
18
+ + (NSString *)serializePlainText:(NSString *)text
19
+ ranges:(NSArray<ENRMFormattingRange *> *)ranges
20
+ blockRanges:(NSArray<ENRMBlockRange *> *)blockRanges
21
+ blockPrefixProvider:(NSString *_Nullable (^_Nullable)(ENRMBlockRange *blockRange))prefixProvider;
22
+
23
+ /// Math-aware serialization — the single output path for a buffer that may hold
24
+ /// math chips. Each chip's `kENRMObjectReplacement` placeholder expands back to
25
+ /// `$latex$` / `$$latex$$`, and **both** the inline ranges and the block ranges
26
+ /// are translated through the same position map before the block-aware overload
27
+ /// above runs. Translating only one of the two is the silent failure this
28
+ /// exists to prevent: one placeholder character becomes n characters, so every
29
+ /// block boundary after a chip would land a line off and `# `/`- `/`1. ` would
30
+ /// prefix the wrong line.
31
+ ///
32
+ /// Chips arrive as plain data (not an `NSAttributedString`), so this stays a pure
33
+ /// function over `NSString` — which is what makes the round trip testable without
34
+ /// a live editor. `ENRMMathAtom.position` is an offset into `text`.
35
+ + (NSString *)serializePlainText:(NSString *)text
36
+ mathAtoms:(NSArray<ENRMMathAtom *> *)mathAtoms
37
+ ranges:(NSArray<ENRMFormattingRange *> *)ranges
38
+ blockRanges:(NSArray<ENRMBlockRange *> *)blockRanges
39
+ blockPrefixProvider:(NSString *_Nullable (^_Nullable)(ENRMBlockRange *blockRange))prefixProvider;
16
40
 
17
41
  @end
18
42
 
@@ -1,9 +1,20 @@
1
1
  #import "ENRMMarkdownSerializer.h"
2
2
 
3
- #import "ENRMFeatureFlags.h"
4
- #if ENRICHED_MARKDOWN_MATH
5
- #import "ENRMMathInlineAttachment.h"
6
- #endif
3
+ #include <vector>
4
+
5
+ /// Translates a range over the pre-expansion text into the expanded text. Both
6
+ /// endpoints go through the same map, which is what keeps inline and block
7
+ /// ranges consistent with each other after a chip expands.
8
+ static NSRange mapRangeThroughPositionMap(NSRange range, const std::vector<NSUInteger> &positionMap,
9
+ NSUInteger textLength)
10
+ {
11
+ NSUInteger start = MIN(range.location, textLength);
12
+ NSUInteger end = MIN(NSMaxRange(range), textLength);
13
+ if (end < start) {
14
+ end = start;
15
+ }
16
+ return NSMakeRange(positionMap[start], positionMap[end] - positionMap[start]);
17
+ }
7
18
 
8
19
  static NSString *openingDelimiterForType(ENRMInputStyleType type)
9
20
  {
@@ -224,60 +235,171 @@ static NSArray<ENRMFormattingRange *> *splitRangesAtParagraphBreaks(NSArray<ENRM
224
235
  return markdown;
225
236
  }
226
237
 
227
- + (NSString *)serializeAttributedString:(NSAttributedString *)attr ranges:(NSArray<ENRMFormattingRange *> *)ranges
238
+ + (NSString *)serializePlainText:(NSString *)text
239
+ ranges:(NSArray<ENRMFormattingRange *> *)ranges
240
+ blockRanges:(NSArray<ENRMBlockRange *> *)blockRanges
241
+ blockPrefixProvider:(NSString *_Nullable (^_Nullable)(ENRMBlockRange *blockRange))prefixProvider
228
242
  {
229
- if (attr.length == 0) {
230
- return [self serializePlainText:@"" ranges:ranges];
243
+ NSString *inlineMarkdown = [self serializePlainText:text ranges:ranges];
244
+
245
+ if (blockRanges.count == 0 || prefixProvider == nil) {
246
+ return inlineMarkdown;
231
247
  }
232
248
 
233
- NSString *plain = attr.string;
234
- NSUInteger length = plain.length;
235
-
236
- // Build expanded text where each math `` becomes its `$latex$` / `$$latex$$`
237
- // markdown and build a position map from original indices to expanded indices.
238
- NSMutableString *expanded = [NSMutableString stringWithCapacity:length];
239
- NSMutableData *mapData = [NSMutableData dataWithLength:(length + 1) * sizeof(NSUInteger)];
240
- NSUInteger *posMap = (NSUInteger *)mapData.mutableBytes;
241
- NSUInteger expandedPos = 0;
242
- for (NSUInteger i = 0; i < length; i++) {
243
- posMap[i] = expandedPos;
244
- unichar c = [plain characterAtIndex:i];
245
- if (c == (unichar)0xFFFC) {
246
- #if ENRICHED_MARKDOWN_MATH
247
- id value = [attr attribute:NSAttachmentAttributeName atIndex:i effectiveRange:NULL];
248
- if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
249
- ENRMMathInlineAttachment *att = value;
250
- NSString *delim = att.displayMode ? @"$$" : @"$";
251
- [expanded appendString:delim];
252
- if (att.latex.length > 0) {
253
- [expanded appendString:att.latex];
249
+ // Block prefixes attach per line. Inline serialization only inserts inline
250
+ // delimiters (never newlines), so the serialized output has the same line
251
+ // count as the plain text — we map a block's plain-text range to line indices
252
+ // and prefix the corresponding serialized lines.
253
+ NSArray<NSString *> *plainLines = [text componentsSeparatedByString:@"\n"];
254
+ NSMutableArray<NSString *> *markdownLines = [[inlineMarkdown componentsSeparatedByString:@"\n"] mutableCopy];
255
+
256
+ // Inline delimiters never cross a newline, so the line partition is preserved.
257
+ // If this ever breaks, prefixes would land on the wrong lines. Contract on
258
+ // both platforms: assert in debug, log and fall back to inline-only output in
259
+ // release — a library must not crash the host app over lost block prefixes.
260
+ NSCAssert(plainLines.count == markdownLines.count,
261
+ @"Block serialization line-count invariant violated: plain=%lu markdown=%lu",
262
+ (unsigned long)plainLines.count, (unsigned long)markdownLines.count);
263
+ if (plainLines.count != markdownLines.count) {
264
+ NSLog(@"[EnrichedMarkdown] Block serialization line-count invariant violated: plain=%lu markdown=%lu",
265
+ (unsigned long)plainLines.count, (unsigned long)markdownLines.count);
266
+ return inlineMarkdown;
267
+ }
268
+
269
+ NSMutableArray<NSNumber *> *lineStartOffsets = [NSMutableArray arrayWithCapacity:plainLines.count];
270
+ NSUInteger runningOffset = 0;
271
+ for (NSString *line in plainLines) {
272
+ [lineStartOffsets addObject:@(runningOffset)];
273
+ runningOffset += line.length + 1; // +1 for the '\n' separator
274
+ }
275
+
276
+ for (ENRMBlockRange *blockRange in blockRanges) {
277
+ NSString *prefix = prefixProvider(blockRange);
278
+ if (prefix.length == 0) {
279
+ continue;
280
+ }
281
+
282
+ NSUInteger blockStart = blockRange.range.location;
283
+ NSUInteger blockEnd = NSMaxRange(blockRange.range);
284
+ BOOL isZeroLength = blockRange.range.length == 0;
285
+ BOOL isListItem = ENRMBlockTypeIsListItem(blockRange.type);
286
+
287
+ for (NSUInteger lineIndex = 0; lineIndex < plainLines.count; lineIndex++) {
288
+ NSUInteger lineStart = lineStartOffsets[lineIndex].unsignedIntegerValue;
289
+ NSUInteger lineEnd = lineStart + plainLines[lineIndex].length;
290
+ BOOL overlaps = isZeroLength ? (lineStart == blockStart) : (lineEnd >= blockStart && lineStart < blockEnd);
291
+ if (overlaps) {
292
+ // A marker-only list line ("- " with no content) re-parses as a setext
293
+ // underline for the previous line; emit an empty list line bare. An
294
+ // empty "# " heading is valid ATX and keeps its prefix.
295
+ if (isListItem && plainLines[lineIndex].length == 0) {
296
+ continue;
254
297
  }
255
- [expanded appendString:delim];
256
- expandedPos += delim.length * 2 + att.latex.length;
257
- continue;
298
+ markdownLines[lineIndex] = [prefix stringByAppendingString:markdownLines[lineIndex]];
299
+ }
300
+ }
301
+ }
302
+
303
+ return [markdownLines componentsJoinedByString:@"\n"];
304
+ }
305
+
306
+ /// The chip's markdown form, delimiters included. Line breaks inside the LaTeX
307
+ /// are collapsed to spaces: a chip is one line box in the editor, and emitting a
308
+ /// real newline would change the serialized line count, which trips the
309
+ /// line-count invariant above and silently drops every block prefix in the
310
+ /// document. LaTeX is whitespace-insensitive here, so the formula is unaffected.
311
+ /// A blank formula expands to nothing rather than to a bare `$$` that would
312
+ /// re-parse as literal text.
313
+ static NSString *mathDelimitedMarkdown(ENRMMathAtom *atom)
314
+ {
315
+ NSMutableString *latex = [NSMutableString stringWithCapacity:atom.latex.length];
316
+ BOOL previousWasBreak = NO;
317
+ for (NSUInteger index = 0; index < atom.latex.length; index++) {
318
+ unichar character = [atom.latex characterAtIndex:index];
319
+ if (character == '\n' || character == '\r' || character == 0x2028 || character == 0x2029) {
320
+ if (!previousWasBreak) {
321
+ [latex appendString:@" "];
258
322
  }
259
- #endif
260
- // Unknown attachment — skip the placeholder char so it doesn't leak.
323
+ previousWasBreak = YES;
261
324
  continue;
262
325
  }
263
- [expanded appendFormat:@"%C", c];
264
- expandedPos += 1;
326
+ [latex appendFormat:@"%C", character];
327
+ previousWasBreak = NO;
328
+ }
329
+
330
+ NSString *trimmed = [latex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
331
+ if (trimmed.length == 0) {
332
+ return @"";
265
333
  }
266
- posMap[length] = expandedPos;
267
-
268
- NSMutableArray<ENRMFormattingRange *> *shifted = [NSMutableArray arrayWithCapacity:ranges.count];
269
- for (ENRMFormattingRange *fr in ranges) {
270
- NSUInteger start = fr.range.location;
271
- NSUInteger end = NSMaxRange(fr.range);
272
- if (start > length)
273
- start = length;
274
- if (end > length)
275
- end = length;
276
- NSRange shiftedRange = NSMakeRange(posMap[start], posMap[end] - posMap[start]);
277
- [shifted addObject:[ENRMFormattingRange rangeWithType:fr.type range:shiftedRange url:fr.url]];
334
+ NSString *delimiter = atom.displayMode ? @"$$" : @"$";
335
+ return [NSString stringWithFormat:@"%@%@%@", delimiter, trimmed, delimiter];
336
+ }
337
+
338
+ + (NSString *)serializePlainText:(NSString *)text
339
+ mathAtoms:(NSArray<ENRMMathAtom *> *)mathAtoms
340
+ ranges:(NSArray<ENRMFormattingRange *> *)ranges
341
+ blockRanges:(NSArray<ENRMBlockRange *> *)blockRanges
342
+ blockPrefixProvider:(NSString *_Nullable (^_Nullable)(ENRMBlockRange *blockRange))prefixProvider
343
+ {
344
+ if (mathAtoms.count == 0) {
345
+ return [self serializePlainText:text ranges:ranges blockRanges:blockRanges blockPrefixProvider:prefixProvider];
346
+ }
347
+
348
+ NSUInteger textLength = text.length;
349
+
350
+ // A chip whose recorded position no longer holds a placeholder is stale (the
351
+ // buffer moved under it); expanding it there would corrupt unrelated text.
352
+ NSMutableDictionary<NSNumber *, NSString *> *latexByPosition =
353
+ [NSMutableDictionary dictionaryWithCapacity:mathAtoms.count];
354
+ for (ENRMMathAtom *atom in mathAtoms) {
355
+ if (atom.position >= textLength) {
356
+ continue;
357
+ }
358
+ if ([text characterAtIndex:atom.position] != kENRMObjectReplacement) {
359
+ continue;
360
+ }
361
+ latexByPosition[@(atom.position)] = mathDelimitedMarkdown(atom);
362
+ }
363
+ if (latexByPosition.count == 0) {
364
+ return [self serializePlainText:text ranges:ranges blockRanges:blockRanges blockPrefixProvider:prefixProvider];
365
+ }
366
+
367
+ // positionMap[i] = offset in `expanded` of the character that was at text[i].
368
+ // Length + 1 so an exclusive end offset at textLength maps too.
369
+ NSMutableString *expanded = [NSMutableString stringWithCapacity:textLength];
370
+ std::vector<NSUInteger> positionMap(textLength + 1, 0);
371
+ for (NSUInteger index = 0; index < textLength; index++) {
372
+ positionMap[index] = expanded.length;
373
+ NSString *replacement = latexByPosition[@(index)];
374
+ if (replacement != nil) {
375
+ [expanded appendString:replacement];
376
+ } else {
377
+ [expanded appendFormat:@"%C", [text characterAtIndex:index]];
378
+ }
379
+ }
380
+ positionMap[textLength] = expanded.length;
381
+
382
+ NSMutableArray<ENRMFormattingRange *> *shiftedRanges = [NSMutableArray arrayWithCapacity:ranges.count];
383
+ for (ENRMFormattingRange *range in ranges) {
384
+ ENRMFormattingRange *shifted = [range copy];
385
+ shifted.range = mapRangeThroughPositionMap(range.range, positionMap, textLength);
386
+ [shiftedRanges addObject:shifted];
387
+ }
388
+
389
+ NSMutableArray<ENRMBlockRange *> *shiftedBlockRanges = [NSMutableArray arrayWithCapacity:blockRanges.count];
390
+ for (ENRMBlockRange *blockRange in blockRanges) {
391
+ // Copy rather than rebuild: `ordinal` carries an ordered item's number and is
392
+ // not part of any initializer, so a rebuilt range renumbers every "1." in the
393
+ // document — a silent failure the copy sidesteps entirely.
394
+ ENRMBlockRange *shifted = [blockRange copy];
395
+ shifted.range = mapRangeThroughPositionMap(blockRange.range, positionMap, textLength);
396
+ [shiftedBlockRanges addObject:shifted];
278
397
  }
279
398
 
280
- return [self serializePlainText:expanded ranges:shifted];
399
+ return [self serializePlainText:expanded
400
+ ranges:shiftedRanges
401
+ blockRanges:shiftedBlockRanges
402
+ blockPrefixProvider:prefixProvider];
281
403
  }
282
404
 
283
405
  @end
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ /// U+FFFC OBJECT REPLACEMENT CHARACTER — the single character a math chip
8
+ /// occupies in the editor buffer. Declared once and shared by every stage of the
9
+ /// round trip (parser writes it, serializer expands it, the view inserts it): a
10
+ /// second copy of this literal is a round-trip bug waiting to happen.
11
+ static const unichar kENRMObjectReplacement = 0xFFFC;
12
+
13
+ /// `kENRMObjectReplacement` as a string, for insertion into text buffers.
14
+ NSString *ENRMObjectReplacementString(void);
15
+
16
+ /// One `$...$` / `$$...$$` formula found in the markdown. The parser has already
17
+ /// put a single `kENRMObjectReplacement` at `position` in the plain text; the
18
+ /// caller turns it into a chip. Pure data — no RaTeX dependency, so it exists in
19
+ /// math-disabled builds too (md4c simply never emits any).
20
+ @interface ENRMMathAtom : NSObject
21
+ @property (nonatomic, assign) NSUInteger position;
22
+ @property (nonatomic, copy) NSString *latex;
23
+ @property (nonatomic, assign) BOOL displayMode;
24
+ @end
25
+
26
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,12 @@
1
+ #import "ENRMMathAtom.h"
2
+
3
+ NSString *ENRMObjectReplacementString(void)
4
+ {
5
+ static NSString *placeholder;
6
+ static dispatch_once_t onceToken;
7
+ dispatch_once(&onceToken, ^{ placeholder = [NSString stringWithCharacters:&kENRMObjectReplacement length:1]; });
8
+ return placeholder;
9
+ }
10
+
11
+ @implementation ENRMMathAtom
12
+ @end
@@ -0,0 +1,45 @@
1
+ #pragma once
2
+
3
+ #import "ENRMFormattingStore.h"
4
+ #import "ENRMInputMentionCandidate.h"
5
+ #import <Foundation/Foundation.h>
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ typedef NS_ENUM(NSInteger, ENRMMentionEventType) {
10
+ ENRMMentionEventStart,
11
+ ENRMMentionEventChange,
12
+ ENRMMentionEventEnd,
13
+ };
14
+
15
+ @interface ENRMMentionEvent : NSObject
16
+ @property (nonatomic, assign) ENRMMentionEventType type;
17
+ @property (nonatomic, copy) NSString *indicator;
18
+ @property (nonatomic, copy, nullable) NSString *text;
19
+ + (instancetype)startWithIndicator:(NSString *)indicator;
20
+ + (instancetype)changeWithIndicator:(NSString *)indicator text:(NSString *)text;
21
+ + (instancetype)endWithIndicator:(NSString *)indicator;
22
+ @end
23
+
24
+ @interface ENRMMentionCoordinator : NSObject
25
+
26
+ @property (nonatomic, readonly, nullable) NSString *activeIndicator;
27
+ @property (nonatomic, readonly) NSRange activeRange;
28
+ @property (nonatomic, readonly, copy) NSString *activeText;
29
+ @property (nonatomic, readonly) BOOL isActive;
30
+
31
+ - (instancetype)initWithFormattingStore:(ENRMFormattingStore *)formattingStore;
32
+
33
+ - (BOOL)containsIndicator:(NSString *)indicator;
34
+ - (NSArray<ENRMMentionEvent *> *)setIndicators:(NSArray<NSString *> *)indicators;
35
+
36
+ /// Re-evaluates the active mention. Returns events for the view to dispatch.
37
+ - (NSArray<ENRMMentionEvent *> *)updateWithText:(nullable NSString *)plainText selectedRange:(NSRange)selectedRange;
38
+
39
+ - (NSArray<ENRMMentionEvent *> *)clearWithIndicatorOverride:(nullable NSString *)indicatorOverride;
40
+
41
+ - (nullable ENRMInputMentionCandidate *)detectCandidateInText:(NSString *)plainText atCursor:(NSUInteger)cursor;
42
+
43
+ @end
44
+
45
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,167 @@
1
+ #import "ENRMMentionCoordinator.h"
2
+ #import "ENRMWordsUtils.h"
3
+
4
+ @implementation ENRMMentionEvent
5
+
6
+ + (instancetype)startWithIndicator:(NSString *)indicator
7
+ {
8
+ ENRMMentionEvent *e = [[ENRMMentionEvent alloc] init];
9
+ e.type = ENRMMentionEventStart;
10
+ e.indicator = indicator;
11
+ return e;
12
+ }
13
+
14
+ + (instancetype)changeWithIndicator:(NSString *)indicator text:(NSString *)text
15
+ {
16
+ ENRMMentionEvent *e = [[ENRMMentionEvent alloc] init];
17
+ e.type = ENRMMentionEventChange;
18
+ e.indicator = indicator;
19
+ e.text = text;
20
+ return e;
21
+ }
22
+
23
+ + (instancetype)endWithIndicator:(NSString *)indicator
24
+ {
25
+ ENRMMentionEvent *e = [[ENRMMentionEvent alloc] init];
26
+ e.type = ENRMMentionEventEnd;
27
+ e.indicator = indicator;
28
+ return e;
29
+ }
30
+
31
+ @end
32
+
33
+ @implementation ENRMMentionCoordinator {
34
+ ENRMFormattingStore *_formattingStore;
35
+ NSArray<NSString *> *_indicators;
36
+ NSString *_activeIndicator;
37
+ NSRange _activeRange;
38
+ NSString *_activeText;
39
+ }
40
+
41
+ - (instancetype)initWithFormattingStore:(ENRMFormattingStore *)formattingStore
42
+ {
43
+ if (self = [super init]) {
44
+ _formattingStore = formattingStore;
45
+ _indicators = @[];
46
+ _activeRange = NSMakeRange(NSNotFound, 0);
47
+ _activeText = @"";
48
+ }
49
+ return self;
50
+ }
51
+
52
+ - (NSString *)activeIndicator
53
+ {
54
+ return _activeIndicator;
55
+ }
56
+
57
+ - (NSRange)activeRange
58
+ {
59
+ return _activeRange;
60
+ }
61
+
62
+ - (NSString *)activeText
63
+ {
64
+ return _activeText;
65
+ }
66
+
67
+ - (BOOL)isActive
68
+ {
69
+ return _activeIndicator != nil;
70
+ }
71
+
72
+ - (BOOL)containsIndicator:(NSString *)indicator
73
+ {
74
+ return [_indicators containsObject:indicator];
75
+ }
76
+
77
+ - (NSArray<ENRMMentionEvent *> *)setIndicators:(NSArray<NSString *> *)indicators
78
+ {
79
+ if ([indicators isEqualToArray:_indicators]) {
80
+ return @[];
81
+ }
82
+ _indicators = [indicators copy];
83
+ NSMutableArray<ENRMMentionEvent *> *events = [NSMutableArray array];
84
+ if (_activeIndicator != nil && ![_indicators containsObject:_activeIndicator]) {
85
+ [events addObjectsFromArray:[self clearWithIndicatorOverride:_activeIndicator]];
86
+ }
87
+ return events;
88
+ }
89
+
90
+ - (NSArray<ENRMMentionEvent *> *)updateWithText:(nullable NSString *)plainText selectedRange:(NSRange)selectedRange
91
+ {
92
+ if (plainText == nil || selectedRange.length != 0) {
93
+ return [self clearWithIndicatorOverride:nil];
94
+ }
95
+ NSUInteger cursor = selectedRange.location;
96
+ if (cursor > plainText.length) {
97
+ return [self clearWithIndicatorOverride:nil];
98
+ }
99
+
100
+ ENRMInputMentionCandidate *candidate = [self detectCandidateInText:plainText atCursor:cursor];
101
+ if (candidate == nil) {
102
+ return [self clearWithIndicatorOverride:nil];
103
+ }
104
+
105
+ NSMutableArray<ENRMMentionEvent *> *events = [NSMutableArray array];
106
+
107
+ if (_activeIndicator == nil || ![_activeIndicator isEqualToString:candidate.indicator] ||
108
+ _activeRange.location != candidate.start) {
109
+ if (_activeIndicator != nil) {
110
+ [events addObject:[ENRMMentionEvent endWithIndicator:_activeIndicator]];
111
+ }
112
+ _activeIndicator = candidate.indicator;
113
+ [events addObject:[ENRMMentionEvent startWithIndicator:candidate.indicator]];
114
+ }
115
+
116
+ _activeRange = NSMakeRange(candidate.start, candidate.end - candidate.start);
117
+
118
+ if (![_activeText isEqualToString:candidate.text]) {
119
+ _activeText = candidate.text;
120
+ [events addObject:[ENRMMentionEvent changeWithIndicator:candidate.indicator text:candidate.text]];
121
+ }
122
+
123
+ return events;
124
+ }
125
+
126
+ - (NSArray<ENRMMentionEvent *> *)clearWithIndicatorOverride:(nullable NSString *)indicatorOverride
127
+ {
128
+ NSString *indicator = indicatorOverride ?: _activeIndicator;
129
+ _activeIndicator = nil;
130
+ _activeRange = NSMakeRange(NSNotFound, 0);
131
+ _activeText = @"";
132
+ if (indicator.length > 0) {
133
+ return @[ [ENRMMentionEvent endWithIndicator:indicator] ];
134
+ }
135
+ return @[];
136
+ }
137
+
138
+ - (nullable ENRMInputMentionCandidate *)detectCandidateInText:(NSString *)plainText atCursor:(NSUInteger)cursor
139
+ {
140
+ if (_indicators.count == 0) {
141
+ return nil;
142
+ }
143
+
144
+ NSUInteger start = [ENRMWordsUtils tokenStartInText:plainText beforePosition:cursor];
145
+ NSString *token = [plainText substringWithRange:NSMakeRange(start, cursor - start)];
146
+ NSString *matchedIndicator = nil;
147
+ for (NSString *indicator in _indicators) {
148
+ if ([token hasPrefix:indicator]) {
149
+ matchedIndicator = indicator;
150
+ break;
151
+ }
152
+ }
153
+ if (matchedIndicator == nil) {
154
+ return nil;
155
+ }
156
+
157
+ if ([_formattingStore rangeOfType:ENRMInputStyleTypeLink containingPosition:start] != nil) {
158
+ return nil;
159
+ }
160
+
161
+ return [ENRMInputMentionCandidate candidateWithIndicator:matchedIndicator
162
+ start:start
163
+ end:cursor
164
+ text:[token substringFromIndex:matchedIndicator.length]];
165
+ }
166
+
167
+ @end
@@ -0,0 +1,38 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ typedef struct {
8
+ NSRange range;
9
+ BOOL shouldRemove;
10
+ } ENRMAdjustedRange;
11
+
12
+ /// Shared shift/clip logic applied to a stored range after a text edit that
13
+ /// replaced `deletedLength` characters at `editLocation` with `insertedLength`
14
+ /// characters. Both ENRMFormattingStore and ENRMBlockStore delegate here so the
15
+ /// overlap classification lives in exactly one place. `shouldRemove` is set
16
+ /// when the range was deleted outright or clipped to zero length.
17
+ ///
18
+ /// Insert-only edits at exactly the range end do NOT grow the range — the typed
19
+ /// characters stay outside it. An insert at exactly the range start grows the
20
+ /// range only when `growsAtStartOnInsert` is YES; otherwise the range shifts and
21
+ /// the typed characters stay outside it. Whether boundary text joins the range is
22
+ /// otherwise decided elsewhere: pending styles for inline ranges, line
23
+ /// re-normalization for block ranges.
24
+ ///
25
+ /// `inheritsReplacementAtStart`: when YES, a replacement whose deletion starts
26
+ /// at the range start lets the inserted text join the range (UIKit attribute
27
+ /// inheritance); when NO, the old clip/remove behavior applies.
28
+ ///
29
+ /// `growsAtStartOnInsert`: when YES, a pure insert at the range start grows the
30
+ /// range to cover the inserted text instead of shifting the range past it. Block
31
+ /// ranges own their whole line, so a character typed at the line start must keep
32
+ /// the line's block; inline styles must NOT set this (a character typed before a
33
+ /// bold run must not become bold).
34
+ ENRMAdjustedRange ENRMAdjustRangeForEdit(NSRange range, NSUInteger editLocation, NSUInteger deletedLength,
35
+ NSUInteger insertedLength, BOOL inheritsReplacementAtStart,
36
+ BOOL growsAtStartOnInsert);
37
+
38
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,91 @@
1
+ #import "ENRMRangeEditAdjustment.h"
2
+
3
+ typedef NS_ENUM(NSInteger, EditOverlap) {
4
+ EditOverlapBeforeEdit,
5
+ EditOverlapAfterEdit,
6
+ EditOverlapFullyDeleted,
7
+ EditOverlapDeletedInside,
8
+ EditOverlapClippedEnd,
9
+ EditOverlapClippedStart,
10
+ };
11
+
12
+ static EditOverlap classifyOverlap(NSUInteger rangeStart, NSUInteger rangeEnd, NSUInteger editLocation,
13
+ NSUInteger deleteEnd)
14
+ {
15
+ if (rangeEnd <= editLocation)
16
+ return EditOverlapBeforeEdit;
17
+ if (rangeStart >= deleteEnd)
18
+ return EditOverlapAfterEdit;
19
+ if (rangeStart >= editLocation && rangeEnd <= deleteEnd)
20
+ return EditOverlapFullyDeleted;
21
+ if (rangeStart < editLocation && rangeEnd > deleteEnd)
22
+ return EditOverlapDeletedInside;
23
+ if (rangeStart < editLocation && rangeEnd <= deleteEnd)
24
+ return EditOverlapClippedEnd;
25
+ return EditOverlapClippedStart;
26
+ }
27
+
28
+ ENRMAdjustedRange ENRMAdjustRangeForEdit(NSRange range, NSUInteger editLocation, NSUInteger deletedLength,
29
+ NSUInteger insertedLength, BOOL inheritsReplacementAtStart,
30
+ BOOL growsAtStartOnInsert)
31
+ {
32
+ ENRMAdjustedRange result = {range, NO};
33
+ NSUInteger rangeStart = range.location;
34
+ NSUInteger rangeEnd = NSMaxRange(range);
35
+
36
+ if (deletedLength > 0) {
37
+ NSUInteger deleteEnd = editLocation + deletedLength;
38
+ BOOL inheritsReplacement = inheritsReplacementAtStart && insertedLength > 0 && rangeStart == editLocation;
39
+
40
+ switch (classifyOverlap(rangeStart, rangeEnd, editLocation, deleteEnd)) {
41
+ case EditOverlapBeforeEdit:
42
+ break;
43
+
44
+ case EditOverlapAfterEdit:
45
+ result.range = NSMakeRange(rangeStart - deletedLength + insertedLength, range.length);
46
+ break;
47
+
48
+ case EditOverlapFullyDeleted:
49
+ if (inheritsReplacement) {
50
+ result.range = NSMakeRange(editLocation, insertedLength);
51
+ } else {
52
+ result.shouldRemove = YES;
53
+ }
54
+ break;
55
+
56
+ case EditOverlapDeletedInside:
57
+ result.range = NSMakeRange(rangeStart, range.length - deletedLength + insertedLength);
58
+ break;
59
+
60
+ case EditOverlapClippedEnd: {
61
+ NSUInteger newEnd = editLocation + insertedLength;
62
+ NSUInteger newLength = newEnd > rangeStart ? newEnd - rangeStart : 0;
63
+ result.range = NSMakeRange(rangeStart, newLength);
64
+ result.shouldRemove = (newLength == 0);
65
+ break;
66
+ }
67
+
68
+ case EditOverlapClippedStart: {
69
+ NSUInteger charsClipped = deleteEnd - rangeStart;
70
+ NSUInteger survivingLength = range.length - charsClipped;
71
+ if (inheritsReplacement) {
72
+ result.range = NSMakeRange(editLocation, insertedLength + survivingLength);
73
+ } else {
74
+ result.range = NSMakeRange(editLocation + insertedLength, survivingLength);
75
+ result.shouldRemove = (survivingLength == 0);
76
+ }
77
+ break;
78
+ }
79
+ }
80
+ } else if (insertedLength > 0) {
81
+ if (rangeStart == editLocation && growsAtStartOnInsert) {
82
+ result.range = NSMakeRange(rangeStart, range.length + insertedLength);
83
+ } else if (rangeStart >= editLocation) {
84
+ result.range = NSMakeRange(rangeStart + insertedLength, range.length);
85
+ } else if (editLocation < rangeEnd) {
86
+ result.range = NSMakeRange(rangeStart, range.length + insertedLength);
87
+ }
88
+ }
89
+
90
+ return result;
91
+ }