react-native-marcus 0.1.1 → 0.2.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/README.md +220 -63
- package/RNMarcus.podspec +6 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +2 -1
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorView.kt +168 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManager.kt +38 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManagerSpec.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +23 -1
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPainter.kt +147 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPass.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownCopy.kt +87 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +652 -113
- package/android/src/main/java/app/getbullet/marcus/MarkdownRanges.kt +47 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +140 -61
- package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +37 -7
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownAbsoluteLineHeightSpan.kt +48 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +102 -48
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +22 -4
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBulletSpan.kt +78 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpan.kt +177 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontStyleSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontWeightSpan.kt +34 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +24 -11
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLetterSpacingSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownTextShadowSpan.kt +32 -0
- package/android/src/main/new_arch/CMakeLists.txt +17 -0
- package/android/src/main/new_arch/RNMarcusSpec.h +1 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.cpp +235 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.h +62 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/test/java/app/getbullet/marcus/MarkdownCopyTest.kt +69 -0
- package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +170 -25
- package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +22 -5
- package/android/src/test/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpanTest.kt +91 -0
- package/android/src/test/resources/render-model.txt +221 -16
- package/apple/MarcusSwizzle.h +25 -0
- package/apple/MarcusTextDecoratorComponentView.h +22 -0
- package/apple/MarcusTextDecoratorComponentView.mm +72 -0
- package/apple/MarcusTextDecoratorShadowNode.h +62 -0
- package/apple/MarcusTextDecoratorShadowNode.mm +192 -0
- package/apple/MarcusTextDecoratorViewManager.h +4 -0
- package/apple/MarcusTextDecoratorViewManager.mm +11 -0
- package/apple/MarcusTextInputDecoratorComponentView.mm +1 -1
- package/apple/MarcusTextInputDecoratorShadowNode.mm +1 -1
- package/apple/MarcusTextLayoutManager.h +40 -0
- package/apple/MarcusTextLayoutManager.mm +173 -0
- package/apple/MarkdownAttributes.h +23 -2
- package/apple/MarkdownAttributes.m +6 -0
- package/apple/MarkdownCopy.swift +63 -0
- package/apple/MarkdownDecorator.swift +2 -2
- package/apple/MarkdownFormatter+React.swift +23 -0
- package/apple/MarkdownFormatter.swift +869 -148
- package/apple/MarkdownParagraphLayoutManager.swift +455 -0
- package/apple/MarkdownSwiftInterop.h +0 -1
- package/apple/MarkdownTextBackground.swift +59 -1
- package/apple/MarkdownTextFieldObserver.swift +2 -2
- package/apple/MarkdownTextLayoutFragment.swift +159 -33
- package/apple/MarkdownTextLayoutManagerDelegate.swift +67 -3
- package/apple/MarkdownTextStorageDelegate.swift +2 -2
- package/apple/MarkdownTextViewObserver.swift +2 -2
- package/apple/MarkdownUtils.swift +38 -0
- package/apple/MarkdownWritingDirection.swift +132 -0
- package/apple/RCTMarcusStyle+Codegen.h +115 -9
- package/apple/RCTMarcusStyle.h +128 -31
- package/apple/RCTMarcusStyle.m +48 -0
- package/apple/RCTParagraphComponentView+Marcus.h +17 -0
- package/apple/RCTParagraphComponentView+Marcus.mm +38 -0
- package/apple/RCTTextInputComponentView+Marcus.mm +1 -25
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorState.h +37 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorViewComponentDescriptor.h +17 -0
- package/lib/commonjs/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/commonjs/MarkdownText.js +330 -0
- package/lib/commonjs/MarkdownText.js.map +1 -0
- package/lib/commonjs/MarkdownText.web.js +529 -0
- package/lib/commonjs/MarkdownText.web.js.map +1 -0
- package/lib/commonjs/MarkdownTextInput.js +22 -27
- package/lib/commonjs/MarkdownTextInput.js.map +1 -1
- package/lib/commonjs/MarkdownTextInput.web.js +12 -7
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -1
- package/lib/commonjs/atomUtils.js +112 -0
- package/lib/commonjs/atomUtils.js.map +1 -0
- package/lib/commonjs/childrenUtils.js +36 -0
- package/lib/commonjs/childrenUtils.js.map +1 -0
- package/lib/commonjs/index.js +8 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/math/environment.js +69 -0
- package/lib/commonjs/math/environment.js.map +1 -0
- package/lib/commonjs/math/index.js +61 -0
- package/lib/commonjs/math/index.js.map +1 -0
- package/lib/commonjs/math/mathjax.js +548 -0
- package/lib/commonjs/math/mathjax.js.map +1 -0
- package/lib/commonjs/metro.js +172 -0
- package/lib/commonjs/metro.js.map +1 -0
- package/lib/commonjs/parser/index.d.ts +3 -0
- package/lib/commonjs/parser/index.js +450 -42
- package/lib/commonjs/parser/index.js.map +4 -4
- package/lib/commonjs/stripUtils.js +743 -0
- package/lib/commonjs/stripUtils.js.map +1 -0
- package/lib/commonjs/styleUtils.js +194 -23
- package/lib/commonjs/styleUtils.js.map +1 -1
- package/lib/commonjs/web/MarkdownElements.css +67 -0
- package/lib/commonjs/web/MarkdownTextInput.css +9 -7
- package/lib/commonjs/web/utils/blockLayout.js +95 -7
- package/lib/commonjs/web/utils/blockLayout.js.map +1 -1
- package/lib/commonjs/web/utils/blockUtils.js +327 -54
- package/lib/commonjs/web/utils/blockUtils.js.map +1 -1
- package/lib/commonjs/web/utils/elementUtils.js +80 -0
- package/lib/commonjs/web/utils/elementUtils.js.map +1 -0
- package/lib/commonjs/web/utils/parserUtils.js +84 -28
- package/lib/commonjs/web/utils/parserUtils.js.map +1 -1
- package/lib/commonjs/web/utils/treeUtils.js +6 -0
- package/lib/commonjs/web/utils/treeUtils.js.map +1 -1
- package/lib/commonjs/web/utils/webStyleUtils.js +25 -5
- package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -1
- package/lib/module/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/module/MarkdownText.js +325 -0
- package/lib/module/MarkdownText.js.map +1 -0
- package/lib/module/MarkdownText.web.js +524 -0
- package/lib/module/MarkdownText.web.js.map +1 -0
- package/lib/module/MarkdownTextInput.js +24 -29
- package/lib/module/MarkdownTextInput.js.map +1 -1
- package/lib/module/MarkdownTextInput.web.js +12 -7
- package/lib/module/MarkdownTextInput.web.js.map +1 -1
- package/lib/module/atomUtils.js +106 -0
- package/lib/module/atomUtils.js.map +1 -0
- package/lib/module/childrenUtils.js +33 -0
- package/lib/module/childrenUtils.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/math/environment.js +67 -0
- package/lib/module/math/environment.js.map +1 -0
- package/lib/module/math/index.js +56 -0
- package/lib/module/math/index.js.map +1 -0
- package/lib/module/math/mathjax.js +541 -0
- package/lib/module/math/mathjax.js.map +1 -0
- package/lib/module/metro.js +169 -0
- package/lib/module/metro.js.map +1 -0
- package/lib/module/parser/index.d.ts +3 -0
- package/lib/module/parser/index.js +450 -42
- package/lib/module/parser/index.js.map +4 -4
- package/lib/module/stripUtils.js +739 -0
- package/lib/module/stripUtils.js.map +1 -0
- package/lib/module/styleUtils.js +196 -25
- package/lib/module/styleUtils.js.map +1 -1
- package/lib/module/web/MarkdownElements.css +67 -0
- package/lib/module/web/MarkdownTextInput.css +9 -7
- package/lib/module/web/utils/blockLayout.js +94 -8
- package/lib/module/web/utils/blockLayout.js.map +1 -1
- package/lib/module/web/utils/blockUtils.js +328 -56
- package/lib/module/web/utils/blockUtils.js.map +1 -1
- package/lib/module/web/utils/elementUtils.js +75 -0
- package/lib/module/web/utils/elementUtils.js.map +1 -0
- package/lib/module/web/utils/parserUtils.js +86 -30
- package/lib/module/web/utils/parserUtils.js.map +1 -1
- package/lib/module/web/utils/treeUtils.js +6 -0
- package/lib/module/web/utils/treeUtils.js.map +1 -1
- package/lib/module/web/utils/webStyleUtils.js +25 -5
- package/lib/module/web/utils/webStyleUtils.js.map +1 -1
- package/lib/typescript/commonjs/e2e/links.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/commonjs/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/atomUtils.d.ts +58 -0
- package/lib/typescript/commonjs/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts +39 -3
- package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/math/environment.d.ts +7 -0
- package/lib/typescript/commonjs/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/index.d.ts +64 -0
- package/lib/typescript/commonjs/src/math/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/metro.d.ts +59 -0
- package/lib/typescript/commonjs/src/metro.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts +3 -3
- package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/commonjs/src/stripUtils.d.ts +108 -0
- package/lib/typescript/commonjs/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts +62 -4
- package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/lib/typescript/module/e2e/links.test.d.ts +2 -0
- package/lib/typescript/module/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/module/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/module/src/atomUtils.d.ts +58 -0
- package/lib/typescript/module/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/module/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/commonTypes.d.ts +39 -3
- package/lib/typescript/module/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/math/environment.d.ts +7 -0
- package/lib/typescript/module/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/module/src/math/index.d.ts +64 -0
- package/lib/typescript/module/src/math/index.d.ts.map +1 -0
- package/lib/typescript/module/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/module/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/module/src/metro.d.ts +59 -0
- package/lib/typescript/module/src/metro.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/index.d.ts +3 -3
- package/lib/typescript/module/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/module/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/module/src/stripUtils.d.ts +108 -0
- package/lib/typescript/module/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/styleUtils.d.ts +62 -4
- package/lib/typescript/module/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/package.json +29 -2
- package/react-native.config.js +8 -1
- package/src/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/src/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/src/MarkdownText.tsx +472 -0
- package/src/MarkdownText.web.tsx +668 -0
- package/src/MarkdownTextInput.tsx +42 -38
- package/src/MarkdownTextInput.web.tsx +36 -13
- package/src/atomUtils.ts +112 -0
- package/src/childrenUtils.ts +39 -0
- package/src/commonTypes.ts +69 -9
- package/src/index.tsx +2 -1
- package/src/math/environment.ts +68 -0
- package/src/math/index.ts +78 -0
- package/src/math/mathjax.ts +604 -0
- package/src/metro.ts +238 -0
- package/src/parser/index.ts +175 -10
- package/src/parser/micromark-extension-mentions.ts +104 -11
- package/src/stripUtils.ts +919 -0
- package/src/styleUtils.ts +290 -26
- package/src/web/MarkdownElements.css +67 -0
- package/src/web/MarkdownTextInput.css +9 -7
- package/src/web/utils/blockLayout.ts +124 -14
- package/src/web/utils/blockUtils.ts +365 -59
- package/src/web/utils/elementUtils.ts +87 -0
- package/src/web/utils/parserUtils.ts +119 -31
- package/src/web/utils/treeUtils.ts +6 -1
- package/src/web/utils/webStyleUtils.ts +32 -8
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +0 -6
- package/apple/RCTMarcusStyle+Codegen.mm +0 -64
- package/apple/RCTMarcusUtils.h +0 -26
- package/apple/RCTMarcusUtils.mm +0 -26
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
package app.getbullet.marcus
|
|
2
2
|
|
|
3
3
|
import android.text.SpannableStringBuilder
|
|
4
|
+
import android.text.Spanned
|
|
4
5
|
import android.text.TextPaint
|
|
6
|
+
import android.text.style.AbsoluteSizeSpan
|
|
7
|
+
import app.getbullet.marcus.spans.MarkdownCodeBlockSpan
|
|
5
8
|
import com.facebook.react.bridge.JavaOnlyMap
|
|
6
9
|
import com.facebook.react.bridge.ReadableMap
|
|
7
10
|
import com.facebook.react.uimanager.DisplayMetricsHolder
|
|
@@ -9,6 +12,8 @@ import java.io.File
|
|
|
9
12
|
import org.json.JSONArray
|
|
10
13
|
import org.json.JSONObject
|
|
11
14
|
import org.junit.Assert.assertEquals
|
|
15
|
+
import org.junit.Assert.assertFalse
|
|
16
|
+
import org.junit.Assert.assertTrue
|
|
12
17
|
import org.junit.Before
|
|
13
18
|
import org.junit.Test
|
|
14
19
|
import org.junit.runner.RunWith
|
|
@@ -26,6 +31,8 @@ import org.robolectric.annotation.Config
|
|
|
26
31
|
* so the Android and iOS outputs stay diffable against each other in a single
|
|
27
32
|
* comparison. Regenerate with `-Dmarcus.updateBaselines=true`.
|
|
28
33
|
*/
|
|
34
|
+
private val INDENT = Regex("""indent\((-?\d+),""")
|
|
35
|
+
|
|
29
36
|
@RunWith(RobolectricTestRunner::class)
|
|
30
37
|
@Config(sdk = [34])
|
|
31
38
|
class MarkdownFormatterTest {
|
|
@@ -81,12 +88,12 @@ class MarkdownFormatterTest {
|
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
@Test
|
|
84
|
-
fun `applies bold across the whole
|
|
91
|
+
fun `applies bold across the whole strong span`() {
|
|
85
92
|
val ssb = SpannableStringBuilder("**bold**")
|
|
86
93
|
formatter.format(
|
|
87
94
|
ssb,
|
|
88
95
|
listOf(
|
|
89
|
-
MarkdownRange("
|
|
96
|
+
MarkdownRange("strong", 0, 8, 0),
|
|
90
97
|
MarkdownRange("syntax", 0, 2, 0),
|
|
91
98
|
MarkdownRange("syntax", 6, 2, 0),
|
|
92
99
|
),
|
|
@@ -104,6 +111,85 @@ class MarkdownFormatterTest {
|
|
|
104
111
|
)
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
// The ranges a display is handed for `- one` and `1. one`: the syntax is gone,
|
|
115
|
+
// and what is left of it is the marker that stands for the bullet or numbers
|
|
116
|
+
// the item.
|
|
117
|
+
private val bulletRanges = listOf(
|
|
118
|
+
MarkdownRange("syntax", 0, 1, 0),
|
|
119
|
+
MarkdownRange("block-prefix", 0, 2, 0),
|
|
120
|
+
MarkdownRange("list-unordered", 0, 5, 1),
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
private val numberRanges = listOf(
|
|
124
|
+
MarkdownRange("syntax", 0, 1, 0),
|
|
125
|
+
MarkdownRange("syntax", 1, 1, 0),
|
|
126
|
+
MarkdownRange("block-prefix", 0, 3, 0),
|
|
127
|
+
MarkdownRange("list-ordered", 0, 6, 1),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
@Test
|
|
131
|
+
fun `draws a bullet in place of an unordered marker`() {
|
|
132
|
+
val model = format("- one", bulletRanges, display = true)
|
|
133
|
+
|
|
134
|
+
assertTrue(model, model.contains("bullet"))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@Test
|
|
138
|
+
fun `scales an ordered marker to its own size`() {
|
|
139
|
+
val model = format("1. one", numberRanges, display = true)
|
|
140
|
+
|
|
141
|
+
// 16 * orderedListMarkerScale, over the `1.` and nothing else.
|
|
142
|
+
assertTrue(model, model.contains("font-size(12)"))
|
|
143
|
+
assertFalse(model, model.contains("bullet"))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@Test
|
|
147
|
+
fun `shows the marker an input was typed with`() {
|
|
148
|
+
val bullet = format("- one", bulletRanges, display = false)
|
|
149
|
+
val number = format("1. one", numberRanges, display = false)
|
|
150
|
+
|
|
151
|
+
assertFalse(bullet, bullet.contains("bullet"))
|
|
152
|
+
assertFalse(number, number.contains("font-size("))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@Test
|
|
156
|
+
fun `indents past the bullet rather than past the marker`() {
|
|
157
|
+
// The circle is 16 * unorderedListMarkerScale wide and holds a marker's
|
|
158
|
+
// padding either side of it, so the text starts further in than the `-` it
|
|
159
|
+
// was written with would have put it.
|
|
160
|
+
val shown = indentOf(format("- one", bulletRanges, display = false))
|
|
161
|
+
val drawn = indentOf(format("- one", bulletRanges, display = true))
|
|
162
|
+
|
|
163
|
+
assertTrue("$drawn is not past $shown", drawn > shown)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@Test
|
|
167
|
+
fun `takes the base font from the spannable when there is no view to ask`() {
|
|
168
|
+
// The measure pass runs before there is a view, so the size the text will be
|
|
169
|
+
// drawn at is only on the spannable. Reading it there is what keeps the
|
|
170
|
+
// bullet the same size in both passes -- and the paragraph the same height.
|
|
171
|
+
val measured = SpannableStringBuilder("- one")
|
|
172
|
+
measured.setSpan(AbsoluteSizeSpan(16, false), 0, measured.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
173
|
+
MarkdownFormatter(RuntimeEnvironment.getApplication().assets, null, true)
|
|
174
|
+
.format(measured, bulletRanges, style, null)
|
|
175
|
+
|
|
176
|
+
assertEquals(
|
|
177
|
+
indentOf(format("- one", bulletRanges, display = true)),
|
|
178
|
+
indentOf(RenderModel.dump("- one", measured)),
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@Test
|
|
183
|
+
fun `takes a box's direction from the code inside it`() {
|
|
184
|
+
assertTrue(codeBlock("```\nكود\n```").rightToLeft)
|
|
185
|
+
assertFalse(codeBlock("```\nconst a = 1\n```").rightToLeft)
|
|
186
|
+
// The whole block rather than its first line: a fence is punctuation and
|
|
187
|
+
// decides nothing, and it is typed in an input and stripped from a display,
|
|
188
|
+
// so a rule that stopped at the first line would answer differently in the
|
|
189
|
+
// two. `MarkdownFormatterTests.swift` pins the same three cases on iOS.
|
|
190
|
+
assertTrue(codeBlock("\nكود\n").rightToLeft)
|
|
191
|
+
}
|
|
192
|
+
|
|
107
193
|
@Test
|
|
108
194
|
fun `leaves plain text unspanned`() {
|
|
109
195
|
val ssb = SpannableStringBuilder("no markdown here")
|
|
@@ -112,8 +198,38 @@ class MarkdownFormatterTest {
|
|
|
112
198
|
assertEquals("(no spans)", RenderModel.dump("no markdown here", ssb))
|
|
113
199
|
}
|
|
114
200
|
|
|
201
|
+
/** The box the formatter puts behind a whole string taken as one block. */
|
|
202
|
+
private fun codeBlock(markdown: String): MarkdownCodeBlockSpan {
|
|
203
|
+
val ssb = SpannableStringBuilder(markdown)
|
|
204
|
+
formatter.format(
|
|
205
|
+
ssb,
|
|
206
|
+
listOf(MarkdownRange("codeblock", 0, markdown.length, 0)),
|
|
207
|
+
style,
|
|
208
|
+
textPaint(),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return ssb.getSpans(0, ssb.length, MarkdownCodeBlockSpan::class.java).single()
|
|
212
|
+
}
|
|
213
|
+
|
|
115
214
|
private fun textPaint() = TextPaint().apply { textSize = 16f }
|
|
116
215
|
|
|
216
|
+
private fun format(markdown: String, ranges: List<MarkdownRange>, display: Boolean): String {
|
|
217
|
+
val ssb = SpannableStringBuilder(markdown)
|
|
218
|
+
MarkdownFormatter(RuntimeEnvironment.getApplication().assets, null, display)
|
|
219
|
+
.format(ssb, ranges, style, textPaint())
|
|
220
|
+
|
|
221
|
+
return RenderModel.dump(markdown, ssb)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** The leading margin the first `indent(first,rest)` in a dump reports. */
|
|
225
|
+
private fun indentOf(model: String): Int {
|
|
226
|
+
val indent = model.lineSequence()
|
|
227
|
+
.mapNotNull { INDENT.find(it) }
|
|
228
|
+
.firstOrNull()
|
|
229
|
+
|
|
230
|
+
return requireNotNull(indent) { "no indent in\n$model" }.groupValues[1].toInt()
|
|
231
|
+
}
|
|
232
|
+
|
|
117
233
|
private fun rangesOf(array: JSONArray): List<MarkdownRange> =
|
|
118
234
|
(0 until array.length()).map { i ->
|
|
119
235
|
val range = array.getJSONObject(i)
|
|
@@ -131,6 +247,12 @@ class MarkdownFormatterTest {
|
|
|
131
247
|
}.bufferedReader().readText()
|
|
132
248
|
|
|
133
249
|
/** The same style the web harness pins, so the dumps are comparable. */
|
|
250
|
+
/**
|
|
251
|
+
* The style the decorators are handed: the shipped defaults, already resolved
|
|
252
|
+
* the way `mergeMarkdownStyleWithDefault` resolves them before one is sent --
|
|
253
|
+
* the per-axis lengths filled in from the single `padding` and `margin`, and
|
|
254
|
+
* each list's marker filled in from `syntax`.
|
|
255
|
+
*/
|
|
134
256
|
private fun styleMap(): ReadableMap {
|
|
135
257
|
fun group(vararg entries: Pair<String, Any>): JavaOnlyMap = JavaOnlyMap().apply {
|
|
136
258
|
entries.forEach { (key, value) ->
|
|
@@ -138,26 +260,51 @@ class MarkdownFormatterTest {
|
|
|
138
260
|
is Int -> putInt(key, value)
|
|
139
261
|
is Double -> putDouble(key, value)
|
|
140
262
|
is String -> putString(key, value)
|
|
263
|
+
is JavaOnlyMap -> putMap(key, value)
|
|
141
264
|
}
|
|
142
265
|
}
|
|
143
266
|
}
|
|
144
267
|
|
|
268
|
+
val marker = group("color" to 0xFF808080.toInt())
|
|
269
|
+
|
|
145
270
|
return JavaOnlyMap().apply {
|
|
146
271
|
putMap("syntax", group("color" to 0xFF808080.toInt()))
|
|
147
|
-
putMap("link", group("color" to 0xFF0000FF.toInt()))
|
|
148
|
-
putMap("
|
|
272
|
+
putMap("link", group("color" to 0xFF0000FF.toInt(), "textDecorationLine" to "underline"))
|
|
273
|
+
putMap("strong", group("fontWeight" to "bold"))
|
|
274
|
+
putMap("emphasis", group("fontStyle" to "italic"))
|
|
275
|
+
putMap("strikethrough", group("textDecorationLine" to "line-through"))
|
|
276
|
+
putMap("heading", group("fontSize" to 38.0, "fontWeight" to "bold", "scale" to 0.85))
|
|
149
277
|
putMap("emoji", group("fontSize" to 16.0, "fontFamily" to "System"))
|
|
150
278
|
putMap(
|
|
151
279
|
"blockquote",
|
|
152
280
|
group(
|
|
153
281
|
"borderColor" to 0xFF808080.toInt(),
|
|
154
282
|
"borderWidth" to 6.0,
|
|
155
|
-
"
|
|
156
|
-
"
|
|
283
|
+
"borderRadius" to 0.0,
|
|
284
|
+
"marginStart" to 6.0,
|
|
285
|
+
"paddingStart" to 6.0,
|
|
286
|
+
),
|
|
287
|
+
)
|
|
288
|
+
putMap(
|
|
289
|
+
"orderedList",
|
|
290
|
+
group(
|
|
291
|
+
"marginStart" to 6.0,
|
|
292
|
+
"paddingStart" to 18.0,
|
|
293
|
+
"markerScale" to 0.8,
|
|
294
|
+
"markerPadding" to 2.0,
|
|
295
|
+
"marker" to marker,
|
|
296
|
+
),
|
|
297
|
+
)
|
|
298
|
+
putMap(
|
|
299
|
+
"unorderedList",
|
|
300
|
+
group(
|
|
301
|
+
"marginStart" to 6.0,
|
|
302
|
+
"paddingStart" to 18.0,
|
|
303
|
+
"markerScale" to 0.3,
|
|
304
|
+
"markerPadding" to 2.0,
|
|
305
|
+
"marker" to marker,
|
|
157
306
|
),
|
|
158
307
|
)
|
|
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
308
|
putMap(
|
|
162
309
|
"code",
|
|
163
310
|
group(
|
|
@@ -165,6 +312,11 @@ class MarkdownFormatterTest {
|
|
|
165
312
|
"fontSize" to 16.0,
|
|
166
313
|
"color" to 0xFF000000.toInt(),
|
|
167
314
|
"backgroundColor" to 0xFFD3D3D3.toInt(),
|
|
315
|
+
"borderRadius" to 4.0,
|
|
316
|
+
"paddingHorizontal" to 2.0,
|
|
317
|
+
"paddingVertical" to 2.0,
|
|
318
|
+
"marginHorizontal" to 2.0,
|
|
319
|
+
"marginVertical" to 2.0,
|
|
168
320
|
),
|
|
169
321
|
)
|
|
170
322
|
putMap(
|
|
@@ -174,30 +326,23 @@ class MarkdownFormatterTest {
|
|
|
174
326
|
"fontSize" to 16.0,
|
|
175
327
|
"color" to 0xFF000000.toInt(),
|
|
176
328
|
"backgroundColor" to 0xFFD3D3D3.toInt(),
|
|
329
|
+
"borderRadius" to 4.0,
|
|
330
|
+
"paddingHorizontal" to 8.0,
|
|
331
|
+
"paddingVertical" to 8.0,
|
|
332
|
+
"marginHorizontal" to 4.0,
|
|
333
|
+
"marginVertical" to 4.0,
|
|
177
334
|
),
|
|
178
335
|
)
|
|
179
336
|
putMap(
|
|
180
|
-
"
|
|
181
|
-
group(
|
|
182
|
-
"color" to 0xFF008000.toInt(),
|
|
183
|
-
"backgroundColor" to 0xFF00FF00.toInt(),
|
|
184
|
-
"borderRadius" to 5.0,
|
|
185
|
-
),
|
|
186
|
-
)
|
|
187
|
-
putMap(
|
|
188
|
-
"mentionUser",
|
|
337
|
+
"mention",
|
|
189
338
|
group(
|
|
190
339
|
"color" to 0xFF0000FF.toInt(),
|
|
191
340
|
"backgroundColor" to 0xFF00FFFF.toInt(),
|
|
192
341
|
"borderRadius" to 5.0,
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
group(
|
|
198
|
-
"color" to 0xFFFF0000.toInt(),
|
|
199
|
-
"backgroundColor" to 0xFFFFC0CB.toInt(),
|
|
200
|
-
"borderRadius" to 5.0,
|
|
342
|
+
"paddingHorizontal" to 2.0,
|
|
343
|
+
"paddingVertical" to 2.0,
|
|
344
|
+
"marginHorizontal" to 0.0,
|
|
345
|
+
"marginVertical" to 0.0,
|
|
201
346
|
),
|
|
202
347
|
)
|
|
203
348
|
}
|
|
@@ -6,13 +6,18 @@ import android.text.style.AbsoluteSizeSpan
|
|
|
6
6
|
import android.text.style.BackgroundColorSpan
|
|
7
7
|
import android.text.style.ForegroundColorSpan
|
|
8
8
|
import android.text.style.LeadingMarginSpan
|
|
9
|
+
import app.getbullet.marcus.spans.MarkdownAbsoluteLineHeightSpan
|
|
9
10
|
import app.getbullet.marcus.spans.MarkdownBackgroundSpan
|
|
10
|
-
import app.getbullet.marcus.spans.
|
|
11
|
+
import app.getbullet.marcus.spans.MarkdownBulletSpan
|
|
12
|
+
import app.getbullet.marcus.spans.MarkdownCodeBlockSpan
|
|
11
13
|
import app.getbullet.marcus.spans.MarkdownFontFamilySpan
|
|
14
|
+
import app.getbullet.marcus.spans.MarkdownFontStyleSpan
|
|
15
|
+
import app.getbullet.marcus.spans.MarkdownFontWeightSpan
|
|
12
16
|
import app.getbullet.marcus.spans.MarkdownGapSpan
|
|
13
|
-
import app.getbullet.marcus.spans.
|
|
17
|
+
import app.getbullet.marcus.spans.MarkdownLetterSpacingSpan
|
|
14
18
|
import app.getbullet.marcus.spans.MarkdownLineHeightSpan
|
|
15
19
|
import app.getbullet.marcus.spans.MarkdownStrikethroughSpan
|
|
20
|
+
import app.getbullet.marcus.spans.MarkdownTextShadowSpan
|
|
16
21
|
import app.getbullet.marcus.spans.MarkdownUnderlineSpan
|
|
17
22
|
|
|
18
23
|
/**
|
|
@@ -51,15 +56,27 @@ object RenderModel {
|
|
|
51
56
|
|
|
52
57
|
/** The shared attribute name for a span, or null for spans we do not model. */
|
|
53
58
|
private fun describe(span: Any): String? = when (span) {
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
// Named by what the span resolves to rather than by its class, so the two
|
|
60
|
+
// weights the model already had a word for keep it: iOS reports a bold run
|
|
61
|
+
// as `bold` whether the style asked for `bold` or for `700`.
|
|
62
|
+
is MarkdownFontWeightSpan ->
|
|
63
|
+
if (span.weight >= 700) "bold" else "weight(${span.weight})"
|
|
64
|
+
is MarkdownFontStyleSpan -> if (span.italic) "italic" else "upright"
|
|
56
65
|
is MarkdownStrikethroughSpan -> "strikethrough"
|
|
57
66
|
is MarkdownUnderlineSpan -> "underline"
|
|
58
67
|
is MarkdownFontFamilySpan -> "font-family"
|
|
59
|
-
is
|
|
68
|
+
is MarkdownLetterSpacingSpan -> "letter-spacing"
|
|
69
|
+
is MarkdownTextShadowSpan -> "shadow"
|
|
70
|
+
is MarkdownLineHeightSpan, is MarkdownAbsoluteLineHeightSpan -> "line-height"
|
|
60
71
|
// The rounded rectangle drawn behind a mention, not a plain background
|
|
61
72
|
// colour -- iOS models the same thing as `MarkdownTextBackground`.
|
|
62
73
|
is MarkdownBackgroundSpan -> "background-shape"
|
|
74
|
+
// The box behind a whole code block, which iOS models as the
|
|
75
|
+
// `MarkdownCodeBlock` it stores under `.marcusCodeBlock`.
|
|
76
|
+
is MarkdownCodeBlockSpan -> "code-block"
|
|
77
|
+
// The circle drawn in place of an unordered item's marker, which iOS models
|
|
78
|
+
// as the `MarkdownListBullet` it stores under `.marcusListBullet`.
|
|
79
|
+
is MarkdownBulletSpan -> "bullet"
|
|
63
80
|
// The space held open after a marker so the next container's gutter lands
|
|
64
81
|
// between the two.
|
|
65
82
|
is MarkdownGapSpan -> "gap"
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
package app.getbullet.marcus.spans
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.graphics.Canvas
|
|
5
|
+
import android.graphics.Color
|
|
6
|
+
import android.graphics.Paint
|
|
7
|
+
import android.graphics.Path
|
|
8
|
+
import android.graphics.RectF
|
|
9
|
+
import org.junit.Assert.assertEquals
|
|
10
|
+
import org.junit.Test
|
|
11
|
+
import org.junit.runner.RunWith
|
|
12
|
+
import org.robolectric.RobolectricTestRunner
|
|
13
|
+
import org.robolectric.annotation.Config
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Where a code block's box lands, which is the one thing about it that a render
|
|
17
|
+
* model cannot show: the span is handed the line's two sides and decides between
|
|
18
|
+
* them itself.
|
|
19
|
+
*
|
|
20
|
+
* The path it draws is captured rather than the pixels it fills, so the numbers
|
|
21
|
+
* asserted here are the ones the span computed. iOS proves the same geometry the
|
|
22
|
+
* other way round, by counting coloured columns, in
|
|
23
|
+
* `MarkdownParagraphLayoutManagerTests` -- there the shapes are drawn straight
|
|
24
|
+
* onto the context with no path to intercept.
|
|
25
|
+
*/
|
|
26
|
+
@RunWith(RobolectricTestRunner::class)
|
|
27
|
+
@Config(sdk = [34])
|
|
28
|
+
class MarkdownCodeBlockSpanTest {
|
|
29
|
+
|
|
30
|
+
@Test
|
|
31
|
+
fun `boxes a left-to-right block from the left edge`() {
|
|
32
|
+
val bounds = box(rightToLeft = false)
|
|
33
|
+
|
|
34
|
+
assertEquals(LEADING_INSET, bounds.left, TOLERANCE)
|
|
35
|
+
assertEquals(WIDTH - MARGIN, bounds.right, TOLERANCE)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Test
|
|
39
|
+
fun `boxes a right-to-left block from the right edge`() {
|
|
40
|
+
val bounds = box(rightToLeft = true)
|
|
41
|
+
|
|
42
|
+
// The padded edge is now the right one, and the bare margin is all that is
|
|
43
|
+
// left on the far side -- the mirror of the case above, on the same numbers.
|
|
44
|
+
assertEquals(MARGIN, bounds.left, TOLERANCE)
|
|
45
|
+
assertEquals(WIDTH - LEADING_INSET, bounds.right, TOLERANCE)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** One line's fill, for a block whose lines start [LEADING_INSET] in. */
|
|
49
|
+
private fun box(rightToLeft: Boolean): RectF {
|
|
50
|
+
val span = MarkdownCodeBlockSpan(
|
|
51
|
+
backgroundColor = Color.RED,
|
|
52
|
+
borderRadius = 0f,
|
|
53
|
+
paddingVertical = 0f,
|
|
54
|
+
marginHorizontal = MARGIN,
|
|
55
|
+
marginVertical = 0f,
|
|
56
|
+
leadingInset = LEADING_INSET,
|
|
57
|
+
rightToLeft = rightToLeft,
|
|
58
|
+
blockStart = 0,
|
|
59
|
+
blockEnd = TEXT.length,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
val canvas = PathRecordingCanvas()
|
|
63
|
+
span.drawBackground(
|
|
64
|
+
canvas, Paint(), 0, WIDTH.toInt(), 0, 16, 20, TEXT, 0, TEXT.length, 0,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return requireNotNull(canvas.bounds) { "the span drew nothing" }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A canvas that keeps the last path filled on it and paints none of it, so a
|
|
72
|
+
* rect can be read back without a bitmap to search.
|
|
73
|
+
*/
|
|
74
|
+
private class PathRecordingCanvas :
|
|
75
|
+
Canvas(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)) {
|
|
76
|
+
|
|
77
|
+
var bounds: RectF? = null
|
|
78
|
+
|
|
79
|
+
override fun drawPath(path: Path, paint: Paint) {
|
|
80
|
+
bounds = RectF().also { path.computeBounds(it, true) }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private companion object {
|
|
85
|
+
const val WIDTH = 300f
|
|
86
|
+
const val MARGIN = 4f
|
|
87
|
+
const val LEADING_INSET = 22f
|
|
88
|
+
const val TOLERANCE = 0.5f
|
|
89
|
+
const val TEXT = "كود"
|
|
90
|
+
}
|
|
91
|
+
}
|