[
  {
    "path": ".github/FUNDING.yml",
    "content": "github: korsbo\n"
  },
  {
    "path": ".github/workflows/CompatHelper.yml",
    "content": "name: CompatHelper\non:\n  schedule:\n    - cron: 0 0 * * *\n  workflow_dispatch:\njobs:\n  CompatHelper:\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"Install CompatHelper\"\n        run: |\n          import Pkg\n          name = \"CompatHelper\"\n          uuid = \"aa819f21-2bde-4658-8897-bab36330d9b7\"\n          version = \"3\"\n          Pkg.add(; name, uuid, version)\n        shell: julia --color=yes {0}\n      - name: \"Run CompatHelper\"\n        run: |\n          import CompatHelper\n          CompatHelper.main()\n        shell: julia --color=yes {0}\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".github/workflows/Invalidations.yml",
    "content": "name: Invalidations\n\non:\n  pull_request:\n\nconcurrency:\n  # Skip intermediate builds: always.\n  # Cancel intermediate builds: always.\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  evaluate:\n    # Only run on PRs to the default branch.\n    # In the PR trigger above branches can be specified only explicitly whereas this check should work for master, main, or any other default branch\n    if: github.base_ref == github.event.repository.default_branch\n    runs-on: ubuntu-latest\n    steps:\n    - uses: julia-actions/setup-julia@v1\n      with:\n        version: '1'\n    - uses: actions/checkout@v3\n    - uses: julia-actions/julia-buildpkg@v1\n    - uses: julia-actions/julia-invalidations@v1\n      id: invs_pr\n\n    - uses: actions/checkout@v3\n      with:\n        ref: ${{ github.event.repository.default_branch }}\n    - uses: julia-actions/julia-buildpkg@v1\n    - uses: julia-actions/julia-invalidations@v1\n      id: invs_default\n    \n    - name: Report invalidation counts\n      run: |\n        echo \"Invalidations on default branch: ${{ steps.invs_default.outputs.total }} (${{ steps.invs_default.outputs.deps }} via deps)\" >> $GITHUB_STEP_SUMMARY\n        echo \"This branch: ${{ steps.invs_pr.outputs.total }} (${{ steps.invs_pr.outputs.deps }} via deps)\" >> $GITHUB_STEP_SUMMARY\n    - name: Check if the PR does increase number of invalidations\n      if: steps.invs_pr.outputs.total > steps.invs_default.outputs.total\n      run: exit 1\n"
  },
  {
    "path": ".github/workflows/TagBot.yml",
    "content": "name: TagBot\non:\n  issue_comment:  # THIS BIT IS NEW\n    types:\n      - created\n  workflow_dispatch:\njobs:\n  TagBot:\n    if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'\n    runs-on: ubuntu-latest\n    steps:\n      - uses: JuliaRegistries/TagBot@v1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          ssh: ${{ secrets.DOCUMENTER_KEY }}"
  },
  {
    "path": ".github/workflows/benchmark.yml",
    "content": "name: Run benchmarks\n\non:\n  pull_request:\n    types: [labeled, opened, synchronize, reopened]\n\njobs:\n  Benchmark:\n    runs-on: ubuntu-latest\n    if: contains(github.event.pull_request.labels.*.name, 'run benchmark')\n    steps:\n      - uses: actions/checkout@v2\n      - uses: julia-actions/setup-julia@latest\n        with:\n          version: 1\n      - uses: julia-actions/julia-buildpkg@latest\n      - name: Install dependencies\n        run: julia -e 'using Pkg; pkg\"add PkgBenchmark BenchmarkCI@0.1\"'\n      - name: Run benchmarks\n        run: julia -e 'using BenchmarkCI; BenchmarkCI.judge()'\n      - name: Post results\n        run: julia -e 'using BenchmarkCI; BenchmarkCI.postjudge()'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Print results\n        run: julia -e 'using BenchmarkCI; BenchmarkCI.displayjudgement()'\n\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non:\n  pull_request:\n    branches:\n      - master\n  push:\n    branches:\n      - master\n    tags: '*'\n\nconcurrency: \n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\n\njobs:\n  test:\n    name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}\n    continue-on-error: ${{ matrix.experimental }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        version:\n          - '1.6'  # lowest julia declared compat in `Project.toml`\n          - '1'\n        experimental:\n          - false\n        os: [ubuntu-latest]\n        arch: [x64]\n        include:  # spare windows/macos CI credits\n          - os: windows-latest\n            experimental: false\n            version: '1'\n            arch: x64\n          - os: macOS-latest\n            experimental: false\n            version: '1'\n            arch: x64\n          - os: ubuntu-latest\n            experimental: true\n            version: '~1.11.0-0'\n            arch: x64\n          - os: ubuntu-latest\n            experimental: true\n            version: 'nightly'\n            arch: x64\n    steps:\n      - uses: actions/checkout@v3\n      - uses: julia-actions/setup-julia@latest\n        with:\n          version: ${{ matrix.version }}\n          arch: ${{ matrix.arch }}\n      - uses: julia-actions/cache@v1\n      - name: install latex dependencies\n        if: startsWith(matrix.os,'ubuntu')\n        run: |\n          sudo apt-get -y update\n          sudo apt-get -y install latexmk texlive-{luatex,latex-extra}\n          sudo fc-cache -vr\n      - uses: julia-actions/julia-buildpkg@latest\n      - uses: julia-actions/julia-runtest@latest\n      - uses: julia-actions/julia-processcoverage@latest\n      - uses: codecov/codecov-action@v3\n        with:\n          file: lcov.info\n\n  docs:\n    name: Documentation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: julia-actions/setup-julia@latest\n        with:\n          version: '1'\n      - run: |\n          julia --project=docs -e '\n            using Pkg\n            Pkg.develop(PackageSpec(path=pwd()))\n            Pkg.instantiate()'\n      # - run: |\n      #     julia --project=docs -e '\n      #       using Documenter: doctest\n      #       using Latexify\n      #       doctest(Latexify)' \n      - run: julia --project=docs docs/make.jl\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.jl.cov\n*.jl.*.cov\n*.jl.mem\ndeps/deps.jl\n*Manifest.toml\n\ndocs/build\ndocs/site\n*.DS_Store\n\n/.benchmarkci\n/benchmark/*.json\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Niklas Korsbo\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Project.toml",
    "content": "name = \"Latexify\"\nuuid = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nauthors = [\"Niklas Korsbo <niklas.korsbo@gmail.com>\"]\nrepo = \"https://github.com/korsbo/Latexify.jl.git\"\nversion = \"0.16.10\"\n\n[deps]\nFormat = \"1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8\"\nGhostscript_jll = \"61579ee1-b43e-5ca0-a5da-69d92c66a64b\"\nInteractiveUtils = \"b77e0a4c-d291-57a0-90e8-8db25a27a240\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nMacroTools = \"1914dd2f-81c6-5fcd-8719-6d5c9610ff09\"\nMarkdown = \"d6f4376e-aef5-505a-96c1-9c027394607a\"\nOrderedCollections = \"bac558e1-5e72-5ebc-8fee-abe8a469f55d\"\nRequires = \"ae029012-a4dd-5104-9daa-d747884805df\"\n\n[weakdeps]\nDataFrames = \"a93c6f00-e57d-5684-b7b6-d8193f3e46c0\"\nSparseArrays = \"2f01184e-e22b-5df5-ae63-d93ebab69eaf\"\nSymEngine = \"123dc426-2d89-5057-bbad-38513e3affd8\"\ntectonic_jll = \"d7dd28d6-a5e6-559c-9131-7eb760cdacc5\"\n\n[extensions]\nDataFramesExt = \"DataFrames\"\nSparseArraysExt = \"SparseArrays\"\nSymEngineExt = \"SymEngine\"\nTectonicExt = \"tectonic_jll\"\n\n[compat]\nDataFrames = \"1\"\nFormat = \"1.3\"\nGhostscript_jll = \"9\"\nLaTeXStrings = \"0.3, 1\"\nMacroTools = \"0.4 - 0.5\"\nOrderedCollections = \"1\"\nRequires = \"0.5, 1\"\nSparseArrays = \"1.6\"\nSymEngine = \"0.11, 0.12, 0.13\"\njulia = \"1.6\"\ntectonic_jll = \"0.15\"\n\n[extras]\nDataFrames = \"a93c6f00-e57d-5684-b7b6-d8193f3e46c0\"\nOffsetArrays = \"6fe1bfb0-de20-5000-8ca7-80f57d26f881\"\nSparseArrays = \"2f01184e-e22b-5df5-ae63-d93ebab69eaf\"\nSymEngine = \"123dc426-2d89-5057-bbad-38513e3affd8\"\nTest = \"8dfed614-e22c-5e08-85e1-65c5234f0b40\"\ntectonic_jll = \"d7dd28d6-a5e6-559c-9131-7eb760cdacc5\"\n\n[targets]\ntest = [\"DataFrames\", \"OffsetArrays\", \"SymEngine\", \"SparseArrays\", \"tectonic_jll\", \"Test\"]\n"
  },
  {
    "path": "README.md",
    "content": "[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://korsbo.github.io/Latexify.jl/stable)\n[![](https://img.shields.io/badge/docs-latest-blue.svg)](https://korsbo.github.io/Latexify.jl/latest)\n[![codecov](https://codecov.io/gh/korsbo/Latexify.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/korsbo/Latexify.jl)\n[![Coverage Status](https://coveralls.io/repos/github/korsbo/Latexify.jl/badge.svg)](https://coveralls.io/github/korsbo/Latexify.jl)\n[![Downloads](https://img.shields.io/badge/dynamic/json?url=http%3A%2F%2Fjuliapkgstats.com%2Fapi%2Fv1%2Fmonthly_downloads%2FLatexify&query=total_requests&suffix=%2Fmonth&label=Downloads)](http://juliapkgstats.com/pkg/Latexify)\n\n\n# Latexify.jl\nThis is a package for generating LaTeX maths from julia objects.\n\nThis package utilises Julias\n[homoiconicity](https://en.wikipedia.org/wiki/Homoiconicity) to convert\nexpressions to LaTeX-formatted strings.  Latexify.jl supplies functionalities\nfor converting a range of different Julia objects, including:\n\n- Expressions,\n- Strings,\n- Numbers (including rationals and complex),\n- Symbolic expressions from SymEngine.jl,\n- ParameterizedFunctions and ReactionNetworks from DifferentialEquations.jl,\n- Other types for which a user recipe has been defined\n\nas well as arrays or dicts of supported types.\n\n\n## Recipes\nTo extend Latexify to work with your own type, you define a recipe using the\n`@latexrecipe` macro. See the documentation.\n\n### Examples\n#### latexifying expressions\n```julia\nusing Latexify\nex = :(x/(y+x)^2)\nlatexify(ex)\n```\nThis generates a LaTeXString (from\n[LaTeXStrings.jl](https://github.com/stevengj/LaTeXStrings.jl)) which, when\nprinted looks like:\n```LaTeX\n$\\frac{x}{\\left( y + x \\right)^{2}}$\n```\n\nAnd when this LaTeXString is displayed in an environment which supports the\ntex/latex MIME type (Jupyter and Pluto notebooks, Jupyterlab and Hydrogen for\nAtom) it will automatically render as:\n\n![fraction](/assets/demo_fraction.png)\n\n\n#### latexifying other things\n\nLatexify.jl is equipped to convert a whole range of types to latex formatted\nmaths. This includes primitive types such as `Symbol`s and `Complex`, but also\nof containers such as `Array`s and `Dict`s.\n\n\n```julia\nusing Latexify\nprint(latexify(\"x+y/(b-2)^2\"))\n```\noutputs:\n```LaTeX\n$x + \\frac{y}{\\left( b - 2 \\right)^{2}}$\n```\n\n```julia\narr = [\"x/y\" 3//7 2+3im; 1 :P_x :(gamma(3))]\nlatexify(arr)\n```\n![matrix](/assets/demo_matrix.png)\n\nThe GitHub website does not really support rendering of equations in the README\nfile, so I therefore refer you to the documentation for more info/examples.\n\n#### latexifying custom types\n\nYou can add support for a type via `@latexrecipe`\n```julia\nusing Latexify\nstruct Ket{T}\n    x::T\nend\n@latexrecipe function f(x::Ket)\n    return Expr(:latexifymerge, \"\\\\left|\", x.x, \"\\\\right>\")\nend\nlatexify(:($(Ket(:a)) + $(Ket(:b))))\n```\n\n![ket](/assets/demo_ket.png)\n\n### Use with DifferentialEquations.jl\nThe [DifferentialEquations.jl](http://docs.juliadiffeq.org/stable/index.html)\nsuite has some nifty tools for generating differential equations.\nOne of them is\n[ParameterizedFunctions](https://github.com/JuliaDiffEq/ParameterizedFunctions.jl)\nwhich allows you to type in an ODE in something which looks very much like just\nplain mathematics.\nThe ability to latexify such ODEs is pretty much what lured me to create this\npackage.\n\n```julia\nusing ParameterizedFunctions\nusing Latexify\n\nf = @ode_def positiveFeedback begin\n    dx = v*y^n/(k^n+y^n) - x\n    dy = x/(k_2+x) - y\nend v n k k_2\n\nlatexify(f)\n```\noutputs:\n\n![positiveFeedback](/assets/ode_positive_feedback.png)\n\n\n[Catalyst.jl](https://github.com/SciML/Catalyst.jl)\nprovides another cool domain-specific language which allows you to generate\nequations using a chemical arrow notation.\n\n\n```julia\nusing Catalyst\nusing Latexify\n\nrn = @reaction_network begin\n  (r_bind, r_unbind), A + B ↔ C\n  hill(C, v, k, n), 0 --> X\n  d_x, X --> 0\nend\n\nlatexify(rn)\n```\n![positiveFeedback](/assets/demo_rn.png)\n\nOr you can output the arrow notation directly to latex:\n\n```julia\nlatexify(rn; env=:arrow)\n```\n![positiveFeedback](/assets/demo_rn_arrow.png)\n\nThere are more stuff that you can do, but for that I will refer you to the\n[docs](https://korsbo.github.io/Latexify.jl/stable).\n\n\n### Display equations in a terminal\n\nOne can use [`ImageInTerminal`](https://github.com/JuliaImages/ImageInTerminal.jl) with the [`Sixel`](https://github.com/JuliaIO/Sixel.jl) backend in order to display rendered `latexify`ed [equations](https://github.com/JuliaImages/ImageInTerminal.jl#display-equations).\n\n\n## Convenience functions\n\n- `copy_to_clipboard(::Bool)`, toggle automatic copying of the resulting LaTeX\n  code to the clipboard (default is false).\n- `auto_display(::Bool)` toggles automatic display of your output, even if it\n  is not the last command to have run.\n- `set_default(; kwargs...)`, set your own default kwargs for your Julia\n  session. This is not to be used within a package since the effect is global.\n- `reset_default(; kwargs...)`, reset the changes you made with the above\n  command.\n- `get_default(; kwargs...)`, view the changes you have made to the default\n  kwargs.\n\n\n## Installation\nThis package is registered in the Julia registry, so to install it you can just\nrun\n\n```julia\nPkg.add(\"Latexify\")\n```\n\n## Further information\nFor further information see the\n[docs](https://korsbo.github.io/Latexify.jl/stable).\n\n## Contributing\nI would be happy to receive feedback, suggestions, and help with improving this\npackage. Please feel free to open an issue or a PR.\n\nIf you want to add support for types defined in another package, primarily\ncreate a PR in that package with a recipe. Latexify.jl is not intended to be a\ncollection of recipes for different types. The exceptions are the few types\nwhich were included before the recipe system was finished. If the other package\nis hesitant to pull in Latexify as a dependency, you can either use\nRequires.jl, or create a separate glue package. If you do add support for\nanother package, please help update the list below:\n\n### Supported types and packages\n* Many base types\n* LaTeXStrings.jl\n* DifferentialEquations.jl\n* DiffEqBiological.jl\n* ParametrizedFunctions.jl\n* DataFrames.jl\n* Symbolics.jl\n* Unitful.jl (via UnitfulLatexify.jl)\n\nAnd more ...\n"
  },
  {
    "path": "assets/Project.toml",
    "content": "[deps]\nCatalyst = \"479239e8-5488-4da2-87a7-35f2df7eef83\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nParameterizedFunctions = \"65888b18-ceab-5e60-b2b9-181511a3b968\"\n"
  },
  {
    "path": "assets/assets.jl",
    "content": "# Generate the assets (pngs for README)\nusing Latexify, LaTeXStrings, ParameterizedFunctions, Catalyst\n\nstruct Ket{T}\n    x::T\nend\n@latexrecipe function f(x::Ket)\n    return Expr(:latexifymerge, \"\\\\left|\", x.x, \"\\\\right>\")\nend\n\nthings = [\n          \"demo_fraction\" => latexify(:(x / (y + x)^2)),\n          \"demo_matrix\" => latexify([\"x/y\" 3//7 2+3im; 1 :P_x :(gamma(3))]; env=:inline),\n          \"demo_ket\" => latexify(:($(Ket(:a)) + $(Ket(:b)))),\n          \"ode_positive_feedback\" => latexify(@ode_def positiveFeedback begin\n                                                  dx = v * y^n / (k^n + y^n) - x\n                                                  dy = x / (k_2 + x) - y\n                                              end v n k k_2),\n          \"demo_rn\" => latexify(@reaction_network demoNetwork begin\n                               (r_bind, r_unbind), A + B ↔ C\n                               Hill(C, v, k, n), 0 --> X\n                               d_x, X --> 0\n                           end; form=:ode),\n          \"demo_rn_arrow\" => latexify(@reaction_network demoNetwork begin\n                                     (r_bind, r_unbind), A + B ↔ C\n                                     Hill(C, v, k, n), 0 --> X\n                                     d_x, X --> 0\n                                 end),\n         ]\n\ncd(\"$(pkgdir(Latexify))/assets\") do\n    for (name, s) in things\n        println(name)\n        render(s, MIME\"image/png\"(); name=name, debug=false, callshow=false, open=false, packages=[\"mhchem\", \"amssymb\"])\n        run(`convert $name.png -flatten $name.png`)\n    end\nend\n"
  },
  {
    "path": "benchmark/Project.toml",
    "content": "[deps]\nBenchmarkCI = \"20533458-34a3-403d-a444-e18f38190b5b\"\nBenchmarkTools = \"6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\nPkgBenchmark = \"32113eaa-f34f-5b0d-bd6c-c81e245fc73d\"\n"
  },
  {
    "path": "benchmark/benchmarks.jl",
    "content": "using BenchmarkTools\nusing Latexify\n\nconst SUITE = BenchmarkGroup()\n\nchars = vcat(\n             'A':'Z',\n             'a':'z',\n             'Α':'Ρ', # skip unprintable char (no \\Varsigma)\n             'Σ':'Ω',\n             'α':'ω',\n             '𝕒':'𝕫',\n             '𝐴':'𝑍',\n            )\n\nSUITE[\"unicode\"] = @benchmarkable latexify(string(c)) setup = (c = rand(chars))\n\nstruct AType\n    x\nend\nstruct BType\n    a\nend\n\n@latexrecipe function f(a::AType)\n    return :($(a.x) + 1)\nend\n@latexrecipe function f(b::BType)\n    return :($(b.a)/2)\nend\n\n\nSUITE[\"user types\"] = @benchmarkable latexify(BType(AType(x))) setup = (x=rand())\n\nSUITE[\"expression\"] = @benchmarkable latexify(:(2x + 3 ∈ 25/4 + y - z^2^4α ? 8 : 9))\n\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "build/\nsite/\n"
  },
  {
    "path": "docs/Project.toml",
    "content": "[deps]\nDocumenter = \"e30172f5-a6a5-5a46-863b-614d45cd2de4\"\nFormat = \"1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8\"\nLaTeXStrings = \"b964fa9f-0449-5b57-a5c2-d3ea65f4040f\"\nLatexify = \"23fbe1c1-3f47-55db-b15f-69d7ec21a316\"\n\n[compat]\nDocumenter = \"1\"\nFormat = \"1\"\nLaTeXStrings = \"1\"\nLatexify = \"0.16\"\n"
  },
  {
    "path": "docs/make.jl",
    "content": "using Documenter\nusing Latexify\nusing LaTeXStrings\n\nBase.show(io::IO, ::MIME\"text/html\", l::LaTeXString) = l.s\nmakedocs(\n    modules = [Latexify],\n    format = Documenter.HTML(prettyurls = get(ENV, \"CI\", nothing) == \"true\", mathengine = MathJax3()),\n    sitename = \"Latexify.jl\",\n    pages = [\n        \"index.md\",\n        # \"Functions\" => [\n        #     \"tutorials/latexify.md\",\n        #     \"tutorials/latexinline.md\",\n        #     \"tutorials/latexalign.md\",\n        #     \"tutorials/latexarray.md\",\n        #     \"tutorials/latextabular.md\"\n        # ],\n        \"tutorials/recipes.md\",\n        \"Use with other packages\" => [\n            \"tutorials/parameterizedfunctions.md\",\n            \"tutorials/Catalyst.md\"\n        ],\n        \"tutorials/notebooks.md\",\n        \"arguments.md\",\n        \"tutorials/inner_workings.md\",\n    ],\n    doctest = false,\n    checkdocs = :exports,\n    warnonly = :missing_docs\n)\n\ndeploydocs(\n    #deps = Deps.pip(\"mkdocs\", \"python-markdown-math\"),\n    repo = \"github.com/korsbo/Latexify.jl.git\",\n    target = \"build\",\n    # make = nothing,\n    # deps = nothing,\n    )\n\n\n# Documenter can also automatically deploy documentation to gh-pages.\n# See \"Hosting Documentation\" and deploydocs() in the Documenter manual\n# for more information.\n#=deploydocs(\n    repo = \"<repository url>\"\n)=#\n"
  },
  {
    "path": "docs/src/arguments.md",
    "content": "# List of possible arguments\n\n## Align\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :align in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Equation\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :equation in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Array\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :array in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Tabular\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :tabular in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Markdown Table\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :mdtable in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Inline and raw\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :raw in arg.env || :inline in arg.env]\nlatexify(args, env=:mdtable)\n```\n\n## Chemical arrow notation\nAvailable with `ReactionNetwork`s from `Catalyst`.\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :arrow in arg.env]\nlatexify(args, env=:mdtable, types=false)\n```\n"
  },
  {
    "path": "docs/src/functions/latexalign.md",
    "content": "# `latexalign`\n\n```@meta\nDocTestSetup = quote\nusing Latexify\nusing DifferentialEquations\nend\n```\n\n```@docs\nlatexalign\n```\n\n```@meta\nDocTestSetup = nothing\n```\n"
  },
  {
    "path": "docs/src/functions/latexarray.md",
    "content": "# `latexarray`\n\n```@meta\nDocTestSetup = quote\nusing Latexify\nusing DifferentialEquations\nend\n```\n\n```@docs\nlatexarray\n```\n\n```@meta\nDocTestSetup = nothing\n```\n"
  },
  {
    "path": "docs/src/functions/latexify.md",
    "content": "# `latexify`\n\n```@meta\nDocTestSetup = quote\nusing Latexify\nend\n```\n\n```@docs\nlatexify\n```\n\n```@meta\nDocTestSetup = nothing\n```\n"
  },
  {
    "path": "docs/src/functions/latexoperation.md",
    "content": "# `latexoperation`\n\nThis function is not exported.\n\n```@meta\nDocTestSetup = quote\nusing Latexify\nusing DifferentialEquations\nend\n```\n\n```@docs\nLatexify.latexoperation\n```\n\n```@meta\nDocTestSetup = nothing\n```\n"
  },
  {
    "path": "docs/src/functions/latexraw.md",
    "content": "# `latexraw`\n\nFormats the input for ``\\LaTeX`` without surrounding it with an environment.\n\n```@docs\nlatexraw\n```\n"
  },
  {
    "path": "docs/src/index.md",
    "content": "# Latexify.jl\n\n[Latexify.jl](https://github.com/korsbo/Latexify.jl) is a package which supplies functions for producing ``\\LaTeX`` \nformatted strings from Julia objects. The package allows for latexification of a many different kinds of Julia object\nand it can output several different ``\\LaTeX`` or Markdown environments.\n\nA small teaser:\n\n```@example main\nusing Latexify\ncopy_to_clipboard(false) # hide\nLatexify.set_default(; starred=true)\nm = [2//3 \"e^(-c*t)\" 1+3im; :(x/(x+k_1)) \"gamma(n)\" :(log10(x))]\nlatexify(m)\n```\n\n## Supported input\nThis package supplies functionality for latexifying objects of the following types:\n\n- Expressions,\n- Strings,\n- Numbers (including rational and complex),\n- Missing,\n- Symbols,\n- Symbolic expressions from SymEngine.jl,\n- DataFrame from DataFrames.jl,\n- Any shape of array containing a mix of any of the above types,\n- ParameterizedFunctions from DifferentialEquations.jl,\n- ReactionNetworks from DifferentialEquations.jl\n\n\nExample:\n\n```@example main\nstr = \"x/(2*k_1+x^2)\"\nlatexify(str)\n```\n\n\n## Supported output\n\nLatexify has support for generating a range of different ``\\LaTeX`` environments.\nThe main function of the package, `latexify()`, automatically picks a suitable output environment based on the type(s) of the input.\nHowever, you can override this by passing the keyword argument `env = `. The following environments are available:\n\n\n| environment | `env= ` | description\n| ------ | ---- | --- |\n| no env | `:raw` | Latexifies an object and returns a ``\\LaTeX`` formatted string. If the input is an array it will be recursed and all its elements latexified. This function does not surround the resulting string in any ``\\LaTeX`` environments.\n| Inline | `:inline` | latexify the input and surround it with $$ for inline rendering. |\n| Align | `:align` | Latexifies input and surrounds it with an align environment. Useful for systems of equations and such fun stuff. |\n| Equation | `:equation` or `:eq` | Latexifies input and surrounds it with an equation environment. |\n| Array | `:array` | Latexify the elements of an Array or a Dict and output them in a ``\\LaTeX`` array. |\n| Tabular | `:table` or `:tabular` | Latexify the elements of an array and output a tabular environment. Note that tabular is not supported by MathJax and will therefore not be rendered in Jupyter, etc.|\n| Markdown Table | `:mdtable` | Output a Markdown table. This will be rendered nicely by Jupyter, etc. |\n| Markdown Text | `:mdtext` | Output and render any string which can be parsed into Markdown. This is really nothing but a call to `Base.Markdown.parse()`,  but it does the trick. Useful for rendering bullet lists and such things. |\n| Chemical arrow notation | `:chem`, `:chemical`, `:arrow` or `:arrows` | Latexify an AbstractReactionNetwork to ``\\LaTeX`` formatted chemical arrow notation using [mhchem](https://ctan.org/pkg/mhchem?lang=en).\n\n## Modifying the output\nSome of the different outputs can be modified using keyword arguments. You can for example transpose an array with `transpose=true` or specify a header of a table or mdtable with `header=[]`. For more options, see the [List of possible arguments](@ref).\n\n## Printing vs displaying\n\n`latexify()` returns a LaTeXString. Using `display()` on such a string will try to render it.\n\n```@example main\nlatexify(\"x/y\") |> display\n```\n$\\frac{x}{y}$\n\nUsing `print()` will output text which is formatted for latex.\n\n```@example main\nlatexify(\"x/y\") |> print\n```\n\n## Number formatting\n\nYou can control the formatting of numbers by passing any of the following to the `fmt` keyword:\n\n\n- a [printf-style](https://en.wikipedia.org/wiki/Printf_format_string) formatting string, for example `fmt = \"%.2e\"`.\n- a single argument function, for example `fmt = x -> round(x, sigdigits=2)`.\n- a formatter supplied by Latexify.jl, for example `fmt = FancyNumberFormatter(2)` (thanks to @simeonschaub). You can pass any of these formatters an integer argument which specifies how many significant digits you want.\n  - `FancyNumberFormatter()` replaces the exponent notation, from `1.2e+3` to `1.2 \\cdot 10^3`. \n  - `StyledNumberFormatter()` replaces the exponent notation, from `1.2e+3` to `1.2 \\mathrm{e} 3`.\n  - `SiunitxNumberFormatter()` uses the `siunitx` package's `\\num`, so all the formatting is offloaded on the `\\LaTeX` engine. Formatting arguments can be supplied as a string to the keyword argument `format_options`. If your `siunitx` installation is version 2 or older, use the keyword argument `version=2` to replace `\\num` by `\\si`. A boolean argument `simple` can be used to control syntax for units. These two latter options do not change output for unitless numbers.\n\n\n\nExamples:\n```@example main\nlatexify(12345.678; fmt=\"%.1e\")\n```\n\n```@example main\nlatexify([12893.1 1.328e2; \"x/y\" 7832//2378]; fmt=FancyNumberFormatter(3))\n```\n```math\n\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.29 \\cdot 10^{4} & 133 \\\\\n\\frac{x}{y} & \\frac{3916}{1189} \\\\\n\\end{array}\n\\right]\n\\end{equation}\n```\n\n```@example main\nusing Format\nlatexify([12893.1 1.328e2]; fmt=x->format(round(x, sigdigits=2), autoscale=:metric))\n```\n\n```@example main\nstr = latexify(12345.678; fmt=SiunitxNumberFormatter(format_options=\"round-mode=places,round-precision=1\", version=3))\nreplace(string(str), \"\\$\"=>\"`\") # hide\n```\n\n## Automatic copying to clipboard\nThe strings that you would see when using print on any of the above functions can be automatically copied to the clipboard if you so specify.\nSince I do not wish to mess with your clipboard without you knowing it, this feature must be activated by you.\n\nTo do so, run\n\n```julia\ncopy_to_clipboard(true)\n```\n\nTo once again disable the feature, pass `false` to the same function.\n\nThe copying to the clipboard will now occur at every call to a Latexify.jl function, regardless of how you chose to display the output.\n\n## Automatic displaying of result\n\nYou can toggle whether the result should be automatically displayed. Instead of\n\n```julia\nlatexify(\"x/y\") |> display\n## or\ndisplay( latexify(\"x/y\") )\n```\n\none can toggle automatic display by:\n\n```julia\nauto_display(true)\n```\n\nafter which all calls to `latexify` will automatically be displayed. This can be rather convenient, but it can also cause a lot of unwanted printouts if you are using `latexify` in any form of loop.\nYou can turn off this behaviour again by passing `false` to the same function.\n\n## Setting your own defaults\nIf you get tired of specifying the same keyword argument over and over in a session, you can just reset its default:\n```julia\nset_default(fmt = \"%.2f\", convert_unicode = false)\n```\n\nNote that this changes Latexify.jl from within and should therefore only be used in your own Julia sessions (do not call this from within your packages). \n\nThe calls are additive so that a new call with \n```julia\nset_default(mult_symbol = \"\")\n```\nwill not cancel out the changes we just made to `fmt` and `convert_unicode`. \n\nTo view your changes, use\n```julia\nget_default()\n```\nand to reset your changes, use\n```julia\nreset_default()\n```\n## Macros\nThree macros are exported. \n\n- `@latexify` simply latexifies the expression that you provide to it, similar to `latexify(:(...))`.\n- `@latexrun` both executes and latexifies the given expression. \n- `@latexdefine` executes the expression, and latexifies the expression together with the its value\n\nThey can for example be useful for latexifying simple mathsy functions like\n```julia\njulia> lstr = @latexrun f(x; y=2) = x/y\nL\"$f\\left( x; y = 2 \\right) = \\frac{x}{y}$\"\n\njulia> f(1)\n0.5\n```\n\n```julia\njulia> @latexdefine x = 1/2\nL\"$x = \\frac{1}{2} = 0.5\n\njulia> x\n0.5\n```\n\nThe arguments to the macro can be interpolated with `$` to use the actual\nvalue, instead of the representation:\n```julia\njulia> @latexify x = abs2(-3)\nL\"$x = \\left|-3\\right|^{2}$\"\n\njulia> @latexify x = $(abs2(-3))\nL\"$x = 9$\"\n```\n\nKeyword arguments can be supplied after these macros:\n```julia\njulia> @latexdefine x env=:equation\nL\"\\begin{equation}\nx = 0.5\n\\end{equation}\n\"\n```\n\nA special keyword `post` can be supplied to `@latexdefine`, which is a\nfunction that will be called on the final right hand sign before\nlatexification. This is merely formatting and will not affect any assignments.\n\n```julia\njulia> @latexdefine x=π  post=round\nL\"$x = \\pi = 3.0$\"\n\njulia> @latexdefine x\nL\"$x = \\pi$\"\n```\n\n## External rendering\nWhile LaTeXStrings already render nicely in many IDEs or in Jupyter, they do not render in the REPL. Therefore, we provide a function `render(str)` which generates a standalone PDF using LuaLaTeX and opens that file in your default PDF viewer.\n\nI have found the following syntax pretty useful:\n```julia\nlatexify(:(x/y)) |> render\n```\n\nAlternatively, `render(str, mime)` can also be used to generate and display DVI, PNG and SVG files, which might be useful for other purposes:\n\n```julia\nlatexify(:(x/y)) |> s -> render(s, MIME(\"image/png\"))\n```\n\nPNG output defaults to using [ghostscript](https://www.ghostscript.com), which is available by default thanks to `Ghostscript_jll`. \n\n[dvipng](http://www.nongnu.org/dvipng) can also be used by passing the keyword `convert = :dvipng` to `render`. However, this requires a working installation of dvipng. \n\nSVG output relies on [dvisvgm](https://dvisvgm.de) or alternatively on [pdf2svg](https://github.com/dawbarton/pdf2svg).\n\nIf your code requires specific packages or document classes to render correctly, you can supply those as keyword arguments:\n\n```julia\nL\"\\qty{1.25}{nm}\" |> render(s, MIME(\"image/png\"); documentclass=\"article\", packages=(\"microtype\", (\"siunitx\", exponent-product=\"\\cdot\")))\n```\n\nThe arguments to these are either strings, or tuples of strings where the first\none is the name of the package or class, and any further are optional arguments.\n\nOne can use `Latexify` together with `ImageInTerminal` to render equations in a [sixel compatible](https://github.com/JuliaIO/Sixel.jl#terminals-that-support-sixel) terminal, where the size of the sixel encoded image can be controlled using `dpi`:\n\n```julia\nusing ImageInTerminal, Latexify\n\nlatexify(:(iħ * (∂Ψ(𝐫, t) / ∂t) = -ħ^2 / 2m * ΔΨ(𝐫, t) + V * Ψ(𝐫, t))) |> s -> render(s, dpi=200)\n```\n\n### Tectonic\n\nThe `tectonic_jll` package can be used as a lightweight compiler for CI and similar setups.\nAn extension to `Latexify` makes `render` (to pdf) automatically use `tectonic_jll` if both packages are loaded.\nTo still render using the default compiler, use `render(...; use_tectonic=false)`.\n\n### Render command-line args\n\nFor fine-tuning or setting other command-line arguments to a render pipeline, you can pass any of the following keyword arguments to `render`, some of which have default values. \nSince these are [interpolated into shell commands](https://julialang.org/blog/2017/10/command-interpolation-for-dummies/), note that you should surround with back-ticks `\\`` rather than quotes.\n- ```lualatex_flags=`` ``` (for default compilation to PDF)\n- ```tectonic_flags=`` ``` (for tectonic_jll compilation to PDF)\n- ```dvilualatex_flags=`` ``` (for compilation to DVI)\n- ```ghostscript_flags=`-sDEVICE=pngalpha -dTextAlphaBits=4 -r$dpi` ``` (for generating PNG from PDF)\n- ```dvipng_flags=`-bg Transparent -D $dpi -T tight` ``` (for dvipng, for generating PNG from DVI)\n- ```pdf2svg_flags=`` ``` (for generating SVG from PDF)\n- ```dvisvgm_flags=`` ``` (for generating SVG from DVI)\n- ```dvilualatex_flags=`` ``` (for generating DVI)\n\n## Legacy support\n\nLatexify.jl has stopped supporting Julia versions older than 0.7. This does not mean that you cannot use Latexify with earlier versions, just that these will not get new features. Latexify.jl's release v0.4.1 was the last which supported Julia 0.6. Choose that release in the dropdown menu if you want to see that documentation.\n"
  },
  {
    "path": "docs/src/table_generator.jl",
    "content": "#=\nIn the documents, there are tables of what keyword arguments can be passed\nto latexify for different outputs or inputs. This file contains that information\nas well as the means to generate tables for the documentation.\n\nThis exists so that I do not have to repeat myself and to type the same\ninformation into multiple places (that way lies madness!). With this code, I\ncan simply filter the information according to some criterion and automatically\nhave it inserted in the docs.\n=#\nusing Latexify\n\nstruct KeywordArgument\n    kw::Symbol\n    env::Array{Symbol}\n    values::String\n    default::String\n    description::String\n    types::Array{Symbol}\nend\n\n#     KeywordArgument(:template, [:array], \"`Bool`\", \"`false`\", \"description\", [:Any]),\nkeyword_arguments = [\n    KeywordArgument(:starred, [:align, :array, :arrow, :equation], \"`Bool`\", \"`false`\", \"Star the environment to prevent equation numbering.\", [:Any]),\n    KeywordArgument(:separator, [:align], \"`String`\", \"`\\\" &= \\\"`\", \"Specify how to separate the left hand side and the right.\", [:Any]),\n    KeywordArgument(:transpose, [:array, :tabular, :mdtable], \"`Bool`\", \"`true`\", \"Flip rows for columns.\", [:Any]),\n    KeywordArgument(:double_linebreak, [:array, :align, :arrow], \"`Bool`\", \"`false`\", \"Add an extra `\\\\\\\\` to the end of the line.\", [:Any]),\n    KeywordArgument(:bracket, [:align], \"`Bool`\", \"`false`\", \"Surround variables with square brackets.\", [:ParameterizedFunction, :ReactionNetwork]),\n    KeywordArgument(:noise, [:align], \"`Bool`\", \"`false`\", \"Display the noise function instead of the deterministic one.\", [:ReactionNetwork]),\n    KeywordArgument(:adjustment, [:tabular, :array, :mdtable], \"`:c` for centered, `:l` for left, `:r` for right, or a vector with one such symbol per column.\", \"`:c`\", \"Set the adjustment of text within the table cells.\", [:Any]),\n    KeywordArgument(:expand, [:arrow, :align], \"`Bool`\", \"`true`\", \"Expand functions such as `hill(x, v, k, n)` to their mathematical expression.\", [:ReactionNetwork]),\n    KeywordArgument(:mathjax, [:arrow], \"`Bool`\", \"`true`\", \"Add `\\\\require{mhchem}` to tell MathJax to load the required module.\", [:ReactionNetwork]),\n    KeywordArgument(:latex, [:mdtable, :tabular], \"`Bool`\", \"`true`\", \"Toggle latexification of the table elements.\", [:Any]),\n    KeywordArgument(:head, [:mdtable, :tabular], \"`Array`\", \"`[]`\", \"Add a header to the table. It will error if it is not of the right length (unless empty). \", [:Any]),\n    KeywordArgument(:side, [:mdtable, :tabular], \"`Array`\", \"`[]`\", \"Add a leftmost column to the table. It will error if it is not of the right length (unless empty). \", [:Any]),\n    KeywordArgument(:fmt, [:mdtable, :tabular, :align, :array, :raw, :inline], \"format string\", \"`\\\"\\\"`\", \"Format number output in accordance with Printf. Example: \\\"%.2e\\\"\", [:Any]),\n    KeywordArgument(:imaginary_unit, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`String`\", \"`\\\"\\\\\\\\mathit{i}\\\"`\", \"The symbol to use to represent the imaginary unit\", [:Any]),\n    KeywordArgument(:escape_underscores, [:mdtable, :mdtext], \"`Bool`\", \"`false`\", \"Prevent underscores from being interpreted as formatting.\", [:Any]),\n    KeywordArgument(:convert_unicode, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`Bool`\", \"`true`\", \"Convert unicode characters to latex commands, for example `α` to `\\\\alpha`\", [:Any]),\n    KeywordArgument(:mult_symbol, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`String`\", \"`\\\"\\\\\\\\cdot\\\"`\", \"Specify the symbol to use for the multiplication operator (`\\\"\\\"` for juxtaposition).\", [:Any]),\n    KeywordArgument(:symbolic, [:align], \"`Bool`\", \"`false`\", \"Use symbolic calculations to clean up the expression.\", [:ReactionNetwork]),\n    KeywordArgument(:clean, [:align], \"`Bool`\", \"`false`\", \"Clean out `1*` terms. Only useful for Catalyst (then named DiffEqBiological) versions 3.4 or below.\", [:ReactionNetwork]),\n    KeywordArgument(:rows, [:align], \"Iterable or symol\", \":all\", \"Which rows to include in the output.\", [:Any]),\n    KeywordArgument(:booktabs, [:tabular], \"`Bool`\", \"`false`\", \"Add top, mid and bottom booktabs rule\", [:Any]),\n    KeywordArgument(:index, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`Symb`\", \"`:bracket`\", \"Represent index specification with `:bracket` (`u[1]`) or `:subscript` (`u_1`). \", [:Any]),\n    KeywordArgument(:snakecase, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`Bool`\", \"`false`\", \"Treat underscores as literal underscores (if not, treat first underscore as subscript).\", [:Any]),\n    KeywordArgument(:safescripts, [:mdtable, :tabular, :align, :array, :raw, :inline], \"`Bool`\", \"`false`\", \"Put scripts inside brackets (`a{_b}`), sometimes making them uglier, but making alternating scripts possible.\", [:Any]),\n    KeywordArgument(:arraystyle, [:array], \"`Symbol`, `String`, `NTuple{3, String}`\", \"`:square`\", \"How to style (brackets around) arrays. `Symbol`s correspond to predefined styles: `:square`, `:round`, `:curly`, `:bmatrix`, `:pmatrix`. A string will be used as an environment, with no further brackets (e.g. `\\\"vmatrix\\\"`). Tuples should be `(<starting bracket>, <ending bracket>, <environment>)`, for instance `:square` corresponds to `(\\\"\\\\n\\\\\\\\left[\\\", \\\"\\\\\\\\right]\\\\n\\\", \\\"array\\\")`.\", [:Any]),\n#     KeywordArgument(:template, [:array], \"`Bool`\", \"`false`\", \"description\", [:Any]),\n    ]\n\n@latexrecipe function f(list::Array{KeywordArgument}; types=true)\n    isempty(list) && return nothing\n    sort!(list, by=x->x.kw)\n    keys = [\"`:$(x.kw)`\" for x in list]\n    # values = [join([\"$i\" for i in x.values], \", \") for x in list]\n    applicable_types = [join([\"`$i`\" for i in x.types], \", \") for x in list]\n    values = [x.values for x in list]\n    defaults = [x.default for x in list]\n    descriptions = [x.description for x in list]\n\n    latex --> false\n    env := :mdtable\n\n    if any(x->x.types != [:Any], list) && types\n        head --> [\"Keyword\", \"Values\", \"Default\", \"Applicable types\", \"Description\"]\n        return hcat(keys, values, defaults, applicable_types, descriptions)\n    else\n        head --> [\"Keyword\", \"Values\", \"Default\", \"Description\"]\n        return hcat(keys, values, defaults, descriptions)\n    end\nend\n"
  },
  {
    "path": "docs/src/tutorials/Catalyst.md",
    "content": "# Use with @reaction_network from Catalyst.jl.\n\nLatexify.jl has methods for dealing with the `ReactionNetwork` models generated by Catalyst.jl. More information regarding these can be found [here](https://github.com/SciML/Catalyst.jl). The latexify end of things are pretty simple: feed a reaction network to `latexify()` and let it do its magic.\n\n```julia\nusing Catalyst\nusing Latexify\ncopy_to_clipboard(true)\n\nhill2(x, v, k) = v*x^2/(k^2 + x^2)\nrn = @reaction_network begin\n  hill2(y, v_x, k_x), 0 --> x\n  p_y, 0 --> y\n  (d_x, d_y), (x, y) --> 0\n  (r_b, r_u), x ↔ y\nend\n\nlatexify(rn; form=:ode)\n```\n```math\n\\begin{align}\n\\frac{dx}{dt} &= \\frac{v_{x} \\cdot y^{2}}{k_{x}^{2} + y^{2}} - d_{x} \\cdot x - r_{b} \\cdot x + r_{u} \\cdot y \\\\\n\\frac{dy}{dt} &= p_{y} - d_{y} \\cdot y + r_{b} \\cdot x - r_{u} \\cdot y \\\\\n\\end{align}\n```\n\nAlternatively, the SDEs generated through the chemical Langevin equations can be displayed by setting the `form` argument to `:sde`. Here, the noise in the reaction network is correlated/\n```julia\nlatexify(rn; form=:sde)\n```\n```math\n\\begin{align}\n\\frac{dx}{dt} &= \\sqrt{\\frac{v_{x} \\cdot y^{2}}{k_{x}^{2} + y^{2}}} - \\sqrt{d_{x} \\cdot x} - \\sqrt{r_{b} \\cdot x} + \\sqrt{r_{u} \\cdot y} \\\\\n\\frac{dy}{dt} &= \\sqrt{p_{y}} - \\sqrt{d_{y} \\cdot y} + \\sqrt{r_{b} \\cdot x} - \\sqrt{r_{u} \\cdot y} \\\\\n\\end{align}\n```\n\nNote: On the current version of Latexify, generation of SDEs from reaction networks is broken.\n\n\n## Chemical arrow notation\n\nCatalyst reaction network is all about chemical arrow notation, so why should we not be able to render arrows?\n\nThis is the default output (when no value to `form` is given).\n\n```julia\nlatexify(rn; env=:chemical)\n```\n\\begin{align}\n\\require{mhchem}\n\\ce{ \\varnothing &->[\\frac{v_{x} \\cdot y^{2}}{k_{x}^{2} + y^{2}}] x}\\\\\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\\\\\n\\ce{ x &<=>[{r_{b}}][{r_{u}}] y}\\\\\\\\\n\\end{align}\n\nThe default output is meant to be rendered directly on the screen. This rendering is typically done by MathJax. To get the chemical arrow notation to render automatically, I have included a MathJax command (`\\require{mhchem}`) in the output string. If you want to use the output in a real LaTeX document, you can pass the keyword argument `mathjax=false` and this extra command will be omitted. In such case you should also add `\\usepackage{mhchem}` to the preamble of your latex document.\n\nAnother keyword argument that may be of use is `expand=false` (defaults to `true`).\nThis determines whether your functions should be expanded or not.\nAlso, `starred=true` will change the outputted latex environment from `align` to `align*`. This results in the equations not being numbered.\n\n```julia\nlatexify(rn; env=:chemical, expand=false, starred=true)\n```\n\n```math\n\\begin{align*}\n\\require{mhchem}\n\\ce{ \\varnothing &->[\\mathrm{hill2}\\left( y, v_{x}, k_{x} \\right)] x}\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\n\\ce{ x &<=>[{r_{b}}][{r_{u}}] y}\\\\\n\\end{align*}\n```\n\n## Available options\n### Align\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if (:ReactionNetwork in arg.types || :Any in arg.types) && :align in arg.env]\nlatexify(args, env=:mdtable, types=false)\n```\n\n### Arrow notation\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if (:ReactionNetwork in arg.types || :Any in arg.types) && :arrow in arg.env]\nlatexify(args, env=:mdtable, types=false)\n```\n"
  },
  {
    "path": "docs/src/tutorials/inner_workings.md",
    "content": "# Inner workings\n\nThis package contains a large number of methods, but two of these are of special importance.\nThese are:\n\n- `latexraw(ex::Expr)`\n\nand\n\n- `latexoperation(ex::Expr, prevOp::AbstractArray)`\n\nThese two methods are involved with all conversions to ``\\LaTeX`` equations. \n\n`latexraw(ex::Expr)` utilises Julias homoiconicity to infer the correct latexification of an expression by recursing through the expression tree. Whenever it hits the end of a recursion it passes the last expression to `latexoperation()`.\nBy the nature of this recursion, this expression is one which only contains symbols or strings.\n\n## Explanation by example\n\nLet's define a variable of the expression type:\n```julia-repl\njulia> ex = :(x + y/z)\n```\n\nThis expression has a field which contains the first operation which must be done, along with the objects that this operation will operate on:\n```julia-repl\njulia> ex.args\n\n3-element Array{Any,1}:\n :+      \n :x      \n :(y / z)\n```\n\nThe first two element are both Symbols, while the third one is an expression:\n```julia-repl\njulia> typeof.(ex.args)\n\n3-element Array{DataType,1}:\n Symbol\n Symbol\n Expr\n```\n\nSince at least one of these elements is an expression, the next step of the recursive algorithm is to dive into that expression:\n\n```julia-repl\njulia> newEX = ex.args[3]\njulia> newEx.args\n\n3-element Array{Any,1}:\n :/\n :y\n :z\n```\n\nSince none of these arguments is another expression, `newEx` will be passed to `latexoperation()`.\nThis function checks which mathematical operation is being done and converts newEx to an appropriately formatted string.\nIn this case, that string will be \"\\\\\\\\frac{y}{z}\" (and yes, a double slash is needed).\n\n`newEx` is now a string (despite its name):\n\n\n```julia\njulia> newEx\n\n\"\\\\frac{y}{z}\"\n```\n\nThe recursive `latexraw()` pulls this value back to the original expression `ex`, such that:\n\n```julia-repl\njulia> ex.args\n\n3-element Array{Any,1}:\n :+      \n :x      \n :\"\\\\frac{y}{z}\"\n```\n\nNow, since this expression does not consist of any further expressions, it is passed to `latexoperation()`.\nThe operator is now \"+\", and it should be applied on the second and third element of the expression, resulting in:\n\n```julia\n\"x + \\\\frac{y}{z}\"\n```\n\nusing the print function you get:\n\n```julia-repl\njulia> print(latexraw(ex))\n\n\"x + \\frac{y}{z}\"\n```\n\nwhich in a ``\\LaTeX`` maths environment renders as:\n\n```math\nx + \\frac{y}{z}\n```\n\n\n\n## Extended functionality\n\n\nWith the above example we can understand how an expression is converted to a ``\\LaTeX`` formatted string (unless my pedagogical skills are worse than I fear).\n\nSo, anything which can be converted to a Julia expression of the Expr type can be latexified.\nLuckily, since Julia needs to convert your code to expressions before it can be evaluated, Julia is already great at doing this.\n\nThere are already some methods for converting other types to expressions and passing them to the core method, for example:\n```julia\nlatexraw(str::String) = latexraw(parse(str))\n```\nbut if you find yourself wanting to parse some other type, it is often easy to overload the `latexraw` function.\n\n\n## Latexifying Arrays\nAlso, if you pass an array to `latexraw`, it will recursively try to convert the elements of that array to ``\\LaTeX`` formatted strings.\n\n\n```julia-repl\njulia> arr = [:(x-y/(k_10+z)), \"x*y*z/3\"]\njulia> latexraw(arr)\n2-element Array{String,1}:\n \"x - \\\\frac{y}{k_{10} + z}\"     \n \"\\\\frac{x \\\\cdot y \\\\cdot z}{3}\"\n\njulia> println.(latexraw(arr))\nx - \\frac{y}{k_{10} + z}\n\\frac{x \\cdot y \\cdot z}{3}\n```\n"
  },
  {
    "path": "docs/src/tutorials/latexalign.md",
    "content": "\n# [`latexalign`](@id latexalign_tutorial)\n\nThis function converts its input to ``\\LaTeX`` align environments.\nOne way of using the function is to pass it two vectors, one which holds the left-hand-side of the equations and the other which holds the right. For example:\n\n\n```julia\nlhs = [\"dx/dt\", \"dy/dt\"]\nrhs = [\"y^2 - x\", \"x/y - y\"]\nprint(latexalign(lhs, rhs))\n```\noutputs:\n\n```maths\n\\begin{align}\n\\frac{dx}{dt} &= y^{2} - x \\\\\n\\frac{dy}{dt} &= \\frac{x}{y} - y \\\\\n\\end{align}\n```\n\nIn Jupyter, this can be rendered by:\n```julia\ndisplay( latexalign(lhs, rhs))\n```\n\n\\begin{align\\*}\n\\frac{dx}{dt} &= y^{2} - x \\\\\\\\\n\\frac{dy}{dt} &= \\frac{x}{y} - y \\\\\\\\\n\\end{align\\*}\n\n\n## Using DifferentialEquations.jl\n\nThe motivation for creating this function was mainly to be able to render ODEs.\nIn my own work, I tend to use [DifferentialEquations.jl](http://docs.juliadiffeq.org/stable/index.html) to define ODEs as [ParameterizedFunctions](http://docs.juliadiffeq.org/stable/analysis/parameterized_functions.html#Function-Definition-Macros-1).\nTherefore, I found it useful to create a method which simply takes the ParameterizedFunction as input:\n\n```julia\nusing Latexify\nusing DifferentialEquations\node = @ode_def positiveFeedback begin\n    dx = y/(k_y + y) - x\n    dy = x^n_x/(k_x^n_x + x^n_x) - y\nend k_y k_x n_x\n\nlatexalign(ode)\n```\n\n\\begin{align}\n\\frac{dx}{dt} &= \\frac{y}{k_{y} + y} - x \\\\\\\\\n\\frac{dy}{dt} &= \\frac{x^{n_{x}}}{k_{x}^{n_{x}} + x^{n_{x}}} - y \\\\\\\\\n\\end{align}\n"
  },
  {
    "path": "docs/src/tutorials/latexarray.md",
    "content": "# `latexarray`\n\n\nThis functions takes a 1 or 2D array and spits out a latex array environment.\nFor example:\n\n```julia-repl\njulia> arr = eye(Int,3)\njulia> print(latexarray(arr))\n\n\\begin{equation}\n\\left[\n\\begin{array}{ccc}\n1 & 0 & 0\\\\\n0 & 1 & 0\\\\\n0 & 0 & 1\\\\\n\\end{array}\n\\right]\n\\end{equation}\n```\nwhich renders as:\n\n\\begin{equation}\n\\left[\n\\begin{array}{ccc}\n1 & 0 & 0\\\\\\\\\n0 & 1 & 0\\\\\\\\\n0 & 0 & 1\\\\\\\\\n\\end{array}\n\\right]\n\\end{equation}\n\n\n`latexraw()` is called for each element of the input, individually.\nIt therefore does not matter if the input array is of a mixed type.\n\n```julia\narr = [1.0, 2-3im, 3//4, :(x/(k_1+x)), \"e^(-k_b*t)\"]\nlatexarray(arr)\n```\nrenders as:\n\n\\begin{equation}\n\\left[\n\\begin{array}{c}\n1.0\\\\\\\\\n2-3\\textit{i}\\\\\\\\\n\\frac{3}{4}\\\\\\\\\n\\frac{x}{k_{1} + x}\\\\\\\\\ne^{- k_{b} \\cdot t}\\\\\\\\\n\\end{array}\n\\right]\n\\end{equation}\n"
  },
  {
    "path": "docs/src/tutorials/latexify.md",
    "content": "# `latexify`\n\nThis is a wrapper of some of the other `latexXXX` functions. It tries to infer a suitable output mode for the given input. If the environment you are using supports the MIME type \"text/latex\", then the output will be rendered nicely.\n\n\n```julia\nusing Latexify\ncopy_to_clipboard(true)\n\nex = :(x/y)\nlatexify(ex)\n\n```\n$\\frac{x}{y}$\n\nIf you `print` the output rather than `display`, then you will enforce the print-out of a string which is ready for some copy-pasting into your LaTeX document.\n\n```julia\nprintln(latexify(ex))\n\n## or the equivalent:\nlatexify(ex) |> println\n```\n```LaTeX\n$\\frac{x}{y}$\n```\n\nA matrix, or a single vector, is turned into an array.\n```julia\nM = signif.(rand(3,4), 2)\n\nlatexify(M)\n```\n\n\\begin{equation}\n\\left[\n\\begin{array}{cccc}\n0.85 & 0.99 & 0.85 & 0.5\\\\\\\\\n0.59 & 0.061 & 0.77 & 0.48\\\\\\\\\n0.7 & 0.17 & 0.7 & 0.82\\\\\\\\\n\\end{array}\n\\right]\n\\end{equation}\n\nYou can transpose the output using the keyword argument `transpose=true`.\n\n\nIf you give two vectors as an argument, they will be displayed as the left-hand-side and right-hand-side of an align environment:\n```julia\nlatexify([\"x/y\", :z], Any[2.3, 1//2])\n```\n\\begin{align}\n\\frac{x}{y} &= 2.3 \\\\\\\\\nz &= \\frac{1}{2} \\\\\\\\\n\\end{align}\n\n\nIf you input a ParameterizedFunction or a ReactionNetwork from DifferentialEquations.jl you will also get an align environment. For more on this, have a look on their respective sections.\n"
  },
  {
    "path": "docs/src/tutorials/latexinline.md",
    "content": "# `latexinline`\ntakes a Julia object `x` and returns a ``\\LaTeX`` formatted string.\nIt also surrounds the output in a simple \\$\\$ environment.\nThis works for `x` of many types, including expressions, which returns ``\\LaTeX`` code for an equation.\n\n\n```julia-repl\njulia> ex = :(x-y/z)\njulia> latexinline(ex)\nL\"$x - \\frac{y}{z}$\"\n```\nIn Jupyter or Hydrogen this automatically renders as:\n\n$x - \\frac{y}{z}$\n\nAmong the supported types are:\n- Expressions,\n- Strings,\n- Numbers (including rational and complex),\n- Symbols,\n- Symbolic expressions from SymEngine.jl.\n- ParameterizedFunctions.\n\nIt can also take arrays, which it recurses and latexifies the elements, returning an array of latex strings.\n"
  },
  {
    "path": "docs/src/tutorials/latextabular.md",
    "content": "# `latextabular`\n\n```julia\nusing Latexify\ncopy_to_clipboard(true)\narr = [\"x/y\" :(y^n); 1.0 :(alpha(x))]\nlatextabular(arr) |> println\n```\n\noutputs:\n```LaTeX\n\\begin{tabular}{cc}\n$\\frac{x}{y}$ & $y^{n}$\\\\\n$1.0$ & $\\alpha\\left( x \\right)$\\\\\n\\end{tabular}\n```\nUnfortunately, this does not render nicely in Markdown. But you get the point.\n\n\n`latextabular` takes two keywords, one for changing the adjustment of the columns (centered by default), and one for transposing the whole thing.\n```julia\nlatextabular(arr; adjustment=:l, transpose=true) |> println\n```\n\n```LaTeX\n\\begin{tabular}{ll}\n$\\frac{x}{y}$ & $1.0$\\\\\n$y^{n}$ & $\\alpha\\left( x \\right)$\\\\\n\\end{tabular}\n```\n\nThe adjustments can be set per column by providing a vector like `[:c, :l, :r]`.\nIf you want to use the `S` column type from `siunitx`, set `latex=false, adjustment=:S`.\nSome post-adjustment may be necessary.\n"
  },
  {
    "path": "docs/src/tutorials/notebooks.md",
    "content": "# Notebook workflows\n\nWhen working in a notebook (These tips assume Pluto, but will apply at least\nin part to other similar environments), there's a number of options to\nincorporate latexifications.\n\nAs a first principle, any cell that returns a single `LaTeXString` (or a\nstring surrounded by `$` in general) will be displayed as math:\n\n```julia\nlatexify(35e-9; fmt=FancyNumberFormatter())\n```\n```math\n3.5 \\cdot 10^{-8}\n```\n\n```julia\n@latexify (3x + 45)/2y\n```\n```math\n\\frac{3 \\cdot x + 45}{2 \\cdot y}\n```\n\nThere's a visual bug in Pluto where any expression looking like an assignment\nis printed with extra unnecessary information. To avoid this, encase such in a `begin/end` block:\n\n```julia\nbegin\n    @latexrun x = 125\nend\n```\n```math\nx = 125\n```\n\n```julia\nbegin\n    @latexdefine y = x\nend\n```\n```math\ny = x = 125\n```\n\nOne very nice workflow is to use `Markdown.parse` to embed latexifications in\nmarkdown text. Note that `md\"\"` does\n*not* work very well for this, as the\ndollar signs signifying math mode will\nclash with those signifying\ninterpolation. In `parse`, you need to\nescape special characters like\nbackslashes, but since we're using\n`Latexify` we don't need to write very\nmany of those anyway.\n\n```julia\nMarkdown.parse(\"\"\"\n## Results\n\nWith the previously calculated \n$(@latexdefine x), we can use\n$(@latexify x = v*t) to calculate\n$(@latexrun v = x/10), giving a final\nvelocity of $(latexify(v)).\n\nIf we want more manual control, we can\ncombine manual dollar signs with\n`env=:raw`: \\$ \\hat{v} =\n$(latexify(v, env=:raw))\\;\\mathrm{m}/\\mathrm{s} \\$\n\"\"\")\n```\n\n## Results\n\nWith the previously calculated \n$x = 125$, we can use $x = v \\cdot t$\nto calculate $v = \\frac{x}{10}$,\ngiving a final velocity of $12.5$.\n\nIf we want more manual control, we can combine manual dollar signs with `env=:raw`: $ \\hat{v} = 12.5\\;\\mathrm{m}/\\mathrm{s} $\n"
  },
  {
    "path": "docs/src/tutorials/parameterizedfunctions.md",
    "content": "# Use with ParameterizedFunctions\n\nIn the [latexalign tutorial](@ref latexalign_tutorial) I mentioned that one can use `latexalign` directly on a [ParameterizedFunction](http://docs.juliadiffeq.org/stable/analysis/parameterized_functions.html#Function-Definition-Macros-1).\nHere, I make a somewhat more convoluted and hard-to-read example (you'll soon se why):\n\n```julia\nusing Latexify\nusing ParameterizedFunctions\ncopy_to_clipboard(true)\n\node = @ode_def positiveFeedback begin\n    dx = y*y*y/(k_y_x + y) - x - x\n    dy = x^n_x/(k_x^n_x + x^n_x) - y\nend k_y k_x n_x\n\nlatexify(ode)\n```\n\n```math\n\\begin{align}\n\\frac{dx}{dt} &= \\frac{y \\cdot y \\cdot y}{k_{y\\_x} + y} - x - x \\\\\n\\frac{dy}{dt} &= \\frac{x^{n_{x}}}{k_{x}^{n_{x}} + x^{n_{x}}} - y \\\\\n\\end{align}\n```\n\nThis is pretty nice, but there are a few parts of the equation which could be reduced.\nUsing a keyword argument, you can utilise the SymEngine.jl to reduce the expression before printing.\n\n```julia\nlatexify(ode, field=:symfuncs)\n```\n```math\n\\begin{align}\n\\frac{dx}{dt} &= -2 \\cdot x + \\frac{y^{3}}{k_{y\\_x} + y} \\\\\n\\frac{dy}{dt} &=  - y + \\frac{x^{n_{x}}}{k_{x}^{n_{x}} + x^{n_{x}}} \\\\\n\\end{align}\n```\n\n### Side-by-side rendering of multiple system.\n\nA vector of ParameterizedFunctions will be rendered side-by-side:\n\n```julia\node2 = @ode_def negativeFeedback begin\n    dx = y/(k_y + y) - x\n    dy = k_x^n_x/(k_x^n_x + x^n_x) - y\nend k_y k_x n_x\n\nlatexify([ode, ode2])\n```\n```math\n\\begin{align}\n\\frac{dx}{dt}  &=  \\frac{y \\cdot y \\cdot y}{k_{y\\_x} + y} - x - x  &  \\frac{dx}{dt}  &=  \\frac{y}{k_{y} + y} - x  &  \\\\\n\\frac{dy}{dt}  &=  \\frac{x^{n_{x}}}{k_{x}^{n_{x}} + x^{n_{x}}} - y  &  \\frac{dy}{dt}  &=  \\frac{k_{x}^{n_{x}}}{k_{x}^{n_{x}} + x^{n_{x}}} - y  &  \\\\\n\\end{align}\n```\n\n### Visualise your parameters.\n\nAnother thing that I have found useful is to display the parameters of these functions. The parameters are usually in a vector, and if it is somewhat long, then it can be annoying to try to figure out which element belongs to which parameter. There are several ways to solve this. Here are two:\n```julia\n## lets say that we have some parameters\nparam = [3.4,5.2,1e-2]\nlatexify(ode.params, param)\n```\n```math\n\\begin{align}\nk_{y} &= 3.4 \\\\\nk_{x} &= 5.2 \\\\\nn_{x} &= 0.01 \\\\\n\\end{align}\n```\n\nor\n\n```julia\nlatexify([ode.params, param]; env=:array, transpose=true)\n```\n```math\n\\begin{equation}\n\\left[\n\\begin{array}{ccc}\nk_{y} & k_{x} & n_{x} \\\\\n3.4 & 5.2 & 0.01 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n```\n\n`signif.()` is your friend if your parameters have more significant numbers than you want to see.\n\n### Get the jacobian, hessian, etc.\n\nParameterizedFunctions symbolically calculates the jacobian, inverse jacobian, hessian, and all kinds of goodness. Since they are available as arrays of symbolic expressions, which are latexifyable, you can render pretty much all of them.\n\n```julia\nlatexify(ode.symjac)\n```\n```math\n\\begin{equation}\n\\left[\n\\begin{array}{cc}\n-2 & \\frac{3 \\cdot y^{2}}{k_{y\\_x} + y} - \\frac{y^{3}}{\\left( k_{y\\_x} + y \\right)^{2}} \\\\\n\\frac{x^{-1 + n_{x}} \\cdot n_{x}}{k_{x}^{n_{x}} + x^{n_{x}}} - \\frac{x^{-1 + 2 \\cdot n_{x}} \\cdot n_{x}}{\\left( k_{x}^{n_{x}} + x^{n_{x}} \\right)^{2}} & -1 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n```\n\n## Available options\n```@eval\nBase.include(@__MODULE__, \"src/table_generator.jl\")\nargs = [arg for arg in keyword_arguments if :ParameterizedFunction in arg.types || :Any in arg.types]\nlatexify(args, env=:mdtable, types=false)\n```\n"
  },
  {
    "path": "docs/src/tutorials/recipes.md",
    "content": "\n# Recipes\n\nRecipes provides a concise means of extending Latexify.jl to work with types of your own making or of other packages. The `@latexrecipe` macro allows you to specify how a an argument type (or a set of types) should be pre-processed before they are passed to the standard `latexify` function. Also, it allows you to define both new keyword arguments as well as to set the defaults of pre-existing ones. The main power of this macro is that is defines the necessary functions *within* Latexify.jl itself, as opposed to within the module where it is called. \n\n\nThe recipe syntax closely follow that of the [Plots.jl](https://github.com/JuliaPlots/Plots.jl) [recipes](https://github.com/JuliaPlots/RecipesBase.jl) and, indeed, most of the code is copied and adapted from them (cred to the authors!). \n\n\n\nSo. The easiest way to explain it is by showing an example where we define a recipe for our type `MyType`. \n\n```julia\nusing Latexify\n\nstruct MyType \n   vector::Vector\nend\n```\n\n```julia\n@latexrecipe function f(x::MyType; reverse=false)\n    ## we can access the input object and perform operations like in a normal function.\n    vec = x.vector\n    if reverse\n        vec = vec[end:-1:1]\n    end\n\n    ## we can define defult keyword arguments to be passed along to latexify \n    ## using an arrow notation, --> \n    env --> :array\n    transpose --> true\n    ## These can be overridden by the keyword arguments passed to the latexify function.\n\n    ## If you use the := operator to specify a value it cannot be overridden.\n    fmt := \"%.2f\"\n\n    ## The return value should be something that latexify already knows how to work with.\n    ## In this case, we have a simple vector which is fine!\n    return vec\nend\n```\n\n```julia\nmytype = MyType([1, 2, 3])\n\nlatexify(mytype; reverse=true)\n```\n\n```math\n\\begin{equation}\n\\left[\n\\begin{array}{c}\n3.00 \\\\\n2.00 \\\\\n1.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n```\n\nThe required signature of the macro is\n```julia\n@latexrecipe function f(x::MyType, ...; ...)\n    return something\nend\n```\n\nHere, the function name is unimportant, but the type signature is key. \nThere must also be an explicit `return` statement which returns something that \nbase Latexify already works with (Arrays, Tuples, Numbers, Symbols, Strings, etc.).\nIn particular, you can not rely on Julia's default to return the value of the \nlast expression evaluated in a function body.\n\nThe special notation `kwarg --> value` resets the default value of a keyword argument for your specific inputs. This will be overridden if the keyword argument in quesion is specified in a call to `latexify`. \nTo disallow this overriding, use `kwarg := value` instead.\n\nThe use of `@latexrecipe` to redefine how an already supported type should be interpreted is highly discouraged. There is (currently) nothing in place to forbid this but it could mess up how latexify works with other packages. Disregarding this in your own sessions is one thing, but doing it in a package could cause very difficult issues for the users of your package. \n\n\nIf a recipe is defined within a module, everything should just work without the need to export anything. \n\nThe special keyword argument `operation` lets you specify that a type corresponds to a specific arithmetic operation.\nFor instance, if we define a type \n```julia\nstruct MyDifference\nx\ny\nend\n```\nthat is meant to represent the operation `x - y`, we might want to create the recipe\n\n```julia\n@latexrecipe function f(m::MyDifference)\n    return :($(m.y) - $(m.x))\nend\n```\nso that the result of `latexify(MyDifference(2,3))` is ``3 - 2``.\nBut right now, `latexify` does not know that this represents an operation, so for instance\n`@latexify $(MyDifference(2,3))*4` gives ``3 - 2 \\cdot 4``, which is incorrect.\nThe way around this is to edit the recipe:\n```julia\n@latexrecipe function f(m::MyDifference)\n    operation := :-\n    return :($(m.y) - $(m.x))\nend\n```\nNow `latexify` knows that `MyDifference` represents a subtraction, and parenthesis rules kick in:\n`@latexify $(MyDifference(2,3))*4` gives ``\\left( 3 - 2 \\right) \\cdot 4``.\n"
  },
  {
    "path": "docs/src/tutorials/rendering_latex.md",
    "content": "# A note on rendering ``\\LaTeX``\nUsing the `print` function on a latexified object prints text which is suitable for copy-pasting into a ``\\LaTeX`` document.\n\nHowever, it is often also useful to be able to render the equation inside the document that one is using to develop code. The Julia REPL does not support this, but IJulia does.\nSo, inside a Jupyter or Pluto notebook (or if you are running Atom with Hydrogen), you can render ``\\LaTeX`` using\n\n```julia\ndisplay(\"text/latex\", x)\n```\nwhere `x` is a latex-formatted string.\n\nThis requires `x` to specify a ``\\LaTeX`` environment. `latexalign` and `latexequation` already does this, but if you want to render the result of `latexify` you must supply an environment (for example `\"\\$ $x \\$\"`).\n"
  },
  {
    "path": "ext/DataFramesExt.jl",
    "content": "module DataFramesExt\n\nusing Latexify\nisdefined(Base, :get_extension) ? (using DataFrames) : (using ..DataFrames)\n\n@latexrecipe function f(d::DataFrame)\n    env --> :mdtable\n    head --> propertynames(d)\n    if kwargs[:env] == :array\n        return vcat(permutedims(propertynames(d)), Matrix(d))\n    end\n    return Matrix(d)\nend\n\nend\n"
  },
  {
    "path": "ext/SparseArraysExt.jl",
    "content": "module SparseArraysExt\n\nusing Latexify\nisdefined(Base, :get_extension) ? (using SparseArrays) : (using ..SparseArrays)\n\n@latexrecipe function f(x::AbstractSparseArray)\n    return collect(x)\nend\n\nend\n"
  },
  {
    "path": "ext/SymEngineExt.jl",
    "content": "module SymEngineExt\n\nusing Latexify\nisdefined(Base, :get_extension) ? (using SymEngine) : (using ..SymEngine)\n\n@latexrecipe function f(x::SymEngine.Basic)\n    return string(x)\nend\n\nend\n"
  },
  {
    "path": "ext/TectonicExt.jl",
    "content": "module TectonicExt\nimport LaTeXStrings.LaTeXString\nimport Latexify.render, Latexify._compile\nisdefined(Base, :get_extension) ? (using tectonic_jll) : (using ..tectonic_jll)\n__precompile__(false)\n\nfunction render(s::LaTeXString, ::MIME\"application/pdf\"; use_tectonic=true, tectonic_flags=``, lualatex_flags=``, kw...)\n    use_tectonic && return _compile(s, `$(tectonic()) --keep-logs $tectonic_flags main.tex`, \"pdf\"; kw...)\n    return _compile(s, `lualatex --interaction=batchmode $lualatex_flags main.tex`, \"pdf\"; kw...)\nend\nend\n"
  },
  {
    "path": "paper/paper.bib",
    "content": "@article{julia,\n\tauthor = {Jeff Bezanson and Alan Edelman and Stefan Karpinski and Viral B. Shah},\n\ttitle = {Julia: A Fresh Approach to Numerical Computing},\n\tjournal = {SIAM Review},\n\tvolume = {59},\n\tnumber = {1},\n\tpages = {65-98},\n\tyear = {2017},\n\tdoi = {10.1137/141000671},\n}\n\n@article{weave,\n\tauthor = {Pastell},\n\ttitle = {Weave.jl: Scientific Reports Using Julia},\n\tjournal = {Journal of Open Source Software},\n\tvolume = {2},\n\tnumber = {11},\n\tpages = {204},\n\tyear = {2017},\n\tdoi = {doi:10.21105/joss.00204},\n}\n\n@article{diffeq,\n    author = {Rackauckas, Christopher and Nie, Qing},\n    doi = {10.5334/jors.151},\n    journal = {The Journal of Open Research Software},\n    keywords = {Applied Mathematics},\n    note = {Exported from https://app.dimensions.ai on 2019/05/05},\n    number = {1},\n    pages = {},\n    title = {DifferentialEquations.jl – A Performant and Feature-Rich Ecosystem for Solving Differential Equations in Julia},\n    url = {https://app.dimensions.ai/details/publication/pub.1085583166 and http://openresearchsoftware.metajnl.com/articles/10.5334/jors.151/galley/245/download/},\n    volume = {5},\n    year = {2017}\n}\n"
  },
  {
    "path": "paper/paper.md",
    "content": "---\ntitle: 'Latexify.jl, translating mathematical Julia objects to renderable equations and tables.'\ntags:\n  - Julia\n  - LaTeX\n  - Markdown\n  - equations\n  - rendering\nauthors:\n  - name: Niklas Korsbo\n    orcid: 0000-0001-9811-3190\n    affiliation: \"1, 2\"\naffiliations:\n - name: The Sainsbury Laboratory, Cambridge University\n   index: 1\n - name: Department of Applied Mathematics and Theoretical Physics, Cambridge University\n   index: 2\ndate: 27 January 2020\nbibliography: paper.bib\n\n---\n\n# Summary\n\nHuman-understandable representation and visualisation of data and objects is\nimportant for understanding and communicating the results of scientific\nsoftware. \n\nLatexify.jl is a tool for converting Julia [@julia] objects to humanly\naccessible and renderable equations and tables.  It allows for the conversion\nof multiple types to LaTeX or Markdown-formatted strings and, in many\ndevelopment environments, for immediate rendering of the result. Among the\nsupported inputs is a class of Expressions that describe mathematical\nequations. These can be translated into LaTeX formatted mathematics and can be\noutputted as LaTeX environments such as align, equation or in-line equations.\nThe conversion can recurse through many container types, even if they contain\nmixed types, and produce resulting tables, arrays or aligned equations for\nLaTeX or Markdown. The output is configurable and a recipe system makes it easy\nto extend Latexify.jl to work with custom types without having to modify\nLatexify.jl itself. This becomes especially powerful in combination with\nJulia's metaprogramming facilities and easily generated domain-specific\nlanguages (DSLs). Latexify.jl can, for example, output the system of\ndifferential equations (and much more) that is automatically generated by a\nchemical reaction arrow DSL provided by Catalyst.jl [@diffeq].  \n\nThe package aims to support the scientific work-flow through facilitating\ninspection, automation and representation. Simple inspection of the equations\nthat a computational model is ultimately simulating may increase\ncomprehensibility and improve troubleshooting.  It, furthermore, allows for\nde-mystification of computational models generated using DSLs.  The\nprogrammatic formatting of equations and tables enables their automatic\ninclusion into generated documents, documentation, reports or posts (possibly\nin combination with tools such as Weave.jl [@weave]). Such programmatic\ntranslation can also help to ensure an accurate correspondence between what\nsoftware does and what reports or articles claim that they do.  It is also just\nrather convenient.\n\n\n# Acknowledgements\n\nI acknowledge the contributions from the Julia programming community and\nespecially those who through issues and pull requests have improved\nLatexify.jl. I would also like to acknowledge my PhD supervisor, Henrik\nJönsson, who supports me in my work while allowing me to allocate my efforts as\nI see fit.\n\nThe development of this package was, in part, supported by the Gatsby\nCharitable Foundation, grant GAT3395-PR4.\n\n# References\n"
  },
  {
    "path": "src/Latexify.jl",
    "content": "module Latexify\n\nif isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol(\"@optlevel\"))\n    @eval Base.Experimental.@optlevel 1\nend\nif isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol(\"@max_methods\"))\n    @eval Base.Experimental.@max_methods 1\nend\n\nusing LaTeXStrings\nusing InteractiveUtils\nusing Markdown\nusing MacroTools: postwalk\nimport MacroTools\nusing Format\nimport Base.showerror\nimport Ghostscript_jll\n\nexport latexify, md, copy_to_clipboard, auto_display, set_default, get_default,\n    reset_default, @latexrecipe, render, @latexify, @latexrun, @latexdefine\n\n## Allow some backwards compatibility until its time to deprecate.\nexport latexequation, latexarray, latexalign, latexraw, latexinline, latextabular, mdtable\n\nexport StyledNumberFormatter, FancyNumberFormatter, SiunitxNumberFormatter\n\nCOPY_TO_CLIPBOARD = false\nfunction copy_to_clipboard(x::Bool)\n    global COPY_TO_CLIPBOARD = x\nend\n\nAUTO_DISPLAY = false\nfunction auto_display(x::Bool)\n    global AUTO_DISPLAY = x\nend\n\nconst DEFAULT_DPI = Ref(300)\n\ninclude(\"unicode2latex.jl\")\ninclude(\"symbol_translations.jl\")\ninclude(\"latexraw.jl\")\ninclude(\"latexoperation.jl\")\ninclude(\"latexarray.jl\")\ninclude(\"latexalign.jl\")\ninclude(\"latexbracket.jl\")\ninclude(\"latexinline.jl\")\ninclude(\"latexequation.jl\")\ninclude(\"latextabular.jl\")\ninclude(\"default_kwargs.jl\")\ninclude(\"recipes.jl\")\ninclude(\"macros.jl\")\n\ninclude(\"mdtable.jl\")\ninclude(\"mdtext.jl\")\ninclude(\"md.jl\")\n\ninclude(\"utils.jl\")\ninclude(\"error.jl\")\n\ninclude(\"numberformatters.jl\")\n\ninclude(\"latexify_function.jl\")\ninclude(\"internal_recipes.jl\")\n\n### Add support for additional packages without adding them as dependencies.\n### Requires on <1.9 and weakdeps/extensions on >=1.9\nif !isdefined(Base, :get_extension)\nusing Requires\nend\n\n@static if !isdefined(Base, :get_extension)\nfunction __init__()\n    @require SymEngine = \"123dc426-2d89-5057-bbad-38513e3affd8\" begin\n        include(\"../ext/SymEngineExt.jl\")\n    end\n    @require DataFrames = \"a93c6f00-e57d-5684-b7b6-d8193f3e46c0\" begin\n        include(\"../ext/DataFramesExt.jl\")\n    end\n    @require SparseArrays =  \"2f01184e-e22b-5df5-ae63-d93ebab69eaf\" begin\n        include(\"../ext/SparseArraysExt.jl\")\n    end\n    @require tectonic_jll =  \"d7dd28d6-a5e6-559c-9131-7eb760cdacc5\" begin\n        include(\"../ext/TectonicExt.jl\")\n    end\nend\nend\n\nmacro generate_test(expr)\n    return :(clipboard(\"@test $($(string(expr))) == replace(\\nraw\\\"$($(esc(expr)))\\\", \\\"\\\\r\\\\n\\\"=>\\\"\\\\n\\\")\\n\"))\nend\n\n\"\"\"\n    @append_latexify_test!(fname, expr)\n\nGenerate a Latexify test and append it to the file `fname`.\n\nThe expression `expr` should return a string when evaluated.\n\nExample use:\n```\nLatexify.@append_latexify_test!(\"./tests/latexify_tests.jl\", latexify(:(x/y)))\n```\n\nThe macro returns the output of the expression and can often be rendered\nfor a visual check that the test itself is ok.\n```\nLatexify.@append_latexify_test!(\"./tests/latexify_tests.jl\", latexify(:(x/y))) |> render\n```\n\"\"\"\nmacro append_latexify_test!(fname, expr)\n    fname = esc(fname)\n    return :(\n    str = \"@test $($(string(expr))) == replace(\\nraw\\\"$($(esc(expr)))\\\", \\\"\\\\r\\\\n\\\"=>\\\"\\\\n\\\")\\n\\n\";\n    open($fname, \"a\") do f\n        write(f,str)\n    end;\n    $(esc(expr))\n    )\nend\n\n\"\"\"\n    @append_test!(fname, expr)\n\nBoth execute and append code to a test file.\n\nThe code can be either a normal expression or a string.\nExample use:\n```\nLatexify.@append_test A = [1 2; 3 4]\n```\n\nUseful for adding code that generates objects to be used in latexify tests.\n\"\"\"\nmacro append_test!(fname, str)\n    fname = esc(fname)\n    returnobj = str isa String ? Meta.parse(str) : str\n    printobj = str isa String ? str : string(MacroTools.striplines(str))\n    return :(\n    open($fname, \"a\") do f\n        write(f, $(esc(printobj)))\n        write(f, \"\\n\\n\")\n    end;\n    $(esc(returnobj))\n    )\nend\n\nend\n"
  },
  {
    "path": "src/default_kwargs.jl",
    "content": "const default_kwargs = Dict{Symbol, Any}()\n\n\"\"\"\n    set_default(; kwargs...)\n\nSet default kwarg values for latexify. \n\nThis works for all keyword arguments except `:env`. It is additive such that if\nyou call it multiple times, defaults will be added or replaced, but not reset.\n\nExample: \n```julia\nset_default(mult_symbol = \"\", transpose = true)\n```\n\nTo reset the defaults that you have set, use `reset_default`.\nTo see your specified defaults, use `get_default`.\n\"\"\"\nfunction set_default(; kwargs...)\n    for key in keys(kwargs)\n        default_kwargs[key] = kwargs[key]\n    end\nend\n\n\"\"\"\n    reset_default()\n\nReset user-specified default kwargs for latexify, set by `set_default`.\n\"\"\"\nreset_default() = empty!(default_kwargs)\n\n\"\"\"\n    get_default\n\nGet a Dict with the user-specified default kwargs for latexify, set by `set_default`.\n\"\"\"\nfunction get_default end\nget_default() = default_kwargs\nget_default(arg::Symbol) = default_kwargs[arg]\nget_default(args::AbstractArray) =  map(x->default_kwargs[x], args)\nget_default(args...) = Tuple(get_default(arg) for arg in args)\n"
  },
  {
    "path": "src/error.jl",
    "content": "abstract type LatexifyException <: Exception end\n\nstruct NoRecipeException <: LatexifyException\n    type::Type\nend\nfunction Base.showerror(io::IO, e::NoRecipeException)\n    return print(io, \"cannot latexify objects of type \", e.type)\nend\nstruct UnrecognizedExpressionException <: LatexifyException\n    ex::Expr\nend\nfunction Base.showerror(io::IO, e::UnrecognizedExpressionException)\n    return print(\n        io,\n        \"latexoperation does not know what to do with one of the expressions provided (\",\n        e.ex,\n        \")\",\n    )\nend\n\nstruct UnrepresentableException <: LatexifyException\n    desc::String\nend\nfunction Base.showerror(io::IO, e::UnrepresentableException)\n    return print(io, e.desc, \" cannot be represented as LaTeX\")\nend\n\nstruct MathParseError <: LatexifyException\n    input::String\nend\nfunction Base.showerror(io::IO, e::MathParseError)\n    return print(\n        io,\n        \"\"\"\n    You are trying to create LaTeX maths from a `String` that cannot be parsed as an expression: `\"\"\",\n        e.input,\n        \"\"\"`.\n`latexify` will, by default, try to parse any string inputs into expressions and this parsing has just failed.\nIf you are passing strings that you want returned verbatim as part of your input, try making them `LaTeXString`s first.\nIf you are trying to make a table with plain text entries, try passing the keyword argument `latex=false`.\nYou should also ensure that you have chosen an output environment that is capable of displaying non-maths objects.\nTry for example `env=:table` for a LaTeX table or `env=:mdtable` for a markdown table.\n\"\"\",\n    )\nend\n\nstruct RecipeException <: Exception\n    msg::String\nend\nBase.showerror(io::IO, e::RecipeException) = print(io, e.msg)\n\nstruct LatexifyRenderError <: Exception\n    logfilename::String\nend\nfunction Base.showerror(io::IO, e::LatexifyRenderError)\n    isfile(e.logfilename) ||\n        return println(io, \"an error occured while rendering LaTeX, no log file available.\")\n    println(io, \"an error occured while rendering LaTeX: \")\n    secondline = false\n    for l in eachline(e.logfilename)\n        if secondline\n            println(io, \"\\t\", l)\n            break\n        end\n        m = match(r\"^! (.*)$\", l)\n        isnothing(m) && continue\n        println(io, \"\\t\", m[1])\n        secondline = true\n    end\n    return print(io, \"Check the log file at \", e.logfilename, \" for more information\")\nend\n"
  },
  {
    "path": "src/internal_recipes.jl",
    "content": "\n@latexrecipe function f(x::UnitRange; expand_ranges=false)\n    expand_ranges && return collect(x)\n    return :($(x.start) : $(x.stop))\nend\n\n@latexrecipe function f(x::StepRange; expand_ranges=false, expand_step_ranges=true)\n    (expand_ranges || expand_step_ranges) && return collect(x)\n    return :($(x.start) : $(step(x)) : $(x.stop))\nend\n\n@latexrecipe function f(x::StepRangeLen{T, <:Any, <:Any}; expand_ranges=false, expand_step_ranges=true) where {T}\n    (expand_ranges || expand_step_ranges) && return collect(x)\n    return :($(T(x.ref + (x.offset-1)*step(x))) : $(T(x.step)) : $(T(x.ref + (x.len-1)*x.step)))\nend\n\n\n\n"
  },
  {
    "path": "src/latexalign.jl",
    "content": "\n@doc doc\"\"\"\n    latexalign()\nGenerate a ``LaTeX`` align environment from an input.\n\n# Examples\n## use with arrays\n\n```julia\nlhs = [:(dx/dt), :(dy/dt), :(dz/dt)]\nrhs = [:(y-x), :(x*z-y), :(-z)]\nlatexalign(lhs, rhs)\n```\n\n```LaTeX\n\\begin{align}\n\\frac{dx}{dt} &= y - x \\\\\\\\\n\\frac{dy}{dt} &= x \\cdot z - y \\\\\\\\\n\\frac{dz}{dt} &= - z \\\\\\\\\n\\end{align}\n```\n\n## use with ParameterizedFunction\n\n```julia-repl\njulia> using DifferentialEquations\njulia> ode = @ode_def foldChangeDetection begin\n    dm = r_m * (i - m)\n    dy = r_y * (p_y * i/m - y)\nend i r_m r_y p_y\n\njulia> latexalign(ode)\n```\n```LaTeX\n\\begin{align}\n\\frac{dm}{dt} &= r_{m} \\cdot \\left( i - m \\right) \\\\\\\\\n\\frac{dy}{dt} &= r_{y} \\cdot \\left( \\frac{p_{y} \\cdot i}{m} - y \\right) \\\\\\\\\n\\end{align}\n```\n\n\"\"\"\nlatexalign(args...; kwargs...) = process_latexify(args...; kwargs..., env=:align)\n\nfunction _latexalign(arr::AbstractMatrix; separator=\" &= \", double_linebreak=false, starred=false, rows=:all, aligned=false, kwargs...)\n    eol = double_linebreak ? \" \\\\\\\\\\\\\\\\\\n\" : \" \\\\\\\\\\n\"\n    arr = latexraw.(arr; kwargs...)\n    separator isa String && (separator = fill(separator, size(arr)[1]))\n    str = \"\"\n    if aligned\n        str *= \"\\\\begin{aligned}\\n\"\n    else\n        str *= \"\\\\begin{align$(starred ? \"*\" : \"\")}\\n\"\n    end\n    if rows == :all\n        iterate_rows = 1:(size(arr)[1])\n    else\n        iterate_rows = rows\n    end\n\n    for i in iterate_rows\n        if i != last(iterate_rows)\n            str *= join(arr[i,:], separator[i]) * eol\n        else\n            str *= join(arr[i,:], separator[i]) * \"\\n\"\n        end\n    end\n    if aligned\n        str *= \"\\\\end{aligned}\\n\"\n    else\n        str *= \"\\\\end{align$(starred ? \"*\" : \"\")}\\n\"\n    end\n    latexstr = LaTeXString(str)\n    COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend\n\nfunction _latexalign(lhs::AbstractArray, rhs::AbstractArray; kwargs...)\n    return latexalign(hcat(lhs, rhs); kwargs...)\nend\n\nfunction _latexalign(lhs::Tuple, rhs::Tuple; kwargs...)\n    return latexalign(hcat(collect(lhs), collect(rhs)); kwargs...)\nend\n\n_latexalign(args::Tuple...; kwargs...) = latexalign(safereduce(hcat, [collect(i) for i in args]); kwargs...)\n\n_latexalign(arg::Tuple; kwargs...) = latexalign(safereduce(hcat, [collect(i) for i in arg]); kwargs...)\n\nfunction _latexalign(nested::AbstractVector{AbstractVector}; kwargs...)\n    return latexalign(safereduce(hcat, nested); kwargs...)\nend\n\nfunction _latexalign(d::AbstractDict; kwargs...)\n    latexalign(collect(keys(d)), collect(values(d)); kwargs...)\nend\n\n\"\"\"\n    _latexalign(vec::AbstractVector)\n\nGo through the elements, split at any = sign, pass on as a matrix.\n\"\"\"\nfunction _latexalign(vec::AbstractVector; kwargs...)\n    lvec = _latexraw.(vec; kwargs...)\n    ## turn the array into a matrix\n    lmat = safereduce(hcat, split.(lvec, \" = \"))\n    ## turn the matrix into arrays of left-hand-side, right-hand-side.\n    larr = [lmat[i,:] for i in 1:size(lmat, 1)]\n    length(larr) < 2 && throw(ArgumentError(\"Invalid input to _latexalign().\"))\n    return latexalign( safereduce(hcat, larr) ; kwargs...)\nend\n"
  },
  {
    "path": "src/latexarray.jl",
    "content": "\n\"\"\"\n    latexarray{T}(arr::AbstractArray{T, 2})\nCreate a LaTeX array environment using [`latexraw`](@ref).\n\n# Examples\n```julia\narr = [1 2; 3 4]\nlatexarray(arr)\n```\n```math\n\"\\\\begin{equation}\\n\\\\left[\\n\\\\begin{array}{cc}\\n1 & 2\\\\\\\\ \\n3 & 4\\\\\\\\ \\n\\\\end{array}\\n\\\\right]\\n\\\\end{equation}\\n\"\n```\n\"\"\"\nlatexarray(args...; kwargs...) = process_latexify(args...;kwargs...,env=:array)\n\nfunction _latexarray(\n        arr::AbstractArray; adjustment=:c, transpose=false,\n        double_linebreak=false, starred=false, arraystyle=:square, kwargs...\n    )\n    if !(0 < ndims(arr) < 3)\n        sentinel = get(kwargs, :sentinel, nothing)\n        isnothing(sentinel) && throw(UnrepresentableException(\"n-dimensional tensors with n≠1,2\"))\n        return sentinel\n    end\n    transpose && (arr = permutedims(arr))\n    rows, columns = axes(arr, 1), axes(arr, 2)\n\n    eol = double_linebreak ? \" \\\\\\\\\\\\\\\\\\n\" : \" \\\\\\\\\\n\"\n\n    if adjustment isa AbstractArray\n        adjustmentstring = join(adjustment)\n    else\n        adjustmentstring = string(adjustment)^length(columns)\n    end\n\n    need_adjustmentstring = true\n    if arraystyle in AMSMATH_MATRICES ||\n        arraystyle isa NTuple{3,String} && arraystyle[3] == \"matrix\"\n        need_adjustmentstring = false\n    end\n    if arraystyle isa String\n        arraystyle = (\"\", \"\", arraystyle)\n    elseif arraystyle isa Symbol\n        arraystyle = ARRAYSTYLES[arraystyle]\n    end\n\n    str = string(arraystyle[1], \"\\\\begin{\", arraystyle[3], \"}\")\n    if need_adjustmentstring\n        str = str * string(\"{\", adjustmentstring, \"}\\n\")\n    else\n        str = str * \"\\n\"\n    end\n\n    for i in rows, j in columns\n        if isassigned(arr, i, j)\n            str *= latexraw(arr[i,j]; kwargs...)\n        else\n            str *= raw\"\\cdot\"\n        end\n        j == last(columns) ? (str *= eol) : (str *= \" & \")\n    end\n\n    str *= string(\"\\\\end{\", arraystyle[3], '}', arraystyle[2])\n    latexstr = LaTeXString(str)\n    # COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend\n\n_latexarray(args::AbstractArray...; kwargs...) = _latexarray(safereduce(hcat, args); kwargs...)\n_latexarray(arg::AbstractDict; kwargs...) = _latexarray(collect(keys(arg)), collect(values(arg)); kwargs...)\n_latexarray(arg::Tuple...; kwargs...) = _latexarray([collect(i) for i in arg]...; kwargs...)\n\nfunction _latexarray(arg::Tuple; kwargs...)\n    if first(arg) isa Tuple || first(arg) isa AbstractArray\n        return _latexarray([collect(i) for i in arg]...; kwargs...)\n    end\n    return _latexarray(collect(arg); kwargs...)\nend\n\nconst ARRAYSTYLES = Dict{Symbol, NTuple{3, String}}(\n                                                                         :array=>(\"\", \"\", \"array\"),\n                                        :square=>(\"\\\\left[\\n\", \"\\n\\\\right]\", \"array\"),\n                                        :round=>(\"\\\\left(\\n\", \"\\n\\\\right)\", \"array\"),\n                                        :curly=>(\"\\\\left\\\\{\\n\", \"\\n\\\\right\\\\}\", \"array\"),\n                                        :matrix=>(\"\",\"\",\"matrix\"),\n                                        :pmatrix=>(\"\",\"\",\"pmatrix\"),\n                                        :bmatrix=>(\"\",\"\",\"bmatrix\"),\n                                        :Bmatrix=>(\"\",\"\",\"Bmatrix\"),\n                                        :vmatrix=>(\"\",\"\",\"vmatrix\"),\n                                        :Vmatrix=>(\"\",\"\",\"Vmatrix\"),\n                                       )\nconst AMSMATH_MATRICES = [:matrix, :pmatrix, :bmatrix, :Bmatrix, :vmatrix, :Vmatrix]\n"
  },
  {
    "path": "src/latexbracket.jl",
    "content": "latexbracket(args...; kwargs...) = process_latexify(args...; kwargs..., env=:bracket)\n\nfunction _latexbracket(x; kwargs...)\n    latexstr = LaTeXString( \"\\\\[\\n\" * latexraw(x; kwargs...) * \"\\\\]\\n\")\n    COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend\n\n_latexbracket(args...; kwargs...) = latexbracket(args; kwargs...)\n"
  },
  {
    "path": "src/latexequation.jl",
    "content": "\nlatexequation(args...; kwargs...) = process_latexify(args...; kwargs..., env=:equation)\n\nfunction _latexequation(eq; starred=false, kwargs...)\n    latexstr = latexraw(eq; kwargs...)\n\n    str = \"\\\\begin{equation$(starred ? \"*\" : \"\")}\\n\"\n    str *= latexstr\n    str *= \"\\n\"\n    str *= \"\\\\end{equation$(starred ? \"*\" : \"\")}\\n\"\n    latexstr = LaTeXString(str)\n    COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend\n\n"
  },
  {
    "path": "src/latexify_function.jl",
    "content": "@doc doc\"\"\"\n    latexify(args...; kwargs...)\n\nLatexify a string, an expression, an array or other complex types.\n\n```julia-repl\njulia> latexify(\"x+y/(b-2)^2\")\nL\"$x + \\frac{y}{\\left( b - 2 \\right)^{2}}$\"\n\njulia> latexify(:(x/(y+x)^2))\nL\"$\\frac{x}{\\left( y + x \\right)^{2}}$\"\n\njulia> latexify([\"x/y\" 3//7 2+3im; 1 :P_x :(gamma(3))])\nL\"\\begin{equation}\n\\left[\n\\begin{array}{ccc}\n\\frac{x}{y} & \\frac{3}{7} & 2+3\\mathit{i} \\\\\n1 & P_{x} & \\Gamma\\left( 3 \\right) \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\"\n```\n\"\"\"\nfunction latexify(args...; kwargs...)\n    kwargs = merge(default_kwargs, kwargs)\n    result = process_latexify(args...; kwargs...)\n\n    should_render = get(kwargs, :render, false)\n    should_render isa Bool || throw(ArgumentError(\n        \"The keyword argument `render` must be either `true` or `false`. Got $should_render\"\n        ))\n\n    should_render && render(result)\n    COPY_TO_CLIPBOARD && clipboard(result)\n    AUTO_DISPLAY && display(result)\n    return result\nend\n\nfunction process_latexify(args...; kwargs...)\n    ## Let potential recipes transform the arguments.\n    args, kwargs = apply_recipe(args...; kwargs...)\n\n    ## If the environment is unspecified, use auto inference.\n    env = get(kwargs, :env, :auto)\n\n    latex_function = infer_output(env, args...)\n\n    result = latex_function(args...; kwargs...)\nend\n\napply_recipe(args...; kwargs...) = (args, kwargs)\n\n# These functions should only be called from inside `latexify()`, so that\n# `apply_recipe` gets a chance to change args\nconst OUTPUTFUNCTIONS = Dict(\n                             :inline    => _latexinline,\n                             :tabular   => _latextabular,\n                             :table     => _latextabular,\n                             :raw       => _latexraw,\n                             :array     => _latexarray,\n                             :align     => _latexalign,\n                             :aligned   => (args...; kwargs...) -> _latexbracket(_latexalign(args...; kwargs..., aligned=true, starred=false); kwargs...),\n                             :eq        => _latexequation,\n                             :equation  => _latexequation,\n                             :bracket   => _latexbracket,\n                             :mdtable   => _mdtable,\n                             :mdtext    => _mdtext,\n                            )\nfunction infer_output(env, args...)\n    env === :auto && return get_latex_function(args...)\n    # Must be like this, because items in OUTPUTFUNCTIONS must be defined\n    env in [:arrows, :chem, :chemical, :arrow] && return _chemical_arrows\n    return OUTPUTFUNCTIONS[env]\nend\n\n\"\"\"\n    get_latex_function(args...)\n\nUse overloading to determine which latex environment to output.\n\nThis determines the default behaviour of `latexify()` for different inputs.\n\"\"\"\nget_latex_function(args...) = _latexinline\nget_latex_function(args::AbstractArray...) = _latexequation\nget_latex_function(args::AbstractDict) = (args...; kwargs...) -> _latexequation(_latexarray(args...; kwargs...); kwargs...)\nget_latex_function(args::Tuple...) = (args...; kwargs...) -> _latexequation(_latexarray(args...; kwargs...); kwargs...)\nget_latex_function(arg::LaTeXString) = (arg; kwargs...) -> arg\n\nfunction get_latex_function(x::AbstractArray{T}) where T <: AbstractArray\n    try\n        x = safereduce(hcat, x)\n        return (args...; kwargs...) -> _latexequation(_latexarray(args...; kwargs...); kwargs...)\n    catch\n        return _latexinline\n    end\nend\n\nget_latex_function(lhs::AbstractVector, rhs::AbstractVector) = _latexalign\n"
  },
  {
    "path": "src/latexinline.jl",
    "content": "latexinline(args...;kwargs...) = process_latexify(args...;kwargs...,env=:inline)\n\nfunction _latexinline(x; kwargs...)\n    latexstr = latexstring( process_latexify(x; kwargs...,env=:raw) )\n    COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend"
  },
  {
    "path": "src/latexoperation.jl",
    "content": "\"\"\"\n    latexoperation(ex::Expr, prevOp::AbstractArray)\n\nTranslate a simple operation given by `ex` to LaTeX maths syntax.\nThis uses the information about the previous operations to decide if\na parenthesis is needed.\n\n\"\"\"\nfunction latexoperation(ex::Expr, prevOp::AbstractArray; kwargs...)::String\n    # If we used `mult_symbol` and `index` as keyword arguments before `kwargs...`\n    # and they are indeed contained in `kwargs`, they would get lost when\n    # passing `kwargs...` to `latexraw`below. Thus, we need to set default\n    # values as follows.\n    mult_symbol = get(kwargs, :mult_symbol, \"\\\\cdot\")\n    index = get(kwargs, :index, :bracket)\n\n    if haskey(kwargs, :cdot)\n        cdot = kwargs[:cdot]\n        mult_symbol = cdot ? \"\\\\cdot\" : \"\"\n        Base.depwarn(\"Latexify received the deprecated keyword argument cdot = $cdot and converted it to mult_symbol = \\\"$mult_symbol\\\". Pass the latter directly to remove this warning.\", :latexoperation)\n    end\n\n    op = ex.args[1]\n    string(op)[1] == '.' && (op = Symbol(string(op)[2:end]))\n\n    filter!(x -> !(x isa LineNumberNode), ex.args)\n    args = map(i -> typeof(i) ∉ (String, LineNumberNode) ? latexraw(i; kwargs...) : i, ex.args)\n\n    # Remove math italics for variables (i.e. words) longer than 2 characters.\n    # args = map(i -> (i isa String && all(map(isletter, collect(i))) && length(i) > 2) ? \"{\\\\rm $i}\" : i, args)\n\n    if ex.head == :latexifymerge\n        if all(prevOp .== :none)\n            return join(args)\n        else\n            return \"$(args[1])\\\\left( $(join(args[2:end])) \\\\right)\"\n        end\n    end\n\n    if ex.head == :call && op isa Function\n        # Convert Expr(:call, sin, 3) to Expr(:call, :sin, 3)\n        op = Symbol(op)\n    end\n\n    if op in [:/, ://]\n        return \"\\\\frac{$(args[2])}{$(args[3])}\"\n\n    elseif op in [:*]\n        str=\"\"\n        for i ∈ eachindex(args)[2:end]\n            arg = args[i]\n            (precedence(prevOp[i]) < precedence(op) || (ex.args[i] isa Complex && !iszero(ex.args[i].re))) && (arg = \"\\\\left( $arg \\\\right)\")\n            str = string(str, arg)\n            i == length(args) || (str *= mult_symbol == \"\" ? \" \" : \" $mult_symbol \")\n        end\n        return str\n\n    elseif op in [:+]\n        str = \"\"\n        for i ∈ eachindex(args)[2:end]\n            arg = args[i]\n            precedence(prevOp[i]) < precedence(op) && (arg = \"\\\\left( $arg \\\\right)\")\n            str = string(str, arg)\n            i == length(args) || (str *= \" + \")\n        end\n        str = replace(str, r\"\\+ *([\\-±∓])\"=>s\"\\1\")\n        return str\n\n    elseif op in [:±, :∓]\n        str = \"\"\n        if length(args) == 2\n            # unary\n            precedence(prevOp[2]) <= precedence(op) && return \"$(arithmetic_operators[op])\\\\left( $(args[2]) \\\\right)\"\n            return \"$(arithmetic_operators[op]) $(args[2])\"\n        end\n        for i ∈ eachindex(args)[2:end]\n            arg = args[i]\n            precedence(prevOp[i]) < precedence(op) && (arg = \"\\\\left( $arg \\\\right)\")\n            str = string(str, arg)\n            i == length(args) || (str *=\" $(arithmetic_operators[op]) \")\n        end\n        return str\n    elseif op in [:-]\n        if length(args) == 2\n            if prevOp[2] == :none && string(args[2])[1] == '-'\n                return \" + \" * string(args[2])[2:end]\n            elseif prevOp[2] == :none && string(args[2])[1] == '+'\n                return \" - \" * string(args[2])[2:end]\n            elseif precedence(prevOp[2]) ≤ precedence(:-) || (ex.args[2] isa Complex && !iszero(ex.args[2].re))\n                return \" - \\\\left( $(args[2]) \\\\right)\"\n            end\n            return \" - $(args[2])\"\n        end\n        if precedence(prevOp[3]) <= precedence(:-) ||\n            (ex.args[3] isa Complex && !iszero(ex.args[3].re))\n            args[3] = \"\\\\left( $(args[3]) \\\\right)\"\n        end\n        precedence(prevOp[2]) < precedence(:-) && (args[2] = \"\\\\left( $(args[2]) \\\\right)\")\n\n        if prevOp[3] ∈ keys(unary_operators)\n            return \"$(args[2]) $(replace(args[3], unary_operators[prevOp[3]] => unary_opposites[prevOp[3]]; count=1))\"\n        end\n        return replace(\"$(args[2]) - $(args[3])\", r\"- *-\"=>\"+ \")\n    elseif op in [:^]\n        if prevOp[2] in trigonometric_functions\n            str = get(functions, prevOp[2], \"\\\\$(prevOp[2])\")\n            return replace(args[2], str => \"$(str)^{$(args[3])}\")\n        end\n        if (prevOp[2] != :none) || (ex.args[2] isa Real && sign(ex.args[2]) == -1) || (ex.args[2] isa Complex && !iszero(ex.args[2].re)) || (ex.args[2] isa Rational)\n            args[2]=\"\\\\left( $(args[2]) \\\\right)\"\n        end\n        return \"$(args[2])^{$(args[3])}\"\n    elseif (ex.head in (:(=), :function)) && length(args) == 2\n        return \"$(args[1]) = $(args[2])\"\n    elseif op == :(!)\n        return \"\\\\neg $(args[2])\"\n    elseif op == :(:) && length(args) == 4\n        return \"$(args[2]) \\\\underset{$(args[3])}{$(binary_operators[:(:)])} $(args[4])\"\n    end\n\n    if ex.head == :.\n        if length(ex.args) >= 2 && (\n                                    ex.args[2] isa Expr && ex.args[2].head == :tuple\n                                   ||\n                                   ex.args[2] isa String\n                                  )\n            # broadcasted function call `f.(x)`\n            ex.head = :call\n        else\n            # property or field `f.x`\n            return \"$(ex.args[1]).$(ex.args[2] isa QuoteNode ? ex.args[2].value : ex.args[2])\"\n        end\n    end\n\n    if op in keys(binary_operators) && length(args) == 3\n        str = \"\"\n        if (precedence(prevOp[2]) < precedence(op)) ||\n            (precedence(prevOp[2]) == precedence(op) && associativity(op) != :left)\n            str = str*\"\\\\left( $(args[2]) \\\\right)\"\n        else\n            str = str*args[2]\n        end\n        str = str*\" $(binary_operators[op]) \"\n        if (precedence(prevOp[3]) < precedence(op)) ||\n            (precedence(prevOp[3]) == precedence(op) && associativity(op) != :right)\n            str = str*\"\\\\left( $(args[3]) \\\\right)\"\n        else\n            str = str*args[3]\n        end\n        return str\n    end\n\n    ### Check for chained comparison operators\n    if ex.head == :comparison\n        for argind in 2:2:length(args)\n            arg = args[argind]\n            string(arg)[1] == '.' && (arg = Symbol(string(arg)[2:end]))\n            args[argind] = get(comparison_operators, arg, string(arg))\n        end\n        str = join(args, \" \")\n        return str\n    end\n\n    if op in keys(functions)\n        return \"$(functions[op])\\\\left( $(join(args[2:end], \", \")) \\\\right)\"\n    end\n\n    op == :abs && return \"\\\\left|$(args[2])\\\\right|\"\n    op == :abs2 && return \"\\\\left|$(args[2])\\\\right|^{2}\"\n    op == :floor && return \"\\\\left\\\\lfloor $(last(args))\\\\right\\\\rfloor \"\n    op == :ceil && return \"\\\\left\\\\lceil $(last(args))\\\\right\\\\rceil \"\n    op == :round && return \"\\\\left\\\\lfloor $(last(args))\\\\right\\\\rceil \"\n    if op == :norm\n        length(args) == 2 && return \"\\\\left\\\\|$(args[2])\\\\right\\\\|\"\n        return \"\\\\left\\\\|$(args[2])\\\\right\\\\|_{$(args[3])}\"\n    end\n    op == :exp && return \"e^{$(args[2])}\"\n    op in (:sqrt, :√, :ssqrt) && return \"\\\\sqrt{$(args[2])}\"\n    op in (:cbrt, :∛, :scbrt) && return \"\\\\sqrt[3]{$(args[2])}\"\n    op in (:fourthroot, :∜) && return \"\\\\sqrt[4]{$(args[2])}\"\n    op in (:sum, :prod) && return \"\\\\$(op) $(args[2])\"\n    op == :binomial && return \"\\\\binom{$(args[2])}{$(args[3])}\"\n\n    ## Leave math italics for single-character operator names (e.g., f(x)).\n    # convert subscript symbols to \\_ if necessary, and make long function names\n    # upright\n    opname = operator_name(op; kwargs...);\n\n    if ex.head == :ref\n        if index == :subscript\n            if prevOp[1] == :ref\n                container = \"\\\\left( $(op) \\\\right)\"\n            else\n                container = opname\n            end\n            return \"$(container)_{$(join(args[2:end], \",\"))}\"\n        elseif index == :bracket\n            argstring = join(args[2:end], \", \")\n            prevOp[1] == :ref && return \"$op\\\\left[$argstring\\\\right]\"\n            return \"$opname\\\\left[$argstring\\\\right]\"\n        else\n            throw(ArgumentError(\"Incorrect `index` keyword argument to latexify. Valid values are :subscript and :bracket\"))\n        end\n    end\n\n    if ex.head == :macrocall && ex.args[1] == Symbol(\"@__dot__\")\n        return string(ex.args[end])\n    end\n\n    if ex.head == :macrocall\n        ex.head = :call\n    end\n\n    if ex.head == :call\n        if length(args) == 1\n            return \"$opname()\"\n        elseif args[2] isa String && occursin(\"=\", args[2])\n            return \"$opname\\\\left( $(join(args[3:end], \", \")); $(args[2]) \\\\right)\"\n        else\n            return \"$opname\\\\left( $(join(args[2:end], \", \")) \\\\right)\"\n        end\n    end\n\n    if ex.head == :tuple\n        # return \"\\\\left(\" * join(ex.args, \", \") * \"\\\\right)\"\n        return join(ex.args, \", \")\n    end\n\n    ex.head == Symbol(\"'\") && return \"$(args[1])'\"\n\n    ## Enable the parsing of kwargs in a function definition\n    ex.head == :kw && return \"$(args[1]) = $(args[2])\"\n    ex.head == :parameters && return join(args, \", \")\n\n    ## Use the last expression in a block.\n    ## This is somewhat shady but it helps with latexifying functions.\n    ex.head == :block && return args[end]\n\n    ## Sort out type annotations. Mainly for function arguments.\n    ex.head == :(::) && length(args) == 1 && return \"::$(args[1])\"\n    ex.head == :(::) && length(args) == 2 && return \"$(args[1])::$(args[2])\"\n\n    ## Pass back values that were explicitly returned.\n    ex.head == :return && length(args) == 1 && return args[1]\n\n    ## Case enviroment for if statements and ternary ifs.\n    if ex.head in (:if, :elseif)\n        textif::String = \"\\\\text{if }\"\n        begincases::String = ex.head == :if ? \"\\\\begin{cases}\\n\" : \"\"\n        endcases::String = ex.head == :if ? \"\\n\\\\end{cases}\" : \"\"\n        if length(args) == 3\n            # Check if already parsed elseif as args[3]\n            haselseif::Bool = occursin(Regex(\"\\\\$textif\"), args[3])\n            otherwise::String = haselseif ? \"\" : \" & \\\\text{otherwise}\"\n            return \"\"\"$begincases$(args[2]) & $textif $(args[1])\\\\\\\\\n                      $(args[3])$otherwise$endcases\"\"\"\n        elseif length(args) == 2\n            return \"$begincases$(args[2]) & $textif $(args[1])$endcases\"\n        end\n    end\n\n    ## Conditional operators converted to logical operators.\n    ex.head == :(&&) && length(args) == 2 && return \"$(args[1]) \\\\wedge $(args[2])\"\n    ex.head == :(||) && length(args) == 2 && return \"$(args[1]) \\\\vee $(args[2])\"\n\n    ## Anonymous function definition\n    ex.head == :(->) && length(args) == 2 && return \"$(args[1]) \\\\mapsto $(args[2])\"\n\n    ## if we have reached this far without a return, then error.\n    sentinel = get(kwargs, :sentinel, nothing)\n    isnothing(sentinel) && throw(UnrecognizedExpressionException(ex))\n    return sentinel\nend\n\nlatexoperation(sym::Symbol, prevOp::AbstractArray; kwargs...) = \"$sym\"\n\nfunction convert_subscript!(ex::Expr, kwargs...)\n    for i in 1:length(ex.args)\n        arg = ex.args[i]\n        if arg isa Symbol\n            ex.args[i] = convert_subscript(arg, kwargs...)\n        end\n    end\n    return nothing\nend\n\nfunction convert_subscript(str::String; snakecase=false, function_name=false, kwargs...)\n    subscript_list = split(str, r\"\\\\?_\")\n    if snakecase\n        return join(subscript_list, \"\\\\_\")\n    else\n        mainscript = subscript_list[1]\n        if function_name && length(mainscript) > 1 && isascii(mainscript)\n            mainscript = \"\\\\mathrm{$mainscript}\"\n        end\n        length(subscript_list) == 1 && return string(mainscript)\n        subscript = join(subscript_list[2:end], \"\\\\_\")\n        return \"$(mainscript)_{$subscript}\"\n    end\nend\n\nconvert_subscript(sym::Symbol; kwargs...) = convert_subscript(string(sym); kwargs...)\nconvert_subscript(n::Number; kwargs...) = convert_subscript(string(n); kwargs...)\n\noperator_name(sym; kwargs...) = convert_subscript(sym; kwargs..., function_name=true)\noperator_name(lnn::LineNumberNode;kwargs...) = \"\"\nfunction operator_name(ex::Expr; kwargs...)\n    if ex.head == :. && ex.args[2] isa QuoteNode\n        return convert_subscript(ex.args[1]; function_name=true, kwargs...) * \".\" * convert_subscript(ex.args[2].value; function_name=true, kwargs...)\n    else\n        error(\"I don't know what this is\")\n    end\nend\nfunction operator_name(str::LaTeXString; kwargs...)\n    return str\nend\n\n\"\"\"\n    precedence(op)\n\nThe operator precedence of `op` strictly with regards to parenthesization.\nIf `f(a, g(b, c))` must be written `a f (b g c)` then precedence(:f) > precedence(:g)\n\"\"\"\nfunction precedence(op::Symbol)\n    startswith(string(op), \"unary\") && return Base.prec_power # Putting unary on par with :^, because there are no integers between 14 and 15. Should consider putting it with :<< instead\n    op ∈ [:comparison, :issubset] && return Base.prec_comparison\n    #op == :∀ && return Base.prec_control_flow\n    op == :(:) && return 10\n    prec = Base.operator_precedence(op)\n    prec == 0 && return 100 # Base treats unknown as parenthesizable, we want no parenthesis if uncertain\n    return prec\nend\nfunction associativity(op::Symbol)\n    startswith(string(op), \"unary\") && return :right\n    op == :comparison && return :none\n    op == :issubset && return :none\n\n    return Base.operator_associativity(op)\nend\n"
  },
  {
    "path": "src/latexraw.jl",
    "content": "@doc doc\"\"\"\n    latexraw(arg)\n\nGenerate LaTeX equations from `arg`.\n\nParses expressions, ParameterizedFunctions, SymEngine.Base and arrays thereof.\nReturns a string formatted for LaTeX.\n\n# Examples\n\n## using expressions\n```jldoctest\nexpr = :(x/(y+x))\nlatexraw(expr)\n\n# output\n\n\"\\\\frac{x}{y + x}\"\n```\n\n```jldoctest\nexpr = Meta.parse(\"x/(y+x)\")\nlatexraw(expr)\n\n# output\n\n\"\\\\frac{x}{y + x}\"\n```\n\n## using ParameterizedFunctions\n```julia\nusing DifferentialEquations;\nf = @ode_def feedback begin\n         dx = y/c_1 - x\n         dy = x^c_2 - y\n       end c_1=>1.0 c_2=>1.0\nlatexraw(f)\n\n# output\n\n2-element Array{String,1}:\n \"dx/dt = \\\\frac{y}{c_{1}} - x\"\n \"dy/dt = x^{c_{2}} - y\"\n```\n\n## using SymEngine\n```jldoctest\nusing SymEngine\n@vars x y\nsymExpr = x + x + x*y*y\nlatexraw(symExpr)\n\n# output\n\n\"2 \\\\cdot x + x \\\\cdot y^{2}\"\n```\n\"\"\"\nlatexraw(args...; kwargs...) = process_latexify(args...; kwargs..., env=:raw)\n\nfunction _latexraw(inputex::Expr; convert_unicode=true, kwargs...)\n    ## Pass all arrays or matrices in the expr to latexarray\n    inputex = postwalk(x -> Meta.isexpr(x, [:hcat, :vcat, :vect, :typed_vcat, :typed_hcat]) ?\n                       latexarray(expr_to_array(x); kwargs...)\n                       : x,\n                       inputex)\n\n    recurseexp!(lstr::LaTeXString) = lstr.s\n    function recurseexp!(ex)\n        prevOp = fill(:none, length(ex.args))\n        if Meta.isexpr(ex, :call) && ex.args[1] in (:sum, :prod) && Meta.isexpr(ex.args[2], :generator)\n            op = ex.args[1]\n            term = latexraw(ex.args[2].args[1])\n            gen = ex.args[2].args[2]\n            itervar = latexraw(gen.args[1])\n            if Meta.isexpr(gen.args[2], :call) && gen.args[2].args[1] == :(:)\n                # sum(x_n for n in n_0:N) => \\sum_{n=n_0}^{N} x_n\n                lower = latexraw(gen.args[2].args[2])\n                upper = latexraw(gen.args[2].args[end])\n                return \"\\\\$(op)_{$(itervar) = $(lower)}^{$(upper)} $term\"\n            elseif gen.args[2] in (:_, :(:))\n                # sum(x_n for n in :) => \\sum_{n} x_n\n                return \"\\\\$(op)_{$(itervar)} $term\"\n            else\n                # sum(x_n for n in N) => \\sum_{n \\in N} x_n\n                set = latexraw(gen.args[2])\n                return \"\\\\$(op)_{$(itervar) \\\\in $set} $term\"\n            end\n        else\n            for i in 1:length(ex.args)\n                prevOp[i] = _getoperation(ex.args[i])\n                if isa(ex.args[i], Expr)\n                    ex.args[i] = recurseexp!(ex.args[i])\n                elseif ex.args[i] isa AbstractArray\n                    ex.args[i] = latexraw(ex.args[i]; kwargs...)\n                end\n            end\n            return latexoperation(ex, prevOp; convert_unicode=convert_unicode, kwargs...)\n        end\n    end\n    ex = deepcopy(inputex)\n    str = recurseexp!(ex)\n    convert_unicode && (str = unicode2latex(str))\n    return LaTeXString(str)\nend\n\n\nfunction _latexraw(args...; kwargs...)\n    length(args) > 1 && return _latexraw(args; kwargs...)\n    sentinel = get(kwargs, :sentinel, nothing)\n    isnothing(sentinel) && throw(NoRecipeException(typeof(args[1])))\n    return sentinel\nend\n_latexraw(arr::Union{AbstractArray, Tuple}; kwargs...) = _latexarray(arr; kwargs...)\n_latexraw(i::Nothing; kwargs...) = \"\"\n_latexraw(i::SubString; parse=true, kwargs...) = latexraw(parse ? Meta.parse(i) : i; kwargs...)\n_latexraw(i::SubString{LaTeXStrings.LaTeXString}; kwargs...) = i\n_latexraw(i::Rational; kwargs...) = i.den == 1 ? latexraw(i.num; kwargs...) : latexraw(:($(i.num)/$(i.den)); kwargs...)\n_latexraw(i::QuoteNode; kwargs...) = _latexraw(i.value; kwargs...)\n_latexraw(i::Function; kwargs...) = _latexraw(Symbol(i); kwargs...)\n\nfunction _latexraw(z::Complex; kwargs...)\n    if iszero(z.re)\n        isone(z.im) && return LaTeXString(get(kwargs, :imaginary_unit, \"\\\\mathit{i}\"))\n        isone(-z.im) && return LaTeXString(\"-$(get(kwargs, :imaginary_unit, \"\\\\mathit{i}\"))\")\n        return LaTeXString(\"$(latexraw(z.im))$(get(kwargs, :imaginary_unit, \"\\\\mathit{i}\"))\")\n    end\n    return LaTeXString(\"$(latexraw(z.re;kwargs...))$(z.im < 0 ? \"-\" : \"+\" )$(latexraw(abs(z.im);kwargs...))$(get(kwargs, :imaginary_unit, \"\\\\mathit{i}\"))\")\nend\n#latexraw(i::DataFrames.DataArrays.NAtype) = \"\\\\textrm{NA}\"\n_latexraw(str::LaTeXStrings.LaTeXString; kwargs...) = str\n\nfunction _latexraw(i::Number; fmt=PlainNumberFormatter(), kwargs...)\n    try isinf(i) && return LaTeXString(\"$(sign(i) == -1 ? \"-\" : \"\")\\\\infty\") catch; end\n    fmt isa String && (fmt = PrintfNumberFormatter(fmt))\n    return fmt(i)\nend\n\nfunction _latexraw(i::Char; convert_unicode=true, kwargs...)\n    LaTeXString(convert_unicode ? unicode2latex(string(i)) : string(i))\nend\n\nfunction _latexraw(i::Symbol; convert_unicode=true, snakecase=false, safescripts=false, kwargs...)\n    str = get(special_symbols, i, string(i))\n    str = convert_subscript(str; snakecase=snakecase)\n    convert_unicode && (str = unicode2latex(str; safescripts=safescripts))\n    return LaTeXString(str)\nend\n\n_latexraw(i::String; parse=true, kwargs...) = _latexraw(Val(parse), i; kwargs...)\n\n_latexraw(::Val{false}, i::String; convert_unicode=true, kwargs...) =\n    LaTeXString(convert_unicode ? unicode2latex(i) : i)\n\nfunction _latexraw(::Val{true}, i::String; kwargs...)\n    try\n        ex = Meta.parse(i)\n        return latexraw(ex; kwargs...)\n    catch err\n        err isa Meta.ParseError && rethrow(MathParseError(i))\n        rethrow(err)\n    end\nend\n\n_latexraw(i::Missing; kwargs...) = \"\\\\textrm{NA}\"\n\n\"\"\"\n    _getoperation(x)\n\nCheck if `x` represents something that could affect the vector of previous operations.\n`:none` by default, recipes can use `operation-->:something` to hack this.\n\"\"\"\nfunction _getoperation(ex::Expr)\n    ex.head == :comparison && return :comparison\n    ex.head == :ref && return :ref\n    ex.head == :call || return :none\n    if length(ex.args) > 1 && (op = ex.args[1]) isa Symbol\n        if length(ex.args) == 2\n            # These are unary operators\n            op == :- && return :unaryminus\n            op == :+ && return :unaryplus\n            op == :± && return :unaryplusminus\n            op == :∓ && return :unaryminusplus\n        end\n        return op\n    end\n    return :none\nend\n_getoperation(x) = :none\n\n"
  },
  {
    "path": "src/latextabular.jl",
    "content": "latextabular(args...; kwargs...) = process_latexify(args...; kwargs..., env=:tabular)\n\nfunction _latextabular(arr::AbstractMatrix; latex::Bool=true, booktabs::Bool=false, head=[], side=[], adjustment=:c, transpose=false, kwargs...)\n    transpose && (arr = permutedims(arr, [2,1]))\n\n    if !isempty(head)\n        arr = vcat(safereduce(hcat, head), arr)\n        @assert length(head) == size(arr, 2) \"The length of the head does not match the shape of the input matrix.\"\n    end\n    if !isempty(side)\n        length(side) == size(arr, 1) - 1 && (side = [\"\"; side])\n        @assert length(side) == size(arr, 1) \"The length of the side does not match the shape of the input matrix.\"\n        arr = hcat(side, arr)\n    end\n\n    (rows, columns) = size(arr)\n\n    if ~isa(adjustment, AbstractArray)\n        adjustment = fill(adjustment, columns)\n    end\n    adjustmentstring = join(adjustment)\n    str = \"\\\\begin{tabular}{$adjustmentstring}\\n\"\n\n    if booktabs\n        str *= \"\\\\toprule\\n\"\n    end\n\n    formatter = get(kwargs, :fmt, nothing)\n    if formatter isa String\n        formatter = PrintfNumberFormatter(formatter)\n    end\n    if formatter isa SiunitxNumberFormatter && any(==(:S), adjustment)\n        # Do not format cell contents, \"S\" column type handles it\n        formatter = string\n    end\n\n    if latex\n        arr = latexinline.(arr; kwargs...)\n    elseif ~isnothing(formatter)\n        arr = map(x -> x isa Number ? formatter(x) : x, arr)\n    end\n\n    # print first row\n    str *= join(arr[1,:], \" & \")\n    str *= \"\\\\\\\\\\n\"\n\n    if booktabs && !isempty(head)\n        str *= \"\\\\midrule\\n\"\n    end\n\n    for i in 2:size(arr, 1)\n        str *= join(arr[i,:], \" & \")\n        str *= \"\\\\\\\\\\n\"\n    end\n\n    if booktabs\n        str *= \"\\\\bottomrule\\n\"\n    end\n\n    str *= \"\\\\end{tabular}\\n\"\n    latexstr = LaTeXString(str)\n    COPY_TO_CLIPBOARD && clipboard(latexstr)\n    return latexstr\nend\n\n\n_latextabular(vec::AbstractVector; kwargs...) = latextabular(safereduce(hcat, vec); kwargs...)\n_latextabular(vectors::AbstractVector...; kwargs...) = latextabular(safereduce(hcat, vectors); kwargs...)\n_latextabular(dict::AbstractDict; kwargs...) = latextabular(hcat(collect(keys(dict)), collect(values(dict))); kwargs...)\n"
  },
  {
    "path": "src/macros.jl",
    "content": "\"\"\"\n    @latexify expression\n\nCreate `LaTeXString` representing `expression`.\nVariables and expressions can be interpolated with `\\$`.\nKeyword arguments can be supplied to `latexify` by appending to the argument.\n\n# Examples\n```julia-repl\njulia> @latexify x^2 + 3/2\nL\"\\$x^{2} + \\\\frac{3}{2}\\$\"\n\njulia> @latexify x^2 + \\$(3/2)\nL\"\\$x^{2} + 1.5\\$\"\n\njulia> @latexify x^2 + 3/2 env=:raw\nL\"x^{2} + \\\\frac{3}{2}\"\n```\n\nSee also [`latexify`](@ref), [`@latexrun`](@ref), [`@latexdefine`](@ref).\n\"\"\"\nmacro latexify(expr, kwargs...)\n    return esc(\n        Expr(\n            :call, :latexify, Expr(:parameters, _extractparam.(kwargs)...), Meta.quot(expr)\n        ),\n    )\nend\n\n\"\"\"\n    @latexrun expression\n\nLatexify and evaluate `expression`. Useful for expressions with side effects, like assignments.\n\n# Examples\n```julia-repl\njulia> @latexrun y = 3/2 + \\$(3/2)\nL\"\\$y = \\\\frac{3}{2} + 1.5\\$\"\n\njulia> y\n3.0\n```\nSee also [`@latexify`](@ref), [`@latexdefine`](@ref).\n\"\"\"\nmacro latexrun(expr, kwargs...)\n    return esc(\n        Expr(\n            :block,\n            _executable(expr),\n            Expr(\n                :call,\n                :latexify,\n                Expr(:parameters, _extractparam.(kwargs)...),\n                Meta.quot(expr),\n            ),\n        ),\n    )\nend\n\n\"\"\"\n    @latexdefine expression\n\nLatexify `expression`, followed by an equals sign and the return value of its evaluation.\nAny side effects of the expression, like assignments, are evaluated as well.\nThe RHS can be formatted or otherwise transformed by supplying a function as kwarg `post`.\n\n# Examples\n```julia-repl\njulia> @latexdefine y = 3/2 + \\$(3/2) env=:equation\nL\"\\\\begin{equation}\ny = \\\\frac{3}{2} + 1.5 = 3.0\n\\\\end{equation}\n\"\n\njulia> y\n3.0\n\njulia> @latexdefine y=π post=round\nL\"\\$x = \\\\pi = 3.0\\$\"\n```\nSee also [`@latexify`](@ref), [`@latexrun`](@ref).\n\"\"\"\nmacro latexdefine(expr, kwargs...)\n    params = _extractparam.(kwargs)\n    post = :identity\n    for param in params\n        if param === :post\n            post = :post\n            break\n        end\n        if param isa Expr && param.args[1] === :post\n            post = param.args[2]\n            break\n        end\n    end\n\n    return esc(\n        Expr(\n            :call,\n            :latexify,\n            Expr(:parameters, _extractparam.(kwargs)...),\n            Expr(:call, :Expr, QuoteNode(:(=)), Meta.quot(expr), Expr(:call, post, _executable(expr))),\n        ),\n    )\nend\n\nfunction _executable(expr)\n    return postwalk(expr) do ex\n        if Meta.isexpr(ex, :$)\n            return ex.args[1]\n        end\n        return ex\n    end\nend\n\n_extractparam(arg::Symbol) = arg\n_extractparam(arg::Expr) = Expr(:kw, arg.args[1], arg.args[2])\n"
  },
  {
    "path": "src/md.jl",
    "content": "\n\nfunction md(args...; env=:auto, kwargs...)\n    md_function = infer_md_output(env, args...)\n\n    m = md_function(args...; kwargs...)\n    COPY_TO_CLIPBOARD && clipboard(m)\n    AUTO_DISPLAY && display(m)\n    return m\nend\n\nmdalign(args...; kwargs...) = latexalign(args...; kwargs...)\nmdarray(args...; kwargs...) = latexarray(args...; kwargs...)\nmd_chemical_arrows(args...; kwargs...) = chemical_arrows(args...; kwargs...)\n\nconst MDOUTPUTS = Dict(\n                       :table => mdtable,\n                       :text => mdtext,\n                       :align => mdalign,\n                       :array => mdarray,\n                       :inline => latexinline\n                      )\nfunction infer_md_output(env, args...)\n    env === :auto && return get_md_function(args...)\n    env in [:arrows, :chem, :chemical, :arrow] && return md_chemical_arrows\n    return MDOUTPUTS[env]\nend\n\n\"\"\"\n    get_md_function(args...)\n\nUse overloading to determine what MD output to generate.\n\nThis determines the default behaviour of `md()` for different inputs.\n\"\"\"\nget_md_function(args...) = mdtext\nget_md_function(args::AbstractArray...) = mdtable\nget_md_function(args::AbstractDict) = mdtable\nget_md_function(args::Tuple) = mdtable\n"
  },
  {
    "path": "src/mdtable.jl",
    "content": "@doc doc\"\"\"\n    mdtable(array; latex=true, head=[], side=[], transpose=false)\n\nLatexify the input and output a markdown-formatted table.\n\n```julia\njulia> using Latexify\njuila> copy_to_clipboard(true)\njulia> M = [\"x/y\" 1//2\n            \"p_m\" \"e^2\"]\njulia> mdtable(M)\n```\n\n| $\\frac{x}{y}$ | $\\frac{1}{2}$ |\n| -------------:| -------------:|\n|       $p_{m}$ |       $e^{2}$ |\n\n```julia\njulia> head = [\"Column 1\", \"Column 2\"]\njulia> side = [\"Row 1\", \"Row 2\"]\njulia> mdtable(M; head=head, side=side)\n```\n\n|     . |      Column 1 |      Column 2 |\n| -----:| -------------:| -------------:|\n| Row 1 | $\\frac{x}{y}$ | $\\frac{1}{2}$ |\n| Row 2 |       $p_{m}$ |       $e^{2}$ |\n\n\nThe value in the top right corner can be set if you let the `side` vector be one element\nlarger than the number of rows of your input:\n\n```julia\njulia> side = [\"Corner\", \"Row 1\", \"Row 2\"]\njulia> mdtable(M; head=head, side=side)\n```\n\n| Corner |      Column 1 |      Column 2 |\n| ------:| -------------:| -------------:|\n|  Row 1 | $\\frac{x}{y}$ | $\\frac{1}{2}$ |\n|  Row 2 |       $p_{m}$ |       $e^{2}$ |\n\n\nThe `head` and `side` vectors are not latexifed, but you can easily do this yourself:\n\n```julia\njulia> head = [\"p_1\", \"p_2\"]\njulia> mdtable(M; head=latexinline(head))\n```\n\n|       $p_{1}$ |       $p_{2}$ |\n| -------------:| -------------:|\n| $\\frac{x}{y}$ | $\\frac{1}{2}$ |\n|       $p_{m}$ |       $e^{2}$ |\n\"\"\"\nmdtable(args...; kwargs...) = latexify(args...; kwargs..., env=:mdtable)\n\nfunction _mdtable(M::AbstractMatrix; latex::Bool=true, escape_underscores=false, head=[], side=[], transpose=false, adjustment=nothing, kwargs...)\n    transpose && (M = permutedims(M, [2,1]))\n    if latex\n        M = _latexinline.(M; kwargs...)\n    elseif haskey(kwargs, :fmt)\n        formatter = kwargs[:fmt] isa String ? PrintfNumberFormatter(kwargs[:fmt]) : kwargs[:fmt]\n        M = map(x -> x isa Number ? formatter(x) : x, M)\n    end\n\n    if !isempty(head)\n        M = vcat(safereduce(hcat, head), M)\n        @assert length(head) == size(M, 2) \"The length of the head does not match the shape of the input matrix.\"\n    end\n    if !isempty(side)\n        length(side) == size(M, 1) - 1 && (side = [LaTeXString(\"∘\"); side])\n        @assert length(side) == size(M, 1) \"The length of the side does not match the shape of the input matrix.\"\n        M = hcat(side, M)\n    end\n\n    if adjustment isa AbstractArray\n        headerrules = get_header_rule.(adjustment)\n    else\n        headerrules = fill(get_header_rule(adjustment), size(M, 2))\n    end\n\n    t = \"| \" * join(M[1,:], \" | \") * \" |\\n\"\n    size(M, 1) > 1 && (t *= \"| \" * join(headerrules, \" | \") * \" |\\n\")\n    for i in 2:size(M,1)\n        t *= \"| \" * join(M[i,:], \" | \") * \" |\\n\"\n    end\n\n    escape_underscores && (t = replace(t, \"_\"=>\"\\\\_\"))\n    t = Markdown.parse(t)\n    COPY_TO_CLIPBOARD && clipboard(t)\n    return t\nend\n\n_mdtable(v::AbstractArray; kwargs...) = _mdtable(reshape(v, (length(v), 1)); kwargs...)\n_mdtable(v::AbstractArray...; kwargs...) = _mdtable(safereduce(hcat, v); kwargs...)\n_mdtable(d::AbstractDict; kwargs...) = _mdtable(collect(keys(d)), collect(values(d)); kwargs...)\n_mdtable(arg::Tuple; kwargs...) = _mdtable(safereduce(hcat, [collect(i) for i in arg]); kwargs...)\n\nget_header_rule(::Nothing) = \"-------\"\nfunction get_header_rule(adjustment::Symbol)\n    adjustment === :c && return \":----:\"\n    adjustment === :l && return \":-----\"\n    adjustment === :r && return \"-----:\"\n    throw(ArgumentError(\"Unknown `adjustment` argument \\\"$adjustment\\\"\"))\nend\n\n"
  },
  {
    "path": "src/mdtext.jl",
    "content": "mdtext(args...; kwargs...) = latexify(args...; kwargs..., env=:mdtext)\n\nfunction _mdtext(s::String; escape_underscores = false, kwargs...)\n    escape_underscores && (s = replace(s, \"_\"=>\"\\\\_\"))\n    m = Markdown.parse(s)\n    return m\nend\n"
  },
  {
    "path": "src/numberformatters.jl",
    "content": "abstract type AbstractNumberFormatter end\n\n(::AbstractNumberFormatter)(x) = string(x)\n\nconst float_regex = r\"(?'mantissa'(?'before_dp'(?'sign'-?)(?'before_dp_nosign'\\d+))(\\.(?'after_dp'\\d+))?)(?'e_or_E'e)(?'raw_exp'(?'sign_exp'-?)\\+?0*(?'mag_exp'\\d+))\"i\n\nstruct PlainNumberFormatter <: AbstractNumberFormatter end\n\nstruct PrintfNumberFormatter <: AbstractNumberFormatter\n    fmt::String\n    f::Function\n\n    PrintfNumberFormatter(fmt::String) = new(fmt, Format.generate_formatter(fmt))\nend\n\n(f::PrintfNumberFormatter)(x) = f.f(x)\n\nstruct StyledNumberFormatter <: AbstractNumberFormatter\n    fmt::String\n    f::Function\n\n    StyledNumberFormatter(fmt::String=\"%.4g\") = new(fmt, Format.generate_formatter(fmt))\nend\n\nStyledNumberFormatter(significant_digits::Int) = StyledNumberFormatter(\"%.$(significant_digits)g\")\n\n(f::StyledNumberFormatter)(x::AbstractFloat) =\n    replace(f.f(x), float_regex => s\"\\g<mantissa> \\\\mathrm{\\g<e_or_E>}{\\g<sign_exp>\\g<mag_exp>}\")\n(f::StyledNumberFormatter)(x::Unsigned) = \"\\\\mathtt{0x$(string(x; base=16, pad=2sizeof(x)))}\"\n\n\nstruct FancyNumberFormatter <: AbstractNumberFormatter\n    fmt::String\n    f::Function\n    exponent_format::SubstitutionString\n\n    FancyNumberFormatter(fmt::String=\"%.4g\",\n                         exponent_format::SubstitutionString=s\"\\g<mantissa> \\\\cdot 10^{\\g<sign_exp>\\g<mag_exp>}\") = new(fmt, Format.generate_formatter(fmt), exponent_format)\nend\n\nFancyNumberFormatter(fmt::String, mult_symbol) =\n    FancyNumberFormatter(fmt, SubstitutionString(\"\\\\g<mantissa> $(escape_string(mult_symbol)) 10^{\\\\g<sign_exp>\\\\g<mag_exp>}\"))\nFancyNumberFormatter(significant_digits, mult_symbol=\"\\\\cdot\") =\n    FancyNumberFormatter(\"%.$(significant_digits)g\", mult_symbol)\n\n\n(f::FancyNumberFormatter)(x::AbstractFloat) = replace(f.f(x), float_regex => f.exponent_format)\n(f::FancyNumberFormatter)(x::Unsigned) = \"\\\\mathtt{0x$(string(x; base=16, pad=2sizeof(x)))}\"\n\nstruct SiunitxNumberFormatter <: AbstractNumberFormatter\n    format_options::String\n    version::Int\n    simple::Bool\nend\nfunction SiunitxNumberFormatter(;format_options=\"\", version=3, simple=false)\n    if ~isempty(format_options) && (~startswith(format_options, '[') || ~endswith(format_options, ']'))\n        format_options = \"[$format_options]\"\n    end\n    SiunitxNumberFormatter(format_options, version, simple)\nend\n\nfunction (f::SiunitxNumberFormatter)(x::Number)\n    return \"\\\\num$(f.format_options){$x}\"\nend\nfunction (f::SiunitxNumberFormatter)(x::Vector{<:Number})\n    return \"\\\\numlist$(f.format_options){$(join(x,';'))}\"\nend\nfunction (f::SiunitxNumberFormatter)(x::AbstractRange{<:Number})\n    return \"\\\\numrange$(f.format_options){$(x.start)}{$(x.stop)}\"\nend\n"
  },
  {
    "path": "src/recipes.jl",
    "content": "# Much of this is copied/adapted from RecipesBase.jl. Cred to everyone who has\n# worked on that package!\n\nconst _debug_recipes = Bool[false]\nfunction debug(v::Bool = true)\n    _debug_recipes[1] = v\nend\n\n# check for flags as part of the `-->` expression\nfunction _is_arrow_tuple(expr::Expr)\n    expr.head == :tuple && !isempty(expr.args) &&\n        isa(expr.args[1], Expr) &&\n        expr.args[1].head == :(-->)\nend\n\nfunction _equals_symbol(arg::Symbol, sym::Symbol)\n    arg == sym\nend\nfunction _equals_symbol(arg::Expr, sym::Symbol) #not sure this method is necessary anymore on 0.7\n    arg.head == :quote && arg.args[1] == sym\nend\nfunction _equals_symbol(arg::QuoteNode, sym::Symbol)\n    arg.value == sym\nend\n_equals_symbol(x, sym::Symbol) = false\n\nfunction create_kw_body(func_signature::Expr)\n    # get the arg list, stripping out any keyword parameters into a\n    # bunch of get!(kw, key, value) lines\n    func_signature.head == :where && return create_kw_body(func_signature.args[1])\n    args = func_signature.args[2:end]\n    kw_body = Expr(:block)\n    kw_dict = Dict{Symbol, Any}()\n    if isa(args[1], Expr) && args[1].head == :parameters\n        for kwpair in args[1].args\n            k, v = kwpair.args\n            if isa(k, Expr) && k.head == :(::)\n                k = k.args[1]\n                @warn(\"Type annotations on keyword arguments not currently supported in recipes. Type information has been discarded\")\n            end\n            push!(kw_body.args, :($k = kwargs[$(Meta.quot(k))]))\n            if v == :nothing\n                kw_dict[k] = nothing\n            else\n                kw_dict[k] = v isa QuoteNode ? v.value : v\n            end\n        end\n        args = args[2:end]\n    end\n    args, kw_body, kw_dict\nend\n\n# build an apply_recipe function header from the recipe function header\nfunction get_function_def(func_signature::Expr, args::Vector)\n    front = func_signature.args[1]\n    kwarg_expr = Expr(:parameters, Expr(:..., esc(:kwargs)))\n    if func_signature.head == :where\n        Expr(:where, get_function_def(front, args), esc.(func_signature.args[2:end])...)\n    elseif func_signature.head == :call\n        #= func = Expr(:call, :(Latexify.apply_recipe), esc.(args)..., Expr(:parameters, :kwargs)) =#\n        func = Expr(:call, :(Latexify.apply_recipe), kwarg_expr, esc.(args)...)\n        if isa(front, Expr) && front.head == :curly\n            Expr(:where, func, esc.(front.args[2:end])...)\n        else\n            func\n        end\n    else\n        throw(RecipeException(\"Expected `func_signature = ...` with func_signature as a call or where Expr... got: $func_signature\"))\n    end\nend\n\n# process the body of the recipe recursively.\n# when we see the series macro, we split that block off:\n    # let\n    #   d2 = copy(d)\n    #   <process_recipe_body on d2>\n    #   RecipeData(d2, block_return)\n    # end\n# and we push this block onto the series_blocks list.\n# then at the end we push the main body onto the series list\nfunction process_recipe_body!(expr::Expr)\n    operation = QuoteNode(:none)\n    for (i,e) in enumerate(expr.args)\n        if isa(e,Expr)\n\n            # process trailing flags, like:\n            #   a --> b, :force\n            force = false\n            if _is_arrow_tuple(e)\n                for flag in e.args\n                    if _equals_symbol(flag, :force)\n                        force = true\n                    end\n                end\n                e = e.args[1]\n            end\n\n            if e.head == :(:=)\n                force = true\n                e.head = :(-->)\n            end\n\n            # we are going to recursively swap out `a --> b, flags...` commands\n            # note: this means \"x may become 5\"\n            if e.head == :(-->)\n                k, v = e.args\n                if isa(k, Symbol)\n                    if k == :operation\n                        operation = v\n                        expr.args[i] = nothing\n                        continue\n                    end\n                    k = QuoteNode(k)\n                end\n\n                set_expr = if force\n                    :(kwargs[$k] = $v)\n                else\n                    :(haskey(kwargs, $k) || (kwargs[$k] = $v))\n                end\n\n                quiet = false\n                expr.args[i] = set_expr\n\n            elseif e.head != :call\n                # we want to recursively replace the arrows, but not inside function calls\n                # as this might include things like Dict(1=>2)\n                process_recipe_body!(e)\n            end\n\n            if  e.head == :return\n                if e.args[1] isa Expr\n                    if e.args[1] isa Tuple\n                        e.args[1] = :(($(e.args[1]), kwargs))\n                    else\n                        e.args[1] = :((($(e.args[1]),), kwargs))\n                    end\n                else\n                    e.args[1] = :((($(e.args[1]),), kwargs))\n                end\n            end\n        end\n    end\n    return operation\nend\n\nmacro latexrecipe(funcexpr)\n    func_signature, func_body = funcexpr.args\n\n    if !(funcexpr.head in (:(=), :function))\n        throw(RecipeException(\"Must wrap a valid function call!\"))\n    end\n\n    if !(isa(func_signature, Expr) && func_signature.head in (:call, :where))\n        throw(RecipeException(\"Expected `func_signature = ...` with func_signature as a call or where Expr... got: $func_signature\"))\n    end\n\n    if length(func_signature.args) < 2\n        throw(RecipeException(\"Missing function arguments... need something to dispatch on!\"))\n    end\n\n    args, kw_body, kw_dict = create_kw_body(func_signature)\n    func = get_function_def(func_signature, args)\n    operation = process_recipe_body!(func_body)\n\n    # now build a function definition for apply_recipe\n    funcdef = Expr(:function, func, esc(quote\n        if Latexify._debug_recipes[1]\n            println(\"apply_recipe args: \", $args)\n        end\n        kwargs = merge($kw_dict, kwargs)\n\n        $kw_body\n        $func_body\n    end))\n\n    getopdef = Expr(:(=), copy(func), esc(operation))\n    signature = getopdef.args[1]\n    while Meta.isexpr(signature, :where)\n        # Get through any layers of `where`\n        signature = signature.args[1]\n    end\n    signature.args[1] = :(Latexify._getoperation)\n\n    return Expr(:block, funcdef, getopdef)\nend\n\n"
  },
  {
    "path": "src/symbol_translations.jl",
    "content": "const functions = Dict{Symbol, String}(\n                                            ## Greek alphabet\n                                            :alpha => \"\\\\alpha\",\n                                            :beta => \"\\\\beta\",\n                                            :gamma => \"\\\\gamma\",\n                                            :delta => \"\\\\delta\",\n                                            :epsilon => \"\\\\epsilon\",\n                                            :zeta => \"\\\\zeta\",\n                                            :eta => \"\\\\eta\",\n                                            :theta => \"\\\\theta\",\n                                            :iota => \"\\\\iota\",\n                                            :kappa => \"\\\\kappa\",\n                                            :lambda => \"\\\\lambda\",\n                                            :mu => \"\\\\mu\",\n                                            :nu => \"\\\\nu\",\n                                            :xi => \"\\\\xi\",\n                                            :pi => \"\\\\pi\",\n                                            :rho => \"\\\\rho\",\n                                            :sigma => \"\\\\sigma\",\n                                            :tau => \"\\\\tau\",\n                                            :upsilon => \"\\\\upsilon\",\n                                            :phi => \"\\\\phi\",\n                                            :chi => \"\\\\chi\",\n                                            :psi => \"\\\\psi\",\n                                            :omega => \"\\\\omega\",\n                                            :Gamma => \"\\\\Gamma\",\n                                            :Delta => \"\\\\Delta\",\n                                            :Theta => \"\\\\Theta\",\n                                            :Lambda => \"\\\\Lambda\",\n                                            :Xi => \"\\\\Xi\",\n                                            :Pi => \"\\\\Pi\",\n                                            :Sigma => \"\\\\Sigma\",\n                                            :Upsilon => \"\\\\Upsilon\",\n                                            :Phi => \"\\\\Phi\",\n                                            :Psi => \"\\\\Psi\",\n                                            :Omega => \"\\\\Omega\",\n                                            ## Trinogometry\n                                            :sin => \"\\\\sin\",\n                                            :cos => \"\\\\cos\",\n                                            :tan => \"\\\\tan\",\n                                            :cot => \"\\\\cot\",\n                                            :sec => \"\\\\sec\",\n                                            :csc => \"\\\\csc\",\n                                            :sinh => \"\\\\sinh\",\n                                            :cosh => \"\\\\cosh\",\n                                            :tanh => \"\\\\tanh\",\n                                            :coth => \"\\\\coth\",\n                                            :asin => \"\\\\arcsin\",\n                                            :acos => \"\\\\arccos\",\n                                            :atan => \"\\\\arctan\",\n                                            :atan2 => \"\\\\arctan\",\n                                            :asinh => \"\\\\mathrm{arcsinh}\",\n                                            :sinc => \"\\\\mathrm{sinc}\",\n                                            :acosh => \"\\\\mathrm{arccosh}\",\n                                            :cosc => \"\\\\mathrm{cosc}\",\n                                            :atanh => \"\\\\mathrm{arctanh}\",\n                                            :acot => \"\\\\mathrm{arccot}\",\n                                            :acoth => \"\\\\mathrm{arccoth}\",\n                                            :asec => \"\\\\mathrm{arcsec}\",\n                                            :sech => \"\\\\mathrm{sech}\",\n                                            :asech => \"\\\\mathrm{arcsech}\",\n                                            :acsc => \"\\\\mathrm{arccsc}\",\n                                            :csch => \"\\\\mathrm{csch}\",\n                                            :acsch => \"\\\\mathrm{arccsch}\",\n                                            ## Misc\n                                            :log => \"\\\\log\",\n                                            :log10 => \"\\\\log_{10}\",\n                                            :log2 => \"\\\\log_{2}\",\n                                            :slog => \"\\\\log\",\n                                            :gamma => \"\\\\Gamma\", # The Gamma function\n                                           )\n\nconst trigonometric_functions = [\n                                 :sin,\n                                 :cos,\n                                 :tan,\n                                 :cot,\n                                 :sec,\n                                 :csc,\n                                 :sinh,\n                                 :cosh,\n                                 :tanh,\n                                 :coth,\n                                 :asin,\n                                 :acos,\n                                 :atan,\n                                 :atan2,\n                                 :asinh,\n                                 :sinc,\n                                 :acosh,\n                                 :cosc,\n                                 :atanh,\n                                 :acot,\n                                 :acoth,\n                                 :asec,\n                                 :sech,\n                                 :asech,\n                                 :acsc,\n                                 :csch,\n                                 :acsch,\n                                ]\n\nconst comparison_operators = Dict(\n                            :< => \"<\",\n                            :> => \">\",\n                            :(==) => \"=\",\n                            :≈ => \"\\\\approx\",\n                            :(===) => \"\\\\equiv\",\n                            :<= => \"\\\\leq\",\n                            :≤ => \"\\\\leq\",\n                            :>= => \"\\\\geq\",\n                            :≥ => \"\\\\geq\",\n                            :!= => \"\\\\neq\",\n                            :≠ => \"\\\\neq\",\n                            :!== => \"\\\\not\\\\equiv\",\n                            :in => \"\\\\in\",\n                            :∈ => \"\\\\in\",\n                            :∉ => \"\\\\notin\",\n                            :∋ => \"\\\\ni\",\n                            :∌ => \"\\\\not\\\\ni\",\n                            :issubset => \"\\\\subseteq\",\n                            :⊆ => \"\\\\subseteq\",\n                            :⊊ => \"\\\\subsetneq\",\n                            :⊃ => \"\\\\supset\",\n                            :⊅ => \"\\\\not\\\\supset\",\n                           )\nconst bitwise_operators = Dict(\n                            #:∀ => \"\\\\forall\",\n                            :& => \"\\\\wedge\",\n                            :| => \"\\\\vee\",\n                            :⊻ => \"\\\\veebar\",\n                            :⊼ => \"\\\\bar{\\\\wedge}\", # Not very good looking, but there is no builtin LaTeX symbol\n                            :>>> => \"\\\\ggg\",\n                            :>> => \"\\\\gg\",\n                            :<< => \"\\\\ll\",\n                           )\nconst arithmetic_operators = Dict(\n                            :^ => \"^\",\n                            :* => \"*\",\n                            :/ => \"/\",\n                            :% => \"\\\\%\",\n                            :\\ => \"\\\\backslash\",\n                            :÷ => \"\\\\div\",\n                            :+ => \"+\",\n                            :- => \"-\",\n                            :± => \"\\\\pm\",\n                            :∓ => \"\\\\mp\",\n                           )\nconst binary_operators = Dict(\n                            comparison_operators...,\n                            bitwise_operators...,\n                            arithmetic_operators...,\n                            :(=>) => \"\\\\Rightarrow\",\n                            :⟹ => \"\\\\Longrightarrow\",\n                            :(:) => \"\\\\mathrel{\\\\ldotp\\\\mkern-2.5mu\\\\ldotp}\"\n                           )\n\nconst unary_operators = Dict(\n                            :unaryminus => \"-\",\n                            :unaryplus => \"+\",\n                            :unaryplusminus => \"\\\\pm\",\n                            :unaryminusplus => \"\\\\mp\"\n                            )\nconst unary_opposites = Dict(\n                             :unaryminus => \"+\",\n                             :unaryplus => \"-\",\n                             :unaryplusminus => \"\\\\mp\",\n                             :unaryminusplus => \"\\\\pm\"\n                            )\nconst special_symbols = Dict(\n                             functions...,\n                             binary_operators...,\n                             :Inf => raw\"\\infty\",\n                            )\n"
  },
  {
    "path": "src/unicode2latex.jl",
    "content": "import OrderedCollections: OrderedDict\nimport Base.Unicode\n\nmathup(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝐀'=#0x1d400 : #='A'=#0x0041) - #='A'=#0x0041  # Mathematical (Bold) Capital\n    elseif islowercase(c)\n        (bold ? #='𝐚'=#0x1d41a : #='a'=#0x0061) - #='a'=#0x0061  # Mathematical (Bold) Small\n    else\n        (bold ? #='𝟎'=#0x1d7ce : #='0'=#0x0030) - #='0'=#0x0030  # Mathematical (Bold) Digit\n    end\n)\nmathscr(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝓐'=#0x1d4d0 : #='𝒜'=#0x1d49c) - #='A'=#0x0041  # Mathematical (Bold) Script Capital\n    elseif islowercase(c)\n        (bold ? #='𝓪'=#0x1d4ea : #='𝒶'=#0x1d4b6) - #='a'=#0x0061  # Mathematical (Bold) Script Small\n    else\n        -UInt32(c)\n    end\n)\nmathit(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝑨'=#0x1d468 : #='𝐴'=#0x1d434) - #='A'=#0x0041  # Mathematical (Bold) Italic Capital\n    elseif islowercase(c)\n        (bold ? #='𝒂'=#0x1d482 : #='𝑎'=#0x1d44e) - #='a'=#0x0061  # Mathematical (Bold) Italic Small\n    else\n        -UInt32(c)\n    end\n)\nmathfrak(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝕬'=#0x1d56c : #='𝔄'=#0x1d504) - #='A'=#0x0041  # Mathematical (Bold) Fraktur Capital\n    elseif islowercase(c)\n        (bold ? #='𝖆'=#0x1d586 : #='𝔞'=#0x1d51e) - #='a'=#0x0061  # Mathematical (Bold) Fraktur Small\n    else\n        -UInt32(c)\n    end\n)\nmathsfup(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝗔'=#0x1d5d4 : #='𝖠'=#0x1d5a0) - #='A'=#0x0041  # Mathematical (Bold) Sans-Serif Capital\n    elseif islowercase(c)\n        (bold ? #='𝗮'=#0x1d5ee : #='𝖺'=#0x1d5ba) - #='a'=#0x0061  # Mathematical (Bold) Sans-Serif Small\n    else\n        (bold ? #='𝟬'=#0x1d7ec : #='𝟢'=#0x1d7e2) - #='0'=#0x0030  # Mathematical (Bold) Sans-Serif Digit\n    end\n)\nmathsfit(c::Char, bold) = Char(\n    UInt32(c) + if isuppercase(c)\n        (bold ? #='𝘼'=#0x1d63c : #='𝘈'=#0x1d608) - #='A'=#0x0041  # Mathematical (Bold) Sans-Serif Italic Capital\n    elseif islowercase(c)\n        (bold ? #='𝙖'=#0x1d656 : #='𝘢'=#0x1d622) - #='a'=#0x0061  # Mathematical (Bold) Sans-Serif Italic Small\n    else\n        -UInt32(c)\n    end\n)\nmathtt(c::Char) = Char(\n    UInt32(c) + if isuppercase(c)\n        #='𝙰'=#0x1d670 - #='A'=#0x0041  # Mathematical Monospace Capital\n    elseif islowercase(c)\n        #='𝚊'=#0x1d68a - #='a'=#0x0061  # Mathematical Monospace Small\n    else\n        #='𝟶'=#0x1d7f6 - #='0'=#0x0030  # Mathematical Monospace Digit\n    end\n)\nmathbb(c::Char) = Char(\n    UInt32(c) + if isuppercase(c)\n        #='𝔸'=#0x1d538 - #='A'=#0x0041  # Mathematical Double-Struck Capital\n    elseif islowercase(c)\n        #='𝕒'=#0x1d552 - #='a'=#0x0061  # Mathematical Double-Struck Small\n    else\n        #='𝟘'=#0x1d7d8 - #='0'=#0x0030  # Mathematical Double-Struck Digit\n    end\n)\n\nconst greek_seq = (  # contiguous unicode sequence\n    raw\"\\Alpha\",\n    raw\"\\Beta\",\n    raw\"\\Gamma\",\n    raw\"\\Delta\",\n    raw\"\\Epsilon\",\n    raw\"\\Zeta\",\n    raw\"\\Eta\",\n    raw\"\\Theta\",\n    raw\"\\Iota\",\n    raw\"\\Kappa\",\n    raw\"\\Lambda\",\n    raw\"\\Mu\",\n    raw\"\\Nu\",\n    raw\"\\Xi\",\n    raw\"\\Omicron\",\n    raw\"\\Pi\",\n    raw\"\\Rho\",\n    raw\"\\varTheta\",\n    raw\"\\Sigma\",\n    raw\"\\Tau\",\n    raw\"\\Upsilon\",\n    raw\"\\Phi\",\n    raw\"\\Chi\",\n    raw\"\\Psi\",\n    raw\"\\Omega\",\n    raw\"\\nabla\",\n    raw\"\\alpha\",\n    raw\"\\beta\",\n    raw\"\\gamma\",\n    raw\"\\delta\",\n    raw\"\\varepsilon\",\n    raw\"\\zeta\",\n    raw\"\\eta\",\n    raw\"\\theta\",\n    raw\"\\iota\",\n    raw\"\\kappa\",\n    raw\"\\lambda\",\n    raw\"\\mu\",\n    raw\"\\nu\",\n    raw\"\\xi\",\n    raw\"\\omicron\",\n    raw\"\\pi\",\n    raw\"\\rho\",\n    raw\"\\varsigma\",\n    raw\"\\sigma\",\n    raw\"\\tau\",\n    raw\"\\upsilon\",\n    raw\"\\varphi\",\n    raw\"\\chi\",\n    raw\"\\psi\",\n    raw\"\\omega\",\n    raw\"\\partial\",\n    raw\"\\epsilon\",\n    raw\"\\vartheta\",\n    raw\"\\varkappa\",\n    raw\"\\phi\",\n    raw\"\\varrho\",\n    raw\"\\varpi\",\n)\n\nconst emphases = (\n    # (\"mathup\", (\"textup\",)) => identity,\n    (\"\", (\"textnormal\",)) => identity,\n    (\"mathbf\", (\"textbf\",)) => c -> mathup(c, true),\n    (\"mathit\", (\"textit\",)) => c -> mathit(c, false),\n    (\"mathbfit\", (\"textit\", \"textbf\")) => c -> mathit(c, true),\n    (\"mathscr\", ()) => c -> mathscr(c, false),\n    (\"mathbfscr\", ()) => c -> mathscr(c, true),\n    (\"mathfrak\", ()) => c -> mathfrak(c, false),\n    (\"mathbffrak\", ()) => c -> mathfrak(c, true),\n    (\"mathsfup\", ()) => c -> mathsfup(c, false),\n    (\"mathbfsfup\", ()) => c -> mathsfup(c, true),\n    (\"mathsfit\", ()) => c -> mathsfit(c, false),\n    (\"mathbfsfit\", ()) => c -> mathsfit(c, true),\n    (\"mathbb\", ()) => mathbb,\n    (\"mathtt\", (\"texttt\",)) => mathtt,\n)\n\n\"\"\"\n    latex_diacritics(c::Char)\n\n- generate latex escape codes for diacritics of the latin alphabet (upper and lower case), see https://en.wikibooks.org/wiki/LaTeX/Special_Characters#Escaped_codes\n- also generate a subset of the following sequence, when the single char normalization is available:\n    - 'à' => \"\\\\`{a}\"  # grave\n    - 'á' => \"\\\\'{a}\"  # acute\n    - 'ä' => \"\\\\\"{a}\"  # umlaut (trema, dieresis)\n    - 'a̋' => \"\\\\H{a}\"  # hungarian umlaut (double acute)\n    - 'a̧' => \"\\\\c{a}\"  # cedilla\n    - 'ą' => \"\\\\k{a}\"  # ogonek\n    - 'a̱' => \"\\\\b{a}\"  # bar under\n    - 'ạ' => \"\\\\d{a}\"  # dot under\n    - 'å' => \"\\\\r{a}\"  # ring\n    - 'ă' => \"\\\\u{a}\"  # breve\n    - 'ǎ' => \"\\\\v{a}\"  # caron (háček)\n    - Some more diacritics are ignored, and rather treated like math modifiers:\n        - 'â' => \"\\\\hat{a}\" # rather than \"\\\\^{a}\", circumflex\n        - 'ã' => \"\\\\tilde{a}\" # rather than \"\\\\~{a}\", tilde\n        - 'ā' => \"\\\\bar{a}\" # rather than \"\\\\={a}\", macron (bar above)\n        - 'ȧ' => \"\\\\dot{a}\" # rather than \"\\\\.{a}\", dot above\n\"\"\"\nfunction latex_diacritics(chars::AbstractVector)\n    out = []\n    for c ∈ chars, (mod, mark) ∈ (\n        '`' => Char(0x300),  # latex sequence \\`{c} maps to 'c' * Char(0x300) := \"c̀\"\n        \"'\" => Char(0x301),\n        #'^' => Char(0x302),\n        #'~' => Char(0x303),\n        #'=' => Char(0x304),\n        'u' => Char(0x306),\n        #'.' => Char(0x307),\n        '\"' => Char(0x308),\n        'r' => Char(0x30a),\n        'H' => Char(0x30b),\n        'v' => Char(0x30c),\n        'd' => Char(0x323),\n        'c' => Char(0x327),\n        'k' => Char(0x328),\n        'b' => Char(0x331),\n    )\n        for ((_, et), func) ∈ emphases\n            isempty(et) && continue\n            repl = \"\\\\$mod{$c}\"\n            for emph ∈ et\n                isempty(emph) && continue\n                repl = \"\\\\$emph{$repl}\"\n            end\n            dia = func(c) * mark\n            # e.g. ('y' * Char(0x30a) == \"ẙ\") != (Char(0x1e99) == 'ẙ'), although they look the same\n            push!(out, dia => repl)\n            alias = length(dia) == 1 ? dia : Unicode.normalize(dia)\n            if alias != dia\n                push!(out, (length(alias) == 1 ? first(alias) : alias) => repl)\n            end\n        end\n    end\n    out\nend\n\nfunction latex_emphasis(chars::AbstractVector)\n    out = []\n    for ((em, _), f) ∈ emphases\n        isempty(em) && continue\n        for c ∈ chars\n            push!(out, f(c) => isempty(em) ? c : \"\\\\$em{$c}\")\n        end\n    end\n    filter(p -> isprint(p.first), out)\nend\n\n# [`LaTeX`] https://tug.ctan.org/info/symbols/comprehensive/symbols-a4.pdf\n# \\mathrm: normal upright Roman font\n# \\mathnormal: normal math italic font\n# \\mathbf: upright Roman boldface letters\n# \\mathsf: upright sans serif letters\n# [`unicode-math`] https://mirrors.ctan.org/macros/unicodetex/latex/unicode-math/unicode-math.pdf\n# \\mathup Upright serif                 ✘ regular text\n# \\mathbfup Bold upright serif          ✘ \\mathbf instead\n# \\mathit Italic serif                  ✔\n# \\mathbfit Bold italic serif           ✔\n# \\mathsfup Upright sans-serif          ✔\n# \\mathsfit Italic sans-serif           ✔\n# \\mathbfsfup Bold upright sans-serif   ✔\n# \\mathbfsfit Bold italic sans-serif    ✔\n# \\mathtt Typewriter                    ✔\n# \\mathbb Blackboard bold               ✔\n# \\mathbbit Blackboard bold italic      ✔\n# \\mathscr Script                       ✔\n# \\mathbfscr Bold script                ✔\n# \\mathcal Calligraphic                 ✘ \\mathscr instead\n# \\mathbfcal Bold calligraphic          ✘ \\mathbfscr instead\n# \\mathfrak Fraktur                     ✔\n# \\mathbffrak Bold Fraktur              ✔\n# [`amssymb`] https://mirrors.ctan.org/fonts/amsfonts/doc/amssymb.pdf\n\nconst unicodedict = OrderedDict{Union{Char,String}, String}(\n    # ↓↓↓ unicode, in increasing order (see https://docs.julialang.org/en/v1/manual/unicode-input)\n    # commented lines are either unsupported in `LaTeX` (or only through a package such as `marvosym` for e.g. `\\jupiter`)\n    # or don't make sense here (letter modifiers such as `\\enclosecircle`)\n    '¡' => raw\"\\textnormal{\\textexclamdown}\",  # \\exclamdown\n    '£' => raw\"\\mathsterling\",  # \\sterling\n    '¥' => raw\"\\mathyen\",  # \\yen\n    '¦' => raw\"\\textnormal{\\textbrokenbar}\",  # \\brokenbar\n    '§' => raw\"\\S\",\n    '©' => raw\"\\copyright\",\n    'ª' => raw\"\\textnormal{\\textordfeminine}\",  # \\ordfeminine\n    '¬' => raw\"\\neg\",  # \\lnot\n    '®' => raw\"\\circledR\",\n    # '¯' => raw\"\\highminus\",\n    '°' => raw\"\\textnormal{\\textdegree}\",  # {^{\\circ}}, \\degree\n    '±' => raw\"\\pm\",\n    '²' => raw\"{^2}\",\n    '³' => raw\"{^3}\",\n    '¶' => raw\"\\P\",\n    '·' => raw\"\\cdotp\",\n    '¹' => raw\"{^1}\",\n    'º' => raw\"\\textnormal{\\textordmasculine}\",  # \\ordmasculine\n    '¼' => raw\"\\tfrac{1}{4}\",\n    '½' => raw\"\\tfrac{1}{2}\",\n    '¾' => raw\"\\tfrac{3}{4}\",\n    '¿' => raw\"\\textnormal{\\textquestiondown}\",  # \\questiondown\n    'Å' => raw\"\\textnormal{\\AA}\",\n    'Æ' => raw\"\\textnormal{\\AE}\",\n    'Ð' => raw\"\\textnormal{\\DH}\",\n    '×' => raw\"\\times\",\n    'Ø' => raw\"\\textnormal{\\O}\",\n    'Þ' => raw\"\\textnormal{\\TH}\",\n    'ß' => raw\"\\textnormal{\\ss}\",\n    'å' => raw\"\\textnormal{\\aa}\",\n    'æ' => raw\"\\textnormal{\\ae}\",\n    'ð' => raw\"\\eth\",  # \\dh\n    '÷' => raw\"\\div\",\n    'ø' => raw\"\\emptyset\",\n    'þ' => raw\"\\textnormal{\\th}\",\n    'Đ' => raw\"\\textnormal{\\DJ}\",\n    'đ' => raw\"\\textnormal{\\dj}\",\n    'ħ' => raw\"\\hslash\",  # \\hbar\n    'ı' => raw\"\\imath\",\n    'Ł' => raw\"\\textnormal{\\L}\",\n    'ł' => raw\"\\textnormal{\\l}\",\n    'Ŋ' => raw\"\\textnormal{\\NG}\",\n    'ŋ' => raw\"\\textnormal{\\ng}\",\n    'Œ' => raw\"\\textnormal{\\OE}\",\n    'œ' => raw\"\\textnormal{\\oe}\",\n    # 'ƕ' => raw\"\\hvlig\",\n    # 'ƞ' => raw\"\\nrleg\",\n    'Ƶ' => raw\"\\Zbar\",\n    # 'ǂ' => raw\"\\doublepipe\",\n    'ȷ' => raw\"\\jmath\",\n    # 'ɐ' => raw\"\\trna\",\n    # 'ɒ' => raw\"\\trnsa\",\n    # 'ɔ' => raw\"\\openo\",\n    # 'ɖ' => raw\"\\rtld\",\n    # 'ə' => raw\"\\schwa\",\n    # 'ɣ' => raw\"\\pgamma\",\n    # 'ɤ' => raw\"\\pbgam\",\n    # 'ɥ' => raw\"\\trnh\",\n    # 'ɬ' => raw\"\\btdl\",\n    # 'ɭ' => raw\"\\rtll\",\n    # 'ɯ' => raw\"\\trnm\",\n    # 'ɰ' => raw\"\\trnmlr\",\n    # 'ɱ' => raw\"\\ltlmr\",\n    # 'ɲ' => raw\"\\ltln\",\n    # 'ɳ' => raw\"\\rtln\",\n    # 'ɷ' => raw\"\\clomeg\",\n    # 'ɸ' => raw\"\\ltphi\",\n    # 'ɹ' => raw\"\\trnr\",\n    # 'ɺ' => raw\"\\trnrl\",\n    # 'ɻ' => raw\"\\rttrnr\",\n    # 'ɼ' => raw\"\\rl\",\n    # 'ɽ' => raw\"\\rtlr\",\n    # 'ɾ' => raw\"\\fhr\",\n    # 'ʂ' => raw\"\\rtls\",\n    # 'ʃ' => raw\"\\esh\",\n    # 'ʇ' => raw\"\\trnt\",\n    # 'ʈ' => raw\"\\rtlt\",\n    # 'ʊ' => raw\"\\pupsil\",\n    # 'ʋ' => raw\"\\pscrv\",\n    # 'ʌ' => raw\"\\invv\",\n    # 'ʍ' => raw\"\\invw\",\n    # 'ʎ' => raw\"\\trny\",\n    # 'ʐ' => raw\"\\rtlz\",\n    # 'ʒ' => raw\"\\yogh\",\n    # 'ʔ' => raw\"\\glst\",\n    # 'ʕ' => raw\"\\reglst\",\n    # 'ʖ' => raw\"\\inglst\",\n    # 'ʞ' => raw\"\\turnk\",\n    # 'ʤ' => raw\"\\dyogh\",\n    # 'ʧ' => raw\"\\tesh\",\n    'ʰ' => raw\"{^h}\",\n    'ʲ' => raw\"{^j}\",\n    'ʳ' => raw\"{^r}\",\n    'ʷ' => raw\"{^w}\",\n    'ʸ' => raw\"{^y}\",\n    'ʼ' => raw\"{'}\",  # \\rasp\n    # 'ˈ' => raw\"\\sverts\",\n    # 'ˌ' => raw\"\\verti\",\n    # 'ː' => raw\"\\lmrk\",  # \\textlengthmark\n    # 'ˑ' => raw\"\\hlmrk\",  # \\texthalflength\n    # '˒' => raw\"\\sbrhr\",\n    # '˓' => raw\"\\sblhr\",\n    # '˔' => raw\"\\rais\",  # \\textraised\n    # '˕' => raw\"\\low\",  # \\textlowered\n    '˘' => raw\"\\textnormal{\\u{}}\",\n    '˜' => raw\"\\textnormal{\\texttildelow}\",  # \\tildelow\n    'ˡ' => raw\"{^l}\",\n    'ˢ' => raw\"{^s}\",\n    'ˣ' => raw\"{^x}\",\n    # '̀' => raw\"\\grave{}\",\n    # '́' => raw\"\\acute{}\",\n    # '̂' => raw\"\\hat{}\",\n    # '̃' => raw\"\\tilde{}\",\n    # '̄' => raw\"\\bar{}\",\n    # '̅' => raw\"\\overbar{}\",\n    # '̆' => raw\"\\breve{}\",\n    # '̇' => raw\"\\dot{}\",\n    # '̈' => raw\"\\ddot{}\",\n    # '̉' => raw\"\\ovhook{}\",\n    # '̊' => raw\"\\ocirc{}\",\n    # '̋' => raw\"\\H{}\",\n    # '̌' => raw\"\\check{}\",\n    # '̐' => raw\"\\candra{}\",\n    # '̒' => raw\"\\oturnedcomma{}\",\n    # '̕' => raw\"\\ocommatopright{}\",\n    # '̚' => raw\"\\droang{}\",\n    # '̡' => raw\"\\palh{}\",\n    # '̢' => raw\"\\rh{}\",\n    # '̧' => raw\"\\c{}\",\n    # '̨' => raw\"\\k{}\",\n    # '̪' => raw\"\\sbbrg{}\",\n    # '̰' => raw\"\\wideutilde{}\",\n    # '̲' => raw\"\\underbar{}\",\n    # '̶' => raw\"\\strike{}\",  # \\sout\n    # '̸' => raw\"\\not{}\",\n    # '͍' => raw\"\\underleftrightarrow{}\",\n    # greek without emphasis\n    'Α' => raw\"\\Alpha\",\n    'Β' => raw\"\\Beta\",\n    'Γ' => raw\"\\Gamma\",\n    'Δ' => raw\"\\Delta\",\n    'Ε' => raw\"\\Epsilon\",\n    'Ζ' => raw\"\\Zeta\",\n    'Η' => raw\"\\Eta\",\n    'Θ' => raw\"\\Theta\",\n    'Ι' => raw\"\\Iota\",\n    'Κ' => raw\"\\Kappa\",\n    'Λ' => raw\"\\Lambda\",\n    'Μ' => raw\"\\Mu\",  # \\upMu\n    'Ν' => raw\"\\Nu\",  # \\upNu\n    'Ξ' => raw\"\\Xi\",\n    'Ο' => raw\"\\Omicron\",  # \\upOmicron\n    'Π' => raw\"\\Pi\",\n    'Ρ' => raw\"\\Rho\",\n    'Σ' => raw\"\\Sigma\",\n    'Τ' => raw\"\\Tau\",\n    'Υ' => raw\"\\Upsilon\",\n    'Φ' => raw\"\\Phi\",\n    'Χ' => raw\"\\Chi\",\n    'Ψ' => raw\"\\Psi\",\n    'Ω' => raw\"\\Omega\",\n    'α' => raw\"\\alpha\",\n    'β' => raw\"\\beta\",\n    'γ' => raw\"\\gamma\",\n    'δ' => raw\"\\delta\",\n    'ε' => raw\"\\varepsilon\",\n    'ζ' => raw\"\\zeta\",\n    'η' => raw\"\\eta\",\n    'θ' => raw\"\\theta\",\n    'ι' => raw\"\\iota\",\n    'κ' => raw\"\\kappa\",\n    'λ' => raw\"\\lambda\",\n    'μ' => raw\"\\mu\",\n    'ν' => raw\"\\nu\",\n    'ξ' => raw\"\\xi\",\n    'ο' => raw\"\\omicron\",  # \\upomicron\n    'π' => raw\"\\pi\",\n    'ρ' => raw\"\\rho\",\n    'ς' => raw\"\\varsigma\",\n    'σ' => raw\"\\sigma\",\n    'τ' => raw\"\\tau\",\n    'υ' => raw\"\\upsilon\",\n    'φ' => raw\"\\varphi\",\n    'χ' => raw\"\\chi\",\n    'ψ' => raw\"\\psi\",\n    'ω' => raw\"\\omega\",\n    # 'ϐ' => raw\"\\varbeta\",\n    'ϑ' => raw\"\\vartheta\",\n    'ϕ' => raw\"\\phi\",\n    'ϖ' => raw\"\\varpi\",\n    # 'Ϙ' => raw\"\\oldKoppa\",\n    # 'ϙ' => raw\"\\oldkoppa\",\n    # 'Ϛ' => raw\"\\Stigma\",\n    # 'ϛ' => raw\"\\upstigma\",\n    'Ϝ' => raw\"\\upDigamma\",\n    'ϝ' => raw\"\\updigamma\",\n    # 'Ϟ' => raw\"\\Koppa\",\n    # 'ϟ' => raw\"\\koppa\",\n    # 'Ϡ' => raw\"\\Sampi\",\n    # 'ϡ' => raw\"\\upsampi\",\n    'ϰ' => raw\"\\varkappa\",\n    'ϱ' => raw\"\\varrho\",\n    'ϴ' => raw\"\\varTheta\",\n    'ϵ' => raw\"\\epsilon\",\n    '϶' => raw\"\\backepsilon\",\n    'ᴬ' => raw\"{^A}\",\n    'ᴮ' => raw\"{^B}\",\n    'ᴰ' => raw\"{^D}\",\n    'ᴱ' => raw\"{^E}\",\n    'ᴳ' => raw\"{^G}\",\n    'ᴴ' => raw\"{^H}\",\n    'ᴵ' => raw\"{^I}\",\n    'ᴶ' => raw\"{^J}\",\n    'ᴷ' => raw\"{^K}\",\n    'ᴸ' => raw\"{^L}\",\n    'ᴹ' => raw\"{^M}\",\n    'ᴺ' => raw\"{^N}\",\n    'ᴼ' => raw\"{^O}\",\n    'ᴾ' => raw\"{^P}\",\n    'ᴿ' => raw\"{^R}\",\n    'ᵀ' => raw\"{^T}\",\n    'ᵁ' => raw\"{^U}\",\n    'ᵂ' => raw\"{^W}\",\n    'ᵃ' => raw\"{^a}\",\n    'ᵅ' => raw\"{^\\alpha}\",\n    'ᵇ' => raw\"{^b}\",\n    'ᵈ' => raw\"{^d}\",\n    'ᵉ' => raw\"{^e}\",\n    'ᵋ' => raw\"{^\\epsilon}\",\n    'ᵍ' => raw\"{^g}\",\n    'ᵏ' => raw\"{^k}\",\n    'ᵐ' => raw\"{^m}\",\n    'ᵒ' => raw\"{^o}\",\n    'ᵖ' => raw\"{^p}\",\n    'ᵗ' => raw\"{^t}\",\n    'ᵘ' => raw\"{^u}\",\n    'ᵛ' => raw\"{^v}\",\n    'ᵝ' => raw\"{^\\beta}\",\n    'ᵞ' => raw\"{^\\gamma}\",\n    'ᵟ' => raw\"{^\\delta}\",\n    'ᵠ' => raw\"{^\\phi}\",\n    'ᵡ' => raw\"{^\\chi}\",\n    'ᵢ' => raw\"{_i}\",\n    'ᵣ' => raw\"{_r}\",\n    'ᵤ' => raw\"{_u}\",\n    'ᵥ' => raw\"{_v}\",\n    'ᵦ' => raw\"{_\\beta}\",\n    'ᵧ' => raw\"{_\\gamma}\",\n    'ᵨ' => raw\"{_\\rho}\",\n    'ᵩ' => raw\"{_\\phi}\",\n    'ᵪ' => raw\"{_\\chi}\",\n    'ᶜ' => raw\"{^c}\",\n    'ᶠ' => raw\"{^f}\",\n    'ᶥ' => raw\"{^\\iota}\",\n    'ᶲ' => raw\"{^\\phi}\",  # \\ltphi\n    'ᶻ' => raw\"{^z}\",\n    'ᶿ' => raw\"{^\\theta}\",\n    # see https://mirrors.ctan.org/macros/latex/contrib/uspace/uspace.pdf\n    ' ' => raw\"\\enspace\",  # 0.5em\n    ' ' => raw\"\\quad\",  # 1em\n    ' ' => raw\"\\thickspace\",  # \\;\n    ' ' => raw\"\\thinspace\",  # \\,\n    ' ' => raw\"\\hspace{0.08333em}\",  # hair space\n    '–' => raw\"\\textnormal{\\textendash}\",  # \\endash\n    '—' => raw\"\\textnormal{\\textemdash}\",  # \\emdash\n    '‖' => raw\"\\Vert\",  # \\|\n    '‘' => raw\"\\textnormal{\\textquoteleft}\",  # \\lq\n    '’' => raw\"\\textnormal{\\textquoteright}\",  # \\rq\n    # '‛' => raw\"\\reapos\",\n    '“' => raw\"\\textnormal{\\textquotedblleft}\",  # \\ldq\n    '”' => raw\"\\textnormal{\\textquotedblright}\",  # \\rdq\n    '†' => raw\"\\dagger\",\n    '‡' => raw\"\\ddagger\",\n    '•' => raw\"\\bullet\",\n    '…' => raw\"\\dots\",  # \\ldots\n    '‰' => raw\"\\textnormal{\\textperthousand}\",  # \\perthousand\n    '‱' => raw\"\\textnormal{\\textpertenthousand}\",  # \\pertenthousand\n    '′' => raw\"\\prime\",\n    '″' => raw\"\\dprime\",  # \\pprime\n    '‴' => raw\"\\trprime\",  # \\ppprime\n    '‵' => raw\"\\backprime\",\n    '‶' => raw\"\\backdprime\",  # \\backpprime\n    '‷' => raw\"\\backtrprime\",  # \\backppprime\n    '‹' => raw\"\\textnormal{\\guilsinglleft}\",\n    '›' => raw\"\\textnormal{\\guilsinglright}\",\n    '⁀' => raw\"\\tieconcat\",\n    '⁗' => raw\"\\qprime\",  # \\pppprime\n    # '⁝' => raw\"\\tricolon\",\n    '⁠' => raw\"\\nolinebreak\",\n    '⁰' => raw\"{^0}\",\n    'ⁱ' => raw\"{^i}\",\n    '⁴' => raw\"{^4}\",\n    '⁵' => raw\"{^5}\",\n    '⁶' => raw\"{^6}\",\n    '⁷' => raw\"{^7}\",\n    '⁸' => raw\"{^8}\",\n    '⁹' => raw\"{^9}\",\n    '⁺' => raw\"{^+}\",\n    '⁻' => raw\"{^-}\",\n    '⁼' => raw\"{^=}\",\n    '⁽' => raw\"{^(}\",\n    '⁾' => raw\"{^)}\",\n    'ⁿ' => raw\"{^n}\",\n    '₀' => raw\"{_0}\",\n    '₁' => raw\"{_1}\",\n    '₂' => raw\"{_2}\",\n    '₃' => raw\"{_3}\",\n    '₄' => raw\"{_4}\",\n    '₅' => raw\"{_5}\",\n    '₆' => raw\"{_6}\",\n    '₇' => raw\"{_7}\",\n    '₈' => raw\"{_8}\",\n    '₉' => raw\"{_9}\",\n    '₊' => raw\"{_+}\",\n    '₋' => raw\"{_-}\",\n    '₌' => raw\"{_=}\",\n    '₍' => raw\"{_(}\",\n    '₎' => raw\"{_)}\",\n    'ₐ' => raw\"{_a}\",\n    'ₑ' => raw\"{_e}\",\n    'ₒ' => raw\"{_o}\",\n    'ₓ' => raw\"{_x}\",\n    # 'ₔ' => raw\"{_\\schwa}\",\n    'ₕ' => raw\"{_h}\",\n    'ₖ' => raw\"{_k}\",\n    'ₗ' => raw\"{_l}\",\n    'ₘ' => raw\"{_m}\",\n    'ₙ' => raw\"{_n}\",\n    'ₚ' => raw\"{_p}\",\n    'ₛ' => raw\"{_s}\",\n    'ₜ' => raw\"{_t}\",\n    # '₧' => raw\"\\pes\",\n    '€' => raw\"\\euro\",\n    # '⃐' => raw\"\\leftharpoonaccent{}\",\n    # '⃑' => raw\"\\rightharpoonaccent{}\",\n    # '⃒' => raw\"\\vertoverlay{}\",\n    # '⃖' => raw\"\\overleftarrow{}\",\n    # '⃗' => raw\"\\vec{}\",\n    # '⃛' => raw\"\\dddot{}\",\n    # '⃜' => raw\"\\ddddot{}\",\n    # '⃝' => raw\"\\enclosecircle{}\",\n    # '⃞' => raw\"\\enclosesquare{}\",\n    # '⃟' => raw\"\\enclosediamond{}\",\n    # '⃡' => raw\"\\overleftrightarrow{}\",\n    # '⃤' => raw\"\\enclosetriangle{}\",\n    # '⃧' => raw\"\\annuity{}\",\n    # '⃨' => raw\"\\threeunderdot{}\",\n    # '⃩' => raw\"\\widebridgeabove{}\",\n    # '⃬' => raw\"\\underrightharpoondown{}\",\n    # '⃭' => raw\"\\underleftharpoondown{}\",\n    # '⃮' => raw\"\\underleftarrow{}\",\n    # '⃯' => raw\"\\underrightarrow{}\",\n    # '⃰' => raw\"\\asteraccent{}\",\n    'ℂ' => raw\"\\mathbb{C}\",\n    'ℇ' => raw\"\\Eulerconst\",  # \\eulermascheroni\n    'ℊ' => raw\"\\mathscr{g}\",\n    'ℋ' => raw\"\\mathscr{H}\",\n    'ℌ' => raw\"\\mathfrak{H}\",\n    'ℍ' => raw\"\\mathbb{H}\",\n    'ℎ' => raw\"\\Planckconst\",  # \\mathit{h}, \\ith, \\planck\n    'ℏ' => raw\"\\hslash\",\n    'ℐ' => raw\"\\mathscr{I}\",\n    'ℑ' => raw\"\\Im\",  # \\mathfrak{I}\n    'ℒ' => raw\"\\mathscr{L}\",\n    'ℓ' => raw\"\\ell\",\n    'ℕ' => raw\"\\mathbb{N}\",\n    '№' => raw\"\\textnormal{\\textnumero}\",  # \\numero\n    '℘' => raw\"\\wp\",\n    'ℙ' => raw\"\\mathbb{P}\",\n    'ℚ' => raw\"\\mathbb{Q}\",\n    'ℛ' => raw\"\\mathscr{R}\",\n    'ℜ' => raw\"\\Re\",  # \\mathfrak{R}\n    'ℝ' => raw\"\\mathbb{R}\",\n    '℞' => raw\"\\textnormal{\\textrecipe}\",  # \\xrat\n    '™' => raw\"\\textnormal{\\texttrademark}\",  # \\trademark\n    'ℤ' => raw\"\\mathbb{Z}\",\n    'Ω' => raw\"\\Omega\",  # \\ohm\n    '℧' => raw\"\\mho\",\n    'ℨ' => raw\"\\mathfrak{Z}\",\n    '℩' => raw\"\\turnediota\",\n    'Å' => raw\"\\Angstrom\",\n    'ℬ' => raw\"\\mathscr{B}\",\n    'ℭ' => raw\"\\mathfrak{C}\",\n    'ℯ' => raw\"\\mathscr{e}\",  # \\euler\n    'ℰ' => raw\"\\mathscr{E}\",\n    'ℱ' => raw\"\\mathscr{F}\",\n    'Ⅎ' => raw\"\\Finv\",\n    'ℳ' => raw\"\\mathscr{M}\",\n    'ℴ' => raw\"\\mathscr{o}\",\n    'ℵ' => raw\"\\aleph\",\n    'ℶ' => raw\"\\beth\",\n    'ℷ' => raw\"\\gimel\",\n    'ℸ' => raw\"\\daleth\",\n    'ℼ' => raw\"\\mathbb{\\pi}\",\n    'ℽ' => raw\"\\mathbb{\\gamma}\",\n    'ℾ' => raw\"\\mathbb{\\Gamma}\",\n    'ℿ' => raw\"\\mathbb{\\Pi}\",\n    '⅀' => raw\"\\mathbb{\\sum}\",\n    '⅁' => raw\"\\Game\",\n    '⅂' => raw\"\\sansLturned\",\n    '⅃' => raw\"\\sansLmirrored\",\n    '⅄' => raw\"\\Yup\",\n    'ⅅ' => raw\"\\mathbbit{D}\",\n    'ⅆ' => raw\"\\mathbbit{d}\",\n    'ⅇ' => raw\"\\mathbbit{e}\",\n    'ⅈ' => raw\"\\mathbbit{i}\",\n    'ⅉ' => raw\"\\mathbbit{j}\",\n    '⅊' => raw\"\\PropertyLine\",\n    '⅋' => raw\"\\upand\",\n    '⅐' => raw\"\\tfrac{1}{7}\",\n    '⅑' => raw\"\\tfrac{1}{9}\",\n    '⅒' => raw\"\\tfrac{1}{10}\",\n    '⅓' => raw\"\\tfrac{1}{3}\",\n    '⅔' => raw\"\\tfrac{2}{3}\",\n    '⅕' => raw\"\\tfrac{1}{5}\",\n    '⅖' => raw\"\\tfrac{2}{5}\",\n    '⅗' => raw\"\\tfrac{3}{5}\",\n    '⅘' => raw\"\\tfrac{4}{5}\",\n    '⅙' => raw\"\\tfrac{1}{6}\",\n    '⅚' => raw\"\\tfrac{5}{6}\",\n    '⅛' => raw\"\\tfrac{1}{8}\",\n    '⅜' => raw\"\\tfrac{3}{8}\",\n    '⅝' => raw\"\\tfrac{5}{8}\",\n    '⅞' => raw\"\\tfrac{7}{8}\",\n    '⅟' => raw\"\\tfrac{1}{}\",\n    '↉' => raw\"\\tfrac{0}{3}\",\n    '←' => raw\"\\leftarrow\",  # \\gets\n    '↑' => raw\"\\uparrow\",\n    '→' => raw\"\\rightarrow\",  # \\to\n    '↓' => raw\"\\downarrow\",\n    '↔' => raw\"\\leftrightarrow\",\n    '↕' => raw\"\\updownarrow\",\n    '↖' => raw\"\\nwarrow\",\n    '↗' => raw\"\\nearrow\",\n    '↘' => raw\"\\searrow\",\n    '↙' => raw\"\\swarrow\",\n    '↚' => raw\"\\nleftarrow\",\n    '↛' => raw\"\\nrightarrow\",\n    '↜' => raw\"\\leftwavearrow\",\n    '↝' => raw\"\\rightwavearrow\",\n    '↞' => raw\"\\twoheadleftarrow\",\n    '↟' => raw\"\\twoheaduparrow\",\n    '↠' => raw\"\\twoheadrightarrow\",\n    '↡' => raw\"\\twoheaddownarrow\",\n    '↢' => raw\"\\leftarrowtail\",\n    '↣' => raw\"\\rightarrowtail\",\n    '↤' => raw\"\\mapsfrom\",\n    '↥' => raw\"\\mapsup\",\n    '↦' => raw\"\\mapsto\",\n    '↧' => raw\"\\mapsdown\",\n    '↨' => raw\"\\updownarrowbar\",\n    '↩' => raw\"\\hookleftarrow\",\n    '↪' => raw\"\\hookrightarrow\",\n    '↫' => raw\"\\looparrowleft\",\n    '↬' => raw\"\\looparrowright\",\n    '↭' => raw\"\\leftrightsquigarrow\",\n    '↮' => raw\"\\nleftrightarrow\",\n    '↯' => raw\"\\downzigzagarrow\",\n    '↰' => raw\"\\Lsh\",\n    '↱' => raw\"\\Rsh\",\n    '↲' => raw\"\\Ldsh\",\n    '↳' => raw\"\\Rdsh\",\n    '↴' => raw\"\\linefeed\",\n    '↵' => raw\"\\carriagereturn\",\n    '↶' => raw\"\\curvearrowleft\",\n    '↷' => raw\"\\curvearrowright\",\n    '↸' => raw\"\\barovernorthwestarrow\",\n    '↹' => raw\"\\barleftarrowrightarrowbar\",\n    '↺' => raw\"\\circlearrowleft\",\n    '↻' => raw\"\\circlearrowright\",\n    '↼' => raw\"\\leftharpoonup\",\n    '↽' => raw\"\\leftharpoondown\",\n    '↾' => raw\"\\upharpoonright\",\n    '↿' => raw\"\\upharpoonleft\",\n    '⇀' => raw\"\\rightharpoonup\",\n    '⇁' => raw\"\\rightharpoondown\",\n    '⇂' => raw\"\\downharpoonright\",\n    '⇃' => raw\"\\downharpoonleft\",\n    '⇄' => raw\"\\rightleftarrows\",\n    '⇅' => raw\"\\updownarrows\",  # \\dblarrowupdown\n    '⇆' => raw\"\\leftrightarrows\",\n    '⇇' => raw\"\\leftleftarrows\",\n    '⇈' => raw\"\\upuparrows\",\n    '⇉' => raw\"\\rightrightarrows\",\n    '⇊' => raw\"\\downdownarrows\",\n    '⇋' => raw\"\\leftrightharpoons\",\n    '⇌' => raw\"\\rightleftharpoons\",\n    '⇍' => raw\"\\nLeftarrow\",\n    '⇎' => raw\"\\nLeftrightarrow\",\n    '⇏' => raw\"\\nRightarrow\",\n    '⇐' => raw\"\\Leftarrow\",\n    '⇑' => raw\"\\Uparrow\",\n    '⇒' => raw\"\\Rightarrow\",\n    '⇓' => raw\"\\Downarrow\",\n    '⇔' => raw\"\\Leftrightarrow\",\n    '⇕' => raw\"\\Updownarrow\",\n    '⇖' => raw\"\\Nwarrow\",\n    '⇗' => raw\"\\Nearrow\",\n    '⇘' => raw\"\\Searrow\",\n    '⇙' => raw\"\\Swarrow\",\n    '⇚' => raw\"\\Lleftarrow\",\n    '⇛' => raw\"\\Rrightarrow\",\n    '⇜' => raw\"\\leftsquigarrow\",\n    '⇝' => raw\"\\rightsquigarrow\",\n    '⇞' => raw\"\\nHuparrow\",\n    '⇟' => raw\"\\nHdownarrow\",\n    '⇠' => raw\"\\leftdasharrow\",\n    '⇡' => raw\"\\updasharrow\",\n    '⇢' => raw\"\\rightdasharrow\",\n    '⇣' => raw\"\\downdasharrow\",\n    '⇤' => raw\"\\barleftarrow\",\n    '⇥' => raw\"\\rightarrowbar\",\n    '⇦' => raw\"\\leftwhitearrow\",\n    '⇧' => raw\"\\upwhitearrow\",\n    '⇨' => raw\"\\rightwhitearrow\",\n    '⇩' => raw\"\\downwhitearrow\",\n    '⇪' => raw\"\\whitearrowupfrombar\",\n    '⇴' => raw\"\\circleonrightarrow\",\n    '⇵' => raw\"\\downuparrows\",  # \\DownArrowUpArrow\n    '⇶' => raw\"\\rightthreearrows\",\n    '⇷' => raw\"\\nvleftarrow\",\n    '⇸' => raw\"\\nvrightarrow\",\n    '⇹' => raw\"\\nvleftrightarrow\",\n    '⇺' => raw\"\\nVleftarrow\",\n    '⇻' => raw\"\\nVrightarrow\",\n    '⇼' => raw\"\\nVleftrightarrow\",\n    '⇽' => raw\"\\leftarrowtriangle\",\n    '⇾' => raw\"\\rightarrowtriangle\",\n    '⇿' => raw\"\\leftrightarrowtriangle\",\n    '∀' => raw\"\\forall\",\n    '∁' => raw\"\\complement\",\n    '∂' => raw\"\\partial\",\n    '∃' => raw\"\\exists\",\n    '∄' => raw\"\\nexists\",\n    '∅' => raw\"\\emptyset\",  # \\O, \\varnothing\n    '∆' => raw\"\\increment\",\n    '∇' => raw\"\\nabla\",  # \\del\n    '∈' => raw\"\\in\",\n    '∉' => raw\"\\notin\",\n    '∊' => raw\"\\smallin\",\n    '∋' => raw\"\\ni\",\n    '∌' => raw\"\\nni\",\n    '∍' => raw\"\\smallni\",\n    '∎' => raw\"\\QED\",\n    '∏' => raw\"\\prod\",\n    '∐' => raw\"\\coprod\",\n    '∑' => raw\"\\sum\",\n    '−' => raw\"\\minus\",\n    '∓' => raw\"\\mp\",\n    '∔' => raw\"\\dotplus\",\n    '∖' => raw\"\\setminus\",\n    '∗' => raw\"\\ast\",\n    '∘' => raw\"\\circ\",\n    '∙' => raw\"\\vysmblkcircle\",\n    '√' => raw\"\\sqrt{}\",  # \\surd\n    '∛' => raw\"\\cuberoot{}\",  # \\cbrt\n    '∜' => raw\"\\fourthroot{}\",\n    '∝' => raw\"\\propto\",\n    '∞' => raw\"\\infty\",\n    '∟' => raw\"\\rightangle\",\n    '∠' => raw\"\\angle\",\n    '∡' => raw\"\\measuredangle\",\n    '∢' => raw\"\\sphericalangle\",\n    '∣' => raw\"\\mid\",\n    '∤' => raw\"\\nmid\",\n    '∥' => raw\"\\parallel\",\n    '∦' => raw\"\\nparallel\",\n    '∧' => raw\"\\wedge\",\n    '∨' => raw\"\\vee\",\n    '∩' => raw\"\\cap\",\n    '∪' => raw\"\\cup\",\n    '∫' => raw\"\\int\",\n    '∬' => raw\"\\iint\",\n    '∭' => raw\"\\iiint\",\n    '∮' => raw\"\\oint\",\n    '∯' => raw\"\\oiint\",\n    '∰' => raw\"\\oiiint\",\n    '∱' => raw\"\\intclockwise\",  # \\clwintegral\n    '∲' => raw\"\\varointclockwise\",\n    '∳' => raw\"\\ointctrclockwise\",\n    '∴' => raw\"\\therefore\",\n    '∵' => raw\"\\because\",\n    '∷' => raw\"\\Colon\",\n    '∸' => raw\"\\dotminus\",\n    '∺' => raw\"\\dotsminusdots\",\n    '∻' => raw\"\\kernelcontraction\",\n    '∼' => raw\"\\sim\",\n    '∽' => raw\"\\backsim\",\n    '∾' => raw\"\\invlazys\",  # \\lazysinv\n    '∿' => raw\"\\sinewave\",\n    '≀' => raw\"\\wr\",\n    '≁' => raw\"\\nsim\",\n    '≂' => raw\"\\eqsim\",\n    \"≂̸\" => raw\"\\not\\eqsim\",  # \\neqsim\n    '≃' => raw\"\\simeq\",\n    '≄' => raw\"\\nsime\",\n    '≅' => raw\"\\cong\",\n    '≆' => raw\"\\simneqq\",  # \\approxnotequal\n    '≇' => raw\"\\ncong\",\n    '≈' => raw\"\\approx\",\n    '≉' => raw\"\\napprox\",\n    '≊' => raw\"\\approxeq\",\n    '≋' => raw\"\\approxident\",  # \\tildetrpl\n    '≌' => raw\"\\backcong\",  # \\allequal\n    '≍' => raw\"\\asymp\",\n    '≎' => raw\"\\Bumpeq\",\n    \"≎̸\" => raw\"\\not\\Bumpeq\",  # \\nBumpeq\n    '≏' => raw\"\\bumpeq\",\n    \"≏̸\" => raw\"\\not\\bumpeq\",  # \\nbumpeq\n    '≐' => raw\"\\doteq\",\n    '≑' => raw\"\\Doteq\",\n    '≒' => raw\"\\fallingdotseq\",\n    '≓' => raw\"\\risingdotseq\",\n    '≔' => raw\"\\coloneq\",\n    '≕' => raw\"\\eqcolon\",\n    '≖' => raw\"\\eqcirc\",\n    '≗' => raw\"\\circeq\",\n    '≘' => raw\"\\arceq\",\n    '≙' => raw\"\\wedgeq\",\n    '≚' => raw\"\\veeeq\",\n    '≛' => raw\"\\stareq\",  # \\starequal\n    '≜' => raw\"\\triangleq\",\n    '≝' => raw\"\\eqdef\",\n    '≞' => raw\"\\measeq\",\n    '≟' => raw\"\\questeq\",\n    '≠' => raw\"\\ne\",\n    '≡' => raw\"\\equiv\",\n    '≢' => raw\"\\nequiv\",\n    '≣' => raw\"\\Equiv\",\n    '≤' => raw\"\\leq\",  # \\les \\le\n    '≥' => raw\"\\geq\",  # \\le\n    '≦' => raw\"\\leqq\",\n    '≧' => raw\"\\geqq\",\n    '≨' => raw\"\\lneqq\",\n    \"≨︀\" => raw\"\\lvertneqq\",\n    '≩' => raw\"\\gneqq\",\n    \"≩︀\" => raw\"\\gvertneqq\",\n    '≪' => raw\"\\ll\",\n    \"≪̸\" => raw\"\\not\\ll\",  # \\NotLessLess\n    '≫' => raw\"\\gg\",\n    \"≫̸\" => raw\"\\not\\gg\",  # \\NotGreaterGreater\n    '≬' => raw\"\\between\",\n    '≭' => raw\"\\nasymp\",\n    '≮' => raw\"\\nless\",\n    '≯' => raw\"\\ngtr\",\n    '≰' => raw\"\\nleq\",\n    '≱' => raw\"\\ngeq\",\n    '≲' => raw\"\\lesssim\",\n    '≳' => raw\"\\gtrsim\",\n    '≴' => raw\"\\nlesssim\",\n    '≵' => raw\"\\ngtrsim\",\n    '≶' => raw\"\\lessgtr\",\n    '≷' => raw\"\\gtrless\",\n    '≸' => raw\"\\not\\lessgtr\",  # \\notlessgreater\n    '≹' => raw\"\\not\\gtrless\",  # \\notgreaterless\n    '≺' => raw\"\\prec\",\n    '≻' => raw\"\\succ\",\n    '≼' => raw\"\\preccurlyeq\",\n    '≽' => raw\"\\succcurlyeq\",\n    '≾' => raw\"\\precsim\",\n    \"≾̸\" => raw\"\\not\\precsim\",  # \\nprecsim\n    '≿' => raw\"\\succsim\",\n    \"≿̸\" => raw\"\\not\\succsim\",  # \\nsuccsim\n    '⊀' => raw\"\\nprec\",\n    '⊁' => raw\"\\nsucc\",\n    '⊂' => raw\"\\subset\",\n    '⊃' => raw\"\\supset\",\n    '⊄' => raw\"\\nsubset\",\n    '⊅' => raw\"\\nsupset\",\n    '⊆' => raw\"\\subseteq\",\n    '⊇' => raw\"\\supseteq\",\n    '⊈' => raw\"\\nsubseteq\",\n    '⊉' => raw\"\\nsupseteq\",\n    '⊊' => raw\"\\subsetneq\",\n    \"⊊︀\" => raw\"\\varsubsetneqq\",\n    '⊋' => raw\"\\supsetneq\",\n    \"⊋︀\" => raw\"\\varsupsetneq\",\n    '⊍' => raw\"\\cupdot\",\n    '⊎' => raw\"\\uplus\",\n    '⊏' => raw\"\\sqsubset\",\n    \"⊏̸\" => raw\"\\not\\sqsubset\",  # \\NotSquareSubset\n    '⊐' => raw\"\\sqsupset\",\n    \"⊐̸\" => raw\"\\not\\sqsupset\",  # \\NotSquareSuperset\n    '⊑' => raw\"\\sqsubseteq\",\n    '⊒' => raw\"\\sqsupseteq\",\n    '⊓' => raw\"\\sqcap\",\n    '⊔' => raw\"\\sqcup\",\n    '⊕' => raw\"\\oplus\",\n    '⊖' => raw\"\\ominus\",\n    '⊗' => raw\"\\otimes\",\n    '⊘' => raw\"\\oslash\",\n    '⊙' => raw\"\\odot\",\n    '⊚' => raw\"\\circledcirc\",\n    '⊛' => raw\"\\circledast\",\n    '⊜' => raw\"\\circledequal\",\n    '⊝' => raw\"\\circleddash\",\n    '⊞' => raw\"\\boxplus\",\n    '⊟' => raw\"\\boxminus\",\n    '⊠' => raw\"\\boxtimes\",\n    '⊡' => raw\"\\boxdot\",\n    '⊢' => raw\"\\vdash\",\n    '⊣' => raw\"\\dashv\",\n    '⊤' => raw\"\\top\",\n    '⊥' => raw\"\\bot\",\n    '⊧' => raw\"\\models\",\n    '⊨' => raw\"\\vDash\",\n    '⊩' => raw\"\\Vdash\",\n    '⊪' => raw\"\\Vvdash\",\n    '⊫' => raw\"\\VDash\",\n    '⊬' => raw\"\\nvdash\",\n    '⊭' => raw\"\\nvDash\",\n    '⊮' => raw\"\\nVdash\",\n    '⊯' => raw\"\\nVDash\",\n    '⊰' => raw\"\\prurel\",\n    '⊱' => raw\"\\scurel\",\n    '⊲' => raw\"\\vartriangleleft\",\n    '⊳' => raw\"\\vartriangleright\",\n    '⊴' => raw\"\\trianglelefteq\",\n    '⊵' => raw\"\\trianglerighteq\",\n    '⊶' => raw\"\\origof\",  # \\original\n    '⊷' => raw\"\\imageof\",  # \\image\n    '⊸' => raw\"\\multimap\",\n    '⊹' => raw\"\\hermitmatrix\",  # \\hermitconjmatrix\n    '⊺' => raw\"\\intercal\",\n    '⊻' => raw\"\\veebar\",  # \\xor\n    '⊼' => raw\"\\barwedge\",  # \\nand\n    '⊽' => raw\"\\barvee\",\n    '⊾' => raw\"\\measuredrightangle\",  # \\rightanglearc\n    '⊿' => raw\"\\varlrtriangle\",\n    '⋀' => raw\"\\bigwedge\",\n    '⋁' => raw\"\\bigvee\",\n    '⋂' => raw\"\\bigcap\",\n    '⋃' => raw\"\\bigcup\",\n    '⋄' => raw\"\\diamond\",\n    '⋅' => raw\"\\cdot\",\n    '⋆' => raw\"\\star\",\n    '⋇' => raw\"\\divideontimes\",\n    '⋈' => raw\"\\bowtie\",\n    '⋉' => raw\"\\ltimes\",\n    '⋊' => raw\"\\rtimes\",\n    '⋋' => raw\"\\leftthreetimes\",\n    '⋌' => raw\"\\rightthreetimes\",\n    '⋍' => raw\"\\backsimeq\",\n    '⋎' => raw\"\\curlyvee\",\n    '⋏' => raw\"\\curlywedge\",\n    '⋐' => raw\"\\Subset\",\n    '⋑' => raw\"\\Supset\",\n    '⋒' => raw\"\\Cap\",\n    '⋓' => raw\"\\Cup\",\n    '⋔' => raw\"\\pitchfork\",\n    '⋕' => raw\"\\equalparallel\",\n    '⋖' => raw\"\\lessdot\",\n    '⋗' => raw\"\\gtrdot\",\n    '⋘' => raw\"\\lll\",  # \\verymuchless\n    '⋙' => raw\"\\ggg\",\n    '⋚' => raw\"\\lesseqgtr\",\n    '⋛' => raw\"\\gtreqless\",\n    '⋜' => raw\"\\eqless\",\n    '⋝' => raw\"\\eqgtr\",\n    '⋞' => raw\"\\curlyeqprec\",\n    '⋟' => raw\"\\curlyeqsucc\",\n    '⋠' => raw\"\\npreccurlyeq\",\n    '⋡' => raw\"\\nsucccurlyeq\",\n    '⋢' => raw\"\\nsqsubseteq\",\n    '⋣' => raw\"\\nsqsupseteq\",\n    '⋤' => raw\"\\sqsubsetneq\",\n    '⋥' => raw\"\\sqsupsetneq\",  # \\sqspne\n    '⋦' => raw\"\\lnsim\",\n    '⋧' => raw\"\\gnsim\",\n    '⋨' => raw\"\\precnsim\",\n    '⋩' => raw\"\\succnsim\",\n    '⋪' => raw\"\\ntriangleleft\",\n    '⋫' => raw\"\\ntriangleright\",\n    '⋬' => raw\"\\ntrianglelefteq\",\n    '⋭' => raw\"\\ntrianglerighteq\",\n    '⋮' => raw\"\\vdots\",\n    '⋯' => raw\"\\cdots\",\n    '⋰' => raw\"\\adots\",\n    '⋱' => raw\"\\ddots\",\n    '⋲' => raw\"\\disin\",\n    '⋳' => raw\"\\varisins\",\n    '⋴' => raw\"\\isins\",\n    '⋵' => raw\"\\isindot\",\n    '⋶' => raw\"\\varisinobar\",\n    '⋷' => raw\"\\isinobar\",\n    '⋸' => raw\"\\isinvb\",\n    '⋹' => raw\"\\isinE\",\n    '⋺' => raw\"\\nisd\",\n    '⋻' => raw\"\\varnis\",\n    '⋼' => raw\"\\nis\",\n    '⋽' => raw\"\\varniobar\",\n    '⋾' => raw\"\\niobar\",\n    '⋿' => raw\"\\bagmember\",\n    '⌀' => raw\"\\diameter\",\n    '⌂' => raw\"\\house\",\n    '⌅' => raw\"\\varbarwedge\",\n    '⌆' => raw\"\\vardoublebarwedge\",\n    '⌈' => raw\"\\lceil\",\n    '⌉' => raw\"\\rceil\",\n    '⌊' => raw\"\\lfloor\",\n    '⌋' => raw\"\\rfloor\",\n    '⌐' => raw\"\\invnot\",\n    '⌑' => raw\"\\sqlozenge\",\n    '⌒' => raw\"\\profline\",\n    '⌓' => raw\"\\profsurf\",\n    # '⌕' => raw\"\\recorder\",\n    '⌗' => raw\"\\viewdata\",\n    '⌙' => raw\"\\turnednot\",\n    '⌜' => raw\"\\ulcorner\",\n    '⌝' => raw\"\\urcorner\",\n    '⌞' => raw\"\\llcorner\",\n    '⌟' => raw\"\\lrcorner\",\n    '⌢' => raw\"\\frown\",\n    '⌣' => raw\"\\smile\",\n    '⌬' => raw\"\\varhexagonlrbonds\",\n    '⌲' => raw\"\\conictaper\",\n    '⌶' => raw\"\\topbot\",\n    '⌽' => raw\"\\obar\",\n    '⌿' => raw\"\\APLnotslash\",  # \\notslash\n    '⍀' => raw\"\\APLnotbackslash\",  # \\notbackslash\n    '⍓' => raw\"\\APLboxupcaret\",  # \\boxupcaret\n    '⍰' => raw\"\\APLboxquestion\",  # \\boxquestion\n    '⎔' => raw\"\\hexagon\",\n    '⎣' => raw\"\\lbracklend\",  # \\dlcorn\n    '⎰' => raw\"\\lmoustache\",\n    '⎱' => raw\"\\rmoustache\",\n    '⎴' => raw\"\\overbracket{}\",\n    '⎵' => raw\"\\underbracket{}\",\n    '⎶' => raw\"\\bbrktbrk\",\n    '⎷' => raw\"\\sqrtbottom\",\n    '⎸' => raw\"\\lvboxline\",\n    '⎹' => raw\"\\rvboxline\",\n    '⏎' => raw\"\\varcarriagereturn\",\n    '⏞' => raw\"\\overbrace{}\",\n    '⏟' => raw\"\\underbrace{}\",\n    '⏢' => raw\"\\trapezium\",\n    '⏣' => raw\"\\benzenr\",\n    '⏤' => raw\"\\strns\",\n    '⏥' => raw\"\\fltns\",\n    '⏦' => raw\"\\accurrent\",\n    '⏧' => raw\"\\elinters\",\n    '␢' => raw\"\\blanksymbol\",\n    '␣' => raw\"\\mathvisiblespace\",  # \\visiblespace\n    'Ⓢ' => raw\"\\circledS\",\n    '┆' => raw\"\\bdtriplevdash\",  # \\dshfnc\n    # '┙' => raw\"\\sqfnw\",\n    '╱' => raw\"\\diagup\",\n    '╲' => raw\"\\diagdown\",\n    '▀' => raw\"\\blockuphalf\",\n    '▄' => raw\"\\blocklowhalf\",\n    '█' => raw\"\\blockfull\",\n    '▌' => raw\"\\blocklefthalf\",\n    '▐' => raw\"\\blockrighthalf\",\n    '░' => raw\"\\blockqtrshaded\",\n    '▒' => raw\"\\blockhalfshaded\",\n    '▓' => raw\"\\blockthreeqtrshaded\",\n    '■' => raw\"\\blacksquare\",\n    '□' => raw\"\\square\",\n    '▢' => raw\"\\squoval\",\n    '▣' => raw\"\\blackinwhitesquare\",\n    '▤' => raw\"\\squarehfill\",\n    '▥' => raw\"\\squarevfill\",\n    '▦' => raw\"\\squarehvfill\",\n    '▧' => raw\"\\squarenwsefill\",\n    '▨' => raw\"\\squareneswfill\",\n    '▩' => raw\"\\squarecrossfill\",\n    '▪' => raw\"\\smblksquare\",\n    '▫' => raw\"\\smwhtsquare\",\n    '▬' => raw\"\\hrectangleblack\",\n    '▭' => raw\"\\hrectangle\",\n    '▮' => raw\"\\vrectangleblack\",\n    '▯' => raw\"\\vrectangle\",  # \\vrecto\n    '▰' => raw\"\\parallelogramblack\",\n    '▱' => raw\"\\parallelogram\",\n    '▲' => raw\"\\bigblacktriangleup\",\n    '△' => raw\"\\bigtriangleup\",\n    '▴' => raw\"\\blacktriangle\",\n    '▵' => raw\"\\vartriangle\",\n    '▶' => raw\"\\blacktriangleright\",\n    '▷' => raw\"\\triangleright\",\n    '▸' => raw\"\\smallblacktriangleright\",\n    '▹' => raw\"\\smalltriangleright\",\n    '►' => raw\"\\blackpointerright\",\n    '▻' => raw\"\\whitepointerright\",\n    '▼' => raw\"\\bigblacktriangledown\",\n    '▽' => raw\"\\bigtriangledown\",\n    '▾' => raw\"\\blacktriangledown\",\n    '▿' => raw\"\\triangledown\",\n    '◀' => raw\"\\blacktriangleleft\",\n    '◁' => raw\"\\triangleleft\",\n    '◂' => raw\"\\smallblacktriangleleft\",\n    '◃' => raw\"\\smalltriangleleft\",\n    '◄' => raw\"\\blackpointerleft\",\n    '◅' => raw\"\\whitepointerleft\",\n    '◆' => raw\"\\mdlgblkdiamond\",\n    '◇' => raw\"\\mdlgwhtdiamond\",\n    '◈' => raw\"\\blackinwhitediamond\",\n    '◉' => raw\"\\fisheye\",\n    '◊' => raw\"\\lozenge\",\n    '○' => raw\"\\bigcirc\",\n    '◌' => raw\"\\dottedcircle\",\n    '◍' => raw\"\\circlevertfill\",\n    '◎' => raw\"\\bullseye\",\n    '●' => raw\"\\mdlgblkcircle\",\n    '◐' => raw\"\\circlelefthalfblack\",  # \\cirfl\n    '◑' => raw\"\\circlerighthalfblack\",  # \\cirfr\n    '◒' => raw\"\\circlebottomhalfblack\",  # \\cirfb\n    '◓' => raw\"\\circletophalfblack\",\n    '◔' => raw\"\\circleurquadblack\",\n    '◕' => raw\"\\blackcircleulquadwhite\",\n    '◖' => raw\"\\blacklefthalfcircle\",\n    '◗' => raw\"\\blackrighthalfcircle\",\n    '◘' => raw\"\\inversebullet\",  # \\rvbull\n    '◙' => raw\"\\inversewhitecircle\",\n    '◚' => raw\"\\invwhiteupperhalfcircle\",\n    '◛' => raw\"\\invwhitelowerhalfcircle\",\n    '◜' => raw\"\\ularc\",\n    '◝' => raw\"\\urarc\",\n    '◞' => raw\"\\lrarc\",\n    '◟' => raw\"\\llarc\",\n    '◠' => raw\"\\topsemicircle\",\n    '◡' => raw\"\\botsemicircle\",\n    '◢' => raw\"\\lrblacktriangle\",\n    '◣' => raw\"\\llblacktriangle\",\n    '◤' => raw\"\\ulblacktriangle\",\n    '◥' => raw\"\\urblacktriangle\",\n    '◦' => raw\"\\smwhtcircle\",\n    '◧' => raw\"\\squareleftblack\",  # \\sqfl\n    '◨' => raw\"\\squarerightblack\",  # \\sqfr\n    '◩' => raw\"\\squareulblack\",\n    '◪' => raw\"\\squarelrblack\",  # \\sqfse\n    '◫' => raw\"\\boxbar\",\n    '◬' => raw\"\\trianglecdot\",\n    '◭' => raw\"\\triangleleftblack\",\n    '◮' => raw\"\\trianglerightblack\",\n    '◯' => raw\"\\lgwhtcircle\",\n    '◰' => raw\"\\squareulquad\",\n    '◱' => raw\"\\squarellquad\",\n    '◲' => raw\"\\squarelrquad\",\n    '◳' => raw\"\\squareurquad\",\n    '◴' => raw\"\\circleulquad\",\n    '◵' => raw\"\\circlellquad\",\n    '◶' => raw\"\\circlelrquad\",\n    '◷' => raw\"\\circleurquad\",\n    '◸' => raw\"\\ultriangle\",\n    '◹' => raw\"\\urtriangle\",\n    '◺' => raw\"\\lltriangle\",\n    '◻' => raw\"\\mdwhtsquare\",\n    '◼' => raw\"\\mdblksquare\",\n    '◽' => raw\"\\mdsmwhtsquare\",\n    '◾' => raw\"\\mdsmblksquare\",\n    '◿' => raw\"\\lrtriangle\",\n    '★' => raw\"\\bigstar\",\n    '☆' => raw\"\\bigwhitestar\",\n    '☉' => raw\"\\astrosun\",\n    '☡' => raw\"\\danger\",\n    '☻' => raw\"\\blacksmiley\",\n    '☼' => raw\"\\sun\",\n    '☽' => raw\"\\rightmoon\",\n    '☾' => raw\"\\leftmoon\",\n    # '☿' => raw\"\\mercury\",\n    '♀' => raw\"\\female\",  # \\venus\n    '♂' => raw\"\\male\",  # \\mars\n    # '♃' => raw\"\\jupiter\",  # `marvosym` or `wasysym`\n    # '♄' => raw\"\\saturn\",\n    # '♅' => raw\"\\uranus\",\n    # '♆' => raw\"\\neptune\",\n    # '♇' => raw\"\\pluto\",\n    # '♈' => raw\"\\aries\",\n    # '♉' => raw\"\\taurus\",\n    # '♊' => raw\"\\gemini\",\n    # '♋' => raw\"\\cancer\",\n    # '♌' => raw\"\\leo\",\n    # '♍' => raw\"\\virgo\",\n    # '♎' => raw\"\\libra\",\n    # '♏' => raw\"\\scorpio\",\n    # '♐' => raw\"\\sagittarius\",\n    # '♑' => raw\"\\capricornus\",\n    # '♒' => raw\"\\aquarius\",\n    # '♓' => raw\"\\pisces\",\n    '♠' => raw\"\\spadesuit\",\n    '♡' => raw\"\\heartsuit\",\n    '♢' => raw\"\\diamondsuit\",\n    '♣' => raw\"\\clubsuit\",\n    '♤' => raw\"\\varspadesuit\",\n    '♥' => raw\"\\varheartsuit\",\n    '♦' => raw\"\\vardiamondsuit\",\n    '♧' => raw\"\\varclubsuit\",\n    '♩' => raw\"\\quarternote\",\n    '♪' => raw\"\\eighthnote\",\n    '♫' => raw\"\\twonotes\",\n    '♭' => raw\"\\flat\",\n    '♮' => raw\"\\natural\",\n    '♯' => raw\"\\sharp\",\n    '♾' => raw\"\\acidfree\",\n    '⚀' => raw\"\\dicei\",\n    '⚁' => raw\"\\diceii\",\n    '⚂' => raw\"\\diceiii\",\n    '⚃' => raw\"\\diceiv\",\n    '⚄' => raw\"\\dicev\",\n    '⚅' => raw\"\\dicevi\",\n    '⚆' => raw\"\\circledrightdot\",\n    '⚇' => raw\"\\circledtwodots\",\n    '⚈' => raw\"\\blackcircledrightdot\",\n    '⚉' => raw\"\\blackcircledtwodots\",\n    '⚥' => raw\"\\Hermaphrodite\",  # \\hermaphrodite\n    '⚪' => raw\"\\mdwhtcircle\",\n    '⚫' => raw\"\\mdblkcircle\",\n    '⚬' => raw\"\\mdsmwhtcircle\",\n    '⚲' => raw\"\\neuter\",\n    '✓' => raw\"\\checkmark\",\n    '✠' => raw\"\\maltese\",\n    '✪' => raw\"\\circledstar\",\n    '✶' => raw\"\\varstar\",\n    '✽' => raw\"\\dingasterisk\",\n    '➛' => raw\"\\draftingarrow\",\n    '⟀' => raw\"\\threedangle\",\n    '⟁' => raw\"\\whiteinwhitetriangle\",\n    '⟂' => raw\"\\perp\",\n    '⟈' => raw\"\\bsolhsub\",\n    '⟉' => raw\"\\suphsol\",\n    '⟑' => raw\"\\wedgedot\",\n    '⟒' => raw\"\\upin\",\n    '⟕' => raw\"\\leftouterjoin\",\n    '⟖' => raw\"\\rightouterjoin\",\n    '⟗' => raw\"\\fullouterjoin\",\n    '⟘' => raw\"\\bigbot\",\n    '⟙' => raw\"\\bigtop\",\n    '⟦' => raw\"\\lBrack\",  # \\llbracket, \\openbracketleft\n    '⟧' => raw\"\\rBrack\",  # \\rrbracket, \\openbracketright\n    '⟨' => raw\"\\langle\",\n    '⟩' => raw\"\\rangle\",\n    '⟰' => raw\"\\UUparrow\",\n    '⟱' => raw\"\\DDownarrow\",\n    '⟵' => raw\"\\longleftarrow\",\n    '⟶' => raw\"\\longrightarrow\",\n    '⟷' => raw\"\\longleftrightarrow\",\n    '⟸' => raw\"\\Longleftarrow\",  # \\impliedby\n    '⟹' => raw\"\\Longrightarrow\",  # \\implies\n    '⟺' => raw\"\\Longleftrightarrow\",  # \\iff\n    '⟻' => raw\"\\longmapsfrom\",\n    '⟼' => raw\"\\longmapsto\",\n    '⟽' => raw\"\\Longmapsfrom\",\n    '⟾' => raw\"\\Longmapsto\",\n    '⟿' => raw\"\\longrightsquigarrow\",\n    '⤀' => raw\"\\nvtwoheadrightarrow\",\n    '⤁' => raw\"\\nVtwoheadrightarrow\",\n    '⤂' => raw\"\\nvLeftarrow\",\n    '⤃' => raw\"\\nvRightarrow\",\n    '⤄' => raw\"\\nvLeftrightarrow\",\n    '⤅' => raw\"\\twoheadmapsto\",\n    '⤆' => raw\"\\Mapsfrom\",\n    '⤇' => raw\"\\Mapsto\",\n    '⤈' => raw\"\\downarrowbarred\",\n    '⤉' => raw\"\\uparrowbarred\",\n    '⤊' => raw\"\\Uuparrow\",\n    '⤋' => raw\"\\Ddownarrow\",\n    '⤌' => raw\"\\leftbkarrow\",\n    '⤍' => raw\"\\rightbkarrow\",  # \\bkarow\n    '⤎' => raw\"\\leftdbkarrow\",\n    '⤏' => raw\"\\dbkarow\",\n    '⤐' => raw\"\\drbkarrow\",\n    '⤑' => raw\"\\rightdotarrow\",\n    '⤒' => raw\"\\baruparrow\",  # \\UpArrowBar\n    '⤓' => raw\"\\downarrowbar\",  # \\DownArrowBar\n    '⤔' => raw\"\\nvrightarrowtail\",\n    '⤕' => raw\"\\nVrightarrowtail\",\n    '⤖' => raw\"\\twoheadrightarrowtail\",\n    '⤗' => raw\"\\nvtwoheadrightarrowtail\",\n    '⤘' => raw\"\\nVtwoheadrightarrowtail\",\n    '⤝' => raw\"\\diamondleftarrow\",\n    '⤞' => raw\"\\rightarrowdiamond\",\n    '⤟' => raw\"\\diamondleftarrowbar\",\n    '⤠' => raw\"\\barrightarrowdiamond\",\n    '⤥' => raw\"\\hksearow\",\n    '⤦' => raw\"\\hkswarow\",\n    '⤧' => raw\"\\tona\",\n    '⤨' => raw\"\\toea\",\n    '⤩' => raw\"\\tosa\",\n    '⤪' => raw\"\\towa\",\n    '⤫' => raw\"\\rdiagovfdiag\",\n    '⤬' => raw\"\\fdiagovrdiag\",\n    '⤭' => raw\"\\seovnearrow\",\n    '⤮' => raw\"\\neovsearrow\",\n    '⤯' => raw\"\\fdiagovnearrow\",\n    '⤰' => raw\"\\rdiagovsearrow\",\n    '⤱' => raw\"\\neovnwarrow\",\n    '⤲' => raw\"\\nwovnearrow\",\n    '⥂' => raw\"\\rightarrowshortleftarrow\",  # \\Rlarr\n    '⥄' => raw\"\\leftarrowshortrightarrow\",  # \\rLarr\n    '⥅' => raw\"\\rightarrowplus\",\n    '⥆' => raw\"\\leftarrowplus\",\n    '⥇' => raw\"\\rightarrowx\",  # \\rarrx\n    '⥈' => raw\"\\leftrightarrowcircle\",\n    '⥉' => raw\"\\twoheaduparrowcircle\",\n    '⥊' => raw\"\\leftrightharpoonupdown\",\n    '⥋' => raw\"\\leftrightharpoondownup\",\n    '⥌' => raw\"\\updownharpoonrightleft\",\n    '⥍' => raw\"\\updownharpoonleftright\",\n    '⥎' => raw\"\\leftrightharpoonupup\",  # \\LeftRightVector\n    '⥏' => raw\"\\updownharpoonrightright\",  # \\RightUpDownVector\n    '⥐' => raw\"\\leftrightharpoondowndown\",  # \\DownLeftRightVector\n    '⥑' => raw\"\\updownharpoonleftleft\",  # \\LeftUpDownVector\n    '⥒' => raw\"\\barleftharpoonup\",  # \\LeftVectorBar\n    '⥓' => raw\"\\rightharpoonupbar\",  # \\RightVectorBar\n    '⥔' => raw\"\\barupharpoonright\",  # \\RightUpVectorBar\n    '⥕' => raw\"\\downharpoonrightbar\",  # \\RightDownVectorBar\n    '⥖' => raw\"\\barleftharpoondown\",  # \\DownLeftVectorBar\n    '⥗' => raw\"\\rightharpoondownbar\",  # \\DownRightVectorBar\n    '⥘' => raw\"\\barupharpoonleft\",  # \\LeftUpVectorBar\n    '⥙' => raw\"\\downharpoonleftbar\",  # \\LeftDownVectorBar\n    '⥚' => raw\"\\leftharpoonupbar\",  # \\LeftTeeVector\n    '⥛' => raw\"\\barrightharpoonup\",  # \\RightTeeVector\n    '⥜' => raw\"\\upharpoonrightbar\",  # \\RightUpTeeVector\n    '⥝' => raw\"\\bardownharpoonright\",  # \\RightDownTeeVector\n    '⥞' => raw\"\\leftharpoondownbar\",  # \\DownLeftTeeVector\n    '⥟' => raw\"\\barrightharpoondown\",  # \\DownRightTeeVector\n    '⥠' => raw\"\\upharpoonleftbar\",  # \\LeftUpTeeVector\n    '⥡' => raw\"\\bardownharpoonleft\",  # \\LeftDownTeeVector\n    '⥢' => raw\"\\leftharpoonsupdown\",\n    '⥣' => raw\"\\upharpoonsleftright\",\n    '⥤' => raw\"\\rightharpoonsupdown\",\n    '⥥' => raw\"\\downharpoonsleftright\",\n    '⥦' => raw\"\\leftrightharpoonsup\",\n    '⥧' => raw\"\\leftrightharpoonsdown\",\n    '⥨' => raw\"\\rightleftharpoonsup\",\n    '⥩' => raw\"\\rightleftharpoonsdown\",\n    '⥪' => raw\"\\leftharpoonupdash\",\n    '⥫' => raw\"\\dashleftharpoondown\",\n    '⥬' => raw\"\\rightharpoonupdash\",\n    '⥭' => raw\"\\dashrightharpoondown\",\n    '⥮' => raw\"\\updownharpoonsleftright\",  # \\UpEquilibrium\n    '⥯' => raw\"\\downupharpoonsleftright\",  # \\ReverseUpEquilibrium\n    '⥰' => raw\"\\rightimply\",  # \\RoundImplies\n    '⦀' => raw\"\\Vvert\",\n    '⦆' => raw\"\\rParen\",  # \\Elroang\n    '⦙' => raw\"\\fourvdots\",  # \\ddfnc\n    '⦛' => raw\"\\measuredangleleft\",\n    '⦜' => raw\"\\rightanglesqr\",  # \\Angle\n    '⦝' => raw\"\\rightanglemdot\",\n    '⦞' => raw\"\\angles\",\n    '⦟' => raw\"\\angdnr\",\n    '⦠' => raw\"\\gtlpar\",  # \\lpargt\n    '⦡' => raw\"\\sphericalangleup\",\n    '⦢' => raw\"\\turnangle\",\n    '⦣' => raw\"\\revangle\",\n    '⦤' => raw\"\\angleubar\",\n    '⦥' => raw\"\\revangleubar\",\n    '⦦' => raw\"\\wideangledown\",\n    '⦧' => raw\"\\wideangleup\",\n    '⦨' => raw\"\\measanglerutone\",\n    '⦩' => raw\"\\measanglelutonw\",\n    '⦪' => raw\"\\measanglerdtose\",\n    '⦫' => raw\"\\measangleldtosw\",\n    '⦬' => raw\"\\measangleurtone\",\n    '⦭' => raw\"\\measangleultonw\",\n    '⦮' => raw\"\\measangledrtose\",\n    '⦯' => raw\"\\measangledltosw\",\n    '⦰' => raw\"\\revemptyset\",\n    '⦱' => raw\"\\emptysetobar\",\n    '⦲' => raw\"\\emptysetocirc\",\n    '⦳' => raw\"\\emptysetoarr\",\n    '⦴' => raw\"\\emptysetoarrl\",\n    '⦷' => raw\"\\circledparallel\",\n    '⦸' => raw\"\\obslash\",\n    '⦼' => raw\"\\odotslashdot\",\n    '⦾' => raw\"\\circledwhitebullet\",\n    '⦿' => raw\"\\circledbullet\",\n    '⧀' => raw\"\\olessthan\",\n    '⧁' => raw\"\\ogreaterthan\",\n    '⧄' => raw\"\\boxdiag\",\n    '⧅' => raw\"\\boxbslash\",\n    '⧆' => raw\"\\boxast\",\n    '⧇' => raw\"\\boxcircle\",\n    '⧊' => raw\"\\triangleodot\",  # \\Lap\n    '⧋' => raw\"\\triangleubar\",  # \\defas\n    '⧏' => raw\"\\ltrivb\",  # \\LeftTriangleBar\n    \"⧏̸\" => raw\"\\not\\ltrivb\",  # \\NotLeftTriangleBar\n    '⧐' => raw\"\\vbrtri\",  # \\RightTriangleBar\n    \"⧐̸\" => raw\"\\not\\vbrtri\",  # \\NotRightTriangleBar\n    '⧟' => raw\"\\dualmap\",\n    '⧡' => raw\"\\lrtriangleeq\",\n    '⧢' => raw\"\\shuffle\",\n    '⧣' => raw\"\\eparsl\",\n    '⧤' => raw\"\\smeparsl\",\n    '⧥' => raw\"\\eqvparsl\",\n    '⧫' => raw\"\\blacklozenge\",\n    '⧴' => raw\"\\ruledelayed\",  # \\RuleDelayed\n    '⧶' => raw\"\\dsol\",\n    '⧷' => raw\"\\rsolbar\",\n    '⧺' => raw\"\\doubleplus\",\n    '⧻' => raw\"\\tripleplus\",\n    '⨀' => raw\"\\bigodot\",\n    '⨁' => raw\"\\bigoplus\",\n    '⨂' => raw\"\\bigotimes\",\n    '⨃' => raw\"\\bigcupdot\",\n    '⨄' => raw\"\\biguplus\",\n    '⨅' => raw\"\\bigsqcap\",\n    '⨆' => raw\"\\bigsqcup\",\n    '⨇' => raw\"\\conjquant\",\n    '⨈' => raw\"\\disjquant\",\n    '⨉' => raw\"\\bigtimes\",\n    '⨊' => raw\"\\modtwosum\",\n    '⨋' => raw\"\\sumint\",\n    '⨌' => raw\"\\iiiint\",\n    '⨍' => raw\"\\intbar\",\n    '⨎' => raw\"\\intBar\",\n    '⨏' => raw\"\\fint\",  # \\clockoint\n    '⨐' => raw\"\\cirfnint\",\n    '⨑' => raw\"\\awint\",\n    '⨒' => raw\"\\rppolint\",\n    '⨓' => raw\"\\scpolint\",\n    '⨔' => raw\"\\npolint\",\n    '⨕' => raw\"\\pointint\",\n    '⨖' => raw\"\\sqint\",  # \\sqrint\n    '⨘' => raw\"\\intx\",\n    '⨙' => raw\"\\intcap\",\n    '⨚' => raw\"\\intcup\",\n    '⨛' => raw\"\\upint\",\n    '⨜' => raw\"\\lowint\",\n    '⨝' => raw\"\\Join\",  # \\join\n    '⨟' => raw\"\\zcmp\",  # \\bbsemi\n    '⨢' => raw\"\\ringplus\",\n    '⨣' => raw\"\\plushat\",\n    '⨤' => raw\"\\simplus\",\n    '⨥' => raw\"\\plusdot\",\n    '⨦' => raw\"\\plussim\",\n    '⨧' => raw\"\\plussubtwo\",\n    '⨨' => raw\"\\plustrif\",\n    '⨩' => raw\"\\commaminus\",\n    '⨪' => raw\"\\minusdot\",\n    '⨫' => raw\"\\minusfdots\",\n    '⨬' => raw\"\\minusrdots\",\n    '⨭' => raw\"\\opluslhrim\",\n    '⨮' => raw\"\\oplusrhrim\",\n    '⨯' => raw\"\\vectimes\",  # \\Times\n    '⨰' => raw\"\\dottimes\",\n    '⨱' => raw\"\\timesbar\",\n    '⨲' => raw\"\\btimes\",\n    '⨳' => raw\"\\smashtimes\",\n    '⨴' => raw\"\\otimeslhrim\",\n    '⨵' => raw\"\\otimesrhrim\",\n    '⨶' => raw\"\\otimeshat\",\n    '⨷' => raw\"\\Otimes\",\n    '⨸' => raw\"\\odiv\",\n    '⨹' => raw\"\\triangleplus\",\n    '⨺' => raw\"\\triangleminus\",\n    '⨻' => raw\"\\triangletimes\",\n    '⨼' => raw\"\\intprod\",\n    '⨽' => raw\"\\intprodr\",\n    '⨿' => raw\"\\amalg\",\n    '⩀' => raw\"\\capdot\",\n    '⩁' => raw\"\\uminus\",\n    '⩂' => raw\"\\barcup\",\n    '⩃' => raw\"\\barcap\",\n    '⩄' => raw\"\\capwedge\",\n    '⩅' => raw\"\\cupvee\",\n    '⩊' => raw\"\\twocups\",\n    '⩋' => raw\"\\twocaps\",\n    '⩌' => raw\"\\closedvarcup\",\n    '⩍' => raw\"\\closedvarcap\",\n    '⩎' => raw\"\\Sqcap\",\n    '⩏' => raw\"\\Sqcup\",\n    '⩐' => raw\"\\closedvarcupsmashprod\",\n    '⩑' => raw\"\\wedgeodot\",\n    '⩒' => raw\"\\veeodot\",\n    '⩓' => raw\"\\Wedge\",  # \\And\n    '⩔' => raw\"\\Vee\",  # \\Or\n    '⩕' => raw\"\\wedgeonwedge\",\n    '⩖' => raw\"\\veeonvee\",  # \\ElOr\n    '⩗' => raw\"\\bigslopedvee\",\n    '⩘' => raw\"\\bigslopedwedge\",\n    '⩚' => raw\"\\wedgemidvert\",\n    '⩛' => raw\"\\veemidvert\",\n    '⩜' => raw\"\\midbarwedge\",\n    '⩝' => raw\"\\midbarvee\",\n    '⩞' => raw\"\\doublebarwedge\",  # \\perspcorrespond\n    '⩟' => raw\"\\wedgebar\",  # \\minhat\n    '⩠' => raw\"\\wedgedoublebar\",\n    '⩡' => raw\"\\varveebar\",\n    '⩢' => raw\"\\doublebarvee\",\n    '⩣' => raw\"\\veedoublebar\",\n    '⩦' => raw\"\\eqdot\",\n    '⩧' => raw\"\\dotequiv\",\n    '⩪' => raw\"\\dotsim\",\n    '⩫' => raw\"\\simrdots\",\n    '⩬' => raw\"\\simminussim\",\n    '⩭' => raw\"\\congdot\",\n    '⩮' => raw\"\\asteq\",\n    '⩯' => raw\"\\hatapprox\",\n    '⩰' => raw\"\\approxeqq\",\n    '⩱' => raw\"\\eqqplus\",\n    '⩲' => raw\"\\pluseqq\",\n    '⩳' => raw\"\\eqqsim\",\n    '⩴' => raw\"\\Coloneq\",\n    '⩵' => raw\"\\eqeq\",  # \\Equal\n    '⩶' => raw\"\\eqeqeq\",\n    '⩷' => raw\"\\ddotseq\",\n    '⩸' => raw\"\\equivDD\",\n    '⩹' => raw\"\\ltcir\",\n    '⩺' => raw\"\\gtcir\",\n    '⩻' => raw\"\\ltquest\",\n    '⩼' => raw\"\\gtquest\",\n    '⩽' => raw\"\\leqslant\",\n    \"⩽̸\" => raw\"\\not\\leqslant\",  # \\nleqslant\n    '⩾' => raw\"\\geqslant\",\n    \"⩾̸\" => raw\"\\not\\geqslant\",  # \\ngeqslant\n    '⩿' => raw\"\\lesdot\",\n    '⪀' => raw\"\\gesdot\",\n    '⪁' => raw\"\\lesdoto\",\n    '⪂' => raw\"\\gesdoto\",\n    '⪃' => raw\"\\lesdotor\",\n    '⪄' => raw\"\\gesdotol\",\n    '⪅' => raw\"\\lessapprox\",\n    '⪆' => raw\"\\gtrapprox\",\n    '⪇' => raw\"\\lneq\",\n    '⪈' => raw\"\\gneq\",\n    '⪉' => raw\"\\lnapprox\",\n    '⪊' => raw\"\\gnapprox\",\n    '⪋' => raw\"\\lesseqqgtr\",\n    '⪌' => raw\"\\gtreqqless\",\n    '⪍' => raw\"\\lsime\",\n    '⪎' => raw\"\\gsime\",\n    '⪏' => raw\"\\lsimg\",\n    '⪐' => raw\"\\gsiml\",\n    '⪑' => raw\"\\lgE\",\n    '⪒' => raw\"\\glE\",\n    '⪓' => raw\"\\lesges\",\n    '⪔' => raw\"\\gesles\",\n    '⪕' => raw\"\\eqslantless\",\n    '⪖' => raw\"\\eqslantgtr\",\n    '⪗' => raw\"\\elsdot\",\n    '⪘' => raw\"\\egsdot\",\n    '⪙' => raw\"\\eqqless\",\n    '⪚' => raw\"\\eqqgtr\",\n    '⪛' => raw\"\\eqqslantless\",\n    '⪜' => raw\"\\eqqslantgtr\",\n    '⪝' => raw\"\\simless\",\n    '⪞' => raw\"\\simgtr\",\n    '⪟' => raw\"\\simlE\",\n    '⪠' => raw\"\\simgE\",\n    '⪡' => raw\"\\Lt\",  # \\NestedLessLess\n    \"⪡̸\" => raw\"\\not\\Lt\",\n    '⪢' => raw\"\\Gt\",  # \\NestedGreaterGreater\n    \"⪢̸\" => raw\"\\not\\Gt\",\n    '⪣' => raw\"\\partialmeetcontraction\",\n    '⪤' => raw\"\\glj\",\n    '⪥' => raw\"\\gla\",\n    '⪦' => raw\"\\ltcc\",\n    '⪧' => raw\"\\gtcc\",\n    '⪨' => raw\"\\lescc\",\n    '⪩' => raw\"\\gescc\",\n    '⪪' => raw\"\\smt\",\n    '⪫' => raw\"\\lat\",\n    '⪬' => raw\"\\smte\",\n    '⪭' => raw\"\\late\",\n    '⪮' => raw\"\\bumpeqq\",\n    '⪯' => raw\"\\preceq\",\n    \"⪯̸\" => raw\"\\not\\preceq\",  # \\npreceq\n    '⪰' => raw\"\\succeq\",\n    \"⪰̸\" => raw\"\\not\\nsucceq\",  # \\nsucceq\n    '⪱' => raw\"\\precneq\",\n    '⪲' => raw\"\\succneq\",\n    '⪳' => raw\"\\preceqq\",\n    '⪴' => raw\"\\succeqq\",\n    '⪵' => raw\"\\precneqq\",\n    '⪶' => raw\"\\succneqq\",\n    '⪷' => raw\"\\precapprox\",\n    '⪸' => raw\"\\succapprox\",\n    '⪹' => raw\"\\precnapprox\",\n    '⪺' => raw\"\\succnapprox\",\n    '⪻' => raw\"\\Prec\",\n    '⪼' => raw\"\\Succ\",\n    '⪽' => raw\"\\subsetdot\",\n    '⪾' => raw\"\\supsetdot\",\n    '⪿' => raw\"\\subsetplus\",\n    '⫀' => raw\"\\supsetplus\",\n    '⫁' => raw\"\\submult\",\n    '⫂' => raw\"\\supmult\",\n    '⫃' => raw\"\\subedot\",\n    '⫄' => raw\"\\supedot\",\n    '⫅' => raw\"\\subseteqq\",\n    \"⫅̸\" => raw\"\\not\\subseteqq\",  # \\subseteqq\n    '⫆' => raw\"\\supseteqq\",\n    \"⫆̸\" => raw\"\\not\\supseteqq\",  # \\supseteqq\n    '⫇' => raw\"\\subsim\",\n    '⫈' => raw\"\\supsim\",\n    '⫉' => raw\"\\subsetapprox\",\n    '⫊' => raw\"\\supsetapprox\",\n    '⫋' => raw\"\\subsetneqq\",\n    '⫌' => raw\"\\supsetneqq\",\n    '⫍' => raw\"\\lsqhook\",\n    '⫎' => raw\"\\rsqhook\",\n    '⫏' => raw\"\\csub\",\n    '⫐' => raw\"\\csup\",\n    '⫑' => raw\"\\csube\",\n    '⫒' => raw\"\\csupe\",\n    '⫓' => raw\"\\subsup\",\n    '⫔' => raw\"\\supsub\",\n    '⫕' => raw\"\\subsub\",\n    '⫖' => raw\"\\supsup\",\n    '⫗' => raw\"\\suphsub\",\n    '⫘' => raw\"\\supdsub\",\n    '⫙' => raw\"\\forkv\",\n    '⫛' => raw\"\\mlcp\",\n    '⫝̸' => raw\"\\forks\",\n    '⫝' => raw\"\\forksnot\",\n    '⫣' => raw\"\\dashV\",\n    '⫤' => raw\"\\Dashv\",\n    '⫪' => raw\"\\barV\",  # \\downvDash\n    '⫫' => raw\"\\Vbar\",  # \\upvDash, \\indep\n    '⫴' => raw\"\\interleave\",\n    '⫶' => raw\"\\threedotcolon\",  # \\tdcol\n    '⫷' => raw\"\\lllnest\",\n    '⫸' => raw\"\\gggnest\",\n    '⫹' => raw\"\\leqqslant\",\n    '⫺' => raw\"\\geqqslant\",\n    '⬒' => raw\"\\squaretopblack\",\n    '⬓' => raw\"\\squarebotblack\",\n    '⬔' => raw\"\\squareurblack\",\n    '⬕' => raw\"\\squarellblack\",\n    '⬖' => raw\"\\diamondleftblack\",\n    '⬗' => raw\"\\diamondrightblack\",\n    '⬘' => raw\"\\diamondtopblack\",\n    '⬙' => raw\"\\diamondbotblack\",\n    '⬚' => raw\"\\dottedsquare\",\n    '⬛' => raw\"\\lgblksquare\",\n    '⬜' => raw\"\\lgwhtsquare\",\n    '⬝' => raw\"\\vysmblksquare\",\n    '⬞' => raw\"\\vysmwhtsquare\",\n    '⬟' => raw\"\\pentagonblack\",\n    '⬠' => raw\"\\pentagon\",\n    '⬡' => raw\"\\varhexagon\",\n    '⬢' => raw\"\\varhexagonblack\",\n    '⬣' => raw\"\\hexagonblack\",\n    '⬤' => raw\"\\lgblkcircle\",\n    '⬥' => raw\"\\mdblkdiamond\",\n    '⬦' => raw\"\\mdwhtdiamond\",\n    '⬧' => raw\"\\mdblklozenge\",\n    '⬨' => raw\"\\mdwhtlozenge\",\n    '⬩' => raw\"\\smblkdiamond\",\n    '⬪' => raw\"\\smblklozenge\",\n    '⬫' => raw\"\\smwhtlozenge\",\n    '⬬' => raw\"\\blkhorzoval\",\n    '⬭' => raw\"\\whthorzoval\",\n    '⬮' => raw\"\\blkvertoval\",\n    '⬯' => raw\"\\whtvertoval\",\n    '⬰' => raw\"\\circleonleftarrow\",\n    '⬱' => raw\"\\leftthreearrows\",\n    '⬲' => raw\"\\leftarrowonoplus\",\n    '⬳' => raw\"\\longleftsquigarrow\",\n    '⬴' => raw\"\\nvtwoheadleftarrow\",\n    '⬵' => raw\"\\nVtwoheadleftarrow\",\n    '⬶' => raw\"\\twoheadmapsfrom\",\n    '⬷' => raw\"\\twoheadleftdbkarrow\",\n    '⬸' => raw\"\\leftdotarrow\",\n    '⬹' => raw\"\\nvleftarrowtail\",\n    '⬺' => raw\"\\nVleftarrowtail\",\n    '⬻' => raw\"\\twoheadleftarrowtail\",\n    '⬼' => raw\"\\nvtwoheadleftarrowtail\",\n    '⬽' => raw\"\\nVtwoheadleftarrowtail\",\n    '⬾' => raw\"\\leftarrowx\",\n    '⬿' => raw\"\\leftcurvedarrow\",\n    '⭀' => raw\"\\equalleftarrow\",\n    '⭁' => raw\"\\bsimilarleftarrow\",\n    '⭂' => raw\"\\leftarrowbackapprox\",\n    '⭃' => raw\"\\rightarrowgtr\",\n    '⭄' => raw\"\\rightarrowsupset\",\n    '⭅' => raw\"\\LLeftarrow\",\n    '⭆' => raw\"\\RRightarrow\",\n    '⭇' => raw\"\\bsimilarrightarrow\",\n    '⭈' => raw\"\\rightarrowbackapprox\",\n    '⭉' => raw\"\\similarleftarrow\",\n    '⭊' => raw\"\\leftarrowapprox\",\n    '⭋' => raw\"\\leftarrowbsimilar\",\n    '⭌' => raw\"\\rightarrowbsimilar\",\n    '⭐' => raw\"\\medwhitestar\",\n    '⭑' => raw\"\\medblackstar\",\n    '⭒' => raw\"\\smwhitestar\",\n    '⭓' => raw\"\\rightpentagonblack\",\n    '⭔' => raw\"\\rightpentagon\",\n    'ⱼ' => raw\"{_j}\",\n    'ⱽ' => raw\"{^V}\",\n    '〒' => raw\"\\postalmark\",\n    'ꜛ' => raw\"{^\\uparrow}\",\n    'ꜜ' => raw\"{^\\downarrow}\",\n    'ꜝ' => raw\"{^!}\",\n    '𝚤' => raw\"\\mathit{\\imath}\",\n    '𝚥' => raw\"\\mathit{\\jmath}\",\n    latex_emphasis(vcat('A':'Z', 'a':'z', '0':'9'))...,\n    map(x -> x[2] => \"\\\\mathbf{$(greek_seq[x[1]])}\", enumerate('𝚨':'𝛡'))...,  # greek with bold emphasis (x58)\n    map(x -> x[2] => \"\\\\mathit{$(greek_seq[x[1]])}\", enumerate('𝛢':'𝜛'))...,  # greek with italic emphasis\n    map(x -> x[2] => \"\\\\mathbfit{$(greek_seq[x[1]])}\", enumerate('𝜜':'𝝕'))...,  # greek with bold+italic emphasis\n    map(x -> x[2] => \"\\\\mathbfsfup{$(greek_seq[x[1]])}\", enumerate('𝝖':'𝞏'))...,  # greek sans-serif with bold emphasis\n    map(x -> x[2] => \"\\\\mathbfsfit{$(greek_seq[x[1]])}\", enumerate('𝞐':'𝟉'))...,  # greek sans-serif with bold+italic emphasis\n    '𝟊' => raw\"\\mbfDigamma\",  # \\Digamma\n    '𝟋' => raw\"\\mbfdigamma\",  # \\digamm\n    latex_diacritics(vcat('A':'Z', 'a':'z'))...,\n)\n\nunicode2latex(c::Char) = unicode2latex(string(c))\nfunction unicode2latex(str::String; safescripts=false)\n    isascii(str) && return str\n\n    str = Unicode.normalize(str; decompose=true) # Get rid of pre-composed characters\n    c_or_s = sizehint!(Union{Char,String}[], length(str))\n\n    it = Iterators.Stateful(str)\n    while !isempty(it)\n        c = popfirst!(it)\n        push!(\n            c_or_s,  # see en.wikipedia.org/wiki/Combining_character\n            if Unicode.category_code(something(peek(it), '0')) == Unicode.UTF8PROC_CATEGORY_MN\n                c * popfirst!(it)\n            else\n                c\n            end\n        )\n    end\n    str_array = map(k -> get(unicodedict, k, k), c_or_s)\n\n    it = Iterators.Stateful(str_array)\n    for (n, x) ∈ enumerate(it)\n        x isa String || continue\n        # Deal with math mode modifiers (\\hat, \\tilde, \\bar, \\dot, ..., \\ddddot)\n        if endswith(x, Char(0x302))\n            x = \"\\\\hat{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x303))\n            x = \"\\\\tilde{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x304))\n            x = \"\\\\bar{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x307))\n            x = \"\\\\dot{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x308))\n            x = \"\\\\ddot{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x20DB))\n            x = \"\\\\dddot{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        elseif endswith(x, Char(0x20DC))\n            x = \"\\\\ddddot{$(unicode2latex(x[begin:prevind(x, end)]))}\"\n            str_array[n] = x\n        end\n        if (next = peek(it)) !== nothing && length(next) == 1\n            c = next isa Char ? next : first(next)\n            if isletter(c) || isdigit(c)\n                str_array[n] = \"{$x}\"\n            end\n        end\n    end\n    str = merge_subscripts(join(str_array); safescripts=safescripts)\n    return merge_superscripts(str; safescripts=safescripts)\nend\n\n\"\"\"\n    merge_superscripts(str; safescripts=false)\n\nMerge sequential superscripts to a better representation.\n\nReturns a string where sequences like \"{^1}{^3}\" are replaced by \"^{1 3}\".\n\nIf `safescripts` is `true`, makes `{^{1 3}}`, which is less aesthetic but might succeed with\ncertain combinations where `false` would not.\n\"\"\"\nfunction merge_superscripts(str; safescripts=false)\n    # pair {^q}{^q}{^q}{^q}{^q} --> {^{q q}}{^{q q}}{^q}\n    str = replace(str, r\"{\\^([^{}]*)}{\\^([^{}]*)}\" => s\"{^{\\1 \\2}}\")\n    # collect ends if needed   {^{q q}}{^{q q}}{^q} --> {^{q q}}{^{q q q}}\n    str = replace(str, r\"{\\^{([^{}]*)}}{\\^([^{}]*)}\" => s\"{^{\\1 \\2}}\")\n    str = replace(str, r\"{\\^{([^{}]*)}}{{\\^([^{}]*)}}\" => s\"{^{\\1 \\2}}\") # if last one was protected by extra {}\n\n    # complete merge  {^{q q}}{^{q q q}} --> {^{q q q q q}}\n    r = r\"{\\^{([^{}]*)}}{\\^{([^{}]*)}}\"\n    while match(r, str) !== nothing\n        str = replace(str, r => s\"{^{\\1 \\2}}\")\n    end\n\n    if ~safescripts\n        # remove external braces\n        str = replace(str, r\"{\\^{([^{}]*)}}\" => s\"^{\\1}\")\n\n        # deal with superscripts that did not need to be merged\n        str = replace(str, r\"{{\\^([^{}]*)}}\" => s\"^{\\1}\")\n        str = replace(str, r\"{\\^([^{}]*)}\" => s\"^\\1\")\n    end\n    return str\nend\n\n\"\"\"\n    merge_subscripts(str; safescripts=false)\n\nMerge sequential subscripts to a better representation.\n\nReturns a string where sequences like \"{_1}{_3}\" are replaced by \"_{1 3}\".\n\nIf `safescripts` is `true`, makes `{_{1 3}}`, which is less aesthetic but might succeed with\ncertain combinations where `false` would not.\n\"\"\"\nfunction merge_subscripts(str; safescripts=false)\n    # pair\n    str = replace(str, r\"{_([^{}]*)}{_([^{}]*)}\" => s\"{_{\\1 \\2}}\")\n    # collect ends if needed\n    str = replace(str, r\"{_{([^{}]*)}}{_([^{}]*)}\" => s\"{_{\\1 \\2}}\")\n    str = replace(str, r\"{_{([^{}]*)}}{{_([^{}]*)}}\" => s\"{_{\\1 \\2}}\") # if last one was protected by extra {}\n\n    # complete merge\n    r = r\"{_{([^{}]*)}}{_{([^{}]*)}}\"\n    while match(r, str) !== nothing\n        str = replace(str, r => s\"{_{\\1 \\2}}\")\n    end\n\n    if ~safescripts\n        # remove external braces\n        str = replace(str, r\"{_{([^{}]*)}}\" => s\"_{\\1}\")\n\n        # deal with subscripts that did not need to be merged\n        str = replace(str, r\"{{_([^{}]*)}}\" => s\"_{\\1}\")\n        str = replace(str, r\"{_([^{}]*)}\" => s\"_\\1\")\n    end\n    return str\n\nend\n"
  },
  {
    "path": "src/utils.jl",
    "content": "\nadd_brackets(ex::Expr, vars) = postwalk(x -> x in vars ? \"\\\\left[ $(convert_subscript(x)) \\\\right]\" : x, ex)\nadd_brackets(arr::AbstractArray, vars) = [add_brackets(element, vars) for element in arr]\nadd_brackets(s::Any, vars) = s\n\ndefault_packages(s) = vcat(\n                           [\"amssymb\", \"amsmath\", \"unicode-math\"],\n                           occursin(\"\\\\ce{\", s) ? [\"mhchem\"] : [],\n                           any(x->occursin(prod(x), s), Iterators.product([\"\\\\si\", \"\\\\SI\", \"\\\\num\", \"\\\\qty\"], [\"{\", \"range{\", \"list{\", \"product{\"])) ? [\"siunitx\"] : [],\n                          )\n\nfunction _writetex(s::LaTeXString;\n        name=tempname(),\n        command=\"\\\\Large\",\n        documentclass=(\"standalone\", \"varwidth=true\"),\n        packages=default_packages(s),\n        preamble=\"\"\n    )\n    doc = \"\"\"\n    \\\\documentclass$(_packagename(documentclass))\n    \"\"\" * prod(map(p -> \"\\\\usepackage$(_packagename(p))\\n\", packages)) * preamble * \"\"\"\n    \\\\begin{document}\n    {\n        $command\n        $s\n    }\n    \\\\end{document}\n    \"\"\"\n    doc = replace(doc, \"\\\\begin{align}\"=>\"\\\\[\\n\\\\begin{aligned}\")\n    doc = replace(doc, \"\\\\end{align}\"=>\"\\\\end{aligned}\\n\\\\]\")\n    doc = replace(doc, \"\\\\require{mhchem}\\n\"=>\"\")\n    texfile = name * \".tex\"\n    write(texfile, doc)\n    texfile\nend\n\nfunction _compile(s::LaTeXString, cmd::Cmd, ext::String;\n        debug=false,\n        name=tempname(),\n        open=true,\n        use_tectonic=false,\n        kw...\n    )\n    use_tectonic && throw(ArgumentError(\"`use_tectonic` requires the `tectonic_jll` package\"))\n    name = abspath(name)\n    mktempdir() do source_dir\n        cd(source_dir) do\n            _writetex(s; name=\"main\", kw...)\n            debug || (cmd = pipeline(cmd, devnull))\n            try\n                run(cmd)\n            catch err\n                isa(err, ProcessFailedException) || rethrow(err)\n                isfile(\"$source_dir/main.log\") || rethrow(LatexifyRenderError(\"\"))\n                mv(\"$source_dir/main.log\", \"$name.log\"; force=true)\n                rethrow(LatexifyRenderError(\"$name.log\"))\n            end\n        end\n        mv(\"$source_dir/main.$ext\", \"$name.$ext\"; force=true)\n    end\n    if open\n        _openfile(name; ext=ext)\n    end\n    return \"$name.$ext\"\nend\n\n\n\nfunction _openfile(name; ext=\"pdf\")\n    if Sys.iswindows()\n        run(`cmd /c \"start $name.$ext\"`, wait=false)\n    elseif Sys.islinux()\n        run(`xdg-open $name.$ext`, wait=false)\n    elseif Sys.isapple()\n        run(`open $name.$ext`, wait=false)\n    elseif Sys.isbsd()\n        run(`xdg-open $name.$ext`, wait=false)\n    end\n\n    return nothing\nend\n\n\n\"\"\"\n    render(::LaTeXString[, ::MIME\"mime\"]; debug=false, name=tempname(), command=\"\\\\Large\", callshow=true, open=true)\n\nDisplay a standalone document with the given input. Supported MIME-type strings are\n\"application/pdf\" (default), \"application/x-dvi\", \"image/png\" and \"image/svg\".\n\"\"\"\nrender(s::LaTeXString; kwargs...) = render(s, best_displayable(); kwargs...)\n\nfunction best_displayable()\n    priority_list = [\n        MIME(\"juliavscode/html\"),\n        MIME(\"application/pdf\"),\n        MIME(\"application/x-dvi\"),\n        MIME(\"image/svg\"),\n        MIME(\"image/png\"),\n    ]\n    for mime_type in priority_list\n        displayable(mime_type) && return mime_type\n    end\n    return MIME(\"application/pdf\")\nend\n\n\nfunction html_wrap(s::LaTeXString; scale=1.1, kwargs...)\n    import_str = \"\"\"\n        <script>\n            MathJax = {\n                tex: {\n                    displayMath: [['\\$', '\\$'], ['\\\\\\\\[', '\\\\\\\\]']]\n                },\n                chtml: {\n                    scale: $scale\n                },\n                svg: {\n                    scale: $scale\n                }\n            };\n        </script>\n        <script src=\"/js/mathjax/tex-chtml.js\" id=\"MathJax-script\" async></script>\n        <script src=\"https://polyfill.io/v3/polyfill.min.js?features=es6\"></script>\n        <script id=\"MathJax-script\" async src=\"https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js\"></script>\n        \"\"\"\n    return import_str * s.s\nend\n\n# render(s::LaTeXString, mime::MIME\"juliavscode/html\"; kwargs...) = render(stdout, mime; kwargs...)\nrender(s::LaTeXString, mime::MIME\"juliavscode/html\"; kwargs...) = display(mime, html_wrap(s; kwargs...))\n\n# `display(MIME(\"application/pdf\")` is generally not defined even though\n# `displayable(MIME(\"application/pdf\")` returns `true`.\n#\n# if callshow && displayable(MIME(\"application/pdf\"))\n#     display(MIME(\"application/pdf\"), read(\"$name.pdf\"))\n# end\nrender(s::LaTeXString, ::MIME\"application/pdf\"; lualatex_flags=``, kw...) = _compile(s, `lualatex --interaction=nonstopmode $lualatex_flags main.tex`, \"pdf\"; kw...)\n\n# `display(MIME(\"application/x-dvi\")` is generally not defined even though\n# `displayable(MIME(\"application/x-dvi\")` returns `true`.\n#\n# if callshow && displayable(MIME(\"application/x-dvi\"))\n#     display(MIME(\"application/x-dvi\"), read(\"$name.dvi\"))\n# end\nrender(s::LaTeXString, ::MIME\"application/x-dvi\"; dvilualatex_flags=``, kw...) = _compile(s,  `dvilualatex --interaction=batchmode $dvilualatex_flags main.tex`, \"dvi\"; kw...)\n\nfunction render(s::LaTeXString, mime::MIME\"image/png\";\n        debug=false,\n        convert = :gs,\n        name=tempname(),\n        callshow=true,\n        open=true,\n        dpi=DEFAULT_DPI[],\n        ghostscript_flags=`-sDEVICE=pngalpha -dTextAlphaBits=4 -r$dpi`,\n        dvipng_flags=`-bg Transparent -D $dpi -T tight`,\n        kw...\n    )\n    ext = \"png\"\n\n    mktemp() do aux_name, _\n        # tex -> dvi -> png is notoriously bad for fonts (not OTF support), see e.g. tex.stackexchange.com/q/537281\n        # prefer tex -> pdf -> png instead\n        if convert === :gs\n            aux_mime = MIME(\"application/pdf\")\n            ghostscript_command = Ghostscript_jll.gs()\n            cmd = `$ghostscript_command $ghostscript_flags  -o $name.$ext $aux_name.pdf`\n        elseif convert === :dvipng\n            aux_mime = MIME(\"application/x-dvi\")\n            deb = debug ? [] : [\"-q\"]\n            cmd = `dvipng $(deb...) $dvipng_flags $aux_name.dvi -o $name.$ext`\n        else\n            throw(ArgumentError(\"$convert program not understood\"))\n        end\n        render(s, aux_mime; debug=debug, name=aux_name, open=false, kw...)\n        debug || (cmd = pipeline(cmd, devnull))\n        run(cmd)\n    end\n\n    if callshow && displayable(mime)\n        display(mime, read(\"$name.$ext\"))\n    elseif open\n        _openfile(name; ext=ext)\n    end\n\n    return nothing\nend\n\n\nfunction render(s::LaTeXString, mime::MIME\"image/svg\";\n        debug=false,\n        convert = :dvisvgm,\n        name=tempname(),\n        callshow=true,\n        open=true,\n        dvisvgm_flags=``,\n        pdf2svg_flags=``,\n        kw...\n    )\n    ext=\"svg\"\n    mktemp() do aux_name, _\n        aux_mime = MIME(\"application/pdf\")\n        if convert === :dvisvgm\n            verb = debug ? 7 : 0\n            cmd = `dvisvgm --no-fonts --pdf -v $verb $dvisvgm_flags $aux_name.pdf -o $name.$ext`\n        elseif convert === :pdf2svg\n            cmd = `pdf2svg $pdf2svg_flags $aux_name.pdf $name.$ext`\n        else\n            throw(ArgumentError(\"$convert program not understood\"))\n        end\n        render(s, aux_mime; debug=debug, name=aux_name, open=false, kw...)\n        debug || (cmd = pipeline(cmd, devnull))\n        run(cmd)\n    end\n\n    # `displayable(MIME(\"image/svg\"))` returns `true` even in a textual\n    # context (e.g., in the REPL), but `display(MIME(\"image/svg+xml\"), ...)`\n    # is the one normally defined.\n    if callshow && displayable(mime)\n        display(MIME(\"image/svg+xml\"), read(\"$name.$ext\"))\n    elseif open\n        _openfile(name; ext=ext)\n    end\n\n    return nothing\nend\n\nsafereduce(f, args) = length(args) == 1 ? f(args[1]) : reduce(f, args)\n\nfunction expr_to_array(ex)\n    ex.head === :typed_vcat && (ex = Expr(:vcat, ex.args[2:end]...))\n    ex.head === :typed_hcat && (ex = Expr(:hcat, ex.args[2:end]...))\n    ex.head === :ref && (ex = Expr(:vect, ex.args[2:end]...))\n    ## If it is a matrix\n    if Meta.isexpr(ex.args[1], :row)\n        return eval(ex.head)(map(y -> permutedims(y.args), ex.args)...)\n    else\n        if ex.head == :hcat\n            return safereduce(hcat, ex.args)\n        elseif ex.head in (:vcat, :vect)\n            return safereduce(vcat, ex.args)\n        end\n    end\nend\n\n_packagename(x::AbstractString) = \"{$x}\"\n_packagename(x::Tuple) = \"[$(join(x[2:end], \", \"))]{$(first(x))}\"\n"
  },
  {
    "path": "test/cdot_test.jl",
    "content": "using Latexify\nusing Markdown\nusing Test\n\n\n#inline\n@test latexify(:(x * y); env=:inline, mult_symbol=\"\") == raw\"$x y$\"\n\n@test latexify(:(x * y); env=:inline, mult_symbol=\"\\\\cdot\") == raw\"$x \\cdot y$\"\n\n@test latexify(:(x*(y+z)*y*(z+a)*(z+b)); env=:inline, mult_symbol=\"\") ==\nraw\"$x \\left( y + z \\right) y \\left( z + a \\right) \\left( z + b \\right)$\"\n\n@test latexify(:(x*(y+z)*y*(z+a)*(z+b)); env=:inline, mult_symbol=\"\\\\cdot\") ==\nraw\"$x \\cdot \\left( y + z \\right) \\cdot y \\cdot \\left( z + a \\right) \\cdot \\left( z + b \\right)$\"\n\n# raw\n@test latexify(:(x * y); env=:raw, mult_symbol=\"\") == raw\"x y\"\n\n@test latexify(:(x * y); env=:raw, mult_symbol=\"\\\\cdot\") == raw\"x \\cdot y\"\n\n@test latexify(:(x * (y + z) * y * (z + a) * (z + b)); env=:raw, mult_symbol=\"\") ==\nraw\"x \\left( y + z \\right) y \\left( z + a \\right) \\left( z + b \\right)\"\n\n@test latexify(:(x * (y + z) * y * (z + a) * (z + b)); env=:raw, mult_symbol=\"\\\\cdot\") ==\nraw\"x \\cdot \\left( y + z \\right) \\cdot y \\cdot \\left( z + a \\right) \\cdot \\left( z + b \\right)\"\n\n# array\n@test latexify( [:(x*y), :(x*(y+z)*y*(z+a)*(z+b))]; env=:equation, transpose=true, mult_symbol=\"\") == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\nx y & x \\left( y + z \\right) y \\left( z + a \\right) \\left( z + b \\right) \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify( [:(x*y), :(x*(y+z)*y*(z+a)*(z+b))]; env=:equation, transpose=true, mult_symbol=\"\\\\cdot\") == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\nx \\cdot y & x \\cdot \\left( y + z \\right) \\cdot y \\cdot \\left( z + a \\right) \\cdot \\left( z + b \\right) \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n\n\n# mdtable\narr = [\"x*(y-1)\", 1.0, 3*2, :(x-2y), :symb]\n\n@test latexify(arr; env=:mdtable, mult_symbol=\"\") ==\nMarkdown.md\"| $x \\left( y - 1 \\right)$ |\n| ------------------------:|\n|                    $1.0$ |\n|                      $6$ |\n|                $x - 2 y$ |\n|                   $symb$ |\n\"\n\n@test latexify(arr; env=:mdtable, mult_symbol=\"\\\\cdot\") ==\nMarkdown.md\"| $x \\cdot \\left( y - 1 \\right)$ |\n| ------------------------------:|\n|                          $1.0$ |\n|                            $6$ |\n|                $x - 2 \\cdot y$ |\n|                         $symb$ |\n\"\n\n\n\n\n# Deprecation of cdot = ... in favor of mult_symbol = ...\n# (cdot takes precedence over mult_symbol)\noutput = @test_deprecated latexify(:(x * y); mult_symbol=\"garbage\", cdot=false)\n@test output == latexify(:(x * y); mult_symbol=\"\")\noutput = @test_deprecated latexify(:(x * y); mult_symbol=\"garbage\", cdot=true)\n@test output == latexify(:(x * y); mult_symbol=\"\\\\cdot\")\n"
  },
  {
    "path": "test/chemical_arrows_test.jl",
    "content": "using DiffEqBiological\nusing Latexify\nusing Test\n\n@reaction_func hill2(x, v, k) = v*x^2/(k^2 + x^2)\n\nrn = @reaction_network MyRnType begin\n  hill2(y, v_x, k_x), 0 --> x\n  p_y, 0 --> y\n  (d_x, d_y), (x, y) --> 0\n  (r_b, r_u), x ↔ y\nend v_x k_x p_y d_x d_y r_b r_u\n\n@test latexify(rn; env=:chem) ==\nraw\"\\begin{align}\n\\require{mhchem}\n\\ce{ \\varnothing &->[\\frac{v_{x} \\cdot y^{2}}{k_{x}^{2} + y^{2}}] x}\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\n\\ce{ x &<=>[r_{b}][r_{u}] y}\n\\end{align}\n\"\n\n@test latexify(rn; env=:chem, expand=false) ==\nraw\"\\begin{align}\n\\require{mhchem}\n\\ce{ \\varnothing &->[\\mathrm{hill2}\\left( y, v_{x}, k_{x} \\right)] x}\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\n\\ce{ x &<=>[r_{b}][r_{u}] y}\n\\end{align}\n\"\n\n@test md(rn; env=:chem) ==\nraw\"\\begin{align}\n\\require{mhchem}\n\\ce{ \\varnothing &->[\\frac{v_{x} \\cdot y^{2}}{k_{x}^{2} + y^{2}}] x}\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\n\\ce{ x &<=>[r_{b}][r_{u}] y}\n\\end{align}\n\"\n\n\n@test md(rn; env=:chem, expand=false, mathjax=false, starred=true, double_linebreak=true) ==\nraw\"\\begin{align*}\n\\ce{ \\varnothing &->[\\mathrm{hill2}\\left( y, v_{x}, k_{x} \\right)] x}\\\\\\\\\n\\ce{ \\varnothing &->[p_{y}] y}\\\\\\\\\n\\ce{ x &->[d_{x}] \\varnothing}\\\\\\\\\n\\ce{ y &->[d_{y}] \\varnothing}\\\\\\\\\n\\ce{ x &<=>[r_{b}][r_{u}] y}\n\\end{align*}\n\"\n\node = @reaction_network InducedDegradation begin\n    (d_F, d_Ff, d_R), (F, Ff, R) --> 0 # degradations\n    (p_F, Ff), 0 --> (F, R)  # productions\n    (r_b * i, r_u), F ↔ Ff # bindin/unbinding\nend  i p_F d_F r_b r_u d_Ff d_R\n\n# @Latexify.generate_test md(ode; env=:chem)\n\n\n@test md(ode; env=:chem) ==\nraw\"\\begin{align}\n\\require{mhchem}\n\\ce{ F &->[d_{F}] \\varnothing}\\\\\n\\ce{ Ff &->[d_{Ff}] \\varnothing}\\\\\n\\ce{ R &->[d_{R}] \\varnothing}\\\\\n\\ce{ \\varnothing &->[p_{F}] F}\\\\\n\\ce{ \\varnothing &->[Ff] R}\\\\\n\\ce{ F &<=>[r_{b} \\cdot i][r_{u}] Ff}\n\\end{align}\n\"\n\n\n# @test_throws MethodError latexify(rn; env=:arrow, bad_kwarg=\"should error\")\n"
  },
  {
    "path": "test/latexalign_test.jl",
    "content": "using Latexify\nusing Test\n\n\n@test latexify(((1.0, 2), (3, 4)); env=:align) == replace(\nraw\"\\begin{align}\n1.0 &= 3 \\\\\n2 &= 4\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(((1.0, 2), (3, 4)); separator = [\" &= \", \" &∈ \"], env = :align) == replace(\nraw\"\\begin{align}\n1.0 &= 3 \\\\\n2 &∈ 4\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n\nlhs = [:a, :b]\nrhs = [1, 2]\n\n@test latexify(lhs, rhs; env = :aligned) == replace(\nraw\"\\[\n\\begin{aligned}\na &= 1 \\\\\nb &= 2\n\\end{aligned}\n\\]\n\", \"\\r\\n\"=>\"\\n\")\n\n# @test_throws MethodError latexify(rn; bad_kwarg=\"should error\")\n\n# Latexify.@generate_test latexify([\"a=1\"], env=:align)\n@test latexify([\"a=1\"], env = :align) == replace(\nraw\"\\begin{align}\na &= 1\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")"
  },
  {
    "path": "test/latexarray_test.jl",
    "content": "using Latexify\nusing Test\n\narr = [1 2; 3 4]\n\n@test latexify(:([x])) == replace(\nraw\"$\\left[\n\\begin{array}{c}\nx \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n# Latexify.@generate_test latexify(arr; env=:inline)\n@test latexify(arr; env = :inline) == replace(\nraw\"$\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n# Latexify.@generate_test latexify(arr; env=:equation)\n@test latexify(arr; env = :equation) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n# Latexify.@generate_test latexify(arr; env=:bracket)\n@test latexify(arr; env = :bracket) == replace(\nraw\"\\[\n\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\\]\n\", \"\\r\\n\"=>\"\\n\")\n\n# Latexify.@generate_test latexify(arr; env=:raw)\n@test latexify(arr; env = :raw) == replace(\nraw\"\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; adjustment=:r) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{rr}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; adjustment=[:l, :r]) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{lr}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\nusing OffsetArrays\n@test latexify(OffsetArray(arr, -1:0, 3:4)) == latexify(arr)\n\n@test latexify(arr; arraystyle = :array) == replace(\nraw\"\\begin{equation}\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :square) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :round) == replace(\nraw\"\\begin{equation}\n\\left(\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right)\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :curly) == replace(\nraw\"\\begin{equation}\n\\left\\{\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right\\}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :matrix) == replace(\nraw\"\\begin{equation}\n\\begin{matrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{matrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :pmatrix) == replace(\nraw\"\\begin{equation}\n\\begin{pmatrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{pmatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :bmatrix) == replace(\nraw\"\\begin{equation}\n\\begin{bmatrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{bmatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :Bmatrix) == replace(\nraw\"\\begin{equation}\n\\begin{Bmatrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{Bmatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :vmatrix) == replace(\nraw\"\\begin{equation}\n\\begin{vmatrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{vmatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = :Vmatrix) == replace(\nraw\"\\begin{equation}\n\\begin{Vmatrix}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{Vmatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; arraystyle = \"smatrix\") == replace(\nraw\"\\begin{equation}\n\\begin{smatrix}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{smatrix}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\narr = [1,2,:(x/y),4]\n\n@test latexify(arr) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n\\frac{x}{y} \\\\\n4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(arr; transpose=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cccc}\n1 & 2 & \\frac{x}{y} & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify((1.0, 2), (3, 4)) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.0 & 3 \\\\\n2 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(((1.0, 2), (3, 4))) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.0 & 3 \\\\\n2 & 4 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify(:(x = [1 2] * [1, 2] * [1 2; 3 4])) == replace(\nraw\"$x = \\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n\\end{array}\n\\right] \\cdot \\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n\\end{array}\n\\right] \\cdot \\left[\n\\begin{array}{cc}\n1 & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify(:(x = $arr)) == replace(\nraw\"$x = \\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n\\frac{x}{y} \\\\\n4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\ntensor = rand(3,3,3)\n@test_throws Latexify.UnrepresentableException(\"n-dimensional tensors with n≠1,2\") latexify(tensor)\n@test latexify(tensor; sentinel=\"\\\\mathrm{NA}\") == replace(raw\"\\begin{equation}\n\\mathrm{NA}\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\ntensor = fill(42)\n@test_throws Latexify.UnrepresentableException(\"n-dimensional tensors with n≠1,2\") latexify(tensor)\n\nundefarr = Array{Any,2}(undef, 2, 2)\n@test latexify(undefarr) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n\\cdot & \\cdot \\\\\n\\cdot & \\cdot \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\nundefarr[1,1] = \"x\"\n@test latexify(undefarr) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\nx & \\cdot \\\\\n\\cdot & \\cdot \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(:((1:3) .+ (1:2:5) .+ 3*(1:3))) == raw\"$\\left( 1 \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} 3 \\right) + \\left( 1 \\underset{2}{\\mathrel{\\ldotp\\mkern-2.5mu\\ldotp}} 5 \\right) + 3 \\cdot \\left( 1 \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} 3 \\right)$\"\n@test latexify(:($(1:3) .+ $(1:2:5) .+ $(3*(1:3)))) == replace(raw\"$1 \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} 3 + \\left[\n\\begin{array}{c}\n1 \\\\\n3 \\\\\n5 \\\\\n\\end{array}\n\\right] + \\left[\n\\begin{array}{c}\n3 \\\\\n6 \\\\\n9 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n@test latexify(:($(1:3) .+ $(1:2:5) .+ $(3*(1:3))), expand_step_ranges=false) == raw\"$1 \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} 3 + 1 \\underset{2}{\\mathrel{\\ldotp\\mkern-2.5mu\\ldotp}} 5 + 3 \\underset{3}{\\mathrel{\\ldotp\\mkern-2.5mu\\ldotp}} 9$\"\n@test latexify(:($(1:3) .+ $(1:2:5) .+ $(3*(1:3))), expand_ranges=true) == latexify(:($(1:3) .+ $(1:2:5) .+ $(3*(1:3))), expand_ranges=true, expand_step_ranges=false) == replace(raw\"$\\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n3 \\\\\n\\end{array}\n\\right] + \\left[\n\\begin{array}{c}\n1 \\\\\n3 \\\\\n5 \\\\\n\\end{array}\n\\right] + \\left[\n\\begin{array}{c}\n3 \\\\\n6 \\\\\n9 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n"
  },
  {
    "path": "test/latexbracket_test.jl",
    "content": "using Latexify, Test\n\n# Latexify.@generate_test latexify(:(x = [1, 2]), env=:bracket)\n@test latexify(:(x = [1, 2]), env = :bracket) == replace(\nraw\"\\[\nx = \\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n\\end{array}\n\\right]\\]\n\", \"\\r\\n\"=>\"\\n\")\n\n\n# Latexify.@generate_test latexify([1, 2], env=:bracket)\n@test latexify([1, 2], env = :bracket) == replace(\nraw\"\\[\n\\left[\n\\begin{array}{c}\n1 \\\\\n2 \\\\\n\\end{array}\n\\right]\\]\n\", \"\\r\\n\"=>\"\\n\")"
  },
  {
    "path": "test/latexequation_test.jl",
    "content": "\n@test latexify(\"x/y\"; env=:eq) == \nraw\"\\begin{equation}\n\\frac{x}{y}\n\\end{equation}\n\"\n\n@test latexify(\"x = a^x/b\"; env=:eq, starred=true) == \nraw\"\\begin{equation*}\nx = \\frac{a^{x}}{b}\n\\end{equation*}\n\"\n"
  },
  {
    "path": "test/latexify_test.jl",
    "content": "using Latexify\nusing LaTeXStrings\nusing Test\n\n\ntest_array = [\"x/y * d\" :x ; :( (t_sub_sub - x)^(2*p) ) 3//4 ]\n\n \n#### Test the setting of default keyword arguments.\n\n@test latexify(\"x * y\") == \nraw\"$x \\cdot y$\"\n\nset_default(mult_symbol = \"\")\n\n@test latexify(\"x * y\") == \nraw\"$x y$\"\n\n@test get_default() == Dict{Symbol,Any}(:mult_symbol => \"\")\n\nset_default(mult_symbol = \"\\\\cdot\", transpose = true)\n\n@test get_default() == Dict{Symbol,Any}(:mult_symbol => \"\\\\cdot\",:transpose => true)\n@test get_default(:mult_symbol) == \"\\\\cdot\"\n@test get_default(:mult_symbol, :transpose) == (\"\\\\cdot\", true)\n@test get_default([:mult_symbol, :transpose]) == [\"\\\\cdot\", true]\n\nreset_default()\n@test get_default() == Dict{Symbol,Any}()\n\n@test latexify(\"x * y\") == \nraw\"$x \\cdot y$\"\n\n@test latexify(\"Plots.jl\") isa LaTeXString\n"
  },
  {
    "path": "test/latexinline_test.jl",
    "content": "using Latexify\nusing LaTeXStrings\n\ntest_array = [\"x/y * d\" :x ; :( (t_sub_sub - x)^(2*p) ) 3//4 ]\n@test latexinline.(test_array) == [\n    L\"$\\frac{x}{y} \\cdot d$\"                          L\"$x$\"         ;\n    L\"$\\left( t_{sub\\_sub} - x \\right)^{2 \\cdot p}$\"  L\"$\\frac{3}{4}$\"\n    ]\n\n# @test_throws ErrorException latexify(\"x/y\"; bad_kwarg=\"should error\")\n"
  },
  {
    "path": "test/latexraw_test.jl",
    "content": "\nusing Latexify\nusing Test\nusing Markdown\n\nstr = \"2*x^2 - y/c_2\"\nex = :(2*x^2 - y/c_2)\n\ndesired_output = \"2 \\\\cdot x^{2} - \\\\frac{y}{c_{2}}\"\n\n@test latexify(:(a = [x / y; 3; 4])) == replace(\nraw\"$a = \\left[\n\\begin{array}{c}\n\\frac{x}{y} \\\\\n3 \\\\\n4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(:(a = [x / y 2 3 4])) == replace(\nraw\"$a = \\left[\n\\begin{array}{cccc}\n\\frac{x}{y} & 2 & 3 & 4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(:(a = [x / y 2; 3 4])) == replace(\nraw\"$a = \\left[\n\\begin{array}{cc}\n\\frac{x}{y} & 2 \\\\\n3 & 4 \\\\\n\\end{array}\n\\right]$\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexraw(str) == latexraw(ex)\n@test latexraw(ex) == desired_output\n\n@test latexify(:(u[1, 2]); index = :bracket) == raw\"$u\\left[1, 2\\right]$\"\n@test latexify(:(u[1, 2]); index = :subscript) == raw\"$u_{1,2}$\"\n@test latexify(:(u[1][1]); index = :bracket) == raw\"$u\\left[1\\right]\\left[1\\right]$\"\n@test latexify(:(u[1][1]); index = :subscript) == raw\"$\\left( u_{1} \\right)_{1}$\"\n@test latexify(:(u_x[1][1]); index=:subscript, snakecase=true) == raw\"$\\left( u\\_x_{1} \\right)_{1}$\"\n@test latexify(:([1 2 3][2]); index=:bracket) == replace(raw\"\"\"$\\left[\n\\begin{array}{ccc}\n1 & 2 & 3 \\\\\n\\end{array}\n\\right]\\left[2\\right]$\"\"\", \"\\r\\n\"=>\"\\n\")\n@test latexify(:([1 2 3][2]); index=:subscript) == replace(raw\"\"\"$\\left[\n\\begin{array}{ccc}\n1 & 2 & 3 \\\\\n\\end{array}\n\\right]_{2}$\"\"\", \"\\r\\n\"=>\"\\n\")\n\narray_test = [ex, str]\n@test all(latexraw.(array_test) .== desired_output)\n\n@test latexraw(:(@__dot__(x / y))) == raw\"\\frac{x}{y}\"\n@test latexraw(:(@. x / y)) == raw\"\\frac{x}{y}\"\n@test latexraw(:(eps())) == raw\"\\mathrm{eps}()\"\n\n@test latexraw(:y_c_a) == raw\"y_{c\\_a}\"\n@test latexraw(1.0) == \"1.0\"\n@test latexraw(1.00) == \"1.0\"\n@test latexraw(1) == \"1\"\n@test latexraw(:(log10(x))) == raw\"\\log_{10}\\left( x \\right)\"\n@test latexraw(:(log(x))) == raw\"\\log\\left( x \\right)\"\n@test latexraw(:(slog(x))) == raw\"\\log\\left( x \\right)\"\n@test latexraw(:(sin(x))) == raw\"\\sin\\left( x \\right)\"\n@test latexraw(:(sin(x)^2)) == raw\"\\sin^{2}\\left( x \\right)\"\n@test latexraw(:(asin(x))) == raw\"\\arcsin\\left( x \\right)\"\n@test latexraw(:(asinh(x))) == raw\"\\mathrm{arcsinh}\\left( x \\right)\"\n@test latexraw(:(sinc(x))) == raw\"\\mathrm{sinc}\\left( x \\right)\"\n@test latexraw(:(acos(x))) == raw\"\\arccos\\left( x \\right)\"\n@test latexraw(:(acosh(x))) == raw\"\\mathrm{arccosh}\\left( x \\right)\"\n@test latexraw(:(cosc(x))) == raw\"\\mathrm{cosc}\\left( x \\right)\"\n@test latexraw(:(atan(x))) == raw\"\\arctan\\left( x \\right)\"\n@test latexraw(:(atan2(x))) == raw\"\\arctan\\left( x \\right)\"\n@test latexraw(:(atanh(x))) == raw\"\\mathrm{arctanh}\\left( x \\right)\"\n@test latexraw(:(acot(x))) == raw\"\\mathrm{arccot}\\left( x \\right)\"\n@test latexraw(:(acoth(x))) == raw\"\\mathrm{arccoth}\\left( x \\right)\"\n@test latexraw(:(asec(x))) == raw\"\\mathrm{arcsec}\\left( x \\right)\"\n@test latexraw(:(sech(x))) == raw\"\\mathrm{sech}\\left( x \\right)\"\n@test latexraw(:(asech(x))) == raw\"\\mathrm{arcsech}\\left( x \\right)\"\n@test latexraw(:(acsc(x))) == raw\"\\mathrm{arccsc}\\left( x \\right)\"\n@test latexraw(:(csch(x))) == raw\"\\mathrm{csch}\\left( x \\right)\"\n@test latexraw(:(acsch(x))) == raw\"\\mathrm{arccsch}\\left( x \\right)\"\n@test latexraw(:(x ± y)) == raw\"x \\pm y\"\n@test latexraw(:(f(x))) ==  raw\"f\\left( x \\right)\"\n@test latexraw(:(f_a(x))) == raw\"f_{a}\\left( x \\right)\"\n@test latexraw(:(fun_a(x))) == raw\"\\mathrm{fun}_{a}\\left( x \\right)\"\n@test latexraw(:(fun_a_b(x))) == raw\"\\mathrm{fun}_{a\\_b}\\left( x \\right)\"\n@test latexraw(:(fun_ab_c(x))) == raw\"\\mathrm{fun}_{ab\\_c}\\left( x \\right)\"\n@test latexraw(\"x = 4*y\") == raw\"x = 4 \\cdot y\"\n@test latexraw(:(sqrt(x))) == raw\"\\sqrt{x}\"\n@test latexraw(:(ssqrt(x))) == raw\"\\sqrt{x}\"\n@test latexraw(:(√(x))) == raw\"\\sqrt{x}\"\n@test latexraw(:(√(π + 1))) == raw\"\\sqrt{\\pi + 1}\"\n@test latexraw(:(cbrt(x))) == raw\"\\sqrt[3]{x}\"\n@test latexraw(:(scbrt(x))) == raw\"\\sqrt[3]{x}\"\n@test latexraw(:(∛(x))) == raw\"\\sqrt[3]{x}\"\n@test latexraw(:(∛(π + 1))) == raw\"\\sqrt[3]{\\pi + 1}\"\n@test latexraw(:(fourthroot(x))) == raw\"\\sqrt[4]{x}\"\n@test latexraw(:(∜(x))) == raw\"\\sqrt[4]{x}\"\n@test latexraw(:(∜(π + 1))) == raw\"\\sqrt[4]{\\pi + 1}\"\n@test latexraw(complex(1,-1)) == raw\"1-1\\mathit{i}\"\n@test latexraw(im) == raw\"\\mathit{i}\"\n@test latexraw(-im) == raw\"-\\mathit{i}\"\n@test latexraw(2im) == raw\"2\\mathit{i}\"\n@test latexraw(1//2) == raw\"\\frac{1}{2}\"\n@test latexraw(missing) == raw\"\\textrm{NA}\"\n@test latexraw(\"x[2]\") == raw\"x\\left[2\\right]\"\n@test latexraw(\"x[2, 3]\") == raw\"x\\left[2, 3\\right]\"\n@test latexraw(\"α\") == raw\"\\alpha\"\n@test latexraw(\"α + 1\") == raw\"\\alpha + 1\"\n@test latexraw(\"α₁\") == raw\"\\alpha_1\"\n@test latexraw(\"γ³\") == raw\"\\gamma^3\"\n@test_broken latexraw(\"β₃_hello\") == raw\"\\beta{_3}_{hello}\"\n@test latexraw(\"β₃₄\") == raw\"\\beta_{3 4}\"\n@test latexraw(\"β₃₄¹⁴\") == raw\"\\beta_{3 4}^{1 4}\"\n@test latexraw(\"β₃¹⁴\") == raw\"\\beta_3^{1 4}\"\n@test latexraw(\"β¹⁴₃\") == raw\"\\beta^{1 4}_3\"\n@test latexraw(\"β¹⁴\") == raw\"\\beta^{1 4}\"\n@test latexraw(\"β⁴\") == raw\"\\beta^4\"\n@test latexraw(\"Aᵢⱼᵝᵞ\") == raw\"A_{i j}^{\\beta \\gamma}\"\n@test latexraw(\"Aᵪₒ¹²\") == raw\"A_{\\chi o}^{1 2}\"\n@test latexraw(Inf) == raw\"\\infty\"\n@test latexraw(:Inf) == raw\"\\infty\"\n@test latexraw(\"Inf\") == raw\"\\infty\"\n@test latexraw(-Inf) == raw\"-\\infty\"\n@test latexraw(:($(3+4im)*a)) == raw\"\\left( 3+4\\mathit{i} \\right) \\cdot a\"\n@test latexraw(:(a*$(3+4im))) == raw\"a \\cdot \\left( 3+4\\mathit{i} \\right)\"\n@test latexraw(:(abs(x))) == raw\"\\left|x\\right|\"\n@test latexraw(:(abs2(x))) == raw\"\\left|x\\right|^{2}\"\n@test latexraw(:(norm(x))) == raw\"\\left\\|x\\right\\|\"\n@test latexraw(:(norm(x, 1.5))) == raw\"\\left\\|x\\right\\|_{1.5}\"\n@test latexraw(:(ceil(x))) == raw\"\\left\\lceil x\\right\\rceil \"\n@test latexraw(:(ceil(Int64, x))) == raw\"\\left\\lceil x\\right\\rceil \"\n@test latexraw(:(floor(x))) == raw\"\\left\\lfloor x\\right\\rfloor \"\n@test latexraw(:(floor(Int64, x))) == raw\"\\left\\lfloor x\\right\\rfloor \"\n@test latexraw(:(round(x))) == raw\"\\left\\lfloor x\\right\\rceil \"\n@test latexraw(:(round(Int64, x))) == raw\"\\left\\lfloor x\\right\\rceil \"\n@test latexraw(:(1*(1 .+ 1))) == raw\"1 \\cdot \\left( 1 + 1 \\right)\"\n@test latexraw(:(1*(1 .- 1))) == raw\"1 \\cdot \\left( 1 - 1 \\right)\"\n@test latexraw(:(1-(1 .+ 1))) == raw\"1 - \\left( 1 + 1 \\right)\"\n@test latexraw(:(1-(1 .- 1))) == raw\"1 - \\left( 1 - 1 \\right)\"\n@test latexraw(:(-1*1)) == raw\"-1 \\cdot 1\"\n@test latexraw(:(-x*y)) == raw\" - x \\cdot y\"\n\n@test latexraw(:(sum(x_n))) == raw\"\\sum x_{n}\"\n@test latexraw(:(sum(x_n for n in _))) == raw\"\\sum_{n} x_{n}\"\n@test latexraw(:(sum(x_n for n in :))) == raw\"\\sum_{n} x_{n}\"\n@test latexraw(:(sum(x_n for n in N))) == raw\"\\sum_{n \\in N} x_{n}\"\n@test latexraw(:(sum(x_n for n in n_0:N))) == raw\"\\sum_{n = n_{0}}^{N} x_{n}\"\n@test latexraw(:(prod(x_n))) == raw\"\\prod x_{n}\"\n@test latexraw(:(prod(x_n for n in _))) == raw\"\\prod_{n} x_{n}\"\n@test latexraw(:(prod(x_n for n in :))) == raw\"\\prod_{n} x_{n}\"\n@test latexraw(:(prod(x_n for n in N))) == raw\"\\prod_{n \\in N} x_{n}\"\n@test latexraw(:(prod(x_n for n in n_0:N))) == raw\"\\prod_{n = n_{0}}^{N} x_{n}\"\n\n@test latexraw(:(binomial(13, 27))) == raw\"\\binom{13}{27}\"\n\n@test latexraw(\"Aᵢᵏ\"; safescripts=true) == raw\"A{_i}{^k}\"\n@test latexraw(\"Aᵢⱼᵏˡ\"; safescripts=true) == raw\"A{_{i j}}{^{k l}}\"\n@test latexraw(\"hello_world\"; snakecase=true) == raw\"hello\\_world\"\n\n@test latexify(:((-1) ^ 2)) == replace(\nraw\"$\\left( -1 \\right)^{2}$\", \"\\r\\n\"=>\"\\n\")\n@test latexify(:($(1 + 2im) ^ 2)) == replace(\nraw\"$\\left( 1+2\\mathit{i} \\right)^{2}$\", \"\\r\\n\"=>\"\\n\")\n@test latexify(:($(3 // 2) ^ 2)) == replace(\nraw\"$\\left( \\frac{3}{2} \\right)^{2}$\", \"\\r\\n\"=>\"\\n\")\n\n### Test broadcasting\n@test latexraw(:(fun.((a, b)))) == raw\"\\mathrm{fun}\\left( a, b \\right)\"\n\n### Test field/property extraction\n@test latexraw(:(Foo.foo)) == raw\"Foo.foo\"\n@test latexraw(:(Foo.fun(a, b))) == raw\"\\mathrm{Foo.fun}\\left( a, b \\right)\"\n\n### Test combined broadcasting and field extraction\n@test latexraw(:(Foo.fun.((a, b)))) == raw\"\\mathrm{Foo.fun}\\left( a, b \\right)\"\n\n\n### Test for correct signs in nested sums/differences.\n@test latexraw(\"-(-1)\") == raw\" + 1\"\n@test latexraw(\"+(-1)\") == raw\"-1\"\n@test latexraw(\"-(+1)\") == raw\" - 1\"\n@test latexraw(\"-(1+1)\") == raw\" - \\left( 1 + 1 \\right)\"\n@test latexraw(\"1-(-2)\") == raw\"1 + 2\"\n@test latexraw(\"1 + (-(2))\") == raw\"1 - 2\"\n@test latexraw(\"1 + (-2 -3 -4)\") == raw\"1 -2 - 3 - 4\"\n@test latexraw(\"1 - 2 - (- 3 - 4)\") == raw\"1 - 2 - \\left(  - 3 - 4 \\right)\"\n@test latexraw(\"1 - 2 - (- 3 -(2) + 4)\") == raw\"1 - 2 - \\left(  - 3 - 2 + 4 \\right)\"\n@test latexraw(\"1 - 2 - (- 3 -(2 - 8) + 4)\") == raw\"1 - 2 - \\left(  - 3 - \\left( 2 - 8 \\right) + 4 \\right)\"\n@test latexraw(:(-$(3+5im))) == raw\" - \\left( 3+5\\mathit{i} \\right)\"\n@test latexraw(:($(3+4im)-$(3+5im))) == raw\"3+4\\mathit{i} - \\left( 3+5\\mathit{i} \\right)\"\n\n# @test_throws ErrorException latexify(\"x/y\"; env=:raw, bad_kwarg=\"should error\")\n\n\n@test latexraw(:(a .< b .<= c < d <= e > f <= g .<= h .< i == j .== k != l .!= m)) ==\nraw\"a < b \\leq c < d \\leq e > f \\leq g \\leq h < i = j = k \\neq l \\neq m\"\n@test latexraw(:(3 * (a .< b .<= c < d <= e > f <= g .<= h .< i == j .== k != l .!= m))) ==\nraw\"3 \\cdot \\left( a < b \\leq c < d \\leq e > f \\leq g \\leq h < i = j = k \\neq l \\neq m \\right)\"\n\n@test latexraw(:(2+3 : b)) == raw\"2 + 3 \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} b\"\n@test latexraw(:(a:3*4)) == raw\"a \\mathrel{\\ldotp\\mkern-2.5mu\\ldotp} 3 \\cdot 4\"\n\n#### Test the imaginary_unit keyword option\n@test latexraw(5im; imaginary_unit=\"\\\\textit{i}\") == raw\"5\\textit{i}\"\n\n#### Test the fmt keyword option\n@test latexify([32894823 1.232212 :P_1; :(x / y) 1.0e10 1289.1]; env=:align, fmt=\"%.2e\") == replace(\nraw\"\\begin{align}\n3.29e+07 &= 1.23e+00 &= P_{1} \\\\\n\\frac{x}{y} &= 1.00e+10 &= 1.29e+03\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify([32894823 1.232212 :P_1; :(x / y) 1.0e10 1289.1]; env=:equation, fmt=\"%.2e\") == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{ccc}\n3.29e+07 & 1.23e+00 & P_{1} \\\\\n\\frac{x}{y} & 1.00e+10 & 1.29e+03 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify([32894823 1.232212 :P_1; :(x / y) 1.0e10 1289.1]; env=:table, fmt=\"%.2e\") == replace(\nraw\"\\begin{tabular}{ccc}\n$3.29e+07$ & $1.23e+00$ & $P_{1}$\\\\\n$\\frac{x}{y}$ & $1.00e+10$ & $1.29e+03$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify([32894823 1.232212 :P_1; :(x / y) 1.0e10 1289.1]; env=:mdtable, fmt=\"%.2e\") ==\nMarkdown.md\"|    $3.29e+07$ | $1.23e+00$ |    $P_{1}$ |\n| -------------:| ----------:| ----------:|\n| $\\frac{x}{y}$ | $1.00e+10$ | $1.29e+03$ |\n\"\n\n@test latexify(1234.2234; env=:inline, fmt=\"%.2e\") ==\nraw\"$1.23e+03$\"\n\n@test latexify(1234.2234; env=:raw, fmt=\"%.2e\") ==\nraw\"1.23e+03\"\n\n\ntest_functions = [:sinh, :alpha, :Theta, :cosc, :acoth, :acot, :asech, :lambda,\n                  :asinh, :sinc, :eta, :kappa, :nu, :asin, :epsilon, :sigma,\n                  :upsilon, :phi, :tanh, :iota, :Psi, :acosh, :log, :zeta, :mu,\n                  :csc, :xi, :tau, :beta, :Lambda, :Xi, :Phi, :acsc, :atan,\n                  :sech, :atanh, :gamma, :Delta, :rho, :sec, :log10, :delta,\n                  :pi, :cot, :log2, :cos, :Omega, :psi, :atan2, :Gamma, :cosh,\n                  :acos, :Pi, :Upsilon, :omega, :coth, :chi, :tan, :csch,\n                  :acsch, :theta, :asec, :Sigma, :sin]\n\n\n@test latexify([\"3*$(func)(x)^2/4 -1\" for func = test_functions]) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{c}\n\\frac{3 \\cdot \\sinh^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\alpha\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Theta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{cosc}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arccoth}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arccot}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arcsech}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\lambda\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arcsinh}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{sinc}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\eta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\kappa\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\nu\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\arcsin^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\epsilon\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\sigma\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\upsilon\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\phi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\tanh^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\iota\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Psi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arccosh}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\log\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\zeta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\mu\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\csc^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\xi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\tau\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\beta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Lambda\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Xi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Phi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arccsc}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\arctan^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{sech}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arctanh}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Gamma\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Delta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\rho\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\sec^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\log_{10}\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\delta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\pi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\cot^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\log_{2}\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\cos^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Omega\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\psi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\arctan^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Gamma\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\cosh^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\arccos^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Pi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Upsilon\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\omega\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\coth^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\chi\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\tan^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{csch}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arccsch}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\theta\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\mathrm{arcsec}^{2}\\left( x \\right)}{4} - 1 \\\\\n\\frac{3 \\cdot \\left( \\Sigma\\left( x \\right) \\right)^{2}}{4} - 1 \\\\\n\\frac{3 \\cdot \\sin^{2}\\left( x \\right)}{4} - 1 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n## Test Expr containing function (note function vs symbol)\n@test latexraw(Expr(:call, sin, 3)) == latexraw(Expr(:call, :sin, 3)) == raw\"\\sin\\left( 3 \\right)\"\n@test latexraw(cos) == latexraw(:cos) == raw\"\\cos\"\n\n## Test logical operators\n@test latexraw(:(x && y)) == \"x \\\\wedge y\"\n@test latexraw(:(x || y)) == \"x \\\\vee y\"\n@test latexraw(:(x || !y)) == \"x \\\\vee \\\\neg y\"\n\n## Test anonymous function\n@test latexraw(:(x -> x^2)) == \"x \\\\mapsto x^{2}\"\n@test latexraw(:(f(p) = x -> p*x)) == \"f\\\\left( p \\\\right) = x \\\\mapsto p \\\\cdot x\"\n\n## Test {cases} enviroment\n@test latexraw(:(R(p,e,d) = e ? 0 : log(p) - d)) == replace(\nraw\"R\\left( p, e, d \\right) = \\begin{cases}\n0 & \\text{if } e\\\\\n\\log\\left( p \\right) - d & \\text{otherwise}\n\\end{cases}\", \"\\r\\n\"=>\"\\n\")\n\n@test latexraw(:(R(p,e,d,t) = if (t && e); 0 elseif (t && !e); d else log(p) end)) == replace(\nraw\"R\\left( p, e, d, t \\right) = \\begin{cases}\n0 & \\text{if } t \\wedge e\\\\\nd & \\text{if } t \\wedge \\neg e\\\\\n\\log\\left( p \\right) & \\text{otherwise}\n\\end{cases}\", \"\\r\\n\"=>\"\\n\")\n\n@test latexraw(:(function reward(p,e,d,t)\n    if t && e\n        return 0\n    elseif t && !e\n        return -1d\n    elseif 2t && e\n        return -2d\n    elseif 3t && e\n        return -3d\n    else\n        return log(p)\n    end\nend)) == replace(\nraw\"\\mathrm{reward}\\left( p, e, d, t \\right) = \\begin{cases}\n0 & \\text{if } t \\wedge e\\\\\n-1 \\cdot d & \\text{if } t \\wedge \\neg e\\\\\n-2 \\cdot d & \\text{if } 2 \\cdot t \\wedge e\\\\\n-3 \\cdot d & \\text{if } 3 \\cdot t \\wedge e\\\\\n\\log\\left( p \\right) & \\text{otherwise}\n\\end{cases}\", \"\\r\\n\"=>\"\\n\")\n\n# Test infix comparison operators\n@testset \"Infix\" begin\n    @test latexraw(:(x ⊊ y)) == raw\"x \\subsetneq y\"\n    @test latexraw(:(x .⊆ y)) == raw\"x \\subseteq y\"\n    @test latexraw(:(x .∌ y)) == raw\"x \\not\\ni y\"\n    @test latexraw(:(x .>= y)) == raw\"x \\geq y\"\n    @test latexraw(:(x .== y)) == raw\"x = y\"\n    @test latexraw(:(issubset(x, y))) == raw\"x \\subseteq y\"\n    @test latexraw(:(x .∉ y)) == raw\"x \\notin y\"\n    @test latexraw(:(x < y)) == raw\"x < y\"\n    @test latexraw(:(x !== y)) == raw\"x \\not\\equiv y\"\n    @test latexraw(:(x ≈ y)) == raw\"x \\approx y\"\n    @test latexraw(:(x .⊅ y)) == raw\"x \\not\\supset y\"\n    @test latexraw(:(x ≥ y)) == raw\"x \\geq y\"\n    @test latexraw(:(x >= y)) == raw\"x \\geq y\"\n    @test latexraw(:(x .∈ y)) == raw\"x \\in y\"\n    @test latexraw(:(x > y)) == raw\"x > y\"\n    @test latexraw(:(x <= y)) == raw\"x \\leq y\"\n    @test latexraw(:(x .⊊ y)) == raw\"x \\subsetneq y\"\n    @test latexraw(:(x .<= y)) == raw\"x \\leq y\"\n    @test latexraw(:(x .≤ y)) == raw\"x \\leq y\"\n    @test latexraw(:(x ⊃ y)) == raw\"x \\supset y\"\n    @test latexraw(:(x == y)) == raw\"x = y\"\n    @test latexraw(:(x in y)) == raw\"x \\in y\"\n    @test latexraw(:(x ≠ y)) == raw\"x \\neq y\"\n    @test latexraw(:(x ⊆ y)) == raw\"x \\subseteq y\"\n    @test latexraw(:(x .≥ y)) == raw\"x \\geq y\"\n    @test latexraw(:(x .< y)) == raw\"x < y\"\n    @test latexraw(:(x != y)) == raw\"x \\neq y\"\n    @test latexraw(:(x .!== y)) == raw\"x \\not\\equiv y\"\n    @test latexraw(:(x === y)) == raw\"x \\equiv y\"\n    @test latexraw(:(x ⊅ y)) == raw\"x \\not\\supset y\"\n    @test latexraw(:(x .∋ y)) == raw\"x \\ni y\"\n    @test latexraw(:(x ∉ y)) == raw\"x \\notin y\"\n    @test latexraw(:(x .≠ y)) == raw\"x \\neq y\"\n    @test latexraw(:(x .!= y)) == raw\"x \\neq y\"\n    @test latexraw(:(x ∈ y)) == raw\"x \\in y\"\n    @test latexraw(:(x .⊃ y)) == raw\"x \\supset y\"\n    @test latexraw(:(x .≈ y)) == raw\"x \\approx y\"\n    @test latexraw(:(x ∋ y)) == raw\"x \\ni y\"\n    @test latexraw(:(x .> y)) == raw\"x > y\"\n    @test latexraw(:(x .=== y)) == raw\"x \\equiv y\"\n    @test latexraw(:(x ≤ y)) == raw\"x \\leq y\"\n    @test latexraw(:(x ∌ y)) == raw\"x \\not\\ni y\"\n    @test latexraw(:(x < 3 + 1)) == raw\"x < 3 + 1\"\n    @test latexraw(:((x < 3) + 1)) == raw\"\\left( x < 3 \\right) + 1\"\n    #@test latexraw(:(∀(x, y))) == raw\"x \\forall y\"\n    @test latexraw(:(a => b)) == raw\"a \\Rightarrow b\"\nend\n"
  },
  {
    "path": "test/latextabular_test.jl",
    "content": "using DataFrames: DataFrame\nusing Latexify\nusing Test\nd = DataFrame(A = 11:13, B = [:X, :Y, :Z])\n\n@test latexify(d; env=:table, side=1:3, latex=false) == replace(\nraw\"\\begin{tabular}{ccc}\n & A & B\\\\\n1 & 11 & X\\\\\n2 & 12 & Y\\\\\n3 & 13 & Z\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n# Latexify.@generate_test latexify([1.]; env=:table)\n@test latexify([1.0]; env = :table) == replace(\nraw\"\\begin{tabular}{c}\n$1.0$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\narr = [\"x/(y-1)\", 1.0, 3//2, :(x-y), :symb]\n\nM = vcat(reduce(hcat, arr), reduce(hcat, arr))\nhead = [\"col$i\" for i in 1:size(M, 2)]\nside = [\"row$i\" for i in 1:size(M, 1)]\n\n\n@test latexify(M; env=:table, head=1:2, adjustment=:l, latex=false, transpose=true) == replace(\nraw\"\\begin{tabular}{ll}\n1 & 2\\\\\nx/(y-1) & x/(y-1)\\\\\n1.0 & 1.0\\\\\n3//2 & 3//2\\\\\nx - y & x - y\\\\\nsymb & symb\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, head=1:2, adjustment=[:c, :r], latex=false, transpose=true) == replace(\nraw\"\\begin{tabular}{cr}\n1 & 2\\\\\nx/(y-1) & x/(y-1)\\\\\n1.0 & 1.0\\\\\n3//2 & 3//2\\\\\nx - y & x - y\\\\\nsymb & symb\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, head=1:2, adjustment=:l, transpose=true) == replace(\nraw\"\\begin{tabular}{ll}\n$1$ & $2$\\\\\n$\\frac{x}{y - 1}$ & $\\frac{x}{y - 1}$\\\\\n$1.0$ & $1.0$\\\\\n$\\frac{3}{2}$ & $\\frac{3}{2}$\\\\\n$x - y$ & $x - y$\\\\\n$symb$ & $symb$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, head=1:5) == replace(\nraw\"\\begin{tabular}{ccccc}\n$1$ & $2$ & $3$ & $4$ & $5$\\\\\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, side=[1, 2]) == replace(\nraw\"\\begin{tabular}{cccccc}\n$1$ & $\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n$2$ & $\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, booktabs=true) == replace(\nraw\"\\begin{tabular}{ccccc}\n\\toprule\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n\\bottomrule\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(M; env=:table, head=1:5, booktabs=true) == replace(\nraw\"\\begin{tabular}{ccccc}\n\\toprule\n$1$ & $2$ & $3$ & $4$ & $5$\\\\\n\\midrule\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n$\\frac{x}{y - 1}$ & $1.0$ & $\\frac{3}{2}$ & $x - y$ & $symb$\\\\\n\\bottomrule\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\nD = Dict(:a=>\"x/(k+x)\", :b=>\"x - y\")\n@test latexify(D; env=:tabular) == replace(\nraw\"\\begin{tabular}{cc}\n$a$ & $\\frac{x}{k + x}$\\\\\n$b$ & $x - y$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(D; env=:tabular, head=[\"Keys\", \"Values\"]) == replace(\nraw\"\\begin{tabular}{cc}\n$Keys$ & $Values$\\\\\n$a$ & $\\frac{x}{k + x}$\\\\\n$b$ & $x - y$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(d; env=:tabular, latex=false, fmt=SiunitxNumberFormatter()) == replace(\nraw\"\\begin{tabular}{cc}\nA & B\\\\\n\\num{11} & X\\\\\n\\num{12} & Y\\\\\n\\num{13} & Z\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(d; env=:tabular, latex=false, fmt=SiunitxNumberFormatter(), adjustment=:S) == replace(\nraw\"\\begin{tabular}{SS}\nA & B\\\\\n11 & X\\\\\n12 & Y\\\\\n13 & Z\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n"
  },
  {
    "path": "test/macros.jl",
    "content": "l = @latexify dummyfunc(x; y=1, z=3) = x^2/y + z\n@test l == raw\"$\\mathrm{dummyfunc}\\left( x; y = 1, z = 3 \\right) = \\frac{x^{2}}{y} + z$\"\n\n@test_throws UndefVarError dummyfunc(1.)\n\nl2 = @latexrun dummyfunc2(x; y=1, z=3) = x^2/y + z\n@test l2 == raw\"$\\mathrm{dummyfunc2}\\left( x; y = 1, z = 3 \\right) = \\frac{x^{2}}{y} + z$\"\n\n@test dummyfunc2(1.) == 4\n\nl3 = @latexify dummyfunc2(x::Number; y=1, z=3) = x^2/y + z\n@test l3 == raw\"$\\mathrm{dummyfunc2}\\left( x::Number; y = 1, z = 3 \\right) = \\frac{x^{2}}{y} + z$\"\n\n\nl4 = @latexify dummyfunc2(::Number; y=1, z=3) = x^2/y + z\n@test l4 == raw\"$\\mathrm{dummyfunc2}\\left( ::Number; y = 1, z = 3 \\right) = \\frac{x^{2}}{y} + z$\"\n\nl5 = @latexify x = abs2(-3)\n@test l5 == raw\"$x = \\left|-3\\right|^{2}$\"\n\nl6 = @latexify x = $(abs2(-3))\n@test l6 == raw\"$x = 9$\"\n\nl7 = @latexrun x = abs2(-3)\n@test l7 == raw\"$x = \\left|-3\\right|^{2}$\"\n@test x == 9\n\nl8 = @latexrun x = $(abs2(-3))\n@test l8 == raw\"$x = 9$\"\n@test x == 9\n\nl9 = @latexdefine x = abs2(-2)\n@test l9 == raw\"$x = \\left|-2\\right|^{2} = 4$\"\n@test x == 4\n\nl10 = @latexdefine x = $(abs2(-2))\n@test l10 == raw\"$x = 4 = 4$\"\n@test x == 4\n\nl11 = @latexify x = 1 env=:raw\n@test l11 == raw\"x = 1\"\n\nl12 = @latexrun x = 1 env=:raw\n@test l12 == raw\"x = 1\"\n\nl13 = @latexdefine y = x env=:raw\n@test l13 == raw\"y = x = 1\"\n\nenv = :raw\nl14 = @latexdefine y env\n@test l14 == raw\"y = 1\"\n\nl15 = @latexdefine y = x post=float\n@test l15 == raw\"$y = x = 1.0$\"\n@test y isa Integer\n\npost = x->round(x; sigdigits=3)\nl16 = @latexdefine y = π post\n@test l16 == raw\"$y = \\pi = 3.14$\"\n@test y == π\n\n@test latexify(:(@hi(x / y))) == replace(\nraw\"$\\mathrm{@hi}\\left( \\frac{x}{y} \\right)$\", \"\\r\\n\"=>\"\\n\")\n"
  },
  {
    "path": "test/manual_test.jl",
    "content": "using Revise\nusing Latexify\nusing DifferentialEquations\nusing DataFrames\nusing LaTeXStrings\n\nrevise()\n\nex = :(min(1,2))\nlatexify(ex)\n\n\"x/y\" |> latexify\nl = latexify(\"x/y\")\n\njoin(1, \",\")\n\n\nf = @ode_def feedback begin\n    dx = y/c_1 - x\n    dy = x^c_2 - y\n    end c_1 c_2\n\nlatexalign(f.syms, f.funcs)\nlatexify(f.syms, f.funcs)\n"
  },
  {
    "path": "test/mdtable_test.jl",
    "content": "using Markdown\nusing Latexify\n\narr = [\"x/(y-1)\", 1.0, 3//2, :(x-y), :symb]\n\nM = vcat(reduce(hcat, arr), reduce(hcat, arr))\nhead = [\"col$i\" for i in 1:size(M, 2)]\nside = [\"row$i\" for i in 1:size(M, 1)]\n\n@test mdtable(arr) == Markdown.md\"\n| $\\frac{x}{y - 1}$ |\n| -----------------:|\n|             $1.0$ |\n|     $\\frac{3}{2}$ |\n|           $x - y$ |\n|            $symb$ |\n\"\n\n@test mdtable(arr; head = [\"head\"]) == Markdown.md\"\n|              head |\n| -----------------:|\n| $\\frac{x}{y - 1}$ |\n|             $1.0$ |\n|     $\\frac{3}{2}$ |\n|           $x - y$ |\n|            $symb$ |\n\"\n\n@test mdtable(arr; head = [\"head\"], side=1:length(arr)) == Markdown.md\"\n|   ∘ |              head |\n| ---:| -----------------:|\n|   1 | $\\frac{x}{y - 1}$ |\n|   2 |             $1.0$ |\n|   3 |     $\\frac{3}{2}$ |\n|   4 |           $x - y$ |\n|   5 |            $symb$ |\n\"\n\n@test mdtable(arr; head = [\"head\"], side=1:length(arr)+1) == Markdown.md\"\n|   1 |              head |\n| ---:| -----------------:|\n|   2 | $\\frac{x}{y - 1}$ |\n|   3 |             $1.0$ |\n|   4 |     $\\frac{3}{2}$ |\n|   5 |           $x - y$ |\n|   6 |            $symb$ |\n\"\n\n@test mdtable(arr, arr) == Markdown.md\"\n| $\\frac{x}{y - 1}$ | $\\frac{x}{y - 1}$ |\n| -----------------:| -----------------:|\n|             $1.0$ |             $1.0$ |\n|     $\\frac{3}{2}$ |     $\\frac{3}{2}$ |\n|           $x - y$ |           $x - y$ |\n|            $symb$ |            $symb$ |\n\"\n\n@test mdtable(arr, arr; head = [\"col1\", \"col2\"]) == Markdown.md\"\n|              col1 |              col2 |\n| -----------------:| -----------------:|\n| $\\frac{x}{y - 1}$ | $\\frac{x}{y - 1}$ |\n|             $1.0$ |             $1.0$ |\n|     $\\frac{3}{2}$ |     $\\frac{3}{2}$ |\n|           $x - y$ |           $x - y$ |\n|            $symb$ |            $symb$ |\n\"\n\n@test mdtable(M) == Markdown.md\"\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n| -----------------:| -----:| -------------:| -------:| ------:|\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n\"\n\n@test mdtable(M; adjustment=:c) == Markdown.md\"\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n| :----------------:| :----:| :------------:| :------:| :-----:|\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n\"\n\n@test mdtable(M; adjustment=[:l :c :r :l nothing]) == Markdown.md\"\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n| :-----------------| :----:| -------------:| :-------| ------:|\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n\"\n\n@test mdtable(M, head=head) == Markdown.md\"\n|              col1 |  col2 |          col3 |    col4 |   col5 |\n| -----------------:| -----:| -------------:| -------:| ------:|\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n| $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n\"\n\n@test mdtable(M, head=head, side=side) == Markdown.md\"\n|    ∘ |              col1 |  col2 |          col3 |    col4 |   col5 |\n| ----:| -----------------:| -----:| -------------:| -------:| ------:|\n| row1 | $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n| row2 | $\\frac{x}{y - 1}$ | $1.0$ | $\\frac{3}{2}$ | $x - y$ | $symb$ |\n\"\n\n@test mdtable(M, head=side, side=head, transpose=true) == Markdown.md\"\n|    ∘ |              row1 |              row2 |\n| ----:| -----------------:| -----------------:|\n| col1 | $\\frac{x}{y - 1}$ | $\\frac{x}{y - 1}$ |\n| col2 |             $1.0$ |             $1.0$ |\n| col3 |     $\\frac{3}{2}$ |     $\\frac{3}{2}$ |\n| col4 |           $x - y$ |           $x - y$ |\n| col5 |            $symb$ |            $symb$ |\n\"\n\n\nm = [\"one_two_tree\"; \"four_five_six\"; \"seven_eight\"]\n@test latexify(m; env=:mdtable, latex=false, escape_underscores=true) == Markdown.md\"\n|  one\\_two\\_tree |\n| -------------:|\n| four\\_five\\_six |\n|   seven_eight |\n\"\n\n\nusing DataFrames\nd = DataFrame(A = 11:13, B = [:X, :Y, :Z])\n\n\n@test latexify(d; env=:mdtable, side=1:3) == Markdown.md\"\n|   ∘ |    A |   B |\n| ---:| ----:| ---:|\n|   1 | $11$ | $X$ |\n|   2 | $12$ | $Y$ |\n|   3 | $13$ | $Z$ |\n\"\n\n@test latexify(d; env=:mdtable) == Markdown.md\"\n|    A |   B |\n| ----:| ---:|\n| $11$ | $X$ |\n| $12$ | $Y$ |\n| $13$ | $Z$ |\n\"\n\n\n\n@test latexify(((1.0, 2), (3, 4)); env=:mdtable) == Markdown.md\"\n| $1.0$ | $3$ |\n| -----:| ---:|\n|   $2$ | $4$ |\n\"\n\n# @test_throws MethodError mdtable(M; bad_kwarg=\"should error\")\n"
  },
  {
    "path": "test/numberformatters_test.jl",
    "content": "using Latexify\nusing Test\nimport Latexify: PlainNumberFormatter, PrintfNumberFormatter\n\n@test FancyNumberFormatter() == FancyNumberFormatter(4) == FancyNumberFormatter(\"%.4g\", \"\\\\cdot\") == FancyNumberFormatter(\"%.4g\", s\"\\g<mantissa> \\\\cdot 10^{\\g<sign_exp>\\g<mag_exp>}\")\n\nx = -23.4728979e7\n\n@test PlainNumberFormatter()(x) == \"-2.34728979e8\"\n@test PrintfNumberFormatter(\"%.4g\")(x) == \"-2.347e+08\"\n@test StyledNumberFormatter()(x) == \"-2.347 \\\\mathrm{e}{8}\"\n@test FancyNumberFormatter()(x) == \"-2.347 \\\\cdot 10^{8}\"\n@test FancyNumberFormatter(\"%.5E\", s\"\\g<mantissa>,\\g<before_dp>,\\g<sign>,\\g<before_dp_nosign>,\\g<after_dp>,\\g<e_or_E>,\\g<raw_exp>,\\g<sign_exp>,\\g<mag_exp>\")(x) == \"-2.34729,-2,-,2,34729,E,+08,,8\"\n\n@test StyledNumberFormatter(4) == StyledNumberFormatter()\n\nxne = -23.4728979e-7\n\n@test FancyNumberFormatter(\"%.5E\", s\"\\g<mantissa>,\\g<before_dp>,\\g<sign>,\\g<before_dp_nosign>,\\g<after_dp>,\\g<e_or_E>,\\g<raw_exp>,\\g<sign_exp>,\\g<mag_exp>\")(xne) == \"-2.34729,-2,-,2,34729,E,-06,-,6\"\n\ny = 0xf43\n\n@test StyledNumberFormatter()(y) == FancyNumberFormatter()(y) == \"\\\\mathtt{0x0f43}\"\n\n@test SiunitxNumberFormatter()(x) == \"\\\\num{-2.34728979e8}\"\n@test SiunitxNumberFormatter(version=2)(x) == \"\\\\num{-2.34728979e8}\"\n@test SiunitxNumberFormatter(format_options=\"something\")(x) == \"\\\\num[something]{-2.34728979e8}\"\n@test SiunitxNumberFormatter(format_options=\"[something]\")(x) == \"\\\\num[something]{-2.34728979e8}\"\n\n@test SiunitxNumberFormatter()([1,2,4]) == \"\\\\numlist{1;2;4}\"\n@test SiunitxNumberFormatter()(1:4) == \"\\\\numrange{1}{4}\"\n\n@test !SiunitxNumberFormatter().simple\n@test SiunitxNumberFormatter(simple=true).simple\n"
  },
  {
    "path": "test/plugins/DataFrames_test.jl",
    "content": "using DataFrames\nusing LaTeXStrings\n\n\ndf = DataFrame(A = 'x':'z', B = [\"α/β\", 1//2, 8])\n\n@test mdtable(df) ==\nMarkdown.md\"|   A |                      B |\n| ---:| ----------------------:|\n| $x$ | $\\frac{\\alpha}{\\beta}$ |\n| $y$ |          $\\frac{1}{2}$ |\n| $z$ |                    $8$ |\n\"\n\n@test latexify(df, latex=true) ==\nMarkdown.md\"|   A |                      B |\n| ---:| ----------------------:|\n| $x$ | $\\frac{\\alpha}{\\beta}$ |\n| $y$ |          $\\frac{1}{2}$ |\n| $z$ |                    $8$ |\n\"\n\n\n\n@test_broken latexify(df; env=:array) == replace(\nL\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\nA & B \\\\\nx & \\frac{\\alpha}{\\beta} \\\\\ny & \\frac{1}{2} \\\\\nz & 8 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify(df; env=:table, latex=true) == replace(\nraw\"\\begin{tabular}{cc}\n$A$ & $B$\\\\\n$x$ & $\\frac{\\alpha}{\\beta}$\\\\\n$y$ & $\\frac{1}{2}$\\\\\n$z$ & $8$\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n@test latexify(df; env=:table, latex=false) == replace(\nraw\"\\begin{tabular}{cc}\nA & B\\\\\nx & α/β\\\\\ny & 1//2\\\\\nz & 8\\\\\n\\end{tabular}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(df; head=[\"x\", \"y\"]) ==\nMarkdown.md\"|   x |                      y |\n| ---:| ----------------------:|\n| $x$ | $\\frac{\\alpha}{\\beta}$ |\n| $y$ |          $\\frac{1}{2}$ |\n| $z$ |                    $8$ |\n\"\n"
  },
  {
    "path": "test/plugins/SparseArrays_test.jl",
    "content": "using SparseArrays\n\nx = sparse([1,2,3],[1,3,2],[0,1,2])\n@test latexraw(x) == replace(raw\"\"\"\\left[\n\\begin{array}{ccc}\n0 & 0 & 0 \\\\\n0 & 0 & 1 \\\\\n0 & 2 & 0 \\\\\n\\end{array}\n\\right]\"\"\", \"\\r\\n\"=>\"\\n\")\n\n"
  },
  {
    "path": "test/plugins/SymEngine_test.jl",
    "content": "using SymEngine\n\n@vars x y\nsymExpr = x + x + x*y*y\n@test latexraw(symExpr) == \"2 \\\\cdot x + x \\\\cdot y^{2}\"\n"
  },
  {
    "path": "test/recipe_test.jl",
    "content": "using Latexify\nusing Test\n\n\nmodule MyModule\nusing Latexify\nstruct MyType\n    vec1\n    vec2\nend\n\nmy_reverse(x) = x[end:-1:1]\n\n@latexrecipe function f(t::MyType; reverse=false)\n    env --> :align\n    fmt := \"%.2f\"\n    return reverse ? (t.vec2, t.vec1) : (t.vec1, t.vec2)\nend\n\nstruct MyVec\n    vec::AbstractVector\nend\n\n@latexrecipe function f(v::MyVec; reverse=false)\n    env --> :equation\n    fmt := \"%.2f\"\n    return reverse ? v.vec[end, -1, 1] : v.vec\nend\n\nstruct MyTup\n    tup::Tuple\nend\n\n@latexrecipe function f(v::MyTup; reverse=false)\n    env --> :equation\n    fmt := \"%.2f\"\n    return reverse ? my_reverse(v.tup) : v.tup\nend\n\nstruct MyDoubleTup\n    tup1::Tuple\n    tup2::Tuple\nend\n\n@latexrecipe function f(t::MyDoubleTup)\n    return t.tup1, t.tup2\nend\n\nstruct MyFloat\n    x::Float64\nend\n\n@latexrecipe function f(m::MyFloat)\n    fmt --> \"%.6e\"\n    return m.x*m.x\nend\n\n@latexrecipe function f(vec::Vector{T}) where T <: MyFloat\n    fmt --> \"%.4e\"\n    return [myfloat.x for myfloat in vec]\nend\n\nstruct MyDoubleVec{T}\n    vec1::AbstractVector{T}\n    vec2::AbstractVector{T}\nend\n\n@latexrecipe function f(vec::MyDoubleVec{T}) where T <: MyFloat\n    return [myfloat.x for myfloat in vec.vec1], [myfloat.x for myfloat in vec.vec2]\nend\n\nstruct MySum\n    x\n    y\nend\n@latexrecipe function f(s::MySum)\n    operation --> :+\n    return :($(s.x) + $(s.y))\nend\n\nend\n\nusing .MyModule\nt = MyModule.MyType([:A, :B, 3.], [1., 2, 3])\nt2 = MyModule.MyType([:X, :Y, :(x/y)], Number[1.23434534, 232423.42345, 12//33])\n\nm = MyModule.MyFloat(3)\n@test latexify(m) == raw\"$9.000000e+00$\"\n@test latexify(:(2+$m)) == raw\"$2 + 9.000000e+00$\"\n\nvec = [MyModule.MyFloat(x) for x in 1:4]\n@test latexify(vec; transpose=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cccc}\n1.0000e+00 & 2.0000e+00 & 3.0000e+00 & 4.0000e+00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\ndouble_vec = MyModule.MyDoubleVec([MyModule.MyFloat(x) for x in 1:4], [MyModule.MyFloat(x) for x in 8:11])\n@test latexify(double_vec) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.0 & 8.0 \\\\\n2.0 & 9.0 \\\\\n3.0 & 10.0 \\\\\n4.0 & 11.0 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n\n@test latexify(t2, fmt=\"%.8f\") == replace(\nraw\"\\begin{align}\nX &= 1.23 \\\\\nY &= 232423.42 \\\\\n\\frac{x}{y} &= \\frac{4.00}{11.00}\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(t) == replace(\nraw\"\\begin{align}\nA &= 1.00 \\\\\nB &= 2.00 \\\\\n3.00 &= 3.00\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(t; reverse=true) == replace(\nraw\"\\begin{align}\n1.00 &= A \\\\\n2.00 &= B \\\\\n3.00 &= 3.00\n\\end{align}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(t; env=:equation) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\nA & 1.00 \\\\\nB & 2.00 \\\\\n3.00 & 3.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(t; env=:equation, reverse=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.00 & A \\\\\n2.00 & B \\\\\n3.00 & 3.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\nvec = MyModule.MyVec([1., 2.])\n@test latexify(vec, transpose=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.00 & 2.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\ntup = MyModule.MyTup((1., 2.))\n\n@test latexify(tup, transpose=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.00 & 2.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(tup, reverse=true, transpose=true) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n2.00 & 1.00 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n\n\ntup2 = MyModule.MyDoubleTup((1., 3), (2., 4.))\n@test latexify(tup2) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{cc}\n1.0 & 2.0 \\\\\n3 & 4.0 \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\nsum1 = MyModule.MySum(3, 4)\n@test latexify(:(2 + $(sum1)^2)) == raw\"$2 + \\left( 3 + 4 \\right)^{2}$\"\n@test latexify(:(2 - $(sum1))) == raw\"$2 - \\left( 3 + 4 \\right)$\"\n\nstruct NothingThing end\n@test_throws Latexify.NoRecipeException(NothingThing) latexify(NothingThing())\n@test latexify(NothingThing(); sentinel=\"this\") == raw\"$this$\"\n@latexrecipe function f(::NothingThing; keyword=nothing)\n    if isnothing(keyword)\n        return L\"a\"\n    elseif keyword == :nothing\n        return L\"b\"\n    end\nend\n@test latexify(NothingThing()) == raw\"$a$\"\n@test latexify(NothingThing(); keyword=nothing) == raw\"$a$\"\n@test latexify(NothingThing(); keyword=:nothing) == raw\"$b$\"\n\n\n"
  },
  {
    "path": "test/runtests.jl",
    "content": "#!/usr/bin/env julia\n\n#Start Test Script\nusing Latexify\nusing LaTeXStrings\nusing Test\n\n# Run tests\n\n@testset \"macro test\" begin include(\"macros.jl\") end\n@testset \"recipe test\" begin include(\"recipe_test.jl\") end\n@testset \"latexify tests\" begin include(\"latexify_test.jl\") end\n@testset \"latexraw tests\" begin include(\"latexraw_test.jl\") end\n@testset \"latexalign tests\" begin include(\"latexalign_test.jl\") end\n@testset \"latexarray tests\" begin include(\"latexarray_test.jl\") end\n@testset \"latexequation tests\" begin include(\"latexequation_test.jl\") end\n@testset \"latexbracket tests\" begin include(\"latexbracket_test.jl\") end\n@testset \"latexinline tests\" begin include(\"latexinline_test.jl\") end\n@testset \"latextabular tests\" begin include(\"latextabular_test.jl\") end\n@testset \"mdtable tests\" begin include(\"mdtable_test.jl\") end\n@testset \"DataFrames Plugin\" begin include(\"plugins/DataFrames_test.jl\") end\n@testset \"SymEngine Plugin\" begin include(\"plugins/SymEngine_test.jl\") end\n@testset \"SparseArrays Plugin\" begin include(\"plugins/SparseArrays_test.jl\") end\n@testset \"unicode2latex\" begin include(\"unicode2latex.jl\") end\n@testset \"cdot test\" begin include(\"cdot_test.jl\") end\n@testset \"numberformatters\" begin include(\"numberformatters_test.jl\") end\n@testset \"utils test\" begin include(\"utils_test.jl\") end\n"
  },
  {
    "path": "test/unicode2latex.jl",
    "content": "@test latexify(\"α\"; convert_unicode=false) == raw\"$α$\"\n\n@test latexify(['α', :β, \"γ/η\"], transpose=true, convert_unicode=false) == replace(\nraw\"\\begin{equation}\n\\left[\n\\begin{array}{ccc}\nα & β & \\frac{γ}{η} \\\\\n\\end{array}\n\\right]\n\\end{equation}\n\", \"\\r\\n\"=>\"\\n\")\n\n@test latexify(\"αaβ\") == raw\"${\\alpha}a\\beta$\"\n\n@test latexify(\"αaβ\").s == raw\"${\\alpha}a\\beta$\"\n\n@test latexify(\"ÀéÜ\"; parse=false).s == raw\"$\\textnormal{\\`{A}}\\textnormal{\\'{e}}\\textnormal{\\\\\\\"{U}}$\"\n\n@test latexify(\"w̋Ṽî\"; parse=false).s == raw\"$\\textnormal{\\H{w}}\\tilde{V}\\hat{i}$\"\n\n@test latexify(\"çĘf̄\"; parse=false).s == raw\"$\\textnormal{\\c{c}}\\textnormal{\\k{E}}\\bar{f}$\"\n\n@test latexify(\"ṞȯX̣\"; parse=false).s == raw\"$\\textnormal{\\b{R}}\\dot{o}\\textnormal{\\d{X}}$\"\n\n@test latexify(\"ẙĞž\"; parse=false).s == raw\"$\\textnormal{\\r{y}}\\textnormal{\\u{G}}\\textnormal{\\v{z}}$\"\n\n@test latexify(\"τ̇\"; parse=false).s == raw\"$\\dot{\\tau}$\"\n@test latexify(\"τ̈\"; parse=false).s == raw\"$\\ddot{\\tau}$\"\n@test latexify(\"τ⃛\"; parse=false).s == raw\"$\\dddot{\\tau}$\"\n@test latexify(\"τ⃜\"; parse=false).s == raw\"$\\ddddot{\\tau}$\"\n\ns = 'y' * Char(0x30a) * 'x' * Char(0x302) * 'a' * Char(0x331)\n@test latexify(s; parse=false).s == raw\"$\\textnormal{\\r{y}}\\hat{x}\\textnormal{\\b{a}}$\"\n\ns = 'Y' * Char(0x30a) * 'X' * Char(0x302) * 'A' * Char(0x331)\n@test latexify(s; parse=false).s == raw\"$\\textnormal{\\r{Y}}\\hat{X}\\textnormal{\\b{A}}$\"\n\ns = 'i' * Char(0x308) * 'z' * Char(0x304) * 'e' * Char(0x306)\n@test latexify(s; parse=false).s == raw\"$\\textnormal{\\\\\\\"{i}}\\bar{z}\\textnormal{\\u{e}}$\"\n\ns = 'I' * Char(0x308) * 'Z' * Char(0x304) * 'E' * Char(0x306)\n@test latexify(s; parse=false).s == raw\"$\\textnormal{\\\\\\\"{I}}\\bar{Z}\\textnormal{\\u{E}}$\"\n\n@test latexify(\"ẋ  + ω̂\") == raw\"$\\dot{x} + \\hat{\\omega}$\"\n\n@test latexify(:(iħ * (∂Ψ(𝐫, t) / ∂t) = -ħ^2 / 2m * ΔΨ(𝐫, t) + V * Ψ(𝐫, t))).s ==\n    raw\"$i\\hslash \\cdot \\frac{\\partial\\Psi\\left( \\mathbf{r}, t \\right)}{{\\partial}t} = \" *\n    raw\"\\frac{ - \\hslash^{2}}{2 \\cdot m} \\cdot \\Delta\\Psi\\left( \\mathbf{r}, t \\right) + V \\cdot \\Psi\\left( \\mathbf{r}, t \\right)$\"\n\nif Sys.islinux()\n    mktempdir() do dn\n        name = tempname()\n        str = map(\n            chunk -> string(\"\\\\[\", join(chunk, \" \"), \"\\\\]\\n\"),\n            Iterators.partition(values(Latexify.unicodedict), 40)\n        ) |> prod\n        Latexify._writetex(\n            LaTeXString(str),\n            name=name,\n            documentclass=\"article\",\n            preamble=\"\\\\usepackage[margin=2cm]{geometry}\"\n        )\n        # should compile, even if some glyphs aren't found in the default font face\n        @test pipeline(`latexmk -output-directory=$dn -quiet -pdflatex=lualatex -pdf $name.tex`, stdout=devnull) |> run |> success\n    end\n\n    # not checked for correctness, only for rendering without errors\n    eq = latexify(:(sin(α) / (β + 1)))\n\n    name = tempname()\n    render(eq, MIME(\"application/pdf\"); name=name, open=false)\n    @test filesize(\"$name.pdf\") > 100\n\n    name = tempname()\n    render(eq, MIME(\"application/x-dvi\"); name=name, open=false)\n    @test filesize(\"$name.dvi\") > 100\n\n    name = tempname()\n    render(eq, MIME(\"image/png\"); name=name, open=false)\n    @test filesize(\"$name.png\") > 100\n\n    name = tempname()\n    render(eq, MIME(\"image/svg\"); name=name, open=false)\n    @test filesize(\"$name.svg\") > 100\nend\n"
  },
  {
    "path": "test/utils_test.jl",
    "content": "xdoty_tex = L\"x \\cdot y\"\n\n#= This test fails after updating dvisvgm, can this functionality be tested in a less dependant way?\nif Sys.islinux()\n    render(xdoty_tex, MIME(\"image/svg\"); name=name, open=false)\n    svg = open(\"$(name).svg\") do f\n        read(f, String)\n    end\n    @test svg == raw\"\"\"\n    <?xml version='1.0' encoding='UTF-8'?>\n    <!-- This file was generated by dvisvgm 2.10 -->\n    <svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='25.707544pt' height='9.165631pt' viewBox='-72.000004 -72.000009 25.707544 9.165631'>\n    <defs>\n    <path id='g0-1' d='M2.75447-3.586549C2.75447-4.002589 2.410161-4.346897 1.994121-4.346897S1.233773-4.002589 1.233773-3.586549S1.578082-2.826201 1.994121-2.826201S2.75447-3.170509 2.75447-3.586549Z'/>\n    <path id='g1-120' d='M6.800097-5.853248C6.341018-5.767171 6.168864-5.422862 6.168864-5.150284C6.168864-4.805976 6.441442-4.691206 6.642289-4.691206C7.072674-4.691206 7.373945-5.064207 7.373945-5.451554C7.373945-6.054095 6.685327-6.326672 6.082787-6.326672C5.207669-6.326672 4.719898-5.465901 4.590783-5.193323C4.26082-6.269288 3.371356-6.326672 3.113124-6.326672C1.649813-6.326672 .875118-4.447321 .875118-4.131704C.875118-4.07432 .932503-4.002589 1.032926-4.002589C1.147696-4.002589 1.176388-4.088666 1.20508-4.146051C1.692851-5.738478 2.654046-6.039748 3.070086-6.039748C3.715665-6.039748 3.84478-5.437208 3.84478-5.092899C3.84478-4.777283 3.758703-4.447321 3.586549-3.758703L3.098778-1.793274C2.883585-.932503 2.467546-.143462 1.707197-.143462C1.635466-.143462 1.276811-.143462 .975541-.329963C1.492004-.430386 1.606774-.860772 1.606774-1.032926C1.606774-1.31985 1.391581-1.492004 1.119003-1.492004C.774695-1.492004 .401693-1.190734 .401693-.731656C.401693-.129116 1.075965 .143462 1.692851 .143462C2.381468 .143462 2.869239-.401693 3.170509-.989888C3.400048-.143462 4.117358 .143462 4.648167 .143462C6.111479 .143462 6.886174-1.73589 6.886174-2.051506C6.886174-2.123237 6.828789-2.180622 6.742712-2.180622C6.613596-2.180622 6.59925-2.108891 6.556211-1.994121C6.168864-.731656 5.336785-.143462 4.691206-.143462C4.189089-.143462 3.916511-.516463 3.916511-1.104657C3.916511-1.420273 3.973896-1.649813 4.203435-2.596661L4.705552-4.547744C4.920745-5.408516 5.408516-6.039748 6.068441-6.039748C6.097133-6.039748 6.498827-6.039748 6.800097-5.853248Z'/>\n    <path id='g1-121' d='M3.773049 1.606774C3.385702 2.151929 2.826201 2.6397 2.123237 2.6397C1.951083 2.6397 1.262465 2.611008 1.047272 1.951083C1.090311 1.965429 1.162042 1.965429 1.190734 1.965429C1.62112 1.965429 1.908044 1.592428 1.908044 1.262465S1.635466 .817733 1.420273 .817733C1.190734 .817733 .688617 .989888 .688617 1.692851C.688617 2.424507 1.305504 2.926624 2.123237 2.926624C3.557857 2.926624 5.006822 1.606774 5.408516 .014346L6.814443-5.58067C6.828789-5.652401 6.857482-5.738478 6.857482-5.824555C6.857482-6.039748 6.685327-6.18321 6.470134-6.18321C6.341018-6.18321 6.039748-6.125826 5.924979-5.69544L4.86336-1.477658C4.791629-1.219427 4.791629-1.190734 4.67686-1.032926C4.389936-.631233 3.916511-.143462 3.227894-.143462C2.424507-.143462 2.352776-.932503 2.352776-1.31985C2.352776-2.137583 2.740123-3.24224 3.127471-4.275166C3.285279-4.691206 3.371356-4.892053 3.371356-5.178977C3.371356-5.781517 2.94097-6.326672 2.238007-6.326672C.918157-6.326672 .387347-4.246474 .387347-4.131704C.387347-4.07432 .444732-4.002589 .545155-4.002589C.674271-4.002589 .688617-4.059973 .746002-4.26082C1.090311-5.465901 1.635466-6.039748 2.194968-6.039748C2.324084-6.039748 2.567969-6.039748 2.567969-5.566324C2.567969-5.193323 2.410161-4.777283 2.194968-4.232128C1.492004-2.352776 1.492004-1.879352 1.492004-1.535043C1.492004-.172154 2.467546 .143462 3.184855 .143462C3.600895 .143462 4.117358 .014346 4.619475-.516463L4.633821-.502117C4.418628 .344309 4.275166 .90381 3.773049 1.606774Z'/>\n    </defs>\n    <g id='page1'>\n    <use x='-72.000004' y='-65.623905' xlink:href='#g1-120'/>\n    <use x='-60.829507' y='-65.623905' xlink:href='#g0-1'/>\n    <use x='-53.656444' y='-65.623905' xlink:href='#g1-121'/>\n    </g>\n    </svg>\"\"\"\nend\n# =#\n\nfilename = Latexify._writetex(xdoty_tex)\ntex = read(filename, String)\n@test tex == replace(raw\"\"\"\n\\documentclass[varwidth=true]{standalone}\n\\usepackage{amssymb}\n\\usepackage{amsmath}\n\\usepackage{unicode-math}\n\\begin{document}\n{\n    \\Large\n    $x \\cdot y$\n}\n\\end{document}\n\"\"\", \"\\r\\n\"=>\"\\n\")\n\nfilename = Latexify._writetex(L\"\\ce{ 2 P_1 &<=>[k_{+}][k_{-}] D_{1}}\")\ntex = read(filename, String)\n@test tex == replace(raw\"\"\"\n\\documentclass[varwidth=true]{standalone}\n\\usepackage{amssymb}\n\\usepackage{amsmath}\n\\usepackage{unicode-math}\n\\usepackage{mhchem}\n\\begin{document}\n{\n    \\Large\n    $\\ce{ 2 P_1 &<=>[k_{+}][k_{-}] D_{1}}$\n}\n\\end{document}\n\"\"\", \"\\r\\n\"=>\"\\n\")\n\nfilename = Latexify._writetex(L\"\\qty{135}{nm}\"; documentclass=(\"article\", \"a4paper\"), packages=(\"siunitx\",))\ntex = read(filename, String)\n@test tex == replace(raw\"\"\"\n\\documentclass[a4paper]{article}\n\\usepackage{siunitx}\n\\begin{document}\n{\n    \\Large\n    $\\qty{135}{nm}$\n}\n\\end{document}\n\"\"\", \"\\r\\n\"=>\"\\n\")\n\n@test Latexify._packagename(\"hi\") == \"{hi}\"\n@test Latexify._packagename((\"hi\", \"x=5\")) == \"[x=5]{hi}\"\n@test Latexify._packagename((\"hi\", \"x=5\", \"y\")) == \"[x=5, y]{hi}\"\n\n@test occursin(\"MathJax\", Latexify.html_wrap(latexify(:(sin(α)))))\n@test Latexify.best_displayable() isa MIME\n\n#@test_throws Latexify.LatexifyRenderError render(L\"x^2^3\") # Does not run on Windows and Mac CI\nlogfile = tempname()\nopen(logfile, \"w\") do io\n    println(io, raw\"\"\"\n            This is LuaHBTeX, Version 1.18.0 (TeX Live 2024/Arch Linux)  (format=lualatex 2024.4.3)  7 AUG 2024 14:19\n            restricted system commands enabled.\n            ** Skipping many files **\n            LaTeX Font Info:    Trying to load font information for U+msb on input line 5.\n            (/usr/share/texmf-dist/tex/latex/amsfonts/umsb.fd\n            File: umsb.fd 2013/01/14 v3.01 AMS symbols B\n            )\n            ! Double superscript.\n            l.8     $x^2^\n            3$\n            I treat `x^1^2' essentially like `x^1{}^2'.\n            ** More lines skipped **\n            \"\"\")\nend\ne = Latexify.LatexifyRenderError(logfile)\n@test sprint(showerror, e) == \"\"\"\nan error occured while rendering LaTeX: \\n\\tDouble superscript.\n\\tl.8     \\$x^2^\nCheck the log file at $logfile for more information\"\"\"\n\n@test_throws ArgumentError render(L\"x^2\"; use_tectonic=true)\nusing tectonic_jll\npdf_file = render(L\"x^2\"; open=false) # should now not throw\n@test isfile(pdf_file)\n@test_throws Latexify.LatexifyRenderError render(L\"x^2^3\"; open=false)\n\n# Check that Ghostscript render works. If it did, no error\npng_return = render(L\"x^2\", MIME(\"image/png\"); open=false)\n@test isnothing(png_return) # unlike PDF output, returns nothing\n"
  }
]