react-native-marcus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +227 -0
- package/RNMarcus.podspec +78 -0
- package/android/build.gradle +220 -0
- package/android/proguard-rules.pro +1 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/cpp/CMakeLists.txt +41 -0
- package/android/src/main/cpp/MarkdownParser.cpp +49 -0
- package/android/src/main/cpp/MarkdownParser.h +56 -0
- package/android/src/main/cpp/OnLoad.cpp +17 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusModule.kt +28 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +31 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +63 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManager.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManagerSpec.kt +21 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +333 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownParseResult.kt +12 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownParser.kt +89 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownRange.kt +11 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +81 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownTextWatcher.kt +17 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +84 -0
- package/android/src/main/java/app/getbullet/marcus/ReactLineHeight.java +29 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +105 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +67 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontFamilySpan.kt +28 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontSizeSpan.kt +7 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownForegroundColorSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +57 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLineHeightSpan.kt +21 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownSpan.kt +7 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownStrikethroughSpan.kt +5 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownUnderlineSpan.kt +5 -0
- package/android/src/main/new_arch/CMakeLists.txt +70 -0
- package/android/src/main/new_arch/RNMarcusSpec.cpp +43 -0
- package/android/src/main/new_arch/RNMarcusSpec.h +36 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.cpp +218 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.h +54 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +156 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +130 -0
- package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +205 -0
- package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +78 -0
- package/android/src/test/resources/render-model.txt +583 -0
- package/apple/MarcusModule.h +8 -0
- package/apple/MarcusModule.mm +26 -0
- package/apple/MarcusRange.h +15 -0
- package/apple/MarcusRange.mm +15 -0
- package/apple/MarcusTextInputDecoratorComponentView.h +12 -0
- package/apple/MarcusTextInputDecoratorComponentView.mm +121 -0
- package/apple/MarcusTextInputDecoratorShadowNode.cpp +251 -0
- package/apple/MarcusTextInputDecoratorShadowNode.h +65 -0
- package/apple/MarcusTextInputDecoratorShadowNode.mm +204 -0
- package/apple/MarcusTextInputDecoratorViewManager.h +8 -0
- package/apple/MarcusTextInputDecoratorViewManager.mm +11 -0
- package/apple/MarkdownAdaptiveImageGlyph.swift +44 -0
- package/apple/MarkdownAttributes.h +31 -0
- package/apple/MarkdownAttributes.m +9 -0
- package/apple/MarkdownBackedTextInputDelegate.swift +117 -0
- package/apple/MarkdownDecorator.swift +316 -0
- package/apple/MarkdownFonts.swift +21 -0
- package/apple/MarkdownFormatter+React.swift +51 -0
- package/apple/MarkdownFormatter.swift +509 -0
- package/apple/MarkdownLog.h +10 -0
- package/apple/MarkdownLog.mm +6 -0
- package/apple/MarkdownParser.swift +200 -0
- package/apple/MarkdownSwiftInterop.h +23 -0
- package/apple/MarkdownTextBackground.swift +17 -0
- package/apple/MarkdownTextFieldObserver.swift +90 -0
- package/apple/MarkdownTextLayoutFragment.swift +205 -0
- package/apple/MarkdownTextLayoutManagerDelegate.swift +84 -0
- package/apple/MarkdownTextStorageDelegate.swift +32 -0
- package/apple/MarkdownTextViewObserver.swift +30 -0
- package/apple/RCTMarcusStyle+Codegen.h +18 -0
- package/apple/RCTMarcusStyle+Codegen.mm +64 -0
- package/apple/RCTMarcusStyle.h +41 -0
- package/apple/RCTMarcusStyle.m +5 -0
- package/apple/RCTMarcusUtils.h +26 -0
- package/apple/RCTMarcusUtils.mm +26 -0
- package/apple/RCTTextInput+AdaptiveImageGlyph.h +16 -0
- package/apple/RCTTextInput+AdaptiveImageGlyph.mm +79 -0
- package/apple/RCTTextInputComponentView+Marcus.h +11 -0
- package/apple/RCTTextInputComponentView+Marcus.mm +79 -0
- package/cpp/MarkdownCxx.modulemap +8 -0
- package/cpp/MarkdownGlobal.cpp +48 -0
- package/cpp/MarkdownGlobal.h +33 -0
- package/cpp/MarkdownWorkletParser.cpp +93 -0
- package/cpp/MarkdownWorkletParser.h +45 -0
- package/cpp/RuntimeDecorator.cpp +39 -0
- package/cpp/RuntimeDecorator.h +14 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorState.h +33 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorViewComponentDescriptor.h +17 -0
- package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/lib/commonjs/MarkdownTextInput.js +99 -0
- package/lib/commonjs/MarkdownTextInput.js.map +1 -0
- package/lib/commonjs/MarkdownTextInput.web.js +618 -0
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -0
- package/lib/commonjs/NativeMarcusModule.js +9 -0
- package/lib/commonjs/NativeMarcusModule.js.map +1 -0
- package/lib/commonjs/commonTypes.js +2 -0
- package/lib/commonjs/commonTypes.js.map +1 -0
- package/lib/commonjs/global.d.js +2 -0
- package/lib/commonjs/global.d.js.map +1 -0
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/parser/index.js +7030 -0
- package/lib/commonjs/parser/index.js.map +7 -0
- package/lib/commonjs/rangeUtils.js +71 -0
- package/lib/commonjs/rangeUtils.js.map +1 -0
- package/lib/commonjs/react-native-web.d.js +2 -0
- package/lib/commonjs/react-native-web.d.js.map +1 -0
- package/lib/commonjs/styleUtils.js +91 -0
- package/lib/commonjs/styleUtils.js.map +1 -0
- package/lib/commonjs/web/InputHistory.js +111 -0
- package/lib/commonjs/web/InputHistory.js.map +1 -0
- package/lib/commonjs/web/MarkdownTextInput.css +72 -0
- package/lib/commonjs/web/utils/blockLayout.js +132 -0
- package/lib/commonjs/web/utils/blockLayout.js.map +1 -0
- package/lib/commonjs/web/utils/blockUtils.js +219 -0
- package/lib/commonjs/web/utils/blockUtils.js.map +1 -0
- package/lib/commonjs/web/utils/browserUtils.js +40 -0
- package/lib/commonjs/web/utils/browserUtils.js.map +1 -0
- package/lib/commonjs/web/utils/cursorUtils.js +157 -0
- package/lib/commonjs/web/utils/cursorUtils.js.map +1 -0
- package/lib/commonjs/web/utils/inputUtils.js +152 -0
- package/lib/commonjs/web/utils/inputUtils.js.map +1 -0
- package/lib/commonjs/web/utils/measureUtils.js +0 -0
- package/lib/commonjs/web/utils/measureUtils.js.map +1 -0
- package/lib/commonjs/web/utils/parserUtils.js +552 -0
- package/lib/commonjs/web/utils/parserUtils.js.map +1 -0
- package/lib/commonjs/web/utils/treeUtils.js +109 -0
- package/lib/commonjs/web/utils/treeUtils.js.map +1 -0
- package/lib/commonjs/web/utils/webStyleUtils.js +59 -0
- package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -0
- package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/lib/module/MarkdownTextInput.js +94 -0
- package/lib/module/MarkdownTextInput.js.map +1 -0
- package/lib/module/MarkdownTextInput.web.js +612 -0
- package/lib/module/MarkdownTextInput.web.js.map +1 -0
- package/lib/module/NativeMarcusModule.js +5 -0
- package/lib/module/NativeMarcusModule.js.map +1 -0
- package/lib/module/commonTypes.js +2 -0
- package/lib/module/commonTypes.js.map +1 -0
- package/lib/module/global.d.js +2 -0
- package/lib/module/global.d.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/parser/index.js +7029 -0
- package/lib/module/parser/index.js.map +7 -0
- package/lib/module/rangeUtils.js +66 -0
- package/lib/module/rangeUtils.js.map +1 -0
- package/lib/module/react-native-web.d.js +2 -0
- package/lib/module/react-native-web.d.js.map +1 -0
- package/lib/module/styleUtils.js +88 -0
- package/lib/module/styleUtils.js.map +1 -0
- package/lib/module/web/InputHistory.js +106 -0
- package/lib/module/web/InputHistory.js.map +1 -0
- package/lib/module/web/MarkdownTextInput.css +72 -0
- package/lib/module/web/utils/blockLayout.js +128 -0
- package/lib/module/web/utils/blockLayout.js.map +1 -0
- package/lib/module/web/utils/blockUtils.js +210 -0
- package/lib/module/web/utils/blockUtils.js.map +1 -0
- package/lib/module/web/utils/browserUtils.js +36 -0
- package/lib/module/web/utils/browserUtils.js.map +1 -0
- package/lib/module/web/utils/cursorUtils.js +150 -0
- package/lib/module/web/utils/cursorUtils.js.map +1 -0
- package/lib/module/web/utils/inputUtils.js +144 -0
- package/lib/module/web/utils/inputUtils.js.map +1 -0
- package/lib/module/web/utils/measureUtils.js +0 -0
- package/lib/module/web/utils/measureUtils.js.map +1 -0
- package/lib/module/web/utils/parserUtils.js +547 -0
- package/lib/module/web/utils/parserUtils.js.map +1 -0
- package/lib/module/web/utils/treeUtils.js +103 -0
- package/lib/module/web/utils/treeUtils.js.map +1 -0
- package/lib/module/web/utils/webStyleUtils.js +54 -0
- package/lib/module/web/utils/webStyleUtils.js.map +1 -0
- package/lib/typescript/commonjs/e2e/checks.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/checks.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/editing.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/editing.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/helpers.d.ts +23 -0
- package/lib/typescript/commonjs/e2e/helpers.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/smoke.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/smoke.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +22 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +41 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts +7 -0
- package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts +10 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +5 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts +8 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts +8 -0
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/rangeUtils.d.ts +6 -0
- package/lib/typescript/commonjs/src/rangeUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts +8 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/InputHistory.d.ts +24 -0
- package/lib/typescript/commonjs/src/web/InputHistory.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +41 -0
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +33 -0
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts +7 -0
- package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts +22 -0
- package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +44 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +25 -0
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +7 -0
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -0
- package/lib/typescript/module/e2e/checks.test.d.ts +2 -0
- package/lib/typescript/module/e2e/checks.test.d.ts.map +1 -0
- package/lib/typescript/module/e2e/editing.test.d.ts +2 -0
- package/lib/typescript/module/e2e/editing.test.d.ts.map +1 -0
- package/lib/typescript/module/e2e/helpers.d.ts +23 -0
- package/lib/typescript/module/e2e/helpers.d.ts.map +1 -0
- package/lib/typescript/module/e2e/smoke.test.d.ts +2 -0
- package/lib/typescript/module/e2e/smoke.test.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts +22 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +41 -0
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -0
- package/lib/typescript/module/src/NativeMarcusModule.d.ts +7 -0
- package/lib/typescript/module/src/NativeMarcusModule.d.ts.map +1 -0
- package/lib/typescript/module/src/commonTypes.d.ts +10 -0
- package/lib/typescript/module/src/commonTypes.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +5 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/index.d.ts +8 -0
- package/lib/typescript/module/src/parser/index.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts +8 -0
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -0
- package/lib/typescript/module/src/rangeUtils.d.ts +6 -0
- package/lib/typescript/module/src/rangeUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/styleUtils.d.ts +8 -0
- package/lib/typescript/module/src/styleUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/InputHistory.d.ts +24 -0
- package/lib/typescript/module/src/web/InputHistory.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts +41 -0
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts +33 -0
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/browserUtils.d.ts +7 -0
- package/lib/typescript/module/src/web/utils/browserUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/cursorUtils.d.ts +12 -0
- package/lib/typescript/module/src/web/utils/cursorUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/inputUtils.d.ts +12 -0
- package/lib/typescript/module/src/web/utils/inputUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/measureUtils.d.ts +22 -0
- package/lib/typescript/module/src/web/utils/measureUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts +44 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts +25 -0
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +7 -0
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -0
- package/package.json +167 -0
- package/react-native.config.js +10 -0
- package/src/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/src/MarkdownTextInput.tsx +139 -0
- package/src/MarkdownTextInput.web.tsx +958 -0
- package/src/NativeMarcusModule.ts +8 -0
- package/src/commonTypes.ts +30 -0
- package/src/global.d.ts +1 -0
- package/src/index.tsx +4 -0
- package/src/parser/index.ts +556 -0
- package/src/parser/micromark-extension-mentions.ts +82 -0
- package/src/rangeUtils.ts +68 -0
- package/src/react-native-web.d.ts +1 -0
- package/src/styleUtils.ts +100 -0
- package/src/web/InputHistory.ts +137 -0
- package/src/web/MarkdownTextInput.css +72 -0
- package/src/web/utils/blockLayout.ts +163 -0
- package/src/web/utils/blockUtils.ts +245 -0
- package/src/web/utils/browserUtils.ts +41 -0
- package/src/web/utils/cursorUtils.ts +204 -0
- package/src/web/utils/inputUtils.ts +206 -0
- package/src/web/utils/measureUtils.ts +0 -0
- package/src/web/utils/parserUtils.ts +813 -0
- package/src/web/utils/treeUtils.ts +149 -0
- package/src/web/utils/webStyleUtils.ts +69 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import android.text.TextPaint
|
|
5
|
+
import com.facebook.react.bridge.JavaOnlyMap
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap
|
|
7
|
+
import com.facebook.react.uimanager.DisplayMetricsHolder
|
|
8
|
+
import java.io.File
|
|
9
|
+
import org.json.JSONArray
|
|
10
|
+
import org.json.JSONObject
|
|
11
|
+
import org.junit.Assert.assertEquals
|
|
12
|
+
import org.junit.Before
|
|
13
|
+
import org.junit.Test
|
|
14
|
+
import org.junit.runner.RunWith
|
|
15
|
+
import org.robolectric.RobolectricTestRunner
|
|
16
|
+
import org.robolectric.RuntimeEnvironment
|
|
17
|
+
import org.robolectric.annotation.Config
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The Android render model, driven by the same corpus every other layer uses.
|
|
21
|
+
*
|
|
22
|
+
* Ranges come from `ranges.json`, produced by the JS parser: a formatter takes
|
|
23
|
+
* ranges rather than markdown, so this suite needs no JS runtime and no device.
|
|
24
|
+
*
|
|
25
|
+
* The whole corpus is dumped into one baseline rather than one file per case,
|
|
26
|
+
* so the Android and iOS outputs stay diffable against each other in a single
|
|
27
|
+
* comparison. Regenerate with `-Dmarcus.updateBaselines=true`.
|
|
28
|
+
*/
|
|
29
|
+
@RunWith(RobolectricTestRunner::class)
|
|
30
|
+
@Config(sdk = [34])
|
|
31
|
+
class MarkdownFormatterTest {
|
|
32
|
+
|
|
33
|
+
private lateinit var style: MarkdownStyle
|
|
34
|
+
private lateinit var formatter: MarkdownFormatter
|
|
35
|
+
|
|
36
|
+
@Before
|
|
37
|
+
fun setUp() {
|
|
38
|
+
val context = RuntimeEnvironment.getApplication()
|
|
39
|
+
// `PixelUtil.toPixelFromDIP` reads these; without them every gutter is NaN.
|
|
40
|
+
DisplayMetricsHolder.initDisplayMetrics(context)
|
|
41
|
+
|
|
42
|
+
style = MarkdownStyle(styleMap(), context)
|
|
43
|
+
formatter = MarkdownFormatter(context.assets)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Test
|
|
47
|
+
fun `formats every fixture into the shared render model`() {
|
|
48
|
+
val cases = JSONArray(resource("cases.json"))
|
|
49
|
+
val ranges = JSONObject(resource("ranges.json"))
|
|
50
|
+
|
|
51
|
+
val dump = buildString {
|
|
52
|
+
for (i in 0 until cases.length()) {
|
|
53
|
+
val entry = cases.getJSONObject(i)
|
|
54
|
+
val id = entry.getString("id")
|
|
55
|
+
val markdown = entry.getString("markdown")
|
|
56
|
+
|
|
57
|
+
val ssb = SpannableStringBuilder(markdown)
|
|
58
|
+
formatter.format(ssb, rangesOf(ranges.getJSONArray(id)), style, textPaint())
|
|
59
|
+
|
|
60
|
+
append(id).append('\n')
|
|
61
|
+
append(RenderModel.dump(markdown, ssb).prependIndent(" ")).append('\n')
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
val baseline = File("src/test/resources/render-model.txt")
|
|
66
|
+
|
|
67
|
+
if (System.getProperty("marcus.updateBaselines") == "true" || !baseline.exists()) {
|
|
68
|
+
baseline.parentFile.mkdirs()
|
|
69
|
+
baseline.writeText(dump)
|
|
70
|
+
println("Wrote baseline to ${baseline.absolutePath}")
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (baseline.readText() != dump) {
|
|
75
|
+
val actual = File("build/render-model-actual.txt")
|
|
76
|
+
actual.parentFile.mkdirs()
|
|
77
|
+
actual.writeText(dump)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
assertEquals(baseline.readText(), dump)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@Test
|
|
84
|
+
fun `applies bold across the whole emphasis span`() {
|
|
85
|
+
val ssb = SpannableStringBuilder("**bold**")
|
|
86
|
+
formatter.format(
|
|
87
|
+
ssb,
|
|
88
|
+
listOf(
|
|
89
|
+
MarkdownRange("bold", 0, 8, 0),
|
|
90
|
+
MarkdownRange("syntax", 0, 2, 0),
|
|
91
|
+
MarkdownRange("syntax", 6, 2, 0),
|
|
92
|
+
),
|
|
93
|
+
style,
|
|
94
|
+
textPaint(),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
assertEquals(
|
|
98
|
+
"""
|
|
99
|
+
0..8 bold
|
|
100
|
+
0..2 color(#808080)
|
|
101
|
+
6..8 color(#808080)
|
|
102
|
+
""".trimIndent(),
|
|
103
|
+
RenderModel.dump("**bold**", ssb).trimIndent(),
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@Test
|
|
108
|
+
fun `leaves plain text unspanned`() {
|
|
109
|
+
val ssb = SpannableStringBuilder("no markdown here")
|
|
110
|
+
formatter.format(ssb, emptyList(), style, textPaint())
|
|
111
|
+
|
|
112
|
+
assertEquals("(no spans)", RenderModel.dump("no markdown here", ssb))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private fun textPaint() = TextPaint().apply { textSize = 16f }
|
|
116
|
+
|
|
117
|
+
private fun rangesOf(array: JSONArray): List<MarkdownRange> =
|
|
118
|
+
(0 until array.length()).map { i ->
|
|
119
|
+
val range = array.getJSONObject(i)
|
|
120
|
+
MarkdownRange(
|
|
121
|
+
range.getString("type"),
|
|
122
|
+
range.getInt("start"),
|
|
123
|
+
range.getInt("length"),
|
|
124
|
+
range.optInt("depth", 0),
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private fun resource(name: String): String =
|
|
129
|
+
requireNotNull(javaClass.classLoader?.getResourceAsStream(name)) {
|
|
130
|
+
"$name is not on the test classpath -- is sourceSets.test.resources pointing at src/__fixtures__?"
|
|
131
|
+
}.bufferedReader().readText()
|
|
132
|
+
|
|
133
|
+
/** The same style the web harness pins, so the dumps are comparable. */
|
|
134
|
+
private fun styleMap(): ReadableMap {
|
|
135
|
+
fun group(vararg entries: Pair<String, Any>): JavaOnlyMap = JavaOnlyMap().apply {
|
|
136
|
+
entries.forEach { (key, value) ->
|
|
137
|
+
when (value) {
|
|
138
|
+
is Int -> putInt(key, value)
|
|
139
|
+
is Double -> putDouble(key, value)
|
|
140
|
+
is String -> putString(key, value)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return JavaOnlyMap().apply {
|
|
146
|
+
putMap("syntax", group("color" to 0xFF808080.toInt()))
|
|
147
|
+
putMap("link", group("color" to 0xFF0000FF.toInt()))
|
|
148
|
+
putMap("heading", group("fontSize" to 38.0, "scale" to 0.85))
|
|
149
|
+
putMap("emoji", group("fontSize" to 16.0, "fontFamily" to "System"))
|
|
150
|
+
putMap(
|
|
151
|
+
"blockquote",
|
|
152
|
+
group(
|
|
153
|
+
"borderColor" to 0xFF808080.toInt(),
|
|
154
|
+
"borderWidth" to 6.0,
|
|
155
|
+
"marginLeft" to 6.0,
|
|
156
|
+
"paddingLeft" to 6.0,
|
|
157
|
+
),
|
|
158
|
+
)
|
|
159
|
+
putMap("orderedList", group("marginLeft" to 6.0, "paddingLeft" to 18.0))
|
|
160
|
+
putMap("unorderedList", group("marginLeft" to 6.0, "paddingLeft" to 18.0))
|
|
161
|
+
putMap(
|
|
162
|
+
"code",
|
|
163
|
+
group(
|
|
164
|
+
"fontFamily" to "monospace",
|
|
165
|
+
"fontSize" to 16.0,
|
|
166
|
+
"color" to 0xFF000000.toInt(),
|
|
167
|
+
"backgroundColor" to 0xFFD3D3D3.toInt(),
|
|
168
|
+
),
|
|
169
|
+
)
|
|
170
|
+
putMap(
|
|
171
|
+
"pre",
|
|
172
|
+
group(
|
|
173
|
+
"fontFamily" to "monospace",
|
|
174
|
+
"fontSize" to 16.0,
|
|
175
|
+
"color" to 0xFF000000.toInt(),
|
|
176
|
+
"backgroundColor" to 0xFFD3D3D3.toInt(),
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
putMap(
|
|
180
|
+
"mentionHere",
|
|
181
|
+
group(
|
|
182
|
+
"color" to 0xFF008000.toInt(),
|
|
183
|
+
"backgroundColor" to 0xFF00FF00.toInt(),
|
|
184
|
+
"borderRadius" to 5.0,
|
|
185
|
+
),
|
|
186
|
+
)
|
|
187
|
+
putMap(
|
|
188
|
+
"mentionUser",
|
|
189
|
+
group(
|
|
190
|
+
"color" to 0xFF0000FF.toInt(),
|
|
191
|
+
"backgroundColor" to 0xFF00FFFF.toInt(),
|
|
192
|
+
"borderRadius" to 5.0,
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
putMap(
|
|
196
|
+
"mentionReport",
|
|
197
|
+
group(
|
|
198
|
+
"color" to 0xFFFF0000.toInt(),
|
|
199
|
+
"backgroundColor" to 0xFFFFC0CB.toInt(),
|
|
200
|
+
"borderRadius" to 5.0,
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import android.text.Spanned
|
|
5
|
+
import android.text.style.AbsoluteSizeSpan
|
|
6
|
+
import android.text.style.BackgroundColorSpan
|
|
7
|
+
import android.text.style.ForegroundColorSpan
|
|
8
|
+
import android.text.style.LeadingMarginSpan
|
|
9
|
+
import app.getbullet.marcus.spans.MarkdownBackgroundSpan
|
|
10
|
+
import app.getbullet.marcus.spans.MarkdownBoldSpan
|
|
11
|
+
import app.getbullet.marcus.spans.MarkdownFontFamilySpan
|
|
12
|
+
import app.getbullet.marcus.spans.MarkdownGapSpan
|
|
13
|
+
import app.getbullet.marcus.spans.MarkdownItalicSpan
|
|
14
|
+
import app.getbullet.marcus.spans.MarkdownLineHeightSpan
|
|
15
|
+
import app.getbullet.marcus.spans.MarkdownStrikethroughSpan
|
|
16
|
+
import app.getbullet.marcus.spans.MarkdownUnderlineSpan
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Serializes the spans a formatted string carries into the shared render model.
|
|
20
|
+
*
|
|
21
|
+
* One line per span, `start..end attribute`, sorted so the output does not
|
|
22
|
+
* depend on the order the formatter happened to apply things in. The attribute
|
|
23
|
+
* vocabulary is deliberately platform neutral -- `bold`, `color(#RRGGBB)`,
|
|
24
|
+
* `indent(first,rest)` -- so an Android dump and an iOS dump of the same case
|
|
25
|
+
* can be diffed against each other directly.
|
|
26
|
+
*
|
|
27
|
+
* Only public API is read. Making span fields visible purely so a test could
|
|
28
|
+
* assert on them would be the test changing the thing it measures.
|
|
29
|
+
*/
|
|
30
|
+
object RenderModel {
|
|
31
|
+
|
|
32
|
+
fun dump(text: CharSequence, spanned: Spanned): String {
|
|
33
|
+
val lines = spanned.getSpans(0, spanned.length, Any::class.java)
|
|
34
|
+
.mapNotNull { span ->
|
|
35
|
+
val attribute = describe(span) ?: return@mapNotNull null
|
|
36
|
+
val start = spanned.getSpanStart(span)
|
|
37
|
+
val end = spanned.getSpanEnd(span)
|
|
38
|
+
Triple(start, end, attribute)
|
|
39
|
+
}
|
|
40
|
+
.sortedWith(compareBy({ it.first }, { -it.second }, { it.third }))
|
|
41
|
+
.map { (start, end, attribute) ->
|
|
42
|
+
"%4d..%-4d %s".format(start, end, attribute)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (lines.isEmpty()) {
|
|
46
|
+
return "(no spans)"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return lines.joinToString("\n")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The shared attribute name for a span, or null for spans we do not model. */
|
|
53
|
+
private fun describe(span: Any): String? = when (span) {
|
|
54
|
+
is MarkdownBoldSpan -> "bold"
|
|
55
|
+
is MarkdownItalicSpan -> "italic"
|
|
56
|
+
is MarkdownStrikethroughSpan -> "strikethrough"
|
|
57
|
+
is MarkdownUnderlineSpan -> "underline"
|
|
58
|
+
is MarkdownFontFamilySpan -> "font-family"
|
|
59
|
+
is MarkdownLineHeightSpan -> "line-height"
|
|
60
|
+
// The rounded rectangle drawn behind a mention, not a plain background
|
|
61
|
+
// colour -- iOS models the same thing as `MarkdownTextBackground`.
|
|
62
|
+
is MarkdownBackgroundSpan -> "background-shape"
|
|
63
|
+
// The space held open after a marker so the next container's gutter lands
|
|
64
|
+
// between the two.
|
|
65
|
+
is MarkdownGapSpan -> "gap"
|
|
66
|
+
is ForegroundColorSpan -> "color(${hex(span.foregroundColor)})"
|
|
67
|
+
is BackgroundColorSpan -> "background(${hex(span.backgroundColor)})"
|
|
68
|
+
is AbsoluteSizeSpan -> "font-size(${span.size})"
|
|
69
|
+
is LeadingMarginSpan ->
|
|
70
|
+
"indent(${span.getLeadingMargin(true)},${span.getLeadingMargin(false)})"
|
|
71
|
+
// Anything still unnamed is flagged rather than dropped: a span the model
|
|
72
|
+
// has no word for is exactly what a reviewer needs to see.
|
|
73
|
+
else -> "?${span.javaClass.simpleName.removePrefix("Markdown").removeSuffix("Span")}"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private fun hex(color: Int): String =
|
|
77
|
+
"#%02X%02X%02X".format(Color.red(color), Color.green(color), Color.blue(color))
|
|
78
|
+
}
|