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.
- package/README.md +54 -8
- package/ReactNativeEnrichedMarkdown.podspec +82 -73
- package/android/build.gradle +186 -1
- package/android/consumer-rules.pro +1 -1
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +9 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +24 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +8 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +9 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +35 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +886 -23
- package/android/src/main/baseline-prof.txt +1 -1
- package/android/src/main/cpp/jni-adapter.cpp +74 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +189 -13
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +50 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +10 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +42 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +82 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyPressEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +54 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +901 -462
- package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +101 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +49 -15
- package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +45 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +396 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +36 -9
- package/android/src/main/jni/CMakeLists.txt +53 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
- package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +7 -2
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +6 -4
- package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
- package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
- package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
- package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
- package/cpp/highlight/HighlightGrammars.hpp +28 -0
- package/cpp/highlight/code_highlight_podspec.rb +211 -0
- package/cpp/highlight/gen-registry.mjs +155 -0
- package/cpp/highlight/grammar-versions.json +159 -0
- package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
- package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
- package/cpp/parser/MD4CParser.cpp +173 -61
- package/cpp/parser/MD4CParser.hpp +1 -0
- package/cpp/parser/MarkdownASTNode.hpp +2 -1
- package/cpp/wasm/ASTSerializer.cpp +2 -0
- package/cpp/wasm/build.sh +1 -0
- package/cpp/wasm/md4c_wasm.cpp +3 -1
- package/docs/ACCESSIBILITY.md +14 -2
- package/docs/API_REFERENCE.md +234 -12
- package/docs/BREAKING_CHANGES.md +129 -0
- package/docs/CODE_HIGHLIGHT.md +133 -0
- package/docs/COPY_OPTIONS.md +47 -3
- package/docs/ELEMENTS_STRUCTURE.md +52 -4
- package/docs/IMAGE_CACHING.md +30 -0
- package/docs/INPUT.md +108 -11
- package/docs/LATEX_MATH.md +87 -45
- package/docs/MACOS.md +1 -1
- package/docs/MARKDOWN_STREAMING.md +27 -1
- package/docs/NATIVE_ASSETS.md +127 -0
- package/docs/RTL.md +1 -1
- package/docs/STYLES.md +46 -6
- package/docs/TESTING.md +112 -0
- package/docs/TEXT.md +16 -6
- package/docs/WEB.md +3 -1
- package/ios/EnrichedMarkdown.h +7 -0
- package/ios/EnrichedMarkdown.mm +284 -75
- package/ios/EnrichedMarkdownText.h +7 -0
- package/ios/EnrichedMarkdownText.mm +101 -73
- package/ios/attachments/ENRMImageAttachment.h +9 -0
- package/ios/attachments/ENRMImageAttachment.m +143 -40
- package/ios/attachments/ENRMMathInlineAttachment.h +2 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +48 -81
- package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +35 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +886 -23
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +131 -0
- package/ios/input/ENRMAutoLinkDetector.h +2 -1
- package/ios/input/ENRMAutoLinkDetector.mm +79 -41
- package/ios/input/ENRMBlockEditCoordinator.h +71 -0
- package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
- package/ios/input/ENRMBlockRange.h +28 -0
- package/ios/input/ENRMBlockRange.mm +30 -0
- package/ios/input/ENRMBlockStore.h +56 -0
- package/ios/input/ENRMBlockStore.mm +275 -0
- package/ios/input/ENRMClipboardCoordinator.h +45 -0
- package/ios/input/ENRMClipboardCoordinator.mm +120 -0
- package/ios/input/ENRMDetectorPipeline.h +2 -1
- package/ios/input/ENRMEditPipeline.h +76 -0
- package/ios/input/ENRMEditPipeline.mm +228 -0
- package/ios/input/ENRMEditSession.h +36 -0
- package/ios/input/ENRMEditSession.mm +63 -0
- package/ios/input/ENRMFormattingStore.h +17 -0
- package/ios/input/ENRMFormattingStore.mm +95 -105
- package/ios/input/ENRMInputBlockType.h +91 -0
- package/ios/input/ENRMInputBlockType.mm +5 -0
- package/ios/input/ENRMInputDecorationDrawer.h +18 -0
- package/ios/input/ENRMInputEventEmitter.h +56 -0
- package/ios/input/ENRMInputEventEmitter.mm +308 -0
- package/ios/input/ENRMInputFormatter.h +29 -69
- package/ios/input/ENRMInputFormatter.mm +216 -124
- package/ios/input/ENRMInputFormatterStyle.h +99 -0
- package/ios/input/ENRMInputFormatterStyle.mm +188 -0
- package/ios/input/ENRMInputLayoutManager.h +9 -0
- package/ios/input/ENRMInputLayoutManager.mm +30 -0
- package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
- package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
- package/ios/input/ENRMInputParser.h +5 -6
- package/ios/input/ENRMInputParser.mm +461 -178
- package/ios/input/ENRMInputRemend.mm +2 -2
- package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
- package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
- package/ios/input/ENRMInputTextView.mm +103 -8
- package/ios/input/ENRMInputTypingAttributesController.h +42 -0
- package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
- package/ios/input/ENRMLinkCoordinator.h +41 -0
- package/ios/input/ENRMLinkCoordinator.mm +89 -0
- package/ios/input/ENRMMarkdownSerializer.h +29 -5
- package/ios/input/ENRMMarkdownSerializer.mm +170 -48
- package/ios/input/ENRMMathAtom.h +26 -0
- package/ios/input/ENRMMathAtom.mm +12 -0
- package/ios/input/ENRMMentionCoordinator.h +45 -0
- package/ios/input/ENRMMentionCoordinator.mm +167 -0
- package/ios/input/ENRMRangeEditAdjustment.h +38 -0
- package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
- package/ios/input/ENRMRangeStoreUtils.h +39 -0
- package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
- package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
- package/ios/input/EnrichedMarkdownTextInput.h +7 -1
- package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
- package/ios/input/InputStylePropsUtils.h +109 -68
- package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
- package/ios/input/styles/ENRMBlockHandler.h +46 -0
- package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
- package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
- package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
- package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
- package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
- package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
- package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
- package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
- package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
- package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
- package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
- package/ios/internals/MeasurementCache.h +33 -7
- package/ios/internals/ShadowMeasurementUtils.h +63 -58
- package/ios/math/ENRMMathChipController.h +74 -0
- package/ios/math/ENRMMathChipController.mm +476 -0
- package/ios/math/ENRMRaTeXBridge.swift +4 -1
- package/ios/parser/ENRMMarkdownParser.h +1 -8
- package/ios/parser/ENRMMarkdownParser.mm +2 -11
- package/ios/parser/MarkdownASTNode.h +2 -1
- package/ios/parser/MarkdownParserBridge.mm +4 -0
- package/ios/renderer/AttributedRenderer.m +20 -2
- package/ios/renderer/BaseRenderer.h +17 -2
- package/ios/renderer/BaseRenderer.m +30 -0
- package/ios/renderer/BlockquoteRenderer.h +1 -1
- package/ios/renderer/BlockquoteRenderer.m +144 -35
- package/ios/renderer/CodeBlockRenderer.h +1 -1
- package/ios/renderer/CodeBlockRenderer.m +27 -23
- package/ios/renderer/CodeRenderer.h +1 -1
- package/ios/renderer/CodeRenderer.m +3 -1
- package/ios/renderer/ENRMImageRenderer.h +1 -1
- package/ios/renderer/ENRMImageRenderer.m +5 -1
- package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
- package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
- package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
- package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
- package/ios/renderer/EmphasisRenderer.h +1 -1
- package/ios/renderer/EmphasisRenderer.m +3 -1
- package/ios/renderer/HeadingRenderer.h +1 -1
- package/ios/renderer/HeadingRenderer.m +13 -6
- package/ios/renderer/HighlightRenderer.h +1 -1
- package/ios/renderer/HighlightRenderer.m +3 -1
- package/ios/renderer/LinkRenderer.h +1 -1
- package/ios/renderer/LinkRenderer.m +3 -1
- package/ios/renderer/ListItemRenderer.h +13 -1
- package/ios/renderer/ListItemRenderer.m +102 -44
- package/ios/renderer/ListRenderer.h +2 -2
- package/ios/renderer/ListRenderer.m +63 -25
- package/ios/renderer/ParagraphRenderer.h +1 -1
- package/ios/renderer/ParagraphRenderer.m +16 -8
- package/ios/renderer/RenderContext.h +10 -0
- package/ios/renderer/RenderContext.m +44 -0
- package/ios/renderer/RendererFactory.m +14 -0
- package/ios/renderer/StrikethroughRenderer.h +1 -1
- package/ios/renderer/StrikethroughRenderer.m +3 -1
- package/ios/renderer/StrongRenderer.h +1 -1
- package/ios/renderer/StrongRenderer.m +3 -1
- package/ios/renderer/SubscriptRenderer.h +1 -1
- package/ios/renderer/SubscriptRenderer.m +3 -1
- package/ios/renderer/SuperscriptRenderer.h +1 -1
- package/ios/renderer/SuperscriptRenderer.m +3 -1
- package/ios/renderer/TextRenderer.h +2 -2
- package/ios/renderer/TextRenderer.m +3 -1
- package/ios/renderer/ThematicBreakRenderer.h +1 -1
- package/ios/renderer/ThematicBreakRenderer.m +3 -1
- package/ios/renderer/UnderlineRenderer.h +1 -1
- package/ios/renderer/UnderlineRenderer.m +3 -1
- package/ios/styles/StyleConfig.h +22 -0
- package/ios/styles/StyleConfig.mm +132 -0
- package/ios/utils/BlockquoteBorder.h +6 -0
- package/ios/utils/BlockquoteBorder.m +249 -52
- package/ios/utils/CodeBlockBackground.m +16 -2
- package/ios/utils/ENRMAtomicSize.h +65 -0
- package/ios/utils/ENRMBlockMenu.h +57 -0
- package/ios/utils/ENRMCodeBlockContent.h +37 -0
- package/ios/utils/ENRMCodeBlockContent.mm +79 -0
- package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
- package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
- package/ios/utils/ENRMFeatureFlags.h +7 -0
- package/ios/utils/ENRMImageDownloader.h +11 -1
- package/ios/utils/ENRMImageDownloader.m +60 -16
- package/ios/utils/ENRMLocalImageLoader.h +31 -0
- package/ios/utils/ENRMLocalImageLoader.m +68 -0
- package/ios/utils/ENRMMathFallback.h +26 -0
- package/ios/utils/ENRMMathFallback.m +18 -0
- package/ios/utils/ENRMTextViewSetup.h +35 -17
- package/ios/utils/EditMenuUtils.h +22 -5
- package/ios/utils/EditMenuUtils.m +53 -9
- package/ios/utils/ImageRequestHeaderUtils.h +35 -0
- package/ios/utils/LastElementUtils.h +1 -0
- package/ios/utils/ListMarkerDrawer.m +29 -42
- package/ios/utils/MarkdownASTSerializer.m +4 -0
- package/ios/utils/ParagraphStyleUtils.h +5 -0
- package/ios/utils/ParagraphStyleUtils.m +77 -17
- package/ios/utils/RenderedMarkdownSegment.h +13 -1
- package/ios/utils/RenderedMarkdownSegment.m +20 -0
- package/ios/utils/SegmentRenderer.m +17 -4
- package/ios/utils/StreamingMarkdownFilter.h +11 -1
- package/ios/utils/StreamingMarkdownFilter.m +98 -2
- package/ios/utils/StylePropsUtils.h +63 -0
- package/ios/utils/TaskListTapUtils.m +24 -0
- package/ios/views/ENRMCodeBlockContainerView.h +53 -0
- package/ios/views/ENRMCodeBlockContainerView.m +559 -0
- package/ios/views/ENRMMathContainerView.h +16 -0
- package/ios/views/ENRMMathContainerView.m +74 -19
- package/ios/views/TableContainerView.h +22 -0
- package/ios/views/TableContainerView.m +261 -175
- package/jest.d.ts +1 -0
- package/jest.js +5 -0
- package/lib/module/EnrichedMarkdownNativeComponent.ts +73 -0
- package/lib/module/EnrichedMarkdownTextInput.js +84 -5
- package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
- package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +74 -0
- package/lib/module/headingDefaults.js +34 -0
- package/lib/module/headingDefaults.js.map +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/jest/index.js +191 -0
- package/lib/module/jest/index.js.map +1 -0
- package/lib/module/native/EnrichedMarkdownText.js +37 -5
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.js +81 -19
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +56 -18
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
- package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
- package/lib/module/normalizeMenuItem.js +1 -1
- package/lib/module/utils/textInputState.js +26 -0
- package/lib/module/utils/textInputState.js.map +1 -0
- package/lib/module/web/EnrichedMarkdownText.js +9 -5
- package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/web/parseMarkdown.js +4 -3
- package/lib/module/web/parseMarkdown.js.map +1 -1
- package/lib/module/web/renderers/InlineRenderers.js +6 -0
- package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
- package/lib/module/web/renderers/ListRenderers.js +7 -2
- package/lib/module/web/renderers/ListRenderers.js.map +1 -1
- package/lib/module/web/renderers/index.js +7 -4
- package/lib/module/web/renderers/index.js.map +1 -1
- package/lib/module/web/styles.js +83 -6
- package/lib/module/web/styles.js.map +1 -1
- package/lib/module/web/utils.js +1 -0
- package/lib/module/web/utils.js.map +1 -1
- package/lib/module/web/wasm/md4c.js +0 -0
- package/lib/module/web/wasm/md4c.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +66 -0
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +66 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/headingDefaults.d.ts +9 -0
- package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +1 -1
- package/lib/typescript/src/index.web.d.ts.map +1 -1
- package/lib/typescript/src/jest/index.d.ts +6 -0
- package/lib/typescript/src/jest/index.d.ts.map +1 -0
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyle.d.ts +72 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +27 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +104 -9
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +19 -0
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +19 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/lib/typescript/src/utils/textInputState.d.ts +24 -0
- package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
- package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/index.d.ts +2 -1
- package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
- package/lib/typescript/src/web/styles.d.ts +2 -1
- package/lib/typescript/src/web/styles.d.ts.map +1 -1
- package/lib/typescript/src/web/types.d.ts +6 -2
- package/lib/typescript/src/web/types.d.ts.map +1 -1
- package/lib/typescript/src/web/utils.d.ts.map +1 -1
- package/package.json +36 -9
- package/postinstall.mjs +131 -0
- package/ratex-version.json +21 -0
- package/src/EnrichedMarkdownNativeComponent.ts +73 -0
- package/src/EnrichedMarkdownTextInput.tsx +159 -8
- package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
- package/src/EnrichedMarkdownTextNativeComponent.ts +74 -0
- package/src/headingDefaults.ts +21 -0
- package/src/index.tsx +9 -0
- package/src/index.web.tsx +1 -0
- package/src/jest/index.tsx +215 -0
- package/src/native/EnrichedMarkdownText.tsx +53 -2
- package/src/normalizeMarkdownStyle.ts +102 -16
- package/src/normalizeMarkdownStyle.web.ts +63 -15
- package/src/normalizeMarkdownTextInputStyle.ts +110 -35
- package/src/normalizeMenuItem.ts +1 -1
- package/src/types/MarkdownStyle.ts +74 -0
- package/src/types/MarkdownStyleInternal.ts +39 -0
- package/src/types/MarkdownTextProps.ts +101 -9
- package/src/types/MarkdownTextProps.web.ts +19 -0
- package/src/types/events.ts +21 -0
- package/src/utils/textInputState.ts +35 -0
- package/src/web/EnrichedMarkdownText.tsx +16 -2
- package/src/web/parseMarkdown.ts +6 -2
- package/src/web/renderers/InlineRenderers.tsx +5 -0
- package/src/web/renderers/ListRenderers.tsx +14 -2
- package/src/web/renderers/index.tsx +6 -2
- package/src/web/styles.ts +89 -5
- package/src/web/types.ts +6 -1
- package/src/web/utils.ts +1 -0
- package/src/web/wasm/md4c.js +0 -0
- package/vendor-grammars.mjs +511 -0
- package/vendor-ratex.mjs +173 -0
- package/app.plugin.js +0 -2
- package/plugin/build/withAndroidMath.js +0 -19
- package/plugin/build/withIosMath.js +0 -28
- package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
- package/plugin/src/withAndroidMath.ts +0 -24
- package/plugin/src/withIosMath.ts +0 -35
- package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
- package/plugin/tsconfig.build.json +0 -16
package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt
CHANGED
|
@@ -1,33 +1,47 @@
|
|
|
1
1
|
package com.swmansion.enriched.markdown.input.formatting
|
|
2
2
|
|
|
3
|
+
import com.swmansion.enriched.markdown.input.model.BlockRange
|
|
4
|
+
import com.swmansion.enriched.markdown.input.model.BlockType
|
|
3
5
|
import com.swmansion.enriched.markdown.input.model.FormattingRange
|
|
6
|
+
import com.swmansion.enriched.markdown.input.model.MAX_LIST_DEPTH
|
|
4
7
|
import com.swmansion.enriched.markdown.input.model.MathAtom
|
|
8
|
+
import com.swmansion.enriched.markdown.input.model.OBJECT_REPLACEMENT
|
|
5
9
|
import com.swmansion.enriched.markdown.input.model.StyleType
|
|
6
10
|
import com.swmansion.enriched.markdown.parser.MarkdownASTNode
|
|
7
11
|
import com.swmansion.enriched.markdown.parser.MarkdownASTNode.NodeType
|
|
8
12
|
import com.swmansion.enriched.markdown.parser.Md4cFlags
|
|
9
13
|
import com.swmansion.enriched.markdown.parser.Parser
|
|
10
14
|
import com.swmansion.enriched.markdown.parser.isTopLevelBlock
|
|
11
|
-
import com.swmansion.enriched.markdown.utils.common.FeatureFlags
|
|
12
15
|
|
|
13
16
|
data class ParseResult(
|
|
14
17
|
val plainText: String,
|
|
15
18
|
val formattingRanges: List<FormattingRange>,
|
|
19
|
+
val blockRanges: List<BlockRange> = emptyList(),
|
|
20
|
+
/**
|
|
21
|
+
* Math nodes, each already represented in [plainText] by a single
|
|
22
|
+
* [OBJECT_REPLACEMENT] character at [MathAtom.position]. The caller turns them
|
|
23
|
+
* into chips via [com.swmansion.enriched.markdown.input.math.MathChipController.applyAtoms];
|
|
24
|
+
* with math disabled md4c never emits the nodes and this stays empty.
|
|
25
|
+
*/
|
|
16
26
|
val mathAtoms: List<MathAtom> = emptyList(),
|
|
17
27
|
)
|
|
18
28
|
|
|
19
29
|
object InputParser {
|
|
20
|
-
private const val ATTACHMENT_CHAR = ''
|
|
21
|
-
|
|
22
30
|
// A source paragraph break: a newline followed by one or more blank lines.
|
|
23
31
|
private val PARAGRAPH_BREAK_RE = Regex("\\n[ \\t]*(?:\\n[ \\t]*)+")
|
|
24
32
|
|
|
25
33
|
fun parseToPlainTextAndRanges(
|
|
26
|
-
|
|
34
|
+
rawMarkdown: String,
|
|
27
35
|
blockSyntax: Boolean = true,
|
|
28
36
|
): ParseResult {
|
|
37
|
+
// U+200B is the editor's reserved empty-list anchor and is stripped from every
|
|
38
|
+
// output path; strip it from incoming markdown too (web paste, JS-supplied
|
|
39
|
+
// values) so a foreign copy can't seed a stray anchor into the buffer. Done
|
|
40
|
+
// before parsing so plain-text offsets and ranges stay consistent — and before
|
|
41
|
+
// the blockSyntax branch, so both paths see the same scrubbed source.
|
|
42
|
+
val markdown = MarkdownSerializer.stripZwsp(rawMarkdown)
|
|
29
43
|
if (markdown.isEmpty()) {
|
|
30
|
-
return ParseResult("", emptyList())
|
|
44
|
+
return ParseResult("", emptyList(), emptyList())
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
if (!blockSyntax) {
|
|
@@ -74,7 +88,12 @@ object InputParser {
|
|
|
74
88
|
if (position < 0 || position >= decoded.length) null else atom.copy(position = position)
|
|
75
89
|
}
|
|
76
90
|
|
|
77
|
-
|
|
91
|
+
// Block ranges are dropped, not shifted: with block syntax off there are no blocks.
|
|
92
|
+
// Under the sentinel the AST holds only Paragraphs and top-level display math, and
|
|
93
|
+
// neither yields a range, so this is a guard rather than a fix — a range that did leak
|
|
94
|
+
// would reach the BlockStore and the serializer would prefix it, breaking the
|
|
95
|
+
// byte-for-byte round trip.
|
|
96
|
+
return ParseResult(decoded, ranges, emptyList(), atoms)
|
|
78
97
|
}
|
|
79
98
|
|
|
80
99
|
private fun parseCompleted(
|
|
@@ -82,16 +101,12 @@ object InputParser {
|
|
|
82
101
|
fallback: String,
|
|
83
102
|
blockSeparators: Boolean,
|
|
84
103
|
): ParseResult {
|
|
85
|
-
val flags =
|
|
86
|
-
|
|
87
|
-
underline = true,
|
|
88
|
-
latexMath = FeatureFlags.IS_MATH_ENABLED,
|
|
89
|
-
permissiveAutolinks = false,
|
|
90
|
-
)
|
|
91
|
-
val ast = Parser.shared.parseMarkdown(completed, flags) ?: return ParseResult(fallback, emptyList())
|
|
104
|
+
val flags = Md4cFlags(underline = true, permissiveAutolinks = false)
|
|
105
|
+
val ast = Parser.shared.parseMarkdown(completed, flags) ?: return ParseResult(fallback, emptyList(), emptyList())
|
|
92
106
|
|
|
93
107
|
val plainText = StringBuilder()
|
|
94
108
|
val ranges = mutableListOf<FormattingRange>()
|
|
109
|
+
val blockRanges = mutableListOf<BlockRange>()
|
|
95
110
|
val mathAtoms = mutableListOf<MathAtom>()
|
|
96
111
|
|
|
97
112
|
// md4c collapses any blank-line run into a single break, unlike iOS which keeps them.
|
|
@@ -108,28 +123,34 @@ object InputParser {
|
|
|
108
123
|
ArrayDeque()
|
|
109
124
|
}
|
|
110
125
|
|
|
111
|
-
walkNode(ast, plainText, ranges, mathAtoms, ArrayDeque(), blankRuns, blockSeparators)
|
|
126
|
+
walkNode(ast, plainText, ranges, blockRanges, mathAtoms, ArrayDeque(), blankRuns, 0, false, blockSeparators)
|
|
112
127
|
|
|
113
|
-
return ParseResult(plainText.toString(), ranges, mathAtoms)
|
|
128
|
+
return ParseResult(plainText.toString(), ranges, blockRanges, mathAtoms)
|
|
114
129
|
}
|
|
115
130
|
|
|
116
131
|
private fun walkNode(
|
|
117
132
|
node: MarkdownASTNode,
|
|
118
133
|
plainText: StringBuilder,
|
|
119
134
|
ranges: MutableList<FormattingRange>,
|
|
135
|
+
blockRanges: MutableList<BlockRange>,
|
|
120
136
|
mathAtoms: MutableList<MathAtom>,
|
|
121
137
|
activeStyles: ArrayDeque<ActiveStyle>,
|
|
122
138
|
blankRuns: ArrayDeque<Int>,
|
|
139
|
+
listDepth: Int,
|
|
140
|
+
orderedContainer: Boolean,
|
|
123
141
|
blockSeparators: Boolean,
|
|
124
142
|
) {
|
|
143
|
+
// Math is atomic in the editor: the whole formula occupies one character, so it
|
|
144
|
+
// takes no style/block bookkeeping and its children are never walked (walking
|
|
145
|
+
// them would append the raw LaTeX as text). Returning here is what makes the
|
|
146
|
+
// chip's position a single offset the controller can hang a span on.
|
|
125
147
|
if (node.type == NodeType.LatexMathInline || node.type == NodeType.LatexMathDisplay) {
|
|
126
|
-
val latex = extractLatex(node)
|
|
127
148
|
val position = plainText.length
|
|
128
|
-
plainText.append(
|
|
149
|
+
plainText.append(OBJECT_REPLACEMENT)
|
|
129
150
|
mathAtoms.add(
|
|
130
151
|
MathAtom(
|
|
131
152
|
position = position,
|
|
132
|
-
latex =
|
|
153
|
+
latex = extractLatex(node),
|
|
133
154
|
displayMode = node.type == NodeType.LatexMathDisplay,
|
|
134
155
|
),
|
|
135
156
|
)
|
|
@@ -143,18 +164,55 @@ object InputParser {
|
|
|
143
164
|
activeStyles.addLast(ActiveStyle(styleType, plainText.length, url))
|
|
144
165
|
}
|
|
145
166
|
|
|
167
|
+
// A list node increments the nesting depth of its items, so a list item's depth
|
|
168
|
+
// is (enclosing list nodes − 1) — matching the iOS depth derivation. Depth comes
|
|
169
|
+
// from this AST nesting, never from counting leading spaces.
|
|
170
|
+
val isListContainer = node.type == NodeType.UnorderedList || node.type == NodeType.OrderedList
|
|
171
|
+
val childListDepth = if (isListContainer) listDepth + 1 else listDepth
|
|
172
|
+
val childOrdered = if (isListContainer) node.type == NodeType.OrderedList else orderedContainer
|
|
173
|
+
|
|
174
|
+
// Each list item starts on its own line; md4c emits no separator between sibling
|
|
175
|
+
// items or before a nested sublist, so insert the line break ourselves.
|
|
176
|
+
if (node.type == NodeType.ListItem && plainText.isNotEmpty() && !plainText.endsWith("\n")) {
|
|
177
|
+
plainText.append("\n")
|
|
178
|
+
}
|
|
179
|
+
val itemStart = if (node.type == NodeType.ListItem) plainText.length else -1
|
|
180
|
+
|
|
181
|
+
// Block-level node: record where its text content begins so we can build a
|
|
182
|
+
// BlockRange on the way back out. PARAGRAPH is the implicit default and is
|
|
183
|
+
// dropped below, so it produces no stored block range.
|
|
184
|
+
val blockLevel = node.getAttribute("level")?.toIntOrNull() ?: 0
|
|
185
|
+
val blockType = nodeTypeToBlockType(node.type, blockLevel)
|
|
186
|
+
val blockStartPosition = plainText.length
|
|
187
|
+
|
|
146
188
|
if (node.type == NodeType.Text) {
|
|
147
189
|
plainText.append(node.content)
|
|
148
|
-
} else if (node.type == NodeType.LineBreak) {
|
|
190
|
+
} else if (node.type == NodeType.LineBreak || node.type == NodeType.SoftBreak) {
|
|
149
191
|
plainText.append("\n")
|
|
150
192
|
}
|
|
151
193
|
|
|
152
194
|
for ((index, child) in node.children.withIndex()) {
|
|
153
|
-
// Keep the source's blank lines between top-level blocks (md4c drops
|
|
154
|
-
|
|
195
|
+
// Keep the source's blank lines between genuinely top-level blocks (md4c drops
|
|
196
|
+
// them, iOS keeps them). Inside a list, items are separated by a single newline
|
|
197
|
+
// (inserted above), not blank lines.
|
|
198
|
+
if (blockSeparators && index > 0 && listDepth == 0 && child.type.isTopLevelBlock() && plainText.isNotEmpty()) {
|
|
155
199
|
plainText.append("\n".repeat(blankRuns.removeFirstOrNull() ?: 2))
|
|
156
200
|
}
|
|
157
|
-
walkNode(child, plainText, ranges, mathAtoms, activeStyles, blankRuns, blockSeparators)
|
|
201
|
+
walkNode(child, plainText, ranges, blockRanges, mathAtoms, activeStyles, blankRuns, childListDepth, childOrdered, blockSeparators)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// A list item owns its own first line; a nested sublist lives on later lines, so
|
|
205
|
+
// the item's range ends at the first newline after its start.
|
|
206
|
+
if (itemStart >= 0) {
|
|
207
|
+
var lineEnd = plainText.indexOf('\n', itemStart)
|
|
208
|
+
if (lineEnd < 0) lineEnd = plainText.length
|
|
209
|
+
if (lineEnd > itemStart) {
|
|
210
|
+
// The item sees listDepth already incremented by its enclosing list node, so
|
|
211
|
+
// its 0-based depth is listDepth − 1 (enclosing list nodes − 1, per iOS).
|
|
212
|
+
val depth = (listDepth - 1).coerceIn(0, MAX_LIST_DEPTH)
|
|
213
|
+
val itemType = if (orderedContainer) BlockType.ORDERED_LIST_ITEM else BlockType.UNORDERED_LIST_ITEM
|
|
214
|
+
blockRanges.add(BlockRange(itemType, itemStart, lineEnd, depth))
|
|
215
|
+
}
|
|
158
216
|
}
|
|
159
217
|
|
|
160
218
|
if (styleType != null) {
|
|
@@ -164,8 +222,22 @@ object InputParser {
|
|
|
164
222
|
ranges.add(FormattingRange(styleType, activeStyle.startPosition, end, activeStyle.url))
|
|
165
223
|
}
|
|
166
224
|
}
|
|
225
|
+
|
|
226
|
+
// Emit the block range for handler-claimed block types only; PARAGRAPH (the
|
|
227
|
+
// implicit default) yields nothing. List items are emitted above with their own
|
|
228
|
+
// line bounds, so they are excluded here.
|
|
229
|
+
if (blockType != null && blockType != BlockType.PARAGRAPH && blockType !in BlockType.LIST_ITEMS) {
|
|
230
|
+
val end = plainText.length
|
|
231
|
+
if (end > blockStartPosition) {
|
|
232
|
+
blockRanges.add(BlockRange(blockType, blockStartPosition, end, blockLevel))
|
|
233
|
+
}
|
|
234
|
+
}
|
|
167
235
|
}
|
|
168
236
|
|
|
237
|
+
/**
|
|
238
|
+
* LaTeX source of a math node. md4c may deliver it either as the node's own
|
|
239
|
+
* content or split across text children, so both are handled.
|
|
240
|
+
*/
|
|
169
241
|
private fun extractLatex(node: MarkdownASTNode): String {
|
|
170
242
|
if (node.content.isNotEmpty()) return node.content
|
|
171
243
|
if (node.children.isEmpty()) return ""
|
|
@@ -187,6 +259,28 @@ object InputParser {
|
|
|
187
259
|
else -> null
|
|
188
260
|
}
|
|
189
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Maps a parser block node to a [BlockType], mirroring [nodeTypeToStyleType]
|
|
264
|
+
* for inline spans. A heading maps to its per-level `HEADING_n` (from the node's
|
|
265
|
+
* `level` attribute); an out-of-range level falls back to PARAGRAPH so a
|
|
266
|
+
* malformed parse degrades gracefully rather than dropping the line.
|
|
267
|
+
*/
|
|
268
|
+
private fun nodeTypeToBlockType(
|
|
269
|
+
nodeType: NodeType,
|
|
270
|
+
level: Int,
|
|
271
|
+
): BlockType? =
|
|
272
|
+
when (nodeType) {
|
|
273
|
+
NodeType.Paragraph -> BlockType.PARAGRAPH
|
|
274
|
+
|
|
275
|
+
NodeType.Heading -> BlockType.forHeadingLevel(level) ?: BlockType.PARAGRAPH
|
|
276
|
+
|
|
277
|
+
// List items are recognized here but emitted with their own per-line bounds and
|
|
278
|
+
// AST-derived nesting depth in the walk above, not via the generic emission.
|
|
279
|
+
NodeType.ListItem -> BlockType.UNORDERED_LIST_ITEM
|
|
280
|
+
|
|
281
|
+
else -> null
|
|
282
|
+
}
|
|
283
|
+
|
|
190
284
|
private data class ActiveStyle(
|
|
191
285
|
val type: StyleType,
|
|
192
286
|
val startPosition: Int,
|
package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt
CHANGED
|
@@ -1,68 +1,197 @@
|
|
|
1
1
|
package com.swmansion.enriched.markdown.input.formatting
|
|
2
2
|
|
|
3
|
-
import android.
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.swmansion.enriched.markdown.input.editing.isLineBreak
|
|
4
5
|
import com.swmansion.enriched.markdown.input.math.MathChipController
|
|
6
|
+
import com.swmansion.enriched.markdown.input.model.BlockRange
|
|
7
|
+
import com.swmansion.enriched.markdown.input.model.BlockType
|
|
5
8
|
import com.swmansion.enriched.markdown.input.model.FormattingRange
|
|
9
|
+
import com.swmansion.enriched.markdown.input.model.OBJECT_REPLACEMENT
|
|
6
10
|
import com.swmansion.enriched.markdown.input.model.StyleType
|
|
7
11
|
|
|
8
12
|
object MarkdownSerializer {
|
|
9
|
-
private const val
|
|
13
|
+
private const val TAG = "MarkdownSerializer"
|
|
14
|
+
|
|
15
|
+
// Zero-width space used by the editor to anchor an empty bullet line; it is an
|
|
16
|
+
// internal editing aid and must never appear in serialized markdown.
|
|
17
|
+
private const val ZWSP = "\u200B"
|
|
10
18
|
|
|
11
19
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
20
|
+
* Single choke point for scrubbing the empty-line ZWSP anchor out of anything
|
|
21
|
+
* bound for JS (serialized markdown here, plain text in `InputEventEmitter`).
|
|
22
|
+
* Route new output paths through this rather than scattering `replace(ZWSP, "")`
|
|
23
|
+
* calls, so the anchor can never leak because one path forgot to strip.
|
|
24
|
+
*/
|
|
25
|
+
fun stripZwsp(text: String): String = text.replace(ZWSP, "")
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Math-aware serialization — the single output path for a buffer that may hold
|
|
29
|
+
* math chips. Each chip's [OBJECT_REPLACEMENT] placeholder expands back to
|
|
30
|
+
* `$latex$` / `$$latex$$`, and **both** the inline ranges and the block ranges
|
|
31
|
+
* are translated through the same position map before the block-aware overload
|
|
32
|
+
* runs. Translating only one of the two is the silent failure this exists to
|
|
33
|
+
* prevent: one placeholder char becomes n characters, so every block boundary
|
|
34
|
+
* after a chip would land a line off and `# `/`- `/`1. ` would prefix the wrong
|
|
35
|
+
* line. [stripZwsp] still happens exactly once, inside the overload below.
|
|
36
|
+
*
|
|
37
|
+
* Chips are passed as plain data (not a `Spanned` + controller) so this stays a
|
|
38
|
+
* pure function over `String` — which is what makes the round-trip testable
|
|
39
|
+
* without a live editor. Positions must be offsets into [text].
|
|
16
40
|
*/
|
|
17
41
|
fun serialize(
|
|
18
|
-
text:
|
|
42
|
+
text: String,
|
|
43
|
+
chips: List<MathChipController.ChipInfo>,
|
|
19
44
|
ranges: List<FormattingRange>,
|
|
20
|
-
|
|
45
|
+
blockRanges: List<BlockRange>,
|
|
46
|
+
blockPrefixProvider: (BlockRange) -> String,
|
|
21
47
|
): String {
|
|
22
|
-
if (
|
|
23
|
-
return serialize(text.toString(), ranges)
|
|
24
|
-
}
|
|
25
|
-
val chips = mathChipController.allChips(text)
|
|
26
|
-
if (chips.isEmpty()) {
|
|
27
|
-
return serialize(text.toString(), ranges)
|
|
28
|
-
}
|
|
48
|
+
if (chips.isEmpty()) return serialize(text, ranges, blockRanges, blockPrefixProvider)
|
|
29
49
|
|
|
30
50
|
val expanded = StringBuilder(text.length)
|
|
51
|
+
// positionMap[i] = offset in `expanded` of the character that was at `text[i]`.
|
|
52
|
+
// Length + 1 so an exclusive end offset at text.length maps too.
|
|
31
53
|
val positionMap = IntArray(text.length + 1)
|
|
32
|
-
val
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
expanded.append(
|
|
44
|
-
expandedPos += delim.length * 2 + chip.latex.length
|
|
54
|
+
val latexByPosition = HashMap<Int, String>(chips.size)
|
|
55
|
+
for (chip in chips) {
|
|
56
|
+
if (chip.position < 0 || chip.position >= text.length) continue
|
|
57
|
+
if (text[chip.position] != OBJECT_REPLACEMENT) continue
|
|
58
|
+
latexByPosition[chip.position] = mathDelimiters(chip)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (i in text.indices) {
|
|
62
|
+
positionMap[i] = expanded.length
|
|
63
|
+
val replacement = latexByPosition[i]
|
|
64
|
+
if (replacement != null) {
|
|
65
|
+
expanded.append(replacement)
|
|
45
66
|
} else {
|
|
46
|
-
expanded.append(
|
|
47
|
-
expandedPos += 1
|
|
67
|
+
expanded.append(text[i])
|
|
48
68
|
}
|
|
49
|
-
i++
|
|
50
69
|
}
|
|
51
|
-
positionMap[text.length] =
|
|
70
|
+
positionMap[text.length] = expanded.length
|
|
52
71
|
|
|
53
|
-
val
|
|
72
|
+
val shiftedRanges =
|
|
54
73
|
ranges.map { range ->
|
|
55
|
-
val rangeStart = range.start.coerceIn(0, text.length)
|
|
56
|
-
val rangeEnd = range.end.coerceIn(0, text.length)
|
|
57
74
|
FormattingRange(
|
|
58
75
|
range.type,
|
|
59
|
-
positionMap[
|
|
60
|
-
positionMap[
|
|
76
|
+
positionMap[range.start.coerceIn(0, text.length)],
|
|
77
|
+
positionMap[range.end.coerceIn(0, text.length)],
|
|
61
78
|
range.url,
|
|
62
79
|
)
|
|
63
80
|
}
|
|
64
81
|
|
|
65
|
-
|
|
82
|
+
val shiftedBlockRanges =
|
|
83
|
+
blockRanges.map { block ->
|
|
84
|
+
// `ordinal` is not a constructor default — it carries an ordered item's
|
|
85
|
+
// number, so rebuilding without it renumbers every "1." in the document.
|
|
86
|
+
BlockRange(
|
|
87
|
+
block.type,
|
|
88
|
+
positionMap[block.start.coerceIn(0, text.length)],
|
|
89
|
+
positionMap[block.end.coerceIn(0, text.length)],
|
|
90
|
+
block.level,
|
|
91
|
+
block.ordinal,
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return serialize(expanded.toString(), shiftedRanges, shiftedBlockRanges, blockPrefixProvider)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The chip's markdown form, delimiters included. Line breaks inside the LaTeX are
|
|
100
|
+
* collapsed to spaces: a chip is one line box in the editor, and emitting a real
|
|
101
|
+
* newline would change the serialized line count, which trips the line-count
|
|
102
|
+
* invariant in [serializeWithAnchors] and silently drops every block prefix in the
|
|
103
|
+
* document. LaTeX is whitespace-insensitive here, so the formula is unaffected.
|
|
104
|
+
* A blank formula expands to nothing rather than to a bare `$$` that would
|
|
105
|
+
* re-parse as literal text.
|
|
106
|
+
*/
|
|
107
|
+
private fun mathDelimiters(chip: MathChipController.ChipInfo): String {
|
|
108
|
+
val latex =
|
|
109
|
+
buildString(chip.latex.length) {
|
|
110
|
+
var previousWasBreak = false
|
|
111
|
+
for (char in chip.latex) {
|
|
112
|
+
if (char.isLineBreak()) {
|
|
113
|
+
if (!previousWasBreak) append(' ')
|
|
114
|
+
previousWasBreak = true
|
|
115
|
+
} else {
|
|
116
|
+
append(char)
|
|
117
|
+
previousWasBreak = false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}.trim()
|
|
121
|
+
if (latex.isEmpty()) return ""
|
|
122
|
+
val delimiter = if (chip.displayMode) "$$" else "$"
|
|
123
|
+
return delimiter + latex + delimiter
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Block-aware serialization: serializes inline styles exactly as the inline-only
|
|
128
|
+
* overload, then prepends each line's block prefix. [blockPrefixProvider] is
|
|
129
|
+
* asked, per block range, for the markdown line marker (e.g. `"# "`, `"- "`);
|
|
130
|
+
* returning `""` leaves the line unprefixed. With empty [blockRanges] the output
|
|
131
|
+
* is identical to the inline-only overload. Any ZWSP empty-line anchor is stripped
|
|
132
|
+
* so an empty bullet still serializes to a bare `"- "` rather than `"- "`.
|
|
133
|
+
*/
|
|
134
|
+
fun serialize(
|
|
135
|
+
text: String,
|
|
136
|
+
ranges: List<FormattingRange>,
|
|
137
|
+
blockRanges: List<BlockRange>,
|
|
138
|
+
blockPrefixProvider: (BlockRange) -> String,
|
|
139
|
+
): String = stripZwsp(serializeWithAnchors(text, ranges, blockRanges, blockPrefixProvider))
|
|
140
|
+
|
|
141
|
+
private fun serializeWithAnchors(
|
|
142
|
+
text: String,
|
|
143
|
+
ranges: List<FormattingRange>,
|
|
144
|
+
blockRanges: List<BlockRange>,
|
|
145
|
+
blockPrefixProvider: (BlockRange) -> String,
|
|
146
|
+
): String {
|
|
147
|
+
val inlineMarkdown = serialize(text, ranges)
|
|
148
|
+
if (blockRanges.isEmpty()) return inlineMarkdown
|
|
149
|
+
|
|
150
|
+
// Block prefixes attach per line. Inline serialization only inserts inline
|
|
151
|
+
// delimiters (never newlines), so the serialized output has the same line
|
|
152
|
+
// count as the plain text — we map a block's plain-text range to line indices
|
|
153
|
+
// and prefix the corresponding serialized lines.
|
|
154
|
+
val plainLines = text.split("\n")
|
|
155
|
+
val markdownLines = inlineMarkdown.split("\n").toMutableList()
|
|
156
|
+
|
|
157
|
+
// Inline delimiters never cross a newline, so the line partition is preserved.
|
|
158
|
+
// If this ever breaks, prefixes would land on the wrong lines. Contract on
|
|
159
|
+
// both platforms: log and fall back to inline-only output — a library must
|
|
160
|
+
// not crash the host app over lost block prefixes.
|
|
161
|
+
if (plainLines.size != markdownLines.size) {
|
|
162
|
+
Log.e(TAG, "Block serialization line-count invariant violated: plain=${plainLines.size} markdown=${markdownLines.size}")
|
|
163
|
+
return inlineMarkdown
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Plain-text character offset at the start of each line.
|
|
167
|
+
val lineStartOffsets = IntArray(plainLines.size)
|
|
168
|
+
var runningOffset = 0
|
|
169
|
+
for (i in plainLines.indices) {
|
|
170
|
+
lineStartOffsets[i] = runningOffset
|
|
171
|
+
runningOffset += plainLines[i].length + 1 // +1 for the '\n' separator
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (blockRange in blockRanges) {
|
|
175
|
+
val prefix = blockPrefixProvider(blockRange)
|
|
176
|
+
if (prefix.isEmpty()) continue
|
|
177
|
+
|
|
178
|
+
val isZeroLength = blockRange.length == 0
|
|
179
|
+
val isListItem = blockRange.type in BlockType.LIST_ITEMS
|
|
180
|
+
for (lineIndex in plainLines.indices) {
|
|
181
|
+
val lineStart = lineStartOffsets[lineIndex]
|
|
182
|
+
val lineEnd = lineStart + plainLines[lineIndex].length
|
|
183
|
+
val overlaps = if (isZeroLength) lineStart == blockRange.start else lineEnd >= blockRange.start && lineStart < blockRange.end
|
|
184
|
+
if (overlaps) {
|
|
185
|
+
// A marker-only list line ("- " with no content) re-parses as a setext
|
|
186
|
+
// underline for the previous line; emit an empty list line bare. An
|
|
187
|
+
// empty "# " heading is valid ATX and keeps its prefix.
|
|
188
|
+
if (isListItem && stripZwsp(plainLines[lineIndex]).isEmpty()) continue
|
|
189
|
+
markdownLines[lineIndex] = prefix + markdownLines[lineIndex]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return markdownLines.joinToString("\n")
|
|
66
195
|
}
|
|
67
196
|
|
|
68
197
|
fun serialize(
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
package com.swmansion.enriched.markdown.input.formatting
|
|
2
|
+
|
|
3
|
+
import com.swmansion.enriched.markdown.input.model.MutableRangeBounds
|
|
4
|
+
|
|
5
|
+
internal fun <T : MutableRangeBounds> sortedInsertionIndex(
|
|
6
|
+
ranges: List<T>,
|
|
7
|
+
location: Int,
|
|
8
|
+
): Int {
|
|
9
|
+
var index = 0
|
|
10
|
+
for (existing in ranges) {
|
|
11
|
+
if (existing.start > location) break
|
|
12
|
+
index++
|
|
13
|
+
}
|
|
14
|
+
return index
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Shared shift/clip logic applied to stored ranges after a text edit. Both
|
|
19
|
+
* [FormattingStore] and [BlockStore] delegate here so the overlap
|
|
20
|
+
* classification lives in exactly one place.
|
|
21
|
+
*/
|
|
22
|
+
internal object RangeEditAdjustment {
|
|
23
|
+
/**
|
|
24
|
+
* Mutates [ranges] in place to follow an edit that replaced [deletedLength]
|
|
25
|
+
* characters at [editLocation] with [insertedLength] characters. Ranges
|
|
26
|
+
* deleted outright or clipped to zero length are removed.
|
|
27
|
+
*
|
|
28
|
+
* Insert-only edits at exactly `range.end` do NOT grow the range — the typed
|
|
29
|
+
* characters stay outside it. An insert at exactly `range.start` grows the
|
|
30
|
+
* range only when [growsAtStartOnInsert] returns true; otherwise the range
|
|
31
|
+
* shifts and the typed characters stay outside it. Whether boundary text
|
|
32
|
+
* otherwise joins the range is decided elsewhere: pending styles for inline
|
|
33
|
+
* ranges, line re-normalization for block ranges.
|
|
34
|
+
*
|
|
35
|
+
* [inheritsReplacementAtStart]: when it returns true for a range whose start
|
|
36
|
+
* is the edit location, replacement text joins the range (UIKit attribute
|
|
37
|
+
* inheritance); when false, the old clip/remove behavior applies.
|
|
38
|
+
*
|
|
39
|
+
* [growsAtStartOnInsert]: when it returns true, a pure insert at `range.start`
|
|
40
|
+
* grows the range to cover the inserted text instead of shifting the range
|
|
41
|
+
* past it. Block ranges own their whole line, so a character typed at the line
|
|
42
|
+
* start must keep the line's block; inline styles must NOT set this (a
|
|
43
|
+
* character typed before a bold run must not become bold).
|
|
44
|
+
*/
|
|
45
|
+
fun <T : MutableRangeBounds> adjustForEdit(
|
|
46
|
+
ranges: MutableList<T>,
|
|
47
|
+
editLocation: Int,
|
|
48
|
+
deletedLength: Int,
|
|
49
|
+
insertedLength: Int,
|
|
50
|
+
inheritsReplacementAtStart: (T) -> Boolean = { false },
|
|
51
|
+
growsAtStartOnInsert: (T) -> Boolean = { false },
|
|
52
|
+
) {
|
|
53
|
+
if (deletedLength == 0 && insertedLength == 0) return
|
|
54
|
+
|
|
55
|
+
val deleteEnd = editLocation + deletedLength
|
|
56
|
+
val indexesToRemove = mutableListOf<Int>()
|
|
57
|
+
|
|
58
|
+
for ((idx, range) in ranges.withIndex()) {
|
|
59
|
+
if (deletedLength > 0) {
|
|
60
|
+
val inheritsReplacement =
|
|
61
|
+
insertedLength > 0 && range.start == editLocation && inheritsReplacementAtStart(range)
|
|
62
|
+
when (classifyOverlap(range.start, range.end, editLocation, deleteEnd)) {
|
|
63
|
+
EditOverlap.BEFORE_EDIT -> { /* no change */ }
|
|
64
|
+
|
|
65
|
+
EditOverlap.AFTER_EDIT -> {
|
|
66
|
+
range.start = range.start - deletedLength + insertedLength
|
|
67
|
+
range.end = range.end - deletedLength + insertedLength
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
EditOverlap.FULLY_DELETED -> {
|
|
71
|
+
if (inheritsReplacement) {
|
|
72
|
+
range.start = editLocation
|
|
73
|
+
range.end = editLocation + insertedLength
|
|
74
|
+
} else {
|
|
75
|
+
indexesToRemove.add(idx)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
EditOverlap.DELETED_INSIDE -> {
|
|
80
|
+
range.end = range.end - deletedLength + insertedLength
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
EditOverlap.CLIPPED_END -> {
|
|
84
|
+
val newEnd = editLocation + insertedLength
|
|
85
|
+
val newLength = if (newEnd > range.start) newEnd - range.start else 0
|
|
86
|
+
range.end = range.start + newLength
|
|
87
|
+
if (newLength == 0) indexesToRemove.add(idx)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
EditOverlap.CLIPPED_START -> {
|
|
91
|
+
val charsClipped = deleteEnd - range.start
|
|
92
|
+
val survivingLength = range.end - range.start - charsClipped
|
|
93
|
+
if (inheritsReplacement) {
|
|
94
|
+
range.start = editLocation
|
|
95
|
+
range.end = editLocation + insertedLength + survivingLength
|
|
96
|
+
} else {
|
|
97
|
+
range.start = editLocation + insertedLength
|
|
98
|
+
range.end = range.start + survivingLength
|
|
99
|
+
if (survivingLength == 0) indexesToRemove.add(idx)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
when {
|
|
105
|
+
range.start == editLocation && growsAtStartOnInsert(range) -> {
|
|
106
|
+
range.end += insertedLength
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
range.start >= editLocation -> {
|
|
110
|
+
range.start += insertedLength
|
|
111
|
+
range.end += insertedLength
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
editLocation > range.start && editLocation < range.end -> {
|
|
115
|
+
range.end += insertedLength
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (idx in indexesToRemove.reversed()) {
|
|
122
|
+
ranges.removeAt(idx)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
ranges.removeAll { it.end - it.start == 0 }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private enum class EditOverlap {
|
|
129
|
+
BEFORE_EDIT,
|
|
130
|
+
AFTER_EDIT,
|
|
131
|
+
FULLY_DELETED,
|
|
132
|
+
DELETED_INSIDE,
|
|
133
|
+
CLIPPED_END,
|
|
134
|
+
CLIPPED_START,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private fun classifyOverlap(
|
|
138
|
+
rangeStart: Int,
|
|
139
|
+
rangeEnd: Int,
|
|
140
|
+
editLocation: Int,
|
|
141
|
+
deleteEnd: Int,
|
|
142
|
+
): EditOverlap {
|
|
143
|
+
if (rangeEnd <= editLocation) return EditOverlap.BEFORE_EDIT
|
|
144
|
+
if (rangeStart >= deleteEnd) return EditOverlap.AFTER_EDIT
|
|
145
|
+
if (rangeStart >= editLocation && rangeEnd <= deleteEnd) return EditOverlap.FULLY_DELETED
|
|
146
|
+
if (rangeStart < editLocation && rangeEnd > deleteEnd) return EditOverlap.DELETED_INSIDE
|
|
147
|
+
return if (rangeStart < editLocation) EditOverlap.CLIPPED_END else EditOverlap.CLIPPED_START
|
|
148
|
+
}
|
|
149
|
+
}
|