MohamedRejeb / compose-rich-editor

A Rich text editor library for both Jetpack Compose and Compose Multiplatform, fully customizable, supports HTML and Markdown.
https://mohamedrejeb.github.io/Compose-Rich-Editor/
Apache License 2.0
945 stars 58 forks source link

Math expressions #276

Open T8RIN opened 3 months ago

T8RIN commented 3 months ago

Is it possible to parse math expressions in markdown, like \(a \times b\)

T8RIN commented 3 months ago

i solved by doing this, but looks ugly

fun String.replaceCodeMarkdown(): String =
    replace("```", "`")
        .replaceFractions()
        .replaceSqrt()
        .replaceMathBBToSymbol()
        .let {
            mathPairs.fold(it) { acc, (pattern, char) ->
                acc.replace(pattern, mathString(char))
            }
        }

private fun mathString(string: String) = string

private fun String.replaceFractions(): String {
    val fraction = Regex("\\\\frac\\{([^}]*)\\}\\{([^}]*)\\}")
    return fraction.replace(this) { matchResult ->
        val numerator = matchResult.groupValues[1]
        val denominator = matchResult.groupValues[2]
        mathString("$numerator/$denominator")
    }
}

private fun String.replaceMathBBToSymbol(): String {
    val replacementMap = mapOf(
        "A" to "𝔸", "B" to "𝔹", "C" to "β„‚", "D" to "𝔻", "E" to "𝔼",
        "F" to "𝔽", "G" to "𝔾", "H" to "ℍ", "I" to "𝕀", "J" to "𝕁",
        "K" to "𝕂", "L" to "𝕃", "M" to "𝕄", "N" to "β„•", "O" to "𝕆",
        "P" to "β„™", "Q" to "β„š", "R" to "ℝ", "S" to "π•Š", "T" to "𝕋",
        "U" to "π•Œ", "V" to "𝕍", "W" to "π•Ž", "X" to "𝕏", "Y" to "𝕐",
        "Z" to "β„€"
    )

    val regex = Regex("\\\\mathbb\\{([A-Za-z])\\}")

    return regex.replace(this) { matchResult ->
        val letter = matchResult.groupValues[1].uppercase()[0].toString()
        replacementMap[letter] ?: letter
    }
}

private fun String.replaceSqrt(): String {
    val sqrt = Regex("\\\\sqrt(?:\\[([^]]+)])?\\{([^}]*)\\}")

    return sqrt.replace(this) { matchResult ->
        val n = matchResult.groupValues[1].takeIf { it.isNotEmpty() }?.toIntOrNull()
        val x = matchResult.groupValues[2]

        mathString(n?.let { "(${n})√$x" } ?: "√$x")
    }
}

private val mathPairs by lazy {
    listOf(
        "\\(" to "(",
        "\\)" to ")",
        "\\[" to "[",
        "\\[" to "]",
        "\\quad" to "  ",
        "\\neg" to "Β¬",
        "\\pm" to "Β±",
        "\\mp" to "βˆ“",
        "\\div" to "Γ·",
        "\\%" to "%",
        "\\oplus" to "βŠ•",
        "\\otimes" to "βŠ—",
        "\\odot" to "βŠ™",
        "\\setminus" to "βˆ–",
        "\\int!!!int!!!int" to "∭",
        "\\int!!!int" to "∬",
        "\\int" to "∫",
        "\\cdot" to "Β·",
        "\\to" to "β†’",
        "\\infty" to "∞",
        "\\Rightarrow" to "β‡’",
        "\\Leftrightarrow" to "⇔",
        "\\forall" to "βˆ€",
        "\\partial" to "βˆ‚",
        "\\exists" to "βˆƒ",
        "\\emptyset" to "βˆ…",
        "\\nabla" to "βˆ‡",
        "\\in" to "∈",
        "\\not\\in" to "βˆ‰",
        "\\notin" to "βˆ‰",
        "\\prod" to "∏",
        "\\sum" to "βˆ‘",
        "\\surd" to "√",
        "\\wedge" to "∧",
        "\\land" to "∧",
        "\\vee" to "∨",
        "\\lor" to "∨",
        "\\lnot" to "!",
        "\\cap" to "∩",
        "\\cup" to "βˆͺ",
        "\\int" to "∫",
        "\\approx" to "β‰ˆ",
        "\\neq" to "β‰ ",
        "\\equiv" to "≑",
        "\\leq" to "≀",
        "\\geq" to "β‰₯",
        "\\subseteq" to "βŠ†",
        "\\subsetneq" to "⊊",
        "\\supseteq" to "βŠ‡",
        "\\supsetneq" to "βŠ‹",
        "\\subset" to "βŠ‚",
        "\\supset" to "βŠƒ",
        "^\\circ" to "Β°",
        "\\times" to "Γ—",
        "\\lfloor" to "⌊",
        "\\rfloor" to "βŒ‹",
        "\\lceil" to "⌈",
        "\\rceil" to "βŒ‰",
        "\\nexists" to "βˆ…",
        "\\Delta" to "Ξ”",
        "\\sphericalangle" to "−",
        "\\measuredangle" to "∑",
        "\\angle" to "∠",
        "\\cong" to "β‰…",
        "\\widehat" to "β—‘",
        "\\parallel" to "βˆ₯",
        "\\perp" to "βŠ₯",
        "\\triangle" to "β–³",
        "\\sim" to "∼",
        "\\overline" to "",
        "\\overrightarrow" to "",
        "\\aleph_0" to "β„΅",
        "\\alpha" to "Ξ±",
        "\\kappa" to "ΞΊ",
        "\\psi" to "ψ",
        "\\digamma" to "z",
        "\\Delta" to "βˆ†",
        "\\Theta" to "Θ",
        "\\beta" to "Ξ²",
        "\\lambda" to "Ξ»",
        "\\rho" to "ρ",
        "\\varepsilon" to "Ξ΅",
        "\\Gamma" to "Ξ“",
        "\\Upsilon" to "Ξ₯",
        "\\chi" to "Ο‡",
        "\\mu" to "Β΅",
        "\\sigma" to "Οƒ",
        "\\varkappa" to "ΞΊ",
        "\\Lambda" to "Ξ›",
        "\\Xi" to "Ξ",
        "\\delta" to "Ξ΄",
        "\\nu" to "Ξ½",
        "\\tau" to "Ο„",
        "\\varphi" to "Ο†",
        "\\Omega" to "Ω",
        "\\epsilon" to "Ξ΅",
        "\\theta" to "ΞΈ",
        "\\varpi" to "Ο€",
        "\\Phi" to "Ξ¦",
        "\\aleph" to "β„΅",
        "\\eta" to "Ξ·",
        "\\omega" to "Ο‰",
        "\\upsilon" to "Ο…",
        "\\varrho" to "ρ",
        "\\Pi" to "Ξ ",
        "\\gamma" to "Ξ³",
        "\\phi" to "Ο†",
        "\\xi" to "ΞΎ",
        "\\varsigma" to "Ο‚",
        "\\Psi" to "Ξ¨",
        "\\iota" to "ΞΉ",
        "\\pi" to "Ο€",
        "\\zeta" to "ΞΆ",
        "\\vartheta" to "Ο‘",
        "\\Sigma" to "Ξ£"
    )
}
MohamedRejeb commented 3 months ago

Hi, Thanks for creating this issue, I think that's an important feature to have, I will try to add it ASAP.

T8RIN commented 3 months ago

Thanks !