diff --git a/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.ji b/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.ji new file mode 100644 index 0000000..500cbfa Binary files /dev/null and b/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.so b/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.so new file mode 100755 index 0000000..1a3a690 Binary files /dev/null and b/.julia-depot/compiled/v1.10/CommonMark/LZtHZ_ujJ6A.so differ diff --git a/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.ji b/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.ji new file mode 100644 index 0000000..e44f5fc Binary files /dev/null and b/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.so b/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.so new file mode 100755 index 0000000..19e2e93 Binary files /dev/null and b/.julia-depot/compiled/v1.10/Glob/3FzEV_ujJ6A.so differ diff --git a/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.ji b/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.ji new file mode 100644 index 0000000..1f8299b Binary files /dev/null and b/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.so b/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.so new file mode 100755 index 0000000..94b72f7 Binary files /dev/null and b/.julia-depot/compiled/v1.10/JuliaFormatter/OWZnm_ujJ6A.so differ diff --git a/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.ji b/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.ji new file mode 100644 index 0000000..99f3535 Binary files /dev/null and b/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.so b/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.so new file mode 100755 index 0000000..5e51637 Binary files /dev/null and b/.julia-depot/compiled/v1.10/JuliaSyntax/KyTzp_ujJ6A.so differ diff --git a/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.ji b/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.ji new file mode 100644 index 0000000..0176ecc Binary files /dev/null and b/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.so b/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.so new file mode 100755 index 0000000..fbb741c Binary files /dev/null and b/.julia-depot/compiled/v1.10/PrecompileTools/AQ9Mk_ujJ6A.so differ diff --git a/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.ji b/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.ji new file mode 100644 index 0000000..273abd2 Binary files /dev/null and b/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.ji differ diff --git a/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.so b/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.so new file mode 100755 index 0000000..48a9871 Binary files /dev/null and b/.julia-depot/compiled/v1.10/Preferences/pWSk8_ujJ6A.so differ diff --git a/.julia-depot/environments/v1.10/Manifest.toml b/.julia-depot/environments/v1.10/Manifest.toml new file mode 100644 index 0000000..d00e9e4 --- /dev/null +++ b/.julia-depot/environments/v1.10/Manifest.toml @@ -0,0 +1,55 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.10" +manifest_format = "2.0" +project_hash = "30b405be1c677184b7703a9bfb3d2100029ccad0" + +[[deps.CommonMark]] +deps = ["PrecompileTools"] +git-tree-sha1 = "351d6f4eaf273b753001b2de4dffb8279b100769" +uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +version = "0.9.1" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.Glob]] +git-tree-sha1 = "83cb0092e2792b9e3a865b6655e88f5b862607e2" +uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" +version = "1.4.0" + +[[deps.JuliaFormatter]] +deps = ["CommonMark", "Glob", "JuliaSyntax", "PrecompileTools", "TOML"] +git-tree-sha1 = "ca9470360f51697fc1bde747760b2d99936619ea" +uuid = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +version = "2.2.0" + +[[deps.JuliaSyntax]] +git-tree-sha1 = "937da4713526b96ac9a178e2035019d3b78ead4a" +uuid = "70703baa-626e-46a2-a12c-08ffd08c73b4" +version = "0.4.10" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "522f093a29b31a93e34eaea17ba055d850edea28" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.5.1" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/.julia-depot/environments/v1.10/Project.toml b/.julia-depot/environments/v1.10/Project.toml new file mode 100644 index 0000000..f3aab8b --- /dev/null +++ b/.julia-depot/environments/v1.10/Project.toml @@ -0,0 +1,2 @@ +[deps] +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" diff --git a/.julia-depot/logs/manifest_usage.toml b/.julia-depot/logs/manifest_usage.toml new file mode 100644 index 0000000..8ff4317 --- /dev/null +++ b/.julia-depot/logs/manifest_usage.toml @@ -0,0 +1,2 @@ +[["/home/runner/work/SimGBS.jl/SimGBS.jl/.julia-depot/environments/v1.10/Manifest.toml"]] +time = 2026-01-17T05:52:38.430Z diff --git a/.julia-depot/packages/CommonMark/lmLkP/.JuliaFormatter.toml b/.julia-depot/packages/CommonMark/lmLkP/.JuliaFormatter.toml new file mode 100644 index 0000000..e69de29 diff --git a/.julia-depot/packages/CommonMark/lmLkP/.ci/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/.ci/Project.toml new file mode 100644 index 0000000..17fae5e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.ci/Project.toml @@ -0,0 +1,6 @@ +[deps] +Changelog = "5217a498-cd5d-4ec6-b8c2-9b85a09b6e3e" + +[compat] +Changelog = "1" +julia = "1" diff --git a/.julia-depot/packages/CommonMark/lmLkP/.ci/changelog.jl b/.julia-depot/packages/CommonMark/lmLkP/.ci/changelog.jl new file mode 100644 index 0000000..1de613d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.ci/changelog.jl @@ -0,0 +1,9 @@ +import Changelog + +cd(dirname(@__DIR__)) do + Changelog.generate( + Changelog.CommonMark(), + "CHANGELOG.md"; + repo = "MichaelHatherly/CommonMark.jl", + ) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/.format/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/.format/Project.toml new file mode 100644 index 0000000..71708c8 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.format/Project.toml @@ -0,0 +1,5 @@ +[deps] +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" + +[compat] +JuliaFormatter = "1" diff --git a/.julia-depot/packages/CommonMark/lmLkP/.format/format.jl b/.julia-depot/packages/CommonMark/lmLkP/.format/format.jl new file mode 100644 index 0000000..c8a993e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.format/format.jl @@ -0,0 +1,6 @@ +import Pkg +Pkg.instantiate() + +import JuliaFormatter + +JuliaFormatter.format(dirname(@__DIR__)) diff --git a/.julia-depot/packages/CommonMark/lmLkP/.gitattributes b/.julia-depot/packages/CommonMark/lmLkP/.gitattributes new file mode 100644 index 0000000..d846be6 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.gitattributes @@ -0,0 +1,3 @@ +/src/writers/templates/* linguist-vendored +/test/samples/cmark/* linguist-vendored +/test/templates/* linguist-vendored diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/dependabot.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/dependabot.yml new file mode 100644 index 0000000..562bcf0 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + labels: + - "dependencies" + - "github-actions" + open-pull-requests-limit: 1 diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/CompatHelper.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/CompatHelper.yml new file mode 100644 index 0000000..81c8c3f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/CompatHelper.yml @@ -0,0 +1,16 @@ +name: CompatHelper +on: + schedule: + - cron: '00 00 * * *' + workflow_dispatch: +jobs: + CompatHelper: + runs-on: ubuntu-latest + steps: + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/LicenseUpdater.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/LicenseUpdater.yml new file mode 100644 index 0000000..1b5b88b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/LicenseUpdater.yml @@ -0,0 +1,17 @@ +name: Update license file + +on: + workflow_dispatch: + schedule: + - cron: '0 3 1 1 *' # 03:00 AM on January 1 + +jobs: + update-license-year: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: FantasticFiasco/action-update-license-year@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/TagBot.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/TagBot.yml new file mode 100644 index 0000000..253866e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/TagBot.yml @@ -0,0 +1,15 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/ci.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/ci.yml new file mode 100644 index 0000000..bbff00d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI + +on: + pull_request: + push: + branches: + - master + tags: + - '*' + +concurrency: + # Skip intermediate builds: all builds except for builds on the `master` branch + # Cancel intermediate builds: only pull request builds + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref != 'refs/heads/master' || github.run_number }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + finalize: + needs: [format, test] + timeout-minutes: 5 + runs-on: ubuntu-latest + if: always() + + steps: + - run: | + echo format: ${{ needs.format.result }} + echo test: ${{ needs.test.result }} + + - run: exit 1 + if: | + (needs.format.result != 'success') || + (needs.test.result != 'success') + + format: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + - run: julia --project=.format .format/format.jl + - run: git diff --color --exit-code + + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + version: + - '1.3' + - '1.6' + - '1.11' + - 'nightly' + os: + - ubuntu-latest + - windows-latest + - macOS-latest + arch: + - x64 + exclude: + - version: "1.6" + os: windows-latest + - version: "1.3" + os: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: actions/cache@v4 + env: + cache-name: cache-artifacts + with: + path: ~/.julia/artifacts + key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} + restore-keys: | + ${{ runner.os }}-test-${{ env.cache-name }}- + ${{ runner.os }}-test- + ${{ runner.os }}- + - uses: julia-actions/julia-buildpkg@latest + - uses: julia-actions/julia-runtest@latest + continue-on-error: ${{ matrix.version == 'nightly' }} diff --git a/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/register.yml b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/register.yml new file mode 100644 index 0000000..6e71f2f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.github/workflows/register.yml @@ -0,0 +1,14 @@ +name: Register Package +on: + workflow_dispatch: + inputs: + version: + description: Version to register or component to bump + required: true +jobs: + register: + runs-on: ubuntu-latest + steps: + - uses: julia-actions/RegisterAction@latest + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.julia-depot/packages/CommonMark/lmLkP/.gitignore b/.julia-depot/packages/CommonMark/lmLkP/.gitignore new file mode 100644 index 0000000..2c37269 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/.gitignore @@ -0,0 +1,7 @@ +*.jl.*.cov +*.jl.cov +*.jl.mem +.DS_Store +Manifest.toml +/dev/ +.vscode/settings.json diff --git a/.julia-depot/packages/CommonMark/lmLkP/CHANGELOG.md b/.julia-depot/packages/CommonMark/lmLkP/CHANGELOG.md new file mode 100644 index 0000000..7c8158a --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/CHANGELOG.md @@ -0,0 +1,304 @@ +# CommonMark.jl changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## [v0.9.0] - 2025-03-06 + +### Added + +- Add `typst` writer [#84] + +## [v0.8.15] - 2024-10-04 + +### Fixed + +- Remove `URIs` dependency [#80] +- Remove `JSON` dependency [#81] +- Reduce stored entity data [#82] + +## [v0.8.14] - 2024-10-04 + +### Fixed + +- Fixed duplicate attributes in HTML rendering [#78] + +## [v0.8.13] - 2024-10-03 + +### Fixed + +- Fixed `sourcepos` for HTML output [#75] +- Correctly restrict `julia` version to those that are actively tested [#76] + +## [v0.8.12] - 2023-04-27 + +### Fixed + +- Migrate to using `PrecompileTools` instead of `SnoopPrecompile` [#64] + +## [v0.8.11] - 2023-04-14 + +### Fixed + +- Early exit while parsing rows with unicode characters [#63] + +## [v0.8.10] - 2023-01-22 + +### Fixed + +- Specialize `occursin` on `Regex` [#62] + +## [v0.8.9] - 2023-01-20 + +### Fixed + +- Improve precompilation with `SnoopPrecompile` workload [#59] + +## [v0.8.8] - 2023-01-18 + +### Fixed + +- Pass `IOContext` through to `JuliaValue`s in HTML renderer [#58] + +## [v0.8.7] - 2022-11-16 + +### Fixed + +- Fixed Unicode bug in admonition syntax [#53] +- Fixed interpolation when mutating interpolated values [#51] +- Fixed interpolation bug with assignment operators [#50] +- Avoid duplicating rules when `enable!`ing and `disable!`ing [#46] + +## [v0.8.6] - 2022-02-10 + +### Fixed + +- Fixed extra whitespace in table parsing + +## [v0.8.5] - 2021-12-16 + +### Fixed + +- Avoid mutating parsed AST in `@cm_str` + +## [v0.8.4] - 2021-12-07 + +### Fixed + +- Fixed method ambiguity in `Base.get!` definition + +## [v0.8.3] - 2021-09-23 + +### Fixed + +- Added `tex` class to rendered math in `html` output + +## [v0.8.2] - 2021-07-15 + +### Added + +- Added `frontmatter` to extract frontmatter from parsed document + +### Fixed + +- Fixed enumi counter bug in `latex` + +## [v0.8.1] - 2021-03-18 + +### Fixed + +- Fixed empty list and block quote rendering of margins + +## [v0.8.0] - 2021-03-10 + +### Added + +- Added `@cm_str` macro +- Added interpolation extension + +## [v0.7.3] - 2021-03-01 + +### Fixed + +- Fixed tab indent in admonitions and footnote bodies + +## [v0.7.2] - 2021-02-06 + +### Fixed + +- Improve types for `Parser` rules and priorities + +## [v0.7.1] - 2020-11-30 + +### Fixed + +- Fixed stackoverflow in `disable!` + +## [v0.7.0] - 2020-11-28 + +### Added + +- Added syntax highlighting hooks to rendering + +### Fixed + +- Improve `latex` rendering +- Escape characters in non-highlighted code blocks + +## [v0.6.4] - 2020-09-03 + +### Fixed + +- Allow empty attribute keys + +## [v0.6.3] - 2020-08-29 + +### Fixed + +- Fixed `latex` table rendering + +## [v0.6.2] - 2020-08-16 + +### Fixed + +- Fixed typo in admonition rendering +- Allow whitespace before attribute syntax +- Pass through node to smartlinks +- Fixed greedy consume in `TypographyRule` + +## [v0.6.1] - 2020-08-07 + +### Fixed + +- Relaxed GitHub-flavoured markdown table parsing + +## [v0.6.0] - 2020-08-06 + +### Added + +- `$` math syntax +- Added header and footer variables to default templates + +## [v0.5.2] - 2020-07-14 + +### Fixed + +- Update HTML block parsing to match upstream changes + +## [v0.5.1] - 2020-07-12 + +### Fixed + +- Fixed bug in `TableRule` + +## [v0.5.0] - 2020-07-04 + +### Added + +- Automatically add IDs to headers with the `AutoIdentifierRule` extension +- Allow passing `Parser`s to `open` to parse files directly +- Non-strict table alignment + +### Fixed + +- Improve `markdown` roundtripping + +## [v0.4.0] - 2020-06-14 + +### Added + +- Attribute extension for attaching metadata to AST nodes +- Template system for writing standalone documents +- Citation and reference extension + +### Fixed + +- Fixed `markdown` to allow for better roundtrip rendering + +## [v0.3.0] - 2020-06-03 + +### Added + +- Raw content extension +- `markdown` and Jupyter `notebook` output + +### Fixed + +- Fixed `latex` rendering bugs where newlines were not preserved + +## [v0.2.0] - 2020-05-26 + +### Added + +- Frontmatter blocks +- Added rules system for parser extensions +- Added callable API for parser objects +- Export public API +- Smart typography rules +- Added custom admonition titles + +### Fixed + +- Fixed pirated `peek` method +- Handle poorly aligned tables better + +## [v0.1.0] - 2020-05-23 + +Initial release. + + + + +[v0.1.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.1.0 +[v0.2.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.2.0 +[v0.3.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.3.0 +[v0.4.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.4.0 +[v0.5.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.5.0 +[v0.5.1]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.5.1 +[v0.5.2]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.5.2 +[v0.6.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.6.0 +[v0.6.1]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.6.1 +[v0.6.2]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.6.2 +[v0.6.3]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.6.3 +[v0.6.4]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.6.4 +[v0.7.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.7.0 +[v0.7.1]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.7.1 +[v0.7.2]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.7.2 +[v0.7.3]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.7.3 +[v0.8.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.0 +[v0.8.1]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.1 +[v0.8.2]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.2 +[v0.8.3]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.3 +[v0.8.4]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.4 +[v0.8.5]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.5 +[v0.8.6]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.6 +[v0.8.7]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.7 +[v0.8.8]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.8 +[v0.8.9]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.9 +[v0.8.10]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.10 +[v0.8.11]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.11 +[v0.8.12]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.12 +[v0.8.13]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.13 +[v0.8.14]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.14 +[v0.8.15]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.8.15 +[v0.9.0]: https://github.com/MichaelHatherly/CommonMark.jl/releases/tag/v0.9.0 +[#46]: https://github.com/MichaelHatherly/CommonMark.jl/issues/46 +[#50]: https://github.com/MichaelHatherly/CommonMark.jl/issues/50 +[#51]: https://github.com/MichaelHatherly/CommonMark.jl/issues/51 +[#53]: https://github.com/MichaelHatherly/CommonMark.jl/issues/53 +[#58]: https://github.com/MichaelHatherly/CommonMark.jl/issues/58 +[#59]: https://github.com/MichaelHatherly/CommonMark.jl/issues/59 +[#62]: https://github.com/MichaelHatherly/CommonMark.jl/issues/62 +[#63]: https://github.com/MichaelHatherly/CommonMark.jl/issues/63 +[#64]: https://github.com/MichaelHatherly/CommonMark.jl/issues/64 +[#75]: https://github.com/MichaelHatherly/CommonMark.jl/issues/75 +[#76]: https://github.com/MichaelHatherly/CommonMark.jl/issues/76 +[#78]: https://github.com/MichaelHatherly/CommonMark.jl/issues/78 +[#80]: https://github.com/MichaelHatherly/CommonMark.jl/issues/80 +[#81]: https://github.com/MichaelHatherly/CommonMark.jl/issues/81 +[#82]: https://github.com/MichaelHatherly/CommonMark.jl/issues/82 +[#84]: https://github.com/MichaelHatherly/CommonMark.jl/issues/84 diff --git a/.julia-depot/packages/CommonMark/lmLkP/LICENSE b/.julia-depot/packages/CommonMark/lmLkP/LICENSE new file mode 100644 index 0000000..cde3d9b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/LICENSE @@ -0,0 +1,113 @@ +Copyright (c) 2020-2025 Michael Hatherly + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +Originally ported from the reference implementation with the following LICENSE: + +Copyright (c) 2014-2025, John MacFarlane + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + +lib/from-code-point.js is derived from a polyfill +Copyright Mathias Bynens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +bench/samples/*.md: + +With the exception of `bench/samples/README.md`, the samples in +`bench/samples` are taken from https://github.com/markdown-it/markdown-it. + +Copyright (c) 2014-2025 Vitaly Puzrin, Alex Kocharin. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +--- + +The CommonMark spec (spec.txt) in test/ is + +Copyright (C) 2014-2025 John MacFarlane + +Released under the Creative Commons CC-BY-SA 4.0 license: +. diff --git a/.julia-depot/packages/CommonMark/lmLkP/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/Project.toml new file mode 100644 index 0000000..8a479a9 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/Project.toml @@ -0,0 +1,22 @@ +name = "CommonMark" +uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +authors = ["Michael Hatherly"] +version = "0.9.1" + +[deps] +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" + +[compat] +JSON = "0.20, 0.21" +PrecompileTools = "1" +julia = "1.3" + +[extras] +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" + +[targets] +test = ["Test", "JSON", "Mustache", "Pkg", "YAML"] diff --git a/.julia-depot/packages/CommonMark/lmLkP/README.md b/.julia-depot/packages/CommonMark/lmLkP/README.md new file mode 100644 index 0000000..9199392 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/README.md @@ -0,0 +1,461 @@ +# CommonMark + +*A [CommonMark](https://spec.commonmark.org/current/)-compliant parser for Julia.* + +![CI](https://github.com/MichaelHatherly/CommonMark.jl/workflows/CI/badge.svg) +[![Codecov](https://codecov.io/gh/MichaelHatherly/CommonMark.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/MichaelHatherly/CommonMark.jl) + +## Interface + +```julia +using CommonMark +``` + +Create a markdown parser with the default CommonMark settings and then add +footnote syntax to our parser. + +```julia +parser = Parser() +enable!(parser, FootnoteRule()) +``` + +Parse some text to an abstract syntax tree from a `String`: + +```julia +ast = parser("Hello *world*") +``` + +Parse the contents of a source file: + +```julia +ast = open(parser, "document.md") +``` + +Write `ast` to a string. + +```julia +body = html(ast) +content = "$body" +``` + +Write to a file. + +```julia +open("file.tex", "w") do file + latex(file, ast) + println(file, "rest of document...") +end +``` + +Or write to a buffer, such as `stdout`. + +```julia +term(stdout, ast) +``` + +### Output Formats + +Supported output formats are currently: + +- `html` +- `latex` +- `typst` +- `term`: colourised and Unicode-formatted for display in a terminal. +- `markdown` +- `notebook`: [Jupyter](https://jupyter.org/) notebooks. + +## Extensions + +Extensions can be enabled using the `enable!` function and disabled using `disable!`. + +### Typography + +Convert ASCII dashes, ellipses, and quotes to their Unicode equivalents. + +```julia +enable!(parser, TypographyRule()) +``` + +Keyword arguments available for `TypographyRule` are + + - `double_quotes` + - `single_quotes` + - `ellipses` + - `dashes` + +which all default to `true`. + +### Admonitions + +```julia +enable!(parser, AdmonitionRule()) +``` + +### Front matter + +Fenced blocks at the start of a file containing structured data. + +``` ++++ +[heading] +content = "..." ++++ + +The rest of the file... +``` + +The block **must** start on the first line of the file. Supported blocks are: + + - `;;;` for JSON + - `+++` for TOML + - `---` for YAML + +To enable provide the `FrontMatterRule` with your choice of parsers for the formats: + +```julia +using JSON +enable!(parser, FrontMatterRule(json=JSON.Parser.parse)) +``` + +You can access front matter from a parsed file using `frontmatter`. As follows. + +```julia +ast = open(parser, "document.md") +meta = frontmatter(ast) +``` + +### Footnotes + +```julia +enable!(parser, FootnoteRule()) +``` + +### Math + +Julia-style inline and display maths: + +````markdown +Some ``\LaTeX`` math: + +```math +f(a) = \frac{1}{2\pi}\int_{0}^{2\pi} (\alpha+R\cos(\theta))d\theta +``` +```` + +Enabled with: + +```julia +enable!(parser, MathRule()) +``` + +Dollar-style inline and display math is also available using + +```julia +enable!(parser, DollarMathRule()) +``` + +Supported syntax: + + * single dollar signs surrounding inline math, + * double dollars surrounding a single line paragraph for display math. + +For more complex math, such as multiline display math, use the literal block +syntax available with `MathRule()`. + +### Tables + +Pipe-style tables, similar to GitHub's tables. Literal `|` characters that are +not wrapped in other syntax such as `*` must be escaped with a backslash. The +number of columns in the table is specified by the second line. + +```markdown +| Column One | Column Two | Column Three | +|:---------- | ---------- |:------------:| +| Row `1` | Column `2` | | +| *Row* 2 | **Row** 2 | Column ``|`` | +``` + +Rows with more cells than specified have the trailing cells discarded, and rows +with less cells are topped up with empty cells. + +Enabled with: + +```julia +enable!(parser, TableRule()) +``` + +### Raw Content + +Overload literal syntax to support passing through any type of raw content. + +```julia +enable!(parser, RawContentRule()) +``` + +By default `RawContentRule` will handle inline and block content in HTML and +LaTeX formats. + +````markdown +This is raw HTML: ``{=html}. + +And here's an HTML block: + +```{=html} +
+
+``` +```` + +````markdown +```{=latex} +\begin{tikzpicture} +\draw[gray, thick] (-1,2) -- (2,-4); +\draw[gray, thick] (-1,-1) -- (2,2); +\filldraw[black] (0,0) circle (2pt) node[anchor=west] {Intersection point}; +\end{tikzpicture} +``` +```` + +This can be used to pass through different complex content that can't be easily +handled by CommonMark natively without any loss of expressiveness. + +Custom raw content handlers can also be passed through when enabling the rule. +The naming scheme is `_inline` or `_block`. + +```julia +enable!(p, RawContentRule(rst_inline=RstInline)) +``` + +The last example would require the definition of a custom `RstInline` struct +and associated display methods for all supported output types, namely: `html`, +`latex`, and `term`. When passing your own keywords to `RawContentRule` the +defaults are not included and must be enabled individually. + +### Attributes + +Block and inline nodes can be tagged with arbitrary metadata in the form of +key/value pairs using the `AttributeRule` extension. + +```julia +enable!(p, AttributeRule()) +``` + +Block attributes appear directly *above* the node that they target: + +```markdown +{#my_id color="red"} +# Heading +``` + +This will attach the metadata `id="my_id"` and `color="red"` to `# Heading`. + +Inline attributes appear directly *after* the node that they target: + +```markdown +*Some styled text*{background="green"}. +``` + +Which will attach metadata `background="green"` to the emphasised text +`Some styled text`. + +CSS-style shorthand syntax `#` and `.` are available to use in +place of `id=""` and `class="name"`. Multiple classes may be specified +sequentially. + +`AttributeRule` does not handle writing metadata to particular formats such as +HTML or LaTeX. It is up to the implementation of a particular writer format to +make use of available metadata itself. The built-in `html` and `latex` outputs +make use of included attributes. `html` will include *all* provided attributes +in the output, while `latex` makes use of *only* the `#` attribute. + +### Citations + +Use the following to enable in-text citations and reference list generation: + +```julia +enable!(p, CitationRule()) +``` + +Syntax for citations is similar to what is offered by +[Pandoc](https://pandoc.org/MANUAL.html#citations). Citations start with `@`. + +```markdown +Citations can either appear in square brackets [@id], or they can be written as +part of the text like @id. Bracketed citations can contain more than one +citation; separated by semi-colons [@one; @two; and @three]. + +{#refs} +# References +``` + +A reference section that will be populated with a list of all references can be +marked using a `{#refs}` attribute from `AttributeRule` at the *toplevel* of +the document. The list will be inserted after the node, in this case `# References`. + +Citations and reference lists are formatted following the +[Chicago Manual of Style](https://www.chicagomanualofstyle.org/home.html). +Styling will, in future versions, be customisable using +[Citation Style Language](https://citationstyles.org/) styles. + +The reference data used for citations must be provided in a format matching +[CSL JSON](https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html). +Pass this data to `CommonMark.jl` when writing an AST to a output format. + +```julia +html(ast, Dict{String,Any}("references" => JSON.parsefile("references.json"))) +``` + +CSL JSON can be exported easily from reference management software such as +[Zotero](https://www.zotero.org/) or generated via `pandoc-citeproc --bib2json` +or similar. The `references` data can be provided by the front matter section +of a document so long as the `FrontMatterRule` has been enabled, though this does +require writing your CSL data manually. + +Note that the text format of the reference list is not important, and does not +*have* to be JSON data. So long as the *shape* of the data matches CSL JSON it +is valid. Below we use YAML `references` embedded in the document's front +matter: + +```markdown +--- +references: +- id: abelson1996 + author: + - family: Abelson + given: Harold + - family: Sussman + given: Gerald Jay + edition: 2nd Editon + event-place: Cambridge + ISBN: 0-262-01153-0 + issued: + date-parts: + - - 1996 + publisher: MIT Press/McGraw-Hill + publisher-place: Cambridge + title: Structure and interpretation of computer programs + type: book +--- + +Here's a citation [@abelson1996]. + +{#refs} +# References +``` + +### Auto Identifiers + +Headings within a document can be assigned `id`s automatically using + +```julia +enable!(p, AutoIdentifierRule()) +``` + +Identifiers are determined with `CommonMark.slugify`, which is based on the +algorithm used by Pandoc. Non-unique identifiers are suffixed with a numeric +counter and so cannot be considered stable. If you need stable identifiers then +you should use `AttributeRule` to assign stable `id`s manually. + +### CommonMark Defaults + +Block rules enabled by default in `Parser` objects: + + - `AtxHeadingRule()` + - `BlockQuoteRule()` + - `FencedCodeBlockRule()` + - `HtmlBlockRule()` + - `IndentedCodeBlockRule()` + - `ListItemRule()` + - `SetextHeadingRule()` + - `ThematicBreakRule()` + +Inline rules enabled by default in `Parser` objects: + + - `AsteriskEmphasisRule()` + - `AutolinkRule()` + - `HtmlEntityRule()` + - `HtmlInlineRule()` + - `ImageRule()` + - `InlineCodeRule()` + - `LinkRule()` + - `UnderscoreEmphasisRule()` + +These can all be disabled using `disable!`. Note that disabling some parser +rules may result in unexpected results. It is recommended to be conservative in +what is disabled. + +**Note** + +Until version `1.0.0` the rules listed above are subject to change and should +be considered unstable regardless of whether they are exported or not. + +## Writer Configuration + +When writing to an output format configuration data can be provided by: + + - passing a `Dict{String,Any}` to the writer method, + - front matter in the source document using the `FrontMatterRule` extension. + +Front matter takes precedence over the passed `Dict`. + +### Notable Variables + +Values used to determine template behaviour: + + - `template-engine::Function` Used to render standalone document templates. + + No default is provided by this package. The `template-engine` function + should follow the interface provided by `Mustache.render`. It is + recommended to use [Mustache.jl](https://github.com/jverzani/Mustache.jl) + to provide this functionalilty. + + Syntax for opening and closing tags used by `CommonMark.jl` is `${...}`. + See the templates in `src/writers/templates` for usage examples. + + - `.template.file::String` Custom template file to use for standalone ``. + + - `.template.string::String` Custom template string to use for standalone ``. + +Generic variables that can be included in templates to customise documents: + + - `abstract::String` Summary of the document. + + - `authors::Vector{String}` Vector of author names. + + - `date::String` Date of file generation. + + - `keywords::Vector{String}` Vector of keywords to be included in the document metadata. + + - `lang::String` Language of the document. + + - `title::String` Title of the document. + + - `subtitle::String` Subtitle of the document. + +Format-specific variables that should be used only in a particular format's +template. They are namespaced to avoid collision with other variables. + + - `html` + + - `html.css::Vector{String}` Vector of CSS files to include in document. + + - `html.js::Vector{String}` Vector of JavaScript files to include in document. + + - `html.header::String` String content to add at end of ``. + + - `html.footer::String` String content to add at end of ``. + + - `latex` + + - `latex.documentclass::String` Class file to use for document. Default is `article`. + + - `latex.preamble::String` String content to add directly before `\begin{document}`. + +The following are automatically available in document templates. + + - `body::String` Main content of the page. + + - `curdir::String` Current directory. + + - `outputfile::String` Name of file that is being written to. When writing to an in-memory + buffer this variable is not defined. diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/benchmark/Project.toml new file mode 100644 index 0000000..4b683a7 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/Project.toml @@ -0,0 +1,2 @@ +[deps] +Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/README.md b/.julia-depot/packages/CommonMark/lmLkP/benchmark/README.md new file mode 100644 index 0000000..9eb3cf7 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/README.md @@ -0,0 +1,10 @@ + +# Benchmarks for CommonMark.jl + +To update the markdown files in `benchmark/results/`, run: +``` +julia benchmark/make.jl +``` +Using [Literate.jl], this will execute the `.jl` files in this directory, and record the results in the generated `.md`'s. + +[Literate.jl]: https://github.com/fredrikekre/Literate.jl diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/make.jl b/.julia-depot/packages/CommonMark/lmLkP/benchmark/make.jl new file mode 100644 index 0000000..d033393 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/make.jl @@ -0,0 +1,26 @@ +using Literate + +gen_results() = + for file in readdir(@__DIR__, join = true) + if endswith(file, ".jl") && file != @__FILE__ + Literate.markdown( + file, + joinpath(@__DIR__, "results"), + execute = true, + flavor = Literate.CommonMarkFlavor(), + credit = false, # It's in the readme and the TOMLs + postprocess = rm_newlines, + ) + end + end + +"Remove the extraneous newlines at the end of output cells" +rm_newlines(md) = replace(md, "\n\n````\n" => "\n````\n") + + +ENV["JULIA_DEBUG"] = "Literate" +# ↪ Running `startup-time.jl` takes a while. +# We set the above flag to get feedback while running this `make.jl` +# (It makes the code block currently being executed get printed). + +gen_results() diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/Project.toml new file mode 100644 index 0000000..5995621 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/Project.toml @@ -0,0 +1,2 @@ +[deps] +CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/startup-time.md b/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/startup-time.md new file mode 100644 index 0000000..8084f17 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/results/startup-time.md @@ -0,0 +1,104 @@ +# Startup latency + +About this file +- It was created in [a PR to add precompilation][1] to CommonMark.jl. +- The `.md` version of this file is auto-generated (see `benchmark/README.md`). + Edit the underlying `.jl` instead. + +[1]: https://github.com/MichaelHatherly/CommonMark.jl/pull/59 + +## Setup + +````julia +using Pkg +Pkg.activate(@__DIR__) +# ↪ Note that this is executed in `benchmark/results/`, +# not in `benchmark/` (where this src .jl file lives) +```` +```` + Activating project at `C:\Users\tfiers\.julia\dev\CommonMark\benchmark\results` +```` + +````julia +parentdir = dirname # (Alias of a built-in function) +benchmark_dir = parentdir(@__DIR__) +reporoot = parentdir(benchmark_dir) + +srcfile = joinpath(reporoot, "src", "CommonMark.jl") +touch(srcfile) # To trigger full re-pre-compilation + +testfile = joinpath(reporoot, "test", "integration.md") +teststr = read(testfile, String) +```` +```` +"---\nfront: matter\n---\n\n# Integration Tests\n\n!!! danger\n\n Warning [@cite] admonition[^1]...\n\n ```math\n maths\n ```\n\n {.class}\n [^1]: 1\n\n footnote content\n\n!!! warning\n\n \"Warning\" [@cite] admonition[^2].\n\n | table |\n | - |\n | content |\n\n [^2]: 2\n\n!!! info\n\n 'Tip' [@cite] 'admonition'[^3].\n\n [^3]: ``x``\n\n!!! note\n\n Note [@cite] \"admonition\"[^4].\n\n ```{=latex}\n latex\n ```\n\n [^4]: 4\n\n!!! tip\n\n Tip [@cite] admonition[^5].\n\n [^5]: 5\n\n{#refs}\n## References\n\n" +```` + +## Results + +### Precompilation time + +````julia +Pkg.precompile("CommonMark") +# (No need for @time, Pkg prints time itself) +```` +```` +Precompiling project... + ✓ CommonMark + 1 dependency successfully precompiled in 7 seconds. 5 already precompiled. +```` + +### Package load time + +````julia +@time using CommonMark +```` +```` + 7.387662 seconds (736.17 k allocations: 43.326 MiB, 0.26% gc time, 0.34% compilation time) +```` + +### First function call times + +````julia +@time parser = Parser(); +```` +```` + 0.753673 seconds (21.06 k allocations: 1.009 MiB, 99.93% compilation time) +```` + +````julia +@time ast = parser(teststr); +```` +```` + 1.462268 seconds (558.29 k allocations: 27.821 MiB, 1.38% gc time, 99.93% compilation time) +```` + +````julia +@time CommonMark.html(ast); +```` +```` + 0.270778 seconds (94.01 k allocations: 4.818 MiB, 99.81% compilation time) +```` + +## Runtime environment + +````julia +using InteractiveUtils +versioninfo() +```` +```` +Julia Version 1.8.1 +Commit afb6c60d69 (2022-09-06 15:09 UTC) +Platform Info: + OS: Windows (x86_64-w64-mingw32) + CPU: 8 × Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz + WORD_SIZE: 64 + LIBM: libopenlibm + LLVM: libLLVM-13.0.1 (ORCJIT, skylake) + Threads: 7 on 8 virtual cores +Environment: + JULIA_DEBUG = Literate + JULIA_EDITOR = code.cmd + JULIA_NUM_THREADS = 7 +```` + diff --git a/.julia-depot/packages/CommonMark/lmLkP/benchmark/startup-time.jl b/.julia-depot/packages/CommonMark/lmLkP/benchmark/startup-time.jl new file mode 100644 index 0000000..e168ec7 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/benchmark/startup-time.jl @@ -0,0 +1,71 @@ + +# # Startup latency +# +# About this file +# - It was created in [a PR to add precompilation][1] to CommonMark.jl. +# - The `.md` version of this file is auto-generated (see `benchmark/README.md`). +# Edit the underlying `.jl` instead. +# +# [1]: https://github.com/MichaelHatherly/CommonMark.jl/pull/59 + + +# ## Setup + +using Pkg +Pkg.activate(@__DIR__) +## ↪ Note that this is executed in `benchmark/results/`, +## not in `benchmark/` (where this src .jl file lives) +#-- + +parentdir = dirname # (Alias of a built-in function) +benchmark_dir = parentdir(@__DIR__) +reporoot = parentdir(benchmark_dir) + +srcfile = joinpath(reporoot, "src", "CommonMark.jl") +touch(srcfile) # To trigger full re-pre-compilation + +testfile = joinpath(reporoot, "test", "integration.md") +teststr = read(testfile, String) + + + +# ## Results + + +# ### Precompilation time +# +Pkg.precompile("CommonMark") +## (No need for @time, Pkg prints time itself) + + +# ### Package load time +# +@time using CommonMark +#src # This is only after a re-precompilation. +#src # +#src # Subsequent package load times in new julia sessions: +#src cmd = `julia --startup-file=no --project=$(@__DIR__) -E "@time using CommonMark"` +#src buf = IOBuffer() +#src run(pipeline(cmd, stdout = buf)) +#src String(take!(buf)) +#src # Hm, still slow. +#src # Let's try again. +#src run(pipeline(cmd, stdout = buf)) +#src String(take!(buf)) +# +#src I'm confused. The above keeps showing 7.8 seconds. + + +# ### First function call times +# +@time parser = Parser(); +#-- +@time ast = parser(teststr); +#-- +@time CommonMark.html(ast); + + +# ## Runtime environment +# +using InteractiveUtils +versioninfo() diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/CommonMark.jl b/.julia-depot/packages/CommonMark/lmLkP/src/CommonMark.jl new file mode 100644 index 0000000..3db590e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/CommonMark.jl @@ -0,0 +1,46 @@ +module CommonMark + +include("utils.jl") +include("ast.jl") +include("parsers.jl") +include("writers.jl") +include("extensions.jl") +include("precompile.jl") + +# Interface +export Parser, enable!, disable!, html, latex, term, markdown, notebook, typst, frontmatter + +# Core block rules +export AtxHeadingRule, + BlockQuoteRule, + FencedCodeBlockRule, + HtmlBlockRule, + IndentedCodeBlockRule, + ListItemRule, + SetextHeadingRule, + ThematicBreakRule + +# Core inline rules +export AsteriskEmphasisRule, + AutolinkRule, + HtmlEntityRule, + HtmlInlineRule, + ImageRule, + InlineCodeRule, + LinkRule, + UnderscoreEmphasisRule + +# Extension rules +export AdmonitionRule, + AttributeRule, + AutoIdentifierRule, + CitationRule, + DollarMathRule, + FootnoteRule, + FrontMatterRule, + MathRule, + RawContentRule, + TableRule, + TypographyRule + +end # module diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/ast.jl b/.julia-depot/packages/CommonMark/lmLkP/src/ast.jl new file mode 100644 index 0000000..ab1e232 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/ast.jl @@ -0,0 +1,178 @@ +abstract type AbstractContainer end +abstract type AbstractBlock <: AbstractContainer end +abstract type AbstractInline <: AbstractContainer end + +is_container(::AbstractContainer) = false + +const SourcePos = NTuple{2,NTuple{2,Int}} + +mutable struct Node + t::AbstractContainer + parent::Node + first_child::Node + last_child::Node + prv::Node + nxt::Node + sourcepos::SourcePos + last_line_blank::Bool + last_line_checked::Bool + is_open::Bool + literal::String + meta::Dict{String,Any} + + Node() = new() + + function Node(t::AbstractContainer, sourcepos = ((0, 0), (0, 0))) + node = new() + node.t = t + node.parent = NULL_NODE + node.first_child = NULL_NODE + node.last_child = NULL_NODE + node.prv = NULL_NODE + node.nxt = NULL_NODE + node.sourcepos = sourcepos + node.last_line_blank = false + node.last_line_checked = false + node.is_open = true + node.literal = "" + node.meta = Dict{String,Any}() + return node + end +end + +function copy_tree(func::Function, root::Node) + lookup = Dict{Node,Node}() + for (old, enter) in root + if enter + lookup[old] = Node() + end + end + for (old, enter) in root + if enter + new = lookup[old] + + # Custom copying of the node payload. + new.t = func(old.t) + + new.parent = get(lookup, old.parent, NULL_NODE) + new.first_child = get(lookup, old.first_child, NULL_NODE) + new.last_child = get(lookup, old.last_child, NULL_NODE) + new.prv = get(lookup, old.prv, NULL_NODE) + new.nxt = get(lookup, old.nxt, NULL_NODE) + + new.sourcepos = old.sourcepos + new.last_line_blank = old.last_line_blank + new.last_line_checked = old.last_line_checked + new.is_open = old.is_open + new.literal = old.literal + + new.meta = copy(old.meta) + end + end + return lookup[root] +end +copy_tree(root::Node) = copy_tree(identity, root) + +const NULL_NODE = Node() +isnull(node::Node) = node === NULL_NODE + +is_container(node::Node) = is_container(node.t)::Bool + +Base.show(io::IO, node::Node) = print(io, "Node($(typeof(node.t)))") + +Base.IteratorSize(::Type{Node}) = Base.SizeUnknown() + +function Base.iterate(node::Node, (sr, sc, se) = (node, node, true)) + cur, entering = sc, se + isnull(cur) && return nothing + if entering && is_container(cur) + if !isnull(cur.first_child) + sc = cur.first_child + se = true + else + # Stay on node but exit. + se = false + end + elseif cur === sr + sc = NULL_NODE + elseif isnull(cur.nxt) + sc = cur.parent + se = false + else + sc = cur.nxt + se = true + end + return (cur, entering), (sr, sc, se) +end + +function append_child(node::Node, child::Node) + unlink(child) + child.parent = node + if !isnull(node.last_child) + node.last_child.nxt = child + child.prv = node.last_child + node.last_child = child + else + node.first_child = child + node.last_child = child + end +end + +function prepend_child(node::Node, child::Node) + unlink(child) + child.parent = node + if !isnull(node.first_child) + node.first_child.prv = child + child.nxt = node.first_child + node.first_child = child + else + node.first_child = child + node.last_child = child + end +end + +function unlink(node::Node) + if !isnull(node.prv) + node.prv.nxt = node.nxt + elseif !isnull(node.parent) + node.parent.first_child = node.nxt + end + + if !isnull(node.nxt) + node.nxt.prv = node.prv + elseif !isnull(node.parent) + node.parent.last_child = node.prv + end + + node.parent = NULL_NODE + node.nxt = NULL_NODE + node.prv = NULL_NODE +end + +function insert_after(node::Node, sibling::Node) + unlink(sibling) + sibling.nxt = node.nxt + if !isnull(sibling.nxt) + sibling.nxt.prv = sibling + end + sibling.prv = node + node.nxt = sibling + sibling.parent = node.parent + if isnull(sibling.nxt) + sibling.parent.last_child = sibling + end +end + +function insert_before(node::Node, sibling::Node) + unlink(sibling) + sibling.prv = node.prv + if !isnull(sibling.prv) + sibling.prv.nxt = sibling + end + sibling.nxt = node + node.prv = sibling + sibling.parent = node.parent + if isnull(sibling.prv) + sibling.parent.first_child = sibling + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions.jl new file mode 100644 index 0000000..43ee046 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions.jl @@ -0,0 +1,10 @@ +include("extensions/math.jl") +include("extensions/tables.jl") +include("extensions/admonitions.jl") +include("extensions/footnotes.jl") +include("extensions/frontmatter.jl") +include("extensions/raw.jl") +include("extensions/attributes.jl") +include("extensions/citations.jl") +include("extensions/autoidentifiers.jl") +include("extensions/interpolation.jl") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/admonitions.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/admonitions.jl new file mode 100644 index 0000000..21e59df --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/admonitions.jl @@ -0,0 +1,138 @@ +struct Admonition <: AbstractBlock + category::String + title::String +end + +is_container(::Admonition) = true +accepts_lines(::Admonition) = false +can_contain(::Admonition, t) = !(t isa Item) +finalize(::Admonition, parser::Parser, node::Node) = nothing +function continue_(::Admonition, parser::Parser, ::Any) + if parser.indent ≥ 4 + advance_offset(parser, 4, true) + elseif parser.blank + advance_next_nonspace(parser) + else + return 1 + end + return 0 +end + +function parse_admonition(parser::Parser, container::Node) + if !parser.indented + ln = SubString(parser.buf, parser.next_nonspace) + m = match(r"^!!! (\w+)(?: \"([^\"]+)\")?$", ln) + if m !== nothing + close_unmatched_blocks(parser) + title = m[2] === nothing ? uppercasefirst(m[1]) : m[2] + add_child(parser, Admonition(m[1], title), parser.next_nonspace) + advance_offset(parser, length(parser.buf) - parser.pos + 1, false) + return 1 + end + end + return 0 +end + +struct AdmonitionRule end +block_rule(::AdmonitionRule) = Rule(parse_admonition, 0.5, "!") + +# +# Writers +# + +function write_html(a::Admonition, rend, node, enter) + if enter + tag(rend, "div", attributes(rend, node, ["class" => "admonition $(a.category)"])) + tag(rend, "p", ["class" => "admonition-title"]) + print(rend.buffer, a.title) + tag(rend, "/p") + else + tag(rend, "/div") + end +end + +# Requires tcolorbox package and custom newtcolorbox definitions. +function write_latex(a::Admonition, w, node, enter) + if enter + cr(w) + literal(w, "\\begin{admonition@$(a.category)}{$(a.title)}\n") + else + literal(w, "\\end{admonition@$(a.category)}\n") + cr(w) + end +end + +function write_typst(a::Admonition, w, node, enter) + if enter + styles = Dict( + "danger" => "#dc2626", + "warning" => "#facc15", + "info" => "#0ea5e9", + "note" => "#9333ea", + "tip" => "#16a34a", + ) + style = get(styles, a.category, "#525252") + fill = "fill: rgb(\"#e5e5e5\")" + inset = "inset: 8pt" + stroke = "stroke: (left: 2pt + rgb(\"$style\"), rest: none)" + width = "width: 100%" + cr(w) + literal(w, "#block($fill, $inset, $stroke, $width)[") + literal(w, "#strong[", a.title, "] \\") + cr(w) + linebreak(w, node) + else + literal(w, "]") + cr(w) + end +end + +function write_term(a::Admonition, rend, node, enter) + styles = Dict( + "danger" => crayon"red bold", + "warning" => crayon"yellow bold", + "info" => crayon"cyan bold", + "note" => crayon"cyan bold", + "tip" => crayon"green bold", + ) + style = get(styles, a.category, crayon"default bold") + if enter + header = rpad("┌ $(a.title) ", available_columns(rend), "─") + print_margin(rend) + print_literal(rend, style, header, inv(style), "\n") + push_margin!(rend, "│", style) + push_margin!(rend, " ", crayon"") + else + pop_margin!(rend) + pop_margin!(rend) + print_margin(rend) + print_literal( + rend, + style, + rpad("└", available_columns(rend), "─"), + inv(style), + "\n", + ) + if !isnull(node.nxt) + print_margin(rend) + print_literal(rend, "\n") + end + end +end + +function write_markdown(a::Admonition, w, node, ent) + if ent + push_margin!(w, " ") + literal(w, "!!! ", a.category) + if lowercase(a.title) != lowercase(a.category) + literal(w, " \"$(a.title)\"") + end + literal(w, "\n") + print_margin(w) + literal(w, "\n") + else + pop_margin!(w) + cr(w) + linebreak(w, node) + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/attributes.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/attributes.jl new file mode 100644 index 0000000..551d345 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/attributes.jl @@ -0,0 +1,168 @@ +struct AttributeRule + nodes::Vector{Node} + AttributeRule() = new([]) +end + +struct Attributes <: AbstractBlock + dict::Dict{String,Any} + block::Bool +end + +is_container(::Attributes) = false +accepts_lines(::Attributes) = false +continue_(::Attributes, ::Parser, ::Node) = 1 +finalize(::Attributes, ::Parser, ::Node) = nothing +can_contain(::Attributes, t) = false + +function parse_block_attributes(parser::Parser, container::Node) + # Block attributes mustn't appear directly after another attribute block. + if !parser.indented && + (isnull(container.last_child) || !(container.last_child.t isa Attributes)) + dict, literal = try_parse_attributes(parser) + if dict !== nothing + advance_next_nonspace(parser) + advance_offset(parser, length(literal), false) + close_unmatched_blocks(parser) + child = add_child(parser, Attributes(dict, true), parser.next_nonspace) + child.literal = literal + advance_offset(parser, length(parser) - position(parser) + 1, false) + return 2 + end + end + return 0 +end + +block_rule(::AttributeRule) = Rule(parse_block_attributes, 1, "{") + +inline_rule(rule::AttributeRule) = + Rule(1, "{") do parser, block + isnull(block.first_child) && return false # Can't have inline attribute as first in block. + dict, literal = try_parse_attributes(parser) + dict === nothing && return false + node = Node(Attributes(dict, false)) + node.literal = literal + push!(rule.nodes, node) + append_child(block, node) + return true + end + +function try_parse_attributes(parser::AbstractParser) + start_mark = pos = position(parser) + while peek(parser, Char) === ' ' + # Consume leading spaces. + read(parser, Char) + end + @assert read(parser, Char) === '{' + valid = false + dict = Dict{String,Any}() + key = "" + while !eof(parser) + pos = position(parser) + char = read(parser, Char) + if char === '}' + valid = key == "" + break + elseif isspace(char) + continue + elseif char === '=' + isempty(key) && break + elseif char === ':' + key = "element" + elseif char === '#' + key = "id" + elseif char === '.' + key = "class" + elseif isletter(char) || isnumeric(char) || char in "-_" + mark = pos + while !eof(parser) + pos = position(parser) + char = peek(parser, Char) + if isletter(char) || isnumeric(char) || char in "-_" + read(parser, Char) + else + break + end + end + word = chop(String(bytes(parser, mark, pos)); tail = 1) + if isempty(key) + # Keys can't start with a number. + startswith(word, r"[0-9]") && break + key = word + # Check for empty attribute syntax. + if !startswith(parser, r"\s*=") + dict[key] = "" + key = "" + end + else + if key == "class" + push!(get!(() -> String[], dict, key), word) + else + dict[key] = word + end + key = "" + end + elseif char in "'\"" + # Simple strings, no escaping done. + delimiter = char + mark = pos + while !eof(parser) + pos = position(parser) + char = read(parser, Char) + if char === delimiter + break + end + end + if isempty(key) + # Strings can't be keys, so fail to parse. + break + else + str = chop(String(bytes(parser, mark, pos)); head = 1, tail = 1) + if key == "class" + push!(get!(() -> String[], dict, key), str) + else + dict[key] = str + end + key = "" + end + end + end + if valid + literal = String(bytes(parser, start_mark, pos)) + return dict, literal + else + seek(parser, start_mark) + return nothing, "" + end +end + +block_modifier(::AttributeRule) = + Rule(1) do parser, node + if node.t isa Attributes && !isnull(node.nxt) + node.nxt.t isa Attributes || (node.nxt.meta = node.t.dict) + end + return nothing + end + +inline_modifier(rule::AttributeRule) = + Rule(1) do parser, block + while !isempty(rule.nodes) + node = pop!(rule.nodes) + if !isnull(node.prv) && !(node.prv.t isa Attributes) + node.prv.meta = node.t.dict + end + end + end + +# Writers. + +write_html(::Attributes, w, n, ent) = nothing +write_latex(::Attributes, w, n, ent) = nothing +write_typst(::Attributes, w, n, ent) = nothing +write_term(::Attributes, w, n, ent) = nothing + +function write_markdown(at::Attributes, w, n, ent) + if ent + at.block && print_margin(w) + literal(w, n.literal, at.block ? "\n" : "") + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/autoidentifiers.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/autoidentifiers.jl new file mode 100644 index 0000000..86fdf6d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/autoidentifiers.jl @@ -0,0 +1,31 @@ +struct AutoIdentifierRule + refs::IdDict{Node,Dict{String,Int}} + AutoIdentifierRule(refs = IdDict()) = new(refs) +end + +reset_rule!(r::AutoIdentifierRule) = (empty!(r.refs); nothing) + +block_modifier(rule::AutoIdentifierRule) = + Rule(100) do parser, block + # Add heading IDs to those without any preset by AttributeRule. + if block.t isa Heading && !haskey(block.meta, "id") + block.meta["id"] = slugify(block.literal) + end + # Then make sure all IDs for the current AutoIdentifierRule are unique using a counter. + if haskey(block.meta, "id") + counter = get!(() -> Dict{String,Int}(), rule.refs, parser.doc) + id = block.meta["id"] + counter[id] = get!(counter, id, 0) + 1 + block.meta["id"] = counter[id] == 1 ? id : "$id-$(counter[id] - 1)" + end + return nothing + end + +# Modelled on pandoc's algorithm. +function slugify(str::AbstractString) + str = lowercase(str) + str = replace(str, r"\p{Z}+" => "-") + str = replace(str, r"[^\p{L}\p{N}\-]+" => "") + str = lstrip(c -> isnumeric(c) || ispunct(c), str) + return isempty(str) ? "section" : str +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/citations.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/citations.jl new file mode 100644 index 0000000..81ef41e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/citations.jl @@ -0,0 +1,248 @@ +struct Citation <: AbstractBlock + id::String + brackets::Bool +end + +struct CitationBracket <: AbstractBlock end + +struct CitationRule + cites::Vector{Node} + CitationRule() = new([]) +end + +inline_rule(rule::CitationRule) = + Rule(1, "@") do parser, block + m = consume(parser, match(r"@[_\w\d][_\w\d:#$%&\-\+\?\<\>~/]*", parser)) + m === nothing && return false + bs = parser.brackets + opener = bs !== nothing && is_bracket(bs.node, "[") + citation = Node(Citation(chop(m.match; head = 1, tail = 0), opener)) + citation.literal = m.match + append_child(block, citation) + push!(rule.cites, citation) + return true + end + +is_bracket(n::Node, c) = n.literal == c && n.t isa Text + +inline_modifier(rule::CitationRule) = + Rule(1) do parser, block + openers = Set{Node}() + closers = Set{Node}() + while !isempty(rule.cites) + cite = pop!(rule.cites) + if cite.t.brackets + opener = closer = cite + while !isnull(opener.prv) + opener = opener.prv + opener in openers && @goto SKIP + opener.t isa Citation && break + if is_bracket(opener, "[") + opener.t = CitationBracket() + push!(openers, opener) + break + end + end + while !isnull(closer.nxt) + closer = closer.nxt + closer in closers && @goto SKIP + closer.t isa Citation && break + if is_bracket(closer, "]") + closer.t = CitationBracket() + push!(closers, closer) + break + end + end + @label SKIP + end + end + end + +struct References <: AbstractBlock end + +block_modifier(::CitationRule) = + Rule(10) do parser, b + if !isnull(b.parent) && b.parent.t isa Document + if haskey(b.meta, "id") && b.meta["id"] == "refs" + insert_after(b, Node(References())) + end + end + return nothing + end + +# Writers. TODO: implement real CSL for citation styling. + +function write_html(c::Citation, w, n, ent) + tag(w, "span", attributes(w, n, ["class" => "citation"])) + tag(w, "a", ["href" => "#ref-$(c.id)"]) + literal(w, CSL.author_year(w.env, c.id)) + tag(w, "/a") + tag(w, "/span") +end + +function write_latex(c::Citation, w, n, ent) + if ent + # Allow the latex writer environment to control how citations are + # printed. `basic` just uses the built in hyperlinking similar to the + # HTML writer. `biblatex` will generate citations suitable for use with + # `biblatex` and `biber`. + if get(w.env, "citations", "basic") == "biblatex" + literal(w, "\\cite{", c.id, "}") + else + name = CSL.author_year(w.env, c.id) + name = name === nothing ? c.id : name + literal(w, "\\protect\\hyperlink{ref-", c.id, "}{", name, "}") + end + end + return nothing +end + +write_markdown(c::Citation, w, n, ent) = literal(w, "@", c.id) +write_typst(c::Citation, w, n, ent) = literal(w, "@", c.id) + +function write_term(c::Citation, w, n, ent) + style = crayon"red" + print_literal(w, style) + push_inline!(w, style) + print_literal(w, CSL.author_year(w.env, c.id)) + pop_inline!(w) + print_literal(w, inv(style)) +end + +write_html(::CitationBracket, w, n, ent) = literal(w, n.literal == "[" ? "(" : ")") +write_latex(::CitationBracket, w, n, ent) = literal(w, n.literal == "[" ? "(" : ")") +write_markdown(::CitationBracket, w, n, ent) = literal(w, n.literal) +write_typst(::CitationBracket, w, n, ent) = literal(w, n.literal) +write_term(::CitationBracket, w, n, ent) = print_literal(w, n.literal == "[" ? "(" : ")") + +write_markdown(::References, w, n, ent) = nothing +write_html(::References, w, n, ent) = write_references(write_html, w) +write_latex(::References, w, n, ent) = write_references(write_latex, w) +write_term(::References, w, n, ent) = write_references(write_term, w) +write_typst(::References, w, n, ent) = nothing # unsupported + +function write_references(f, writer) + ast = build_references(get(writer.env, "references", nothing)) + f(writer, ast) +end + +struct ReferenceList <: AbstractBlock end + +is_container(::ReferenceList) = true + +write_markdown(::ReferenceList, w, n, ent) = nothing +write_html(::ReferenceList, w, n, ent) = nothing +write_latex(::ReferenceList, w, n, ent) = nothing +write_term(::ReferenceList, w, n, ent) = nothing + +function build_references(items::AbstractVector) + block = Node(ReferenceList()) + for item in sort!(items; by = CSL.authors_long) + append_child(block, build_reference(item)) + end + return block +end +build_references(::Nothing) = Node(ReferenceList()) + +function build_reference(item::AbstractDict) + paragraph = Node(Paragraph()) + paragraph.meta["id"] = "ref-$(get(item, "id", ""))" + # Authors. + authors = CSL.authors_long(item) + authors === nothing || append_child(paragraph, text("$authors. ")) + # Year of publication. + year = CSL.year(item) + year === nothing || append_child(paragraph, text("$year. ")) + # Title of document. + title = Node(Emph()) + append_child(title, text(CSL.title(item) * ". ")) + append_child(paragraph, title) + # Publisher and location of publication. + publisher = CSL.publisher(item) + publisher === nothing || append_child(paragraph, text("$publisher. ")) + # Digital object identifier. + doi = CSL.doi(item) + doi === nothing || append_child(paragraph, text("doi:$doi. ")) + # Document URL. + url = CSL.url(item) + if url !== nothing + link = Node(Link()) + link.t.title = url + link.t.destination = url + append_child(link, text(url)) + append_child(paragraph, link) + append_child(paragraph, text(". ")) + end + return paragraph +end + +module CSL + +rget(f, col, key, keys...) = contains(col, key) ? rget(f, col[key], keys...) : f() +rget(f, col, key) = tryget(f, col, key) +tryget(f, d, key) = contains(d, key) ? d[key] : f() +contains(d::AbstractDict, key) = haskey(d, key) +contains(v::AbstractVector, index) = index in keys(v) +contains(others...) = false + +year(item) = rget(() -> nothing, item, "issued", "date-parts", 1, 1) +authors(item) = + filter(d -> d isa Dict && haskey(d, "family"), rget(() -> [], item, "author")) +title(item) = rget(() -> nothing, item, "title") + +function year(env::AbstractDict, id::AbstractString) + y = year(get_item(env, id)) + return y === nothing ? "@$id" : y +end + +author_short(item) = get(() -> get(item, "given", ""), item, "family") + +function authors_short(item) + names = sort(authors(item); by = author_short) + n = length(names) + n === 0 && return "Unknown" + 1 ≤ n ≤ 2 && return join(author_short.(names), " and ") + n === 3 && return join(author_short.(names), ", ", ", and ") + return author_short(names[1]) * " et al." +end + +function author_long(item, first) + family = get(item, "family", "") + given = get(item, "given", "") + given == "" && return family + family == "" && return given + return first ? "$family, $given" : "$given $family" +end + +function authors_long(item) + names = sort(authors(item); by = author_short) + return join((author_long(a, n == 1) for (n, a) in enumerate(names)), ", ", ", and ") +end + +mapbib(items::AbstractVector) = + Dict{String,Dict}(item["id"] => item for item in items if haskey(item, "id")) + +function get_item(env, id) + if haskey(env, "references") + refs = get!(() -> mapbib(env["references"]), env, "ref-map") + haskey(refs, id) && return refs[id] + end + return nothing +end + +function author_year(env::AbstractDict, id::AbstractString) + item = get_item(env, id) + return item === nothing ? "@$id" : author_year(item) +end +author_year(item) = "$(authors_short(item)) $(year(item))" + +publisher(d) = _publisher(get(d, "publisher-place", nothing), get(d, "publisher", nothing)) +_publisher(place, name) = "$place: $name" +_publisher(::Nothing, name::AbstractString) = name +_publisher(place::AbstractString, ::Nothing) = place +_publisher(::Nothing, ::Nothing) = nothing + +url(d) = get(d, "URL", nothing) +doi(d) = get(d, "DOI", nothing) + +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/footnotes.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/footnotes.jl new file mode 100644 index 0000000..5e6c16e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/footnotes.jl @@ -0,0 +1,169 @@ +struct FootnoteRule + cache::Dict{String,Node} + FootnoteRule() = new(Dict()) +end +block_rule(fr::FootnoteRule) = + Rule(0.5, "[") do parser, container + if !parser.indented + ln = SubString(parser.buf, parser.next_nonspace) + m = match(r"^\[\^([\w\d]+)\]:[ ]?", ln) + if m !== nothing + close_unmatched_blocks(parser) + fr.cache[m[1]] = + add_child(parser, FootnoteDefinition(m[1]), parser.next_nonspace) + advance_offset(parser, length(m.match), false) + return 1 + end + end + return 0 + end +inline_rule(fr::FootnoteRule) = + Rule(0.5, "[") do p, node + m = consume(p, match(r"^\[\^([\w\d]+)]", p)) + m === nothing && return false + append_child(node, Node(FootnoteLink(m[1], fr))) + return true + end + +struct FootnoteDefinition <: AbstractBlock + id::String +end + +struct FootnoteLink <: AbstractInline + id::String + rule::FootnoteRule +end + +is_container(::FootnoteDefinition) = true +accepts_lines(::FootnoteDefinition) = false +can_contain(::FootnoteDefinition, t) = !(t isa Item) +finalize(::FootnoteDefinition, ::Parser, ::Node) = nothing +function continue_(::FootnoteDefinition, parser::Parser, ::Any) + if parser.indent ≥ 4 + advance_offset(parser, 4, true) + elseif parser.blank + advance_next_nonspace(parser) + else + return 1 + end + return 0 +end + +# +# Writers +# + +# Definitions + +function write_html(f::FootnoteDefinition, rend, node, enter) + if enter + tag( + rend, + "div", + attributes(rend, node, ["class" => "footnote", "id" => "footnote-$(f.id)"]), + ) + tag(rend, "p", ["class" => "footnote-title"]) + print(rend.buffer, f.id) + tag(rend, "/p") + else + tag(rend, "/div") + end +end + +function write_latex(f::FootnoteDefinition, w, node, enter) + get(w.buffer, :footnote, false) || (w.enabled = !enter) + return nothing +end + +function write_typst(f::FootnoteDefinition, w, node, enter) + get(w.buffer, :footnote, false) || (w.enabled = !enter) + return nothing +end + +function write_term(f::FootnoteDefinition, rend, node, enter) + style = crayon"red" + if enter + header = rpad("┌ [^$(f.id)] ", available_columns(rend), "─") + print_margin(rend) + print_literal(rend, style, header, inv(style), "\n") + push_margin!(rend, "│", style) + push_margin!(rend, " ", crayon"") + else + pop_margin!(rend) + pop_margin!(rend) + print_margin(rend) + print_literal( + rend, + style, + rpad("└", available_columns(rend), "─"), + inv(style), + "\n", + ) + if !isnull(node.nxt) + print_margin(rend) + print_literal(rend, "\n") + end + end +end + +function write_markdown(f::FootnoteDefinition, w, node, ent) + if ent + push_margin!(w, 1, "[^$(f.id)]: ", " "^4) + else + pop_margin!(w) + cr(w) + end +end + +# Links + +function write_html(f::FootnoteLink, rend, node, enter) + tag( + rend, + "a", + attributes(rend, node, ["href" => "#footnote-$(f.id)", "class" => "footnote"]), + ) + print(rend.buffer, f.id) + tag(rend, "/a") +end + +function write_latex(f::FootnoteLink, w, node, enter) + if haskey(f.rule.cache, f.id) + seen = get!(() -> Set{String}(), w, :footnotes) + if f.id in seen + literal(w, "\\footref{fn:$(f.id)}") + else + push!(seen, f.id) + literal(w, "\\footnote{") + latex(IOContext(w.buffer, :footnote => true), f.rule.cache[f.id]) + literal(w, "\\label{fn:$(f.id)}}") + end + end + return nothing +end + +function write_typst(f::FootnoteLink, w, node, enter) + if haskey(f.rule.cache, f.id) + seen = get!(() -> Set{String}(), w, :footnotes) + if f.id in seen + literal(w, "#footnote()") + else + push!(seen, f.id) + literal(w, "#footnote[") + typst(IOContext(w.buffer, :footnote => true), f.rule.cache[f.id]) + literal(w, "] ") + end + end + return nothing +end + +function write_term(f::FootnoteLink, rend, node, enter) + style = crayon"red" + print_literal(rend, style) + push_inline!(rend, style) + print_literal(rend, "[^", f.id, "]") + pop_inline!(rend) + print_literal(rend, inv(style)) +end + +write_markdown(f::FootnoteLink, w, node, ent) = literal(w, "[^", f.id, "]") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/frontmatter.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/frontmatter.jl new file mode 100644 index 0000000..ec44249 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/frontmatter.jl @@ -0,0 +1,90 @@ +struct FrontMatter <: AbstractBlock + fence::String + data::Dict{String,Any} + FrontMatter(fence) = new(fence, Dict()) +end + +accepts_lines(::FrontMatter) = true + +# GitLab uses the following: +# +# * `---` for YAML +# * `+++` for TOML +# * `;;;` for JSON +# +const reFrontMatter = r"^(\-{3}|\+{3}|;{3})$" + +function continue_(frontmatter::FrontMatter, parser::Parser, container::Node) + ln = SubString(parser.buf, parser.next_nonspace) + if !parser.indented + m = Base.match(reFrontMatter, SubString(ln, parser.next_nonspace)) + if m !== nothing && m.match == frontmatter.fence + finalize(parser, container, parser.line_number) + return 2 + end + end + return 0 +end + +function finalize(frontmatter::FrontMatter, parser::Parser, block::Node) + _, rest = split(block.literal, '\n'; limit = 2) + block.literal = rest + return nothing +end + +can_contain(t::FrontMatter) = false + +function parse_front_matter(parser::Parser, container::Node) + if parser.line_number === 1 && !parser.indented && container.t isa Document + m = Base.match(reFrontMatter, SubString(parser.buf, parser.next_nonspace)) + if m !== nothing + close_unmatched_blocks(parser) + container = add_child(parser, FrontMatter(m.match), parser.next_nonspace) + advance_next_nonspace(parser) + advance_offset(parser, length(m.match), false) + return 2 + end + end + return 0 +end + +struct FrontMatterRule + json::Function + toml::Function + yaml::Function + + function FrontMatterRule(; fs...) + λ = str -> Dict{String,Any}() + return new(get(fs, :json, λ), get(fs, :toml, λ), get(fs, :yaml, λ)) + end +end + +block_rule(::FrontMatterRule) = Rule(parse_front_matter, 0.5, ";+-") +block_modifier(f::FrontMatterRule) = + Rule(0.5) do parser, node + if node.t isa FrontMatter + fence = node.t.fence + λ = fence == ";;;" ? f.json : fence == "+++" ? f.toml : f.yaml + try + merge!(node.t.data, λ(node.literal)) + catch err + node.literal = string(err) + end + end + return nothing + end + +# Frontmatter isn't displayed in the resulting output. + +write_html(::FrontMatter, rend, node, enter) = nothing +write_latex(::FrontMatter, rend, node, enter) = nothing +write_term(::FrontMatter, rend, node, enter) = nothing +write_typst(::FrontMatter, rend, node, enter) = nothing + +function write_markdown(f::FrontMatter, w, node, ent) + literal(w, f.fence, "\n") + # If frontmatter is not well-formed then it won't be round-trippable. + literal(w, node.literal) + literal(w, f.fence, "\n") + linebreak(w, node) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/interpolation.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/interpolation.jl new file mode 100644 index 0000000..483313b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/interpolation.jl @@ -0,0 +1,242 @@ +# This extension captures parsed Julia expressions from a markdown string, +# which can then be evaluated into the macro expansion's context to embed the +# values of the expressions in the markdown AST. Should only really be used +# from within the `@cm_str` macro otherwise the expressions won't have "time" +# to actually evaluate. + +# Captures an interpolated Julia expression and its position in the string +struct JuliaExpression <: AbstractInline + pos::Int + ex::Any +end +# Captures an expression and the future value associated with it after +# macro expansion. +struct JuliaValue <: AbstractInline + ex::Any + ref::Any +end + +# This rule should only be used from the exported `@cm_str` macro and not +# `enabled!` directly by users on a `Parser` object. +struct JuliaInterpolationRule + captured::Vector{JuliaExpression} + JuliaInterpolationRule() = new(JuliaExpression[]) +end + +const reInterpHere = r"^\$" + +inline_rule(ji::JuliaInterpolationRule) = + Rule(1, "\$") do p, node + dollar = match(reInterpHere, p) + if dollar === nothing || length(dollar.match) > 1 + return false + else + consume(p, dollar) + after_opener, count = position(p), length(dollar.match) + ex, after_expr = Meta.parse(rest(p), 1; greedy = false, raise = false) + after_expr += after_opener + if Meta.isexpr(ex, [:error, :incomplete]) + # Bails out on Julia parse errors, do we rather want to propagate them? + return false + else + seek(p, after_expr - 1) # Offset Meta.parse end position. + ref = JuliaExpression(length(ji.captured) + 1, ex) + push!(ji.captured, ref) + append_child(node, Node(ref)) + return true + end + end + end + +export @cm_str + +""" + cm"" + +A string macro for markdown text that implements standard string interpolation. +Returns a parsed markdown AST with the values of the interpolation expressions +embedded in the AST. + +```julia +value = "interpolated" +cm"Some *\$(value)* text." +``` + +The default syntax rules used for parsing are: + + - `AdmonitionRule` + - `AttributeRule` + - `AutoIdentifierRule` + - `CitationRule` + - `FootnoteRule` + - `MathRule` + - `RawContentRule` + - `TableRule` + - `TypographyRule` + +which matches closely with the default syntax supported in `Markdown.@md_str`. + +!!! info + + The `DollarMathRule` is not enabled since it conflicts with the + interpolation syntax. Use double backticks and `math` language literal + blocks for maths that is provided by the `MathRule`. + +A custom `Parser` can be invoked when using `cm""` by providing a suffix +to the macro call, for example: + +```julia +more = "more" +cm"Some **\$(uppercase(more))** text."none +``` + +where the suffixed `none` will invoke a basic `Parser` with no additional +syntax rules `enabled!`. To use your own custom parser, for example to only +enable the `TypographyRule`, you can suffix the call with a named function from +the current module's global scope that returns the `Parser` object with the +required rules enabled: + +```julia +custom() = enable!(Parser(), TypographyRule()) +``` + +It can then be used as + +```julia +str = "custom" +cm"A '\$(titlecase(str))' parser..."custom +``` +""" +macro cm_str(str, name = "jmd") + ji = JuliaInterpolationRule() + parser = _init_parser(__module__, name) + enable!(parser, ji) + multiline = occursin("\n", str) + ast = parser( + str; + source = String(__source__.file), + line = __source__.line + Int(multiline), + ) + # We construct an expression that first, one-by-one and in order, evaluates each + # of the interpolated expressions that appeared in the string, adds them to a + # list, and finally calls _interp! on it to update the AST with the evaluated + # values. + expr = Expr(:block, :(values = [])) + for v in ji.captured + push!(expr.args, :( + let x = $(esc(v.ex)) + push!(values, x) + end + )) + end + push!(expr.args, :(_interp!($ast, $(ji.captured), values))) + return expr +end + +function _interp!(ast::Node, refs::Vector, values::Vector) + # Copy the parsed AST and replace any interpolations with their values. + replace(t::JuliaExpression) = JuliaValue(t.ex, values[t.pos]) + replace(@nospecialize(other)) = other + return copy_tree(replace, ast) +end + +function _init_parser(mod::Module, name::AbstractString)::Parser + options = ( + jmd = function () + p = Parser() + enable!( + p, + [ + AdmonitionRule(), + AttributeRule(), + AutoIdentifierRule(), + CitationRule(), + FootnoteRule(), + MathRule(), + RawContentRule(), + TableRule(), + TypographyRule(), + ], + ) + return p + end, + none = () -> Parser(), + ) + s = Symbol(name) + if isdefined(mod, s) + obj = getfield(mod, s) + if isa(obj, Function) + try + p = obj() + isa(p, Parser) && return p + catch + end + end + end + return get(options, s, Parser)() +end + +# +# Writers +# + +# JuliaExpression + +function write_html(jv::JuliaExpression, rend, node, enter) + tag(rend, "span", attributes(rend, node, ["class" => "julia-expr"])) + print(rend.buffer, sprint(print, '$', "($(jv.ex))")) + tag(rend, "/span") +end + +function write_latex(jv::JuliaExpression, rend, node, enter) + print(rend.buffer, "\\texttt{", '\\', '$', '(') + latex_escape(rend, string(jv.ex)) + print(rend.buffer, ")}") +end + +function write_typst(jv::JuliaExpression, rend, node, enter) + print(rend.buffer, string(jv.ex)) +end + +function write_term(jv::JuliaExpression, rend, node, enter) + style = crayon"yellow" + push_inline!(rend, style) + print_literal(rend, style, sprint(print, '$', "($(jv.ex))"), inv(style)) + pop_inline!(rend) +end + +# JuliaValue + +function write_html(jv::JuliaValue, rend, node, enter) + tag(rend, "span", attributes(rend, node, ["class" => "julia-value"])) + print(rend.buffer, sprint(_showas, MIME("text/html"), jv.ref; context = rend.buffer)) + tag(rend, "/span") +end + +function write_latex(jv::JuliaValue, rend, node, enter) + print(rend.buffer, sprint(_showas, MIME("text/latex"), jv.ref)) +end + +function _showas(io::IO, m::MIME, collection::Union{Tuple,AbstractArray,Base.Generator}) + for each in collection + _showas(io, m, each) + print(io, " ") + end +end +_showas(io::IO, m::MIME, obj) = showable(m, obj) ? show(io, m, obj) : print(io, obj) + +function write_term(jv::JuliaValue, rend, node, enter) + style = crayon"yellow" + push_inline!(rend, style) + print_literal(rend, style, sprint(print, jv.ref), inv(style)) + pop_inline!(rend) +end + +function write_typst(jv::JuliaValue, rend, node, enter) + literal(rend, sprint(print, jv.ref)) +end + +# Markdown output should be roundtrip-able, so printout the interpolated +# expression rather than it's value. +write_markdown(jv::Union{JuliaExpression,JuliaValue}, rend, node, ent) = + print(rend.buffer, '$', "($(jv.ex))") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/math.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/math.jl new file mode 100644 index 0000000..47a0c0a --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/math.jl @@ -0,0 +1,183 @@ +# +# Inline math +# + +struct Math <: AbstractInline end + +function parse_inline_math_backticks(p::InlineParser, node::Node) + ticks = match(reTicksHere, p) + if ticks === nothing || isodd(length(ticks.match)) + return false + end + consume(p, ticks) + after_opener, count = position(p), length(ticks.match) + while true + matched = consume(p, match(reTicks, p)) + matched === nothing && break + if length(matched.match) === count + before_closer = position(p) - count - 1 + raw = String(bytes(p, after_opener, before_closer)) + child = Node(Math()) + child.literal = strip(replace(raw, r"\s+" => ' ')) + append_child(node, child) + return true + end + end + # We didn't match an even length sequence. + seek(p, after_opener) + append_child(node, text(ticks.match)) + return true +end + +# +# Display math +# + +struct DisplayMath <: AbstractBlock end + +function handle_fenced_math_block(node::Node, info, source) + node.t = DisplayMath() + node.literal = strip(source, '\n') +end + +struct MathRule end +block_modifier(::MathRule) = + Rule(1.5) do parser, node + if node.t isa CodeBlock && node.t.info == "math" + node.t = DisplayMath() + node.literal = strip(node.literal, '\n') + end + return nothing + end +inline_rule(::MathRule) = Rule(parse_inline_math_backticks, 0, "`") + +# +# Dollar math +# + +struct DollarMathRule end + +function parse_block_dollar_math(p::Parser, node::Node) + if node.t isa Paragraph + left = match(r"^(\$+)", node.literal) + left === nothing && return nothing + right = match(r"(\$+)$", rstrip(node.literal)) + right === nothing && return nothing + if length(left[1]) == length(right[1]) == 2 + node.literal = strip(c -> isspace(c) || c === '$', node.literal) + node.t = DisplayMath() + end + end + return nothing +end + +block_modifier(::DollarMathRule) = Rule(parse_block_dollar_math, 0) + +const reDollarsHere = r"^\$+" +const reDollars = r"\$+" + +function parse_inline_dollar_math(p::InlineParser, node::Node) + dollars = match(reDollarsHere, p) + if dollars === nothing || length(dollars.match) > 1 + return false + end + consume(p, dollars) + after_opener, count = position(p), length(dollars.match) + while true + matched = consume(p, match(reDollars, p)) + matched === nothing && break + if length(matched.match) === count + before_closer = position(p) - count - 1 + raw = String(bytes(p, after_opener, before_closer)) + child = Node(Math()) + child.literal = strip(replace(raw, r"\s+" => ' ')) + append_child(node, child) + return true + end + end + # We didn't match a balanced closing sequence. + seek(p, after_opener) + append_child(node, text(dollars.match)) + return true +end + +inline_rule(::DollarMathRule) = Rule(parse_inline_dollar_math, 0, "\$") + +# +# Writers +# + +function write_html(::Math, rend, node, enter) + tag(rend, "span", attributes(rend, node, ["class" => "math tex"])) + print(rend.buffer, "\\(", node.literal, "\\)") + tag(rend, "/span") +end + +function write_latex(::Math, rend, node, enter) + print(rend.buffer, "\\(", node.literal, "\\)") +end + +function write_typst(::Math, rend, node, enter) + print(rend.buffer, "\$", strip(node.literal), "\$") +end + +function write_term(::Math, rend, node, enter) + style = crayon"magenta" + push_inline!(rend, style) + print_literal(rend, style, node.literal, inv(style)) + pop_inline!(rend) +end + +function write_markdown(::Math, w, node, ent) + num = foldl(eachmatch(r"`+", node.literal); init = 0) do a, b + max(a, length(b.match)) + end + literal(w, "`"^(num == 2 ? 4 : 2)) + literal(w, node.literal) + literal(w, "`"^(num == 2 ? 4 : 2)) +end + +function write_html(::DisplayMath, rend, node, enter) + tag(rend, "div", attributes(rend, node, ["class" => "display-math tex"])) + print(rend.buffer, "\\[", node.literal, "\\]") + tag(rend, "/div") +end + +function write_latex(::DisplayMath, rend, node, enter) + println(rend.buffer, "\\begin{equation*}") + println(rend.buffer, node.literal) + println(rend.buffer, "\\end{equation*}") +end + +function write_typst(::DisplayMath, rend, node, enter) + print(rend.buffer, "\$ ") + print(rend.buffer, strip(node.literal)) + println(rend.buffer, " \$") +end + +function write_term(::DisplayMath, rend, node, enter) + pipe = crayon"magenta" + style = crayon"dark_gray" + for line in eachline(IOBuffer(node.literal)) + print_margin(rend) + print_literal(rend, " ", pipe, "│", inv(pipe), " ") + print_literal(rend, style, line, inv(style), "\n") + end + if !isnull(node.nxt) + print_margin(rend) + print_literal(rend, "\n") + end +end + +function write_markdown(::DisplayMath, w, node, ent) + print_margin(w) + literal(w, "```math\n") + for line in eachline(IOBuffer(node.literal)) + print_margin(w) + literal(w, line, "\n") + end + print_margin(w) + literal(w, "```") + cr(w) + linebreak(w, node) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/raw.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/raw.jl new file mode 100644 index 0000000..7e4ebdf --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/raw.jl @@ -0,0 +1,113 @@ +struct LaTeXInline <: AbstractInline end +struct LaTeXBlock <: AbstractBlock end +struct TypstInline <: AbstractInline end +struct TypstBlock <: AbstractBlock end + +const RAW_CONTENT_DEFAULTS = Dict( + "html_inline" => HtmlInline, + "latex_inline" => LaTeXInline, + "typst_inline" => TypstInline, + "html_block" => HtmlBlock, + "latex_block" => LaTeXBlock, + "typst_block" => TypstBlock, +) + +struct RawContentRule + formats::Dict{String,Any} + function RawContentRule(; formats...) + return isempty(formats) ? new(RAW_CONTENT_DEFAULTS) : + new(Dict("$k" => v for (k, v) in formats)) + end +end + +const reRawContent = r"^{=([a-z]+)}" + +inline_rule(rule::RawContentRule) = + Rule(1, "{") do parser, block + if !isnull(block.last_child) && block.last_child.t isa Code + m = match(reRawContent, parser) + if m !== nothing + key = "$(m[1])_inline" + if haskey(rule.formats, key) + block.last_child.t = rule.formats[key]() + consume(parser, m) + return true + end + end + end + return false + end + +block_modifier(rule::RawContentRule) = + Rule(2) do parser, node + if node.t isa CodeBlock + m = match(reRawContent, node.t.info) + m === nothing && return nothing + key = "$(m[1])_block" + haskey(rule.formats, key) && (node.t = rule.formats[key]()) + end + return nothing + end + +# Raw LaTeX doesn't get displayed in HTML documents. +write_html(::LaTeXBlock, w, n, en) = nothing +write_html(::LaTeXInline, w, n, ent) = nothing + +# Raw Typst doesn't get displayed in HTML documents. +write_html(::TypstBlock, w, n, en) = nothing +write_html(::TypstInline, w, n, ent) = nothing + +# Don't do any kind of escaping for the content. +function write_latex(::LaTeXBlock, w, n, ent) + cr(w) + literal(w, n.literal) + cr(w) +end +write_latex(::LaTeXInline, w, n, ent) = literal(w, n.literal) + +write_latex(::TypstBlock, w, n, en) = nothing +write_latex(::TypstInline, w, n, ent) = nothing + +function write_typst(::TypstBlock, w, n, ent) + cr(w) + literal(w, n.literal) + cr(w) +end +write_typst(::TypstInline, w, n, ent) = literal(w, n.literal) + +write_typst(::LaTeXBlock, w, n, ent) = nothing +write_typst(::LaTeXInline, w, n, ent) = nothing + +# Printing to terminal using the same implementations as for HTML content. +write_term(::LaTeXBlock, w, n, ent) = write_term(HtmlBlock(), w, n, ent) +write_term(::LaTeXInline, w, n, ent) = write_term(HtmlInline(), w, n, ent) + +# Printing to terminal using the same implementations as for HTML content. +write_term(::TypstBlock, w, n, ent) = write_term(HtmlBlock(), w, n, ent) +write_term(::TypstInline, w, n, ent) = write_term(HtmlInline(), w, n, ent) + +function write_markdown(t::Union{LaTeXBlock,TypstBlock}, w, n, ent) + print_margin(w) + literal(w, "```{=$(_raw_tag(t))}\n") + for line in eachline(IOBuffer(n.literal)) + print_margin(w) + literal(w, line, "\n") + end + print_margin(w) + literal(w, "```\n") + linebreak(w, n) +end + +function write_markdown(t::Union{LaTeXInline,TypstInline}, w, n, ent) + num = foldl(eachmatch(r"`+", n.literal); init = 0) do a, b + max(a, length(b.match)) + end + literal(w, '`'^(num == 1 ? 2 : 1)) + literal(w, n.literal) + literal(w, '`'^(num == 1 ? 2 : 1), "{=$(_raw_tag(t))}") +end + +_raw_tag(::LaTeXInline) = "latex" +_raw_tag(::LaTeXBlock) = "latex" +_raw_tag(::TypstInline) = "typst" +_raw_tag(::TypstBlock) = "typst" diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/extensions/tables.jl b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/tables.jl new file mode 100644 index 0000000..86ccc1a --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/extensions/tables.jl @@ -0,0 +1,401 @@ +abstract type TableComponent <: AbstractBlock end + +is_container(::TableComponent) = true +accepts_lines(::TableComponent) = false +finalize(table::TableComponent, parser::Parser, node::Node) = nothing +can_contain(::TableComponent, ::Any) = false + +struct Table <: TableComponent + spec::Vector{Symbol} + Table(spec) = new(spec) +end + +continue_(table::Table, parser::Parser, container::Node) = 0 + +struct TableHeader <: TableComponent end + +struct TableBody <: TableComponent end + +continue_(table::TableBody, parser::Parser, container::Node) = 1 + +struct TableRow <: TableComponent end + +contains_inlines(::TableRow) = true + +struct TableCell <: TableComponent + align::Symbol + header::Bool + column::Int +end + +contains_inlines(::TableCell) = true + +function gfm_table(parser::Parser, container::Node) + if !parser.indented + if container.t isa Paragraph + header = container.literal + spec_str = SubString(parser.buf, parser.next_nonspace) + if valid_table_spec(spec_str) + # Parse the table spec line. + spec = parse_table_spec(spec_str) + table = Node(Table(spec), container.sourcepos) + # Build header row with cells for each column. + head = Node(TableHeader(), container.sourcepos) + append_child(table, head) + row = Node(TableRow(), container.sourcepos) + row.literal = header + append_child(head, row) + # Insert the empty body for the table. + body = Node(TableBody(), container.sourcepos) + append_child(table, body) + # Splice the newly created table in place of the paragraph. + insert_after(container, table) + unlink(container) + parser.tip = table + advance_offset(parser, length(parser.buf) - parser.pos + 1, false) + return 2 + end + end + if container.t isa Table + line = SubString(parser.buf, parser.next_nonspace) + if valid_table_row(line) + row = Node(TableRow(), container.sourcepos) + append_child(container.last_child, row) + row.literal = line + advance_offset(parser, length(parser.buf) - parser.pos + 1, false) + return 2 + end + end + end + return 0 +end + +valid_table_row(str) = startswith(str, '|') +valid_table_spec(str) = !occursin(r"[^\|:\- ]", str) + +function parse_table_spec(str) + map(eachmatch(r"\|([ ]*[: ]?[-]+[ :]?[ ]*)\|", str; overlap = true)) do match + str = strip(match[1]) + left, right = str[1] === ':', str[end] === ':' + center = left && right + align = center ? :center : right ? :right : :left + return align + end +end + +struct TableRule + pipes::Vector{Node} + TableRule() = new([]) +end + +block_rule(::TableRule) = Rule(gfm_table, 0.5, "|") + +struct TablePipe <: AbstractInline end + +inline_rule(rule::TableRule) = + Rule(0, "|") do parser, block + block.t isa TableRow || return false + @assert read(parser, Char) == '|' + eof(parser) && return true # Skip last pipe. + pipe = Node(TablePipe()) + append_child(block, pipe) + push!(rule.pipes, pipe) + return true + end + +# Low priority since this *must* happen after nested structure of emphasis and +# links is determined. 100 should do fine. +inline_modifier(rule::TableRule) = + Rule(100) do parser, block + block.t isa TableRow || return + isheader = block.parent.t isa TableHeader + spec = block.parent.parent.t.spec + max_cols = length(spec) + col = 1 + cells = Node[] + while !isempty(rule.pipes) + pipe = popfirst!(rule.pipes) + if pipe.parent === block + # Top-level pipe must be replaced with a table cell containing + # everything up until the next pipe. + cell = Node(TableCell(spec[min(col, max_cols)], isheader, col)) + n = pipe.nxt + elems = Node[] + # Find all nodes between this pipe and the next. + while !isnull(n) && !(n.t isa TablePipe) + push!(elems, n) + n = n.nxt + end + total = length(elems) + for (nth, elem) in enumerate(elems) + # Strip surronding whitespace in each cell. + lit = elem.literal + lit = (nth === 1 && elem.t isa Text) ? lstrip(lit) : lit + lit = (nth === total && elem.t isa Text) ? rstrip(lit) : lit + elem.literal = lit + append_child(cell, elem) + end + push!(cells, cell) + unlink(pipe) + col += 1 + else + # Replace nested pipes with text literals since they can't + # demarcate a cell boarder. + pipe.t = Text() + pipe.literal = "|" + end + end + if length(cells) < max_cols + # Add addtional cells in this row is below number in spec. + extra = (length(cells)+1):max_cols + append!(cells, (Node(TableCell(:left, isheader, n)) for n in extra)) + end + for (nth, cell) in enumerate(cells) + # Drop additional cells if they are longer that the spec. + nth ≤ length(spec) ? append_child(block, cell) : unlink(cell) + end + end + +# +# Writers +# + +# HTML + +write_html(::Table, rend, n, ent) = + tag(rend, ent ? "table" : "/table", ent ? attributes(rend, n) : []) +write_html(::TableHeader, rend, node, enter) = tag(rend, enter ? "thead" : "/thead") +write_html(::TableBody, rend, node, enter) = tag(rend, enter ? "tbody" : "/tbody") +write_html(::TableRow, rend, node, enter) = tag(rend, enter ? "tr" : "/tr") + +function write_html(cell::TableCell, rend, node, enter) + tag_name = cell.header ? "th" : "td" + tag(rend, enter ? "$tag_name align=\"$(cell.align)\"" : "/$tag_name") +end + +# LaTeX + +function write_latex(table::Table, rend, node, enter) + if enter + print(rend.buffer, "\\begin{longtable}[]{@{}") + join(rend.buffer, (string(align)[1] for align in table.spec)) + println(rend.buffer, "@{}}") + else + println(rend.buffer, "\\end{longtable}") + end +end + +function write_latex(::TableHeader, rend, node, enter) + if enter + println(rend.buffer, "\\hline") + else + println(rend.buffer, "\\hline") + println(rend.buffer, "\\endfirsthead") + end +end + +function write_latex(::TableBody, rend, node, enter) + if !enter + println(rend.buffer, "\\hline") + end +end + +function write_latex(::TableRow, rend, node, enter) + enter ? nothing : println(rend.buffer, "\\tabularnewline") +end + +function write_latex(::TableCell, rend, node, enter) + if !enter && node.parent.last_child !== node + print(rend.buffer, " & ") + end +end + +# Typst + +function write_typst(table::Table, rend, node, enter) + if enter + align = "align: (" * join(table.spec, ", ") * ")" + columns = "columns: $(length(table.spec))" + fill = "fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") }" + println(rend.buffer, "#table($align, $columns, $fill,") + else + println(rend.buffer, ")") + end +end + +function write_typst(::TableHeader, rend, node, enter) + if enter + println(rend.buffer, "table.header(") + else + println(rend.buffer, "),") + end +end + +write_typst(::TableBody, rend, node, enter) = nothing + +function write_typst(::TableRow, rend, node, enter) + if enter + else + println(rend.buffer) + end +end + +function write_typst(::TableCell, rend, node, enter) + if enter + print(rend.buffer, "[") + else + print(rend.buffer, "],") + end +end + +# Term + +function write_term(table::Table, rend, node, enter) + if enter + cells, widths = calculate_columns_widths(table, node) do node + length(replace(term(node), r"\e\[[0-9]+(?:;[0-9]+)*m" => "")) + end + rend.context[:cells] = cells + rend.context[:widths] = widths + + print_margin(rend) + print(rend.format.buffer, "┏━") + join(rend.format.buffer, ("━"^w for w in widths), "━┯━") + println(rend.format.buffer, "━┓") + else + print_margin(rend) + print(rend.format.buffer, "┗━") + join(rend.format.buffer, ("━"^w for w in rend.context[:widths]), "━┷━") + println(rend.format.buffer, "━┛") + + delete!(rend.context, :cells) + delete!(rend.context, :widths) + end + return nothing +end + +function write_term(::TableHeader, rend, node, enter) + if !enter + print_margin(rend) + print(rend.format.buffer, "┠─") + join(rend.format.buffer, ("─"^w for w in rend.context[:widths]), "─┼─") + println(rend.format.buffer, "─┨") + end + return nothing +end + +write_term(::TableBody, rend, node, enter) = nothing + +function write_term(::TableRow, rend, node, enter) + if enter + print_margin(rend) + print(rend.format.buffer, "┃ ") + else + println(rend.format.buffer, " ┃") + end + return nothing +end + +function write_term(cell::TableCell, rend, node, enter) + if haskey(rend.context, :widths) + pad = rend.context[:widths][cell.column] - rend.context[:cells][node] + if enter + if cell.align == :left + elseif cell.align == :right + print(rend.format.buffer, ' '^pad) + elseif cell.align == :center + left = Int(round(pad / 2, RoundDown)) + print(rend.format.buffer, ' '^left) + end + else + if cell.align == :left + print(rend.format.buffer, ' '^pad) + elseif cell.align == :right + elseif cell.align == :center + right = Int(round(pad / 2, RoundUp)) + print(rend.format.buffer, ' '^right) + end + if !isnull(node.nxt) + print(rend.format.buffer, " │ ") + end + end + end + return nothing +end + +# Markdown + +function write_markdown(table::Table, w::Writer, node, enter) + if enter + cells, widths = + calculate_columns_widths(node -> length(markdown(node)), table, node) + w.context[:cells] = cells + w.context[:widths] = widths + else + delete!(w.context, :cells) + delete!(w.context, :widths) + linebreak(w, node) + end + return nothing +end + +function write_markdown(::TableHeader, w, node, enter) + if enter + else + spec = node.parent.t.spec + print_margin(w) + literal(w, "|") + for (width, align) in zip(w.context[:widths], spec) + literal(w, align in (:left, :center) ? ":" : " ") + literal(w, "-"^width) + literal(w, align in (:center, :right) ? ":" : " ") + literal(w, "|") + end + cr(w) + end + return nothing +end + +write_markdown(::TableBody, w, node, enter) = nothing + +function write_markdown(::TableRow, w, node, enter) + if enter + print_margin(w) + literal(w, "| ") + else + literal(w, " |") + cr(w) + end + return nothing +end + +function write_markdown(cell::TableCell, w, node, enter) + if haskey(w.context, :widths) + if !enter + padding = w.context[:widths][cell.column] - w.context[:cells][node] + literal(w, " "^padding) + isnull(node.nxt) || literal(w, " | ") + end + end + return nothing +end + +# Utilities. + +function calculate_columns_widths(width_func, table, node) + cells, widths = Dict{Node,Int}(), ones(Int, length(table.spec)) + index = 0 + for (n, enter) in node + if enter + if n.t isa TableRow + index = 0 + elseif n.t isa TableCell + index += 1 + cell = width_func(n) + widths[index] = max(widths[index], cell) + cells[n] = cell + end + end + end + return cells, widths +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers.jl new file mode 100644 index 0000000..893a1ef --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers.jl @@ -0,0 +1,82 @@ +import Base: peek + +abstract type AbstractParser end +# .buf, .pos, .len must exist. + +Base.String(p::AbstractParser) = String(p.buf) +Base.position(p::AbstractParser) = p.pos +Base.length(p::AbstractParser) = p.len +Base.eof(p::AbstractParser) = position(p) > length(p) +Base.seek(p::AbstractParser, pos) = p.pos = pos +Base.seekstart(p::AbstractParser) = p.pos = 1 + +Base.peek(p::AbstractParser, ::Type{UInt8}) = p.buf[position(p)] +Base.peek(p::AbstractParser, ::Type{Char}) = String(p.buf)[position(p)] + +trypeek(p::AbstractParser, ::Type{UInt8}, default = nothing) = + get(p.buf, position(p), default) +trypeek(p::AbstractParser, ::Type{Char}, default = nothing) = + get(String(p.buf), thisind(p), default) # TODO thisind + +function Base.read(p::AbstractParser, ::Type{T}) where {T<:Union{Char,UInt8}} + obj = peek(p, T) + seek(p, nextind(p)) + return obj +end + +rest(p::AbstractParser) = SubString(String(p), thisind(p)) # TODO thisind, ALLOCATES lots. + +buffer(p::AbstractParser) = _buffer(p.buf) +_buffer(s::AbstractString) = codeunits(s) +_buffer(other) = other + +bytes(p::AbstractParser, from, to) = view(buffer(p), from:to) + +or(value, default) = value +or(::Nothing, default) = default + +prev(p::AbstractParser, ::Type{Char}) = String(p.buf)[prevind(p)] +next(p::AbstractParser, ::Type{Char}) = String(p.buf)[nextind(p)] + +prev(p::AbstractParser, ::Type{UInt8}) = p.buf[position(p)-1] +next(p::AbstractParser, ::Type{UInt8}) = p.buf[position(p)+1] + +tryprev(p::AbstractParser, ::Type{Char}, default = nothing) = + get(String(p.buf), prevind(p), default) +trynext(p::AbstractParser, ::Type{Char}, default = nothing) = + get(String(p.buf), nextind(p), default) + +tryprev(p::AbstractParser, ::Type{UInt8}, default = nothing) = + get(p.buf, position(p) - 1, default) +trynext(p::AbstractParser, ::Type{UInt8}, default = nothing) = + get(p.buf, position(p) + 1, default) + +Base.prevind(p::AbstractParser) = prevind(String(p), position(p)) +Base.thisind(p::AbstractParser) = thisind(String(p), position(p)) +Base.nextind(p::AbstractParser) = nextind(String(p), position(p)) + +Base.findnext(f::Function, p::AbstractParser) = findnext(f, String(p), position(p)) +Base.findprev(f::Function, p::AbstractParser) = findprev(f, String(p), position(p)) + +Base.startswith(p::AbstractParser, prefix) = startswith(rest(p), prefix) +Base.occursin(pat::Regex, p::AbstractParser) = occursin(pat, rest(p)) + +Base.match(re::Regex, p::AbstractParser) = match(re, rest(p)) + +function consume(parser::AbstractParser, m::RegexMatch) + parser.pos += (m.offset - 1) + m.match.ncodeunits + return m +end +consume(p::AbstractParser, n::Nothing) = n + +function consume(p::AbstractParser, index::Integer) + seek(p, index) + seek(p, nextind(p)) + return index +end + +dispatch(p::AbstractParser, args...) = dispatch(p.table, args...) + +include("parsers/rules.jl") +include("parsers/inlines.jl") +include("parsers/blocks.jl") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks.jl new file mode 100644 index 0000000..cf3b231 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks.jl @@ -0,0 +1,454 @@ +const CODE_INDENT = 4 + +const reHtmlBlockOpen = [ + r"^<(?:script|pre|textarea|style)(?:\s|>|$)"i, + r"^", r"\?>", r">", r"\]\]>"] +const reThematicBreak = r"^(?:(?:\*[ \t]*){3,}|(?:_[ \t]*){3,}|(?:-[ \t]*){3,})[ \t]*$" +const reNonSpace = r"[^ \t\f\v\r\n]" +const reBulletListMarker = r"^[*+-]" +const reOrderedListMarker = r"^(\d{1,9})([.)])" +const reATXHeadingMarker = r"^#{1,6}(?:[ \t]+|$)" +const reCodeFence = r"^`{3,}(?!.*`)|^~{3,}" +const reClosingCodeFence = r"^(?:`{3,}|~{3,})(?= *$)" +const reSetextHeadingLine = r"^(?:=+|-+)[ \t]*$" +const reLineEnding = r"\r\n|\n|\r" + +mutable struct Parser <: AbstractParser + doc::Node + block_starts::Dict{Char,Vector{Function}} + tip::Node + oldtip::Node + buf::String + line_number::Int + pos::Int + len::Int + column::Int + next_nonspace::Int + next_nonspace_column::Int + indent::Int + indented::Bool + blank::Bool + partially_consumed_tab::Bool + all_closed::Bool + last_matched_container::Node + refmap::Dict{String,Tuple{String,String}} + last_line_length::Int + inline_parser::InlineParser + rules::Vector{Any} + modifiers::Vector{Function} + priorities::IdDict{Function,Float64} + + function Parser() + parser = new() + parser.doc = Node(Document(), ((1, 1), (0, 0))) + parser.block_starts = Dict() + parser.tip = parser.doc + parser.oldtip = parser.doc + parser.buf = "" + parser.line_number = 0 + parser.pos = 1 + parser.len = 0 + parser.column = 0 + parser.next_nonspace = 1 + parser.next_nonspace_column = 0 + parser.indent = 0 + parser.indented = false + parser.blank = false + parser.partially_consumed_tab = false + parser.all_closed = true + parser.last_matched_container = parser.doc + parser.refmap = Dict() + parser.last_line_length = 0 + parser.inline_parser = InlineParser() + parser.rules = [] + parser.modifiers = Function[] + parser.priorities = IdDict{Function,Float64}() + + # Enable the standard CommonMark rule set. + enable!(parser, COMMONMARK_BLOCK_RULES) + enable!(parser, COMMONMARK_INLINE_RULES) + + return parser + end +end + +Base.show(io::IO, parser::Parser) = print(io, "Parser($(parser.doc))") + +is_blank(s::AbstractString) = !occursin(reNonSpace, s) + +is_space_or_tab(s::AbstractString) = s in (" ", "\t") +is_space_or_tab(c::AbstractChar) = c in (' ', '\t') +is_space_or_tab(other) = false + +function ends_with_blank_line(block::Node) + while !isnull(block) + if block.last_line_blank + return true + end + if !block.last_line_checked && (block.t isa List || block.t isa Item) + block.last_line_checked = true + block = block.last_child + else + block.last_line_checked = true + break + end + end + return false +end + +struct Document <: AbstractBlock end + +is_container(::Document) = true +accepts_lines(::Document) = false +continue_(::Document, ::Parser, ::Node) = 0 +finalize(::Document, ::Parser, ::Node) = nothing +can_contain(::Document, t) = !(t isa Item) + +include("blocks/lists.jl") +include("blocks/blockquotes.jl") +include("blocks/headings.jl") +include("blocks/thematic_breaks.jl") +include("blocks/codeblocks.jl") +include("blocks/htmlblocks.jl") +include("blocks/paragraphs.jl") + +# Block start functions. +# +# Return values +# 0 = no match +# 1 = matched container, keep going +# 2 = matched leaf, no more block starts + +const COMMONMARK_BLOCK_RULES = [ + BlockQuoteRule(), + AtxHeadingRule(), + FencedCodeBlockRule(), + HtmlBlockRule(), + SetextHeadingRule(), + ThematicBreakRule(), + ListItemRule(), + IndentedCodeBlockRule(), +] + +function add_line(parser::Parser) + if parser.partially_consumed_tab + # Skip over tab. + parser.pos += 1 + # Add space characters. + chars_to_tab = 4 - (parser.column % 4) + parser.tip.literal *= (' '^chars_to_tab) + end + parser.tip.literal *= (SubString(parser.buf, parser.pos) * '\n') +end + +function add_child(parser::Parser, tag::AbstractContainer, offset::Integer) + while !can_contain(parser.tip.t, tag) + finalize(parser, parser.tip, parser.line_number - 1) + end + column_number = offset + 1 + new_block = Node(tag, ((parser.line_number, column_number), (0, 0))) + append_child(parser.tip, new_block) + parser.tip = new_block + return new_block +end + +function close_unmatched_blocks(parser::Parser) + if !parser.all_closed + while parser.oldtip !== parser.last_matched_container + parent = parser.oldtip.parent + finalize(parser, parser.oldtip, parser.line_number - 1) + parser.oldtip = parent + end + parser.all_closed = true + end + return nothing +end + +function find_next_nonspace(parser::Parser) + buf = parser.buf + i = parser.pos + cols = parser.column + + c = get(buf, i, '\0') + while c !== '\0' + if c === ' ' + i += 1 + cols += 1 + elseif c === '\t' + i += 1 + cols += (4 - (cols % 4)) + else + break + end + c = get(buf, i, '\0') + end + parser.blank = c in ('\n', '\r', '\0') + parser.next_nonspace = i + parser.next_nonspace_column = cols + parser.indent = parser.next_nonspace_column - parser.column + parser.indented = parser.indent ≥ CODE_INDENT +end + +function advance_next_nonspace(parser::Parser) + parser.pos = parser.next_nonspace + parser.column = parser.next_nonspace_column + parser.partially_consumed_tab = false +end + +function advance_offset(parser::Parser, count::Integer, columns::Bool) + buf = parser.buf + c = get(buf, parser.pos, '\0') + while count > 0 && c !== '\0' + if c === '\t' + chars_to_tab = 4 - (parser.column % 4) + if columns + parser.partially_consumed_tab = chars_to_tab > count + chars_to_advance = min(count, chars_to_tab) + parser.column += chars_to_advance + parser.pos += parser.partially_consumed_tab ? 0 : 1 + count -= chars_to_advance + else + parser.partially_consumed_tab = false + parser.column += chars_to_tab + parser.pos += 1 + count -= 1 + end + else + parser.partially_consumed_tab = false + parser.pos = nextind(buf, parser.pos) + # Assume ASCII; block starts are ASCII. + parser.column += 1 + count -= 1 + end + c = get(buf, parser.pos, '\0') + end +end + +function incorporate_line(parser::Parser, ln::AbstractString) + all_matched = true + + container = parser.doc + parser.oldtip = parser.tip + parser.pos = 1 + parser.column = 0 + parser.blank = false + parser.partially_consumed_tab = false + parser.line_number += 1 + + # Replace NUL characters for security. + ln = occursin(r"\u0000", ln) ? replace(ln, '\0' => '\uFFFD') : ln + + parser.buf = ln + parser.len = length(ln) + + # For each containing block, try to parse the associated line start. Bail + # out on failure: container will point to the last matching block. Set + # all_matched to false if not all containers match. + while true + last_child = container.last_child + (!isnull(last_child) && last_child.is_open) || break + + container = last_child + + find_next_nonspace(parser) + + rv = continue_(container.t, parser, container)::Int + if rv == 0 + # Matched, keep going. + elseif rv == 1 + # Failed to match a block. + all_matched = false + elseif rv == 2 + # Hit end of line for fenced code close and can return. + parser.last_line_length = length(ln) + return + else + # Shouldn't reach this location. + error("continue_ returned illegal value, must be 0, 1, or 2") + end + + if !all_matched + # Back up to last matching block. + container = container.parent + break + end + end + + parser.all_closed = (container === parser.oldtip) + parser.last_matched_container = container + + matched_leaf = !(container.t isa Paragraph) && accepts_lines(container.t) + # Unless last matched container is a code block, try new container starts, + # adding children to the last matched container. + while !matched_leaf + + find_next_nonspace(parser) + next_nonspace_char = get(ln, parser.next_nonspace, '\0') + # This is a little performance optimization. Should not affect correctness. + if !parser.indented && !haskey(parser.block_starts, next_nonspace_char) + advance_next_nonspace(parser) + break + end + found = false + if haskey(parser.block_starts, next_nonspace_char) + for λ in parser.block_starts[next_nonspace_char] + res = λ(parser, container) + if res === 1 + found = true + container = parser.tip + break + elseif res === 2 + found = true + container = parser.tip + matched_leaf = true + break + end + end + end + if !found + for λ in parser.block_starts['\0'] + res = λ(parser, container) + if res === 1 + found = true + container = parser.tip + break + elseif res === 2 + found = true + container = parser.tip + matched_leaf = true + break + end + end + end + if !found + # Nothing matched. + advance_next_nonspace(parser) + break + end + end + + # What remains at the offset is a text line. Add the text to the + # appropriate container. + if !parser.all_closed && !parser.blank && parser.tip.t isa Paragraph + # Lazy paragraph continuation. + add_line(parser) + else + # Not a lazy continuation, finalize any blocks not matched. + close_unmatched_blocks(parser) + if parser.blank && !isnull(container.last_child) + container.last_child.last_line_blank = true + end + + t = container.t + + # Block quote lines are never blank as they start with > and we don't + # count blanks in fenced code for purposes of tight/loose lists or + # breaking out of lists. We also don't set last_line_blank on an empty + # list item, or if we just closed a fenced block. + last_line_blank = + parser.blank && !( + t isa BlockQuote || + (t isa CodeBlock && container.t.is_fenced) || + ( + t isa Item && + isnull(container.first_child) && + container.sourcepos[1][1] == parser.line_number + ) + ) + + # Propagate `last_line_blank` up through parents. + cont = container + while !isnull(cont) + cont.last_line_blank = last_line_blank + cont = cont.parent + end + + if accepts_lines(t) + add_line(parser) + # If HtmlBlock, check for end condition. + if t isa HtmlBlock && container.t.html_block_type in 1:5 + str = SubString(parser.buf, parser.pos) + if occursin(reHtmlBlockClose[container.t.html_block_type], str) + parser.last_line_length = length(ln) + finalize(parser, container, parser.line_number) + end + end + elseif parser.pos ≤ length(ln) && !parser.blank + # Create a paragraph container for one line. + container = add_child(parser, Paragraph(), parser.pos) + advance_next_nonspace(parser) + add_line(parser) + end + end + + parser.last_line_length = length(ln) + return nothing +end + +function finalize(parser::Parser, block::Node, line_number::Integer) + above = block.parent + block.is_open = false + block.sourcepos = (block.sourcepos[1], (line_number, parser.last_line_length)) + + finalize(block.t, parser, block) + + parser.tip = above + return nothing +end + +function process_inlines(parser::Parser, block::Node) + parser.inline_parser.refmap = parser.refmap + for (node, entering) in block + if entering + for fn in parser.modifiers + fn(parser, node) + end + else + if contains_inlines(node.t) + parse(parser.inline_parser, node) + end + end + end +end + +contains_inlines(t) = false +contains_inlines(::Paragraph) = true +contains_inlines(::Heading) = true + +function parse(parser::Parser, my_input::IO; kws...) + parser.doc = Node(Document(), ((1, 1), (0, 0))) + isempty(kws) || (merge!(parser.doc.meta, Dict(string(k) => v for (k, v) in kws))) + parser.tip = parser.doc + parser.refmap = Dict{String,Tuple{String,String}}() + parser.line_number = get(parser.doc.meta, "line", 1) - 1 + parser.last_line_length = 0 + parser.pos = 1 + parser.column = 0 + parser.last_matched_container = parser.doc + parser.buf = "" + parser.len = 0 + line_count = 0 + for line in eachline(my_input) + incorporate_line(parser, line)::Nothing + line_count += 1 + end + while !isnull(parser.tip) + finalize(parser, parser.tip, line_count) + end + process_inlines(parser, parser.doc) + return parser.doc +end + +(p::Parser)(text::AbstractString; kws...) = p(IOBuffer(text); kws...) +(p::Parser)(io::IO; kws...) = parse(p, io; kws...) + +Base.open(p::Parser, file::AbstractString; kws...) = + open(io -> p(io; :source => file, kws...), file) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/blockquotes.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/blockquotes.jl new file mode 100644 index 0000000..91326a0 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/blockquotes.jl @@ -0,0 +1,41 @@ +struct BlockQuote <: AbstractBlock end + +is_container(::BlockQuote) = true + +accepts_lines(::BlockQuote) = false + +function continue_(::BlockQuote, parser::Parser, container::Node) + ln = parser.buf + if !parser.indented && get(ln, parser.next_nonspace, nothing) == '>' + advance_next_nonspace(parser) + advance_offset(parser, 1, false) + if is_space_or_tab(get(ln, parser.pos, nothing)) + advance_offset(parser, 1, true) + end + else + return 1 + end + return 0 +end + +finalize(::BlockQuote, ::Parser, ::Node) = nothing + +can_contain(::BlockQuote, t) = !(t isa Item) + +function block_quote(parser::Parser, container::Node) + if !parser.indented && get(parser.buf, parser.next_nonspace, nothing) == '>' + advance_next_nonspace(parser) + advance_offset(parser, 1, false) + # optional following space + if is_space_or_tab(get(parser.buf, parser.pos, nothing)) + advance_offset(parser, 1, true) + end + close_unmatched_blocks(parser) + add_child(parser, BlockQuote(), parser.next_nonspace) + return 1 + end + return 0 +end + +struct BlockQuoteRule end +block_rule(::BlockQuoteRule) = Rule(block_quote, 1, ">") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/codeblocks.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/codeblocks.jl new file mode 100644 index 0000000..fdc61fe --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/codeblocks.jl @@ -0,0 +1,109 @@ +mutable struct CodeBlock <: AbstractBlock + info::String + is_fenced::Bool + fence_char::Char + fence_length::Int + fence_offset::Int + CodeBlock() = new("", false, '\0', 0, 0) +end + +accepts_lines(::CodeBlock) = true + +function continue_(::CodeBlock, parser::Parser, container::Node) + ln = parser.buf + indent = parser.indent + if container.t.is_fenced + match = + indent <= 3 && + length(ln) >= parser.next_nonspace + 1 && + ln[parser.next_nonspace] == container.t.fence_char && + Base.match(reClosingCodeFence, SubString(ln, parser.next_nonspace)) + t = + indent <= 3 && + length(ln) >= parser.next_nonspace + 1 && + ln[parser.next_nonspace] == container.t.fence_char + m = + t ? Base.match(reClosingCodeFence, SubString(ln, parser.next_nonspace)) : + nothing + if m !== nothing && length(m.match) >= container.t.fence_length + # closing fence - we're at end of line, so we can return + finalize(parser, container, parser.line_number) + return 2 + else + # skip optional spaces of fence offset + i = container.t.fence_offset + while i > 0 && is_space_or_tab(get(ln, parser.pos, nothing)) + advance_offset(parser, 1, true) + i -= 1 + end + end + else + # indented + if indent >= CODE_INDENT + advance_offset(parser, CODE_INDENT, true) + elseif parser.blank + advance_next_nonspace(parser) + else + return 1 + end + end + return 0 +end + +# TODO: make more robust and finalize the 'spec'. +function split_info_line(str) + line = rstrip(lstrip(str, '{'), '}') + return split(line, ' ') +end + +function finalize(::CodeBlock, parser::Parser, block::Node) + if block.t.is_fenced + # first line becomes info string + first_line, rest = split(block.literal, '\n'; limit = 2) + info = unescape_string(strip(first_line)) + block.t.info = info + block.literal = rest + else + # indented + block.literal = replace(block.literal, r"(\n *)+$" => "\n") + end + return nothing +end + +can_contain(t) = false + +function fenced_code_block(parser::Parser, container::Node) + if !parser.indented + m = Base.match(reCodeFence, SubString(parser.buf, parser.next_nonspace)) + if m !== nothing + fence_length = length(m.match) + close_unmatched_blocks(parser) + container = add_child(parser, CodeBlock(), parser.next_nonspace) + container.t.is_fenced = true + container.t.fence_length = fence_length + container.t.fence_char = m.match[1] + container.t.fence_offset = parser.indent + advance_next_nonspace(parser) + advance_offset(parser, fence_length, false) + return 2 + end + end + return 0 +end + +struct FencedCodeBlockRule end +block_rule(::FencedCodeBlockRule) = Rule(fenced_code_block, 3, "`~") + +function indented_code_block(parser::Parser, container::Node) + if parser.indented && !(parser.tip.t isa Paragraph) && !parser.blank + # indented code + advance_offset(parser, CODE_INDENT, true) + close_unmatched_blocks(parser) + add_child(parser, CodeBlock(), parser.pos) + return 2 + end + return 0 +end + +struct IndentedCodeBlockRule end +block_rule(::IndentedCodeBlockRule) = Rule(indented_code_block, 8, "") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/headings.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/headings.jl new file mode 100644 index 0000000..3296c67 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/headings.jl @@ -0,0 +1,73 @@ +mutable struct Heading <: AbstractBlock + level::Int + Heading() = new(0) +end + +is_container(::Heading) = true + +accepts_lines(::Heading) = false + +continue_(::Heading, ::Parser, ::Node) = 1 + +finalize(::Heading, ::Parser, ::Node) = nothing + +can_contain(::Heading, t) = false + +function atx_heading(parser::Parser, container::Node) + if !parser.indented + m = Base.match(reATXHeadingMarker, SubString(parser.buf, parser.next_nonspace)) + if m !== nothing + advance_next_nonspace(parser) + advance_offset(parser, length(m.match), false) + close_unmatched_blocks(parser) + container = add_child(parser, Heading(), parser.next_nonspace) + # number of #s + container.t.level = length(strip(m.match)) + # remove trailing ###s + container.literal = replace( + replace(SubString(parser.buf, parser.pos), r"^[ \t]*#+[ \t]*$" => ""), + r"[ \t]+#+[ \t]*$" => "", + ) + advance_offset(parser, length(parser.buf) - parser.pos + 1, false) + return 2 + end + end + return 0 +end + +struct AtxHeadingRule end +block_rule(::AtxHeadingRule) = Rule(atx_heading, 2, "#") + +function setext_heading(parser::Parser, container::Node) + if !parser.indented && container.t isa Paragraph + m = Base.match(reSetextHeadingLine, SubString(parser.buf, parser.next_nonspace)) + if m !== nothing + close_unmatched_blocks(parser) + # resolve reference link definitiosn + while get(container.literal, 1, nothing) == '[' + pos = + parse_reference(parser.inline_parser, container.literal, parser.refmap) + if pos == 0 + break + end + container.literal = container.literal[pos+1:end] + end + if !isempty(container.literal) + heading = Node(Heading(), container.sourcepos) + heading.t.level = m.match[1] == '=' ? 1 : 2 + heading.literal = container.literal + insert_after(container, heading) + unlink(container) + parser.tip = heading + advance_offset(parser, length(parser.buf) - parser.pos + 1, false) + return 2 + else + return 0 + end + end + end + return 0 +end + +struct SetextHeadingRule end +block_rule(::SetextHeadingRule) = Rule(setext_heading, 5, "-=") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/htmlblocks.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/htmlblocks.jl new file mode 100644 index 0000000..61eb717 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/htmlblocks.jl @@ -0,0 +1,36 @@ +mutable struct HtmlBlock <: AbstractBlock + html_block_type::Int + HtmlBlock() = new(0) +end + +accepts_lines(::HtmlBlock) = true + +function continue_(::HtmlBlock, parser::Parser, container::Node) + (parser.blank && container.t.html_block_type in 6:7) ? 1 : 0 +end + +function finalize(::HtmlBlock, parser::Parser, block::Node) + block.literal = replace(block.literal, r"(\n *)+$" => "") + return nothing +end + +can_contain(::HtmlBlock, t) = false + +function html_block(parser::Parser, container::Node) + if !parser.indented && get(parser.buf, parser.next_nonspace, nothing) == '<' + s = SubString(parser.buf, parser.next_nonspace) + for (block_type, regex) in enumerate(reHtmlBlockOpen) + if occursin(regex, s) && (block_type < 7 || !(container.t isa Paragraph)) + close_unmatched_blocks(parser) + # Don't adjust parser.pos; spaces are part of HTML block. + b = add_child(parser, HtmlBlock(), parser.pos) + b.t.html_block_type = block_type + return 2 + end + end + end + return 0 +end + +struct HtmlBlockRule end +block_rule(::HtmlBlockRule) = Rule(html_block, 4, "<>") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/lists.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/lists.jl new file mode 100644 index 0000000..c34725d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/lists.jl @@ -0,0 +1,169 @@ +mutable struct ListData + type::Symbol + tight::Bool + bullet_char::Char + start::Int + delimiter::String + padding::Int + marker_offset::Int + ListData(indent = 0) = new(:bullet, true, ' ', 1, "", 0, indent) +end + +mutable struct Item <: AbstractBlock + list_data::ListData + Item() = new(ListData()) +end + +mutable struct List <: AbstractBlock + list_data::ListData + List() = new(ListData()) +end + +is_container(::List) = true +is_container(::Item) = true + +function parse_list_marker(parser::Parser, container::Node) + if parser.indent ≥ 4 + return nothing + end + rest = SubString(parser.buf, parser.next_nonspace) + data = ListData(parser.indent) + m = Base.match(reBulletListMarker, rest) + if m !== nothing + data.type = :bullet + data.bullet_char = m.match[1] + else + m2 = Base.match(reOrderedListMarker, rest) + if m2 !== nothing && (!(container.t isa Paragraph) || m2.captures[1] == "1") + m = m2 + data.type = :ordered + data.start = Base.parse(Int, m.captures[1]) + data.delimiter = m.captures[2] + else + return nothing + end + end + + # Make sure we have spaces after. + nextc = get(parser.buf, parser.next_nonspace + length(m.match), '\0') + if nextc ∉ ('\0', '\t', ' ') + return nothing + end + + # If it interrupts paragraph make sure first line isn't blank. + if container.t isa Paragraph && + !occursin(reNonSpace, SubString(parser.buf, parser.next_nonspace + length(m.match))) + return nothing + end + + # We've got a match so advance offset and calculate padding. + advance_next_nonspace(parser) # ... to start of marker. + advance_offset(parser, length(m.match), true) # ... to end of marker. + spaces_start_col = parser.column + spaces_start_offset = parser.pos + while true + advance_offset(parser, 1, true) + nextc = get(parser.buf, parser.pos, '\0') + if parser.column - spaces_start_col < 5 && is_space_or_tab(nextc) + nothing + else + break + end + end + blank_item = get(parser.buf, parser.pos, nothing) === nothing + spaces_after_marker = parser.column - spaces_start_col + if spaces_after_marker ≥ 5 || spaces_after_marker < 1 || blank_item + data.padding = length(m.match) + 1 + parser.column = spaces_start_col + parser.pos = spaces_start_offset + if is_space_or_tab(get(parser.buf, parser.pos, '\0')) + advance_offset(parser, 1, true) + end + else + data.padding = length(m.match) + spaces_after_marker + end + return data +end + +function lists_match(list_data::ListData, item_data::ListData) + return list_data.type == item_data.type && + list_data.delimiter == item_data.delimiter && + list_data.bullet_char == item_data.bullet_char +end + +accepts_lines(::List) = false + +continue_(::List, ::Parser, ::Node) = 0 + +function finalize(::List, parser::Parser, block::Node) + item = block.first_child + while !isnull(item) + # Check for non-final list item ending with blank line. + if ends_with_blank_line(item) && !isnull(item.nxt) + block.t.list_data.tight = false + break + end + # Recurse into children of list item, to see if there are spaces between any. + subitem = item.first_child + while !isnull(subitem) + if ends_with_blank_line(subitem) && (!isnull(item.nxt) || !isnull(subitem.nxt)) + block.t.list_data.tight = false + break + end + subitem = subitem.nxt + end + item = item.nxt + end + return nothing +end + +can_contain(::List, t) = t isa Item + +accepts_lines(::Item) = false + +function continue_(::Item, parser::Parser, container::Node) + if parser.blank + if isnull(container.first_child) + # Blank line after empty list item. + return 1 + else + advance_next_nonspace(parser) + end + elseif parser.indent ≥ + (container.t.list_data.marker_offset + container.t.list_data.padding) + advance_offset( + parser, + container.t.list_data.marker_offset + container.t.list_data.padding, + true, + ) + else + return 1 + end + return 0 +end + +finalize(::Item, ::Parser, ::Node) = nothing + +can_contain(::Item, t) = !(t isa Item) + +function list_item(parser::Parser, container::Node) + if (!parser.indented || container.t isa List) + data = parse_list_marker(parser, container) + if data !== nothing + close_unmatched_blocks(parser) + # Add the list if needed. + if !(parser.tip.t isa List) || !lists_match(container.t.list_data, data) + container = add_child(parser, List(), parser.next_nonspace) + container.t.list_data = data + end + # Add the list item. + container = add_child(parser, Item(), parser.next_nonspace) + container.t.list_data = data + return 1 + end + end + return 0 +end + +struct ListItemRule end +block_rule(::ListItemRule) = Rule(list_item, 7, "1234567890-+*") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/paragraphs.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/paragraphs.jl new file mode 100644 index 0000000..9ad18a3 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/paragraphs.jl @@ -0,0 +1,24 @@ +struct Paragraph <: AbstractBlock end + +is_container(::Paragraph) = true + +accepts_lines(::Paragraph) = true + +continue_(::Paragraph, parser::Parser, ::Node) = parser.blank ? 1 : 0 + +function finalize(::Paragraph, p::Parser, block::Node) + has_reference_defs = false + # Try parsing the beginning as link reference definitions. + while get(block.literal, 1, nothing) === '[' + pos = parse_reference(p.inline_parser, block.literal, p.refmap) + pos == 0 && break + block.literal = block.literal[pos+1:end] + has_reference_defs = true + end + if has_reference_defs && is_blank(block.literal) + unlink(block) + end + return nothing +end + +can_contain(::Paragraph, t) = false diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/thematic_breaks.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/thematic_breaks.jl new file mode 100644 index 0000000..90f185d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/blocks/thematic_breaks.jl @@ -0,0 +1,22 @@ +struct ThematicBreak <: AbstractBlock end + +accepts_lines(::ThematicBreak) = false + +continue_(::ThematicBreak, ::Parser, ::Node) = 1 + +finalize(::ThematicBreak, ::Parser, ::Node) = nothing + +can_contain(::ThematicBreak, t) = false + +function thematic_break(p::Parser, container::Node) + if !p.indented && occursin(reThematicBreak, SubString(p.buf, p.next_nonspace)) + close_unmatched_blocks(p) + add_child(p, ThematicBreak(), p.next_nonspace) + advance_offset(p, length(p.buf) - p.pos + 1, false) + return 2 + end + return 0 +end + +struct ThematicBreakRule end +block_rule(::ThematicBreakRule) = Rule(thematic_break, 6, "*-_") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines.jl new file mode 100644 index 0000000..577832f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines.jl @@ -0,0 +1,132 @@ +const ESCAPED_CHAR = "\\\\$(ESCAPABLE)" +const WHITESPACECHAR = collect(" \t\n\x0b\x0c\x0d") + +const reLinkTitle = Regex( + "^(?:\"($(ESCAPED_CHAR)|[^\"\\x00])*\"|'($(ESCAPED_CHAR)|[^'\\x00])*'|\\(($(ESCAPED_CHAR)|[^()\\x00])*\\))", +) +const reLinkDestinationBraces = r"^(?:<(?:[^<>\n\\\x00]|\\.)*>)" +const reEscapable = Regex("^$(ESCAPABLE)") +const reEntityHere = Regex("^$(ENTITY)", "i") +const reTicks = r"`+" +const reTicksHere = r"^`+" +const reEllipses = r"\.\.\." +const reDash = r"--+" +const reEmailAutolink = + r"^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>" +const reAutolink = r"^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*>"i +const reSpnl = r"^ *(?:\n *)?" +const reWhitespaceChar = r"^^[ \t\n\x0b\x0c\x0d]" +const reWhitespace = r"[ \t\n\x0b\x0c\x0d]+" +const reUnicodeWhitespaceChar = r"^\s" +const reFinalSpace = r" *$" +const reInitialSpace = r"^ *" +const reSpaceAtEndOfLine = r"^ *(?:\n|$)" +const reLinkLabel = r"^\[(?:[^\\\[\]]|\\.){0,1000}\]" + +mutable struct Delimiter + cc::Char + numdelims::Int + origdelims::Int + node::Node + previous::Union{Nothing,Delimiter} + next::Union{Nothing,Delimiter} + can_open::Bool + can_close::Bool +end + +mutable struct Bracket + node::Node + previous::Union{Nothing,Bracket} + previousDelimiter::Union{Nothing,Delimiter} + index::Int + image::Bool + active::Bool + bracket_after::Bool +end + +mutable struct InlineParser <: AbstractParser + # required + buf::String + pos::Int + len::Int + # extra + brackets::Union{Nothing,Bracket} + delimiters::Union{Nothing,Delimiter} + refmap::Dict{String,Any} + inline_parsers::Dict{Char,Vector{Function}} + modifiers::Vector{Function} + + function InlineParser() + parser = new() + parser.buf = "" + parser.pos = 1 + parser.len = length(parser.buf) + parser.brackets = nothing + parser.delimiters = nothing + parser.refmap = Dict() + parser.inline_parsers = Dict() + parser.modifiers = Function[] + return parser + end +end + +include("inlines/code.jl") +include("inlines/escapes.jl") +include("inlines/autolinks.jl") +include("inlines/html.jl") +include("inlines/emphasis.jl") +include("inlines/links.jl") +include("inlines/text.jl") + +const COMMONMARK_INLINE_RULES = [ + AutolinkRule(), + InlineCodeRule(), + AsteriskEmphasisRule(), + UnderscoreEmphasisRule(), + BackslashEscapeRule(), + HtmlInlineRule(), + HtmlEntityRule(), + LinkRule(), + ImageRule(), + TextRule(), + NewlineRule(), +] + +function parse_inline(parser::InlineParser, block::Node) + c = trypeek(parser, Char) + c === nothing && return false + res = false + if haskey(parser.inline_parsers, c) + for λ in parser.inline_parsers[c] + res = λ(parser, block) + res && break + end + else + for λ in parser.inline_parsers['\0'] + res = λ(parser, block) + res && break + end + end + if !res + read(parser, Char) + append_child(block, text(c)) + end + return true +end + +function parse_inlines(parser::InlineParser, block::Node) + parser.buf = strip(block.literal) + block.literal = "" + parser.pos = 1 + parser.len = ncodeunits(parser.buf) + parser.delimiters = nothing + parser.brackets = nothing + while (parse_inline(parser, block)) + nothing + end + for fn in parser.modifiers + fn(parser, block) + end +end + +parse(parser::InlineParser, block::Node) = parse_inlines(parser, block) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/autolinks.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/autolinks.jl new file mode 100644 index 0000000..56998ea --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/autolinks.jl @@ -0,0 +1,27 @@ +function parse_autolink(parser::InlineParser, block::Node) + m = consume(parser, match(reEmailAutolink, parser)) + if m !== nothing + dest = chop(m.match; head = 1, tail = 1) + node = Node(Link()) + node.t.destination = normalize_uri("mailto:$(dest)") + node.t.title = "" + append_child(node, text(dest)) + append_child(block, node) + return true + else + m = consume(parser, match(reAutolink, parser)) + if m !== nothing + dest = chop(m.match; head = 1, tail = 1) + node = Node(Link()) + node.t.destination = normalize_uri(dest) + node.t.title = "" + append_child(node, text(dest)) + append_child(block, node) + return true + end + end + return false +end + +struct AutolinkRule end +inline_rule(::AutolinkRule) = Rule(parse_autolink, 1, "<") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/code.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/code.jl new file mode 100644 index 0000000..e803ae5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/code.jl @@ -0,0 +1,42 @@ +struct Code <: AbstractInline end + +function parse_backticks(parser::InlineParser, block::Node) + # Any length sequence of backticks is a valid code opener. + ticks = consume(parser, match(reTicksHere, parser)) + ticks === nothing && return false + after_opener, count = position(parser), length(ticks.match) + while true + # Scan through the string for a matching backtick sequence. + matched = consume(parser, match(reTicks, parser)) + matched === nothing && break + if length(matched.match) === count + before_closer = position(parser) - count - 1 + raw = String(bytes(parser, after_opener, before_closer)) + node = Node(Code()) + node.literal = normalize_inline_code(raw) + append_child(block, node) + return true + end + end + # If we got here, we didn't match a closing backtick sequence. + seek(parser, after_opener) + append_child(block, text(ticks.match)) + return true +end + +# Conforming inline code normalization: +# +# - replace all newline characters with spaces +# - when the string is not just space characters strip exactly +# one leading and trailing space characters. +function normalize_inline_code(str::AbstractString) + str = replace(str, '\n' => ' ') + all_space = all(c -> c === ' ', str) + if !all_space && occursin(r"^ .+ $", str) + str = chop(str; head = 1, tail = 1) + end + return str +end + +struct InlineCodeRule end +inline_rule(::InlineCodeRule) = Rule(parse_backticks, 1, "`") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/emphasis.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/emphasis.jl new file mode 100644 index 0000000..af01008 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/emphasis.jl @@ -0,0 +1,224 @@ +struct Emph <: AbstractInline end + +is_container(::Emph) = true + +struct Strong <: AbstractInline end + +is_container(::Strong) = true + +parse_asterisk(parser, block) = handle_delim(parser, '*', block) +parse_underscore(parser, block) = handle_delim(parser, '_', block) + +function scan_delims(parser::InlineParser, c::AbstractChar) + numdelims = 0 + startpos = position(parser) + + c_before = tryprev(parser, Char, '\n') + + if c in (''', '"') + numdelims += 1 + @assert read(parser, Char) === c + else + while trypeek(parser, Char) === c + numdelims += 1 + @assert read(parser, Char) === c + end + end + numdelims == 0 && return (0, false, false) + + c_after = trypeek(parser, Char, '\n') + + ws_after = Base.Unicode.isspace(c_after) + punct_after = Base.Unicode.ispunct(c_after) + ws_before = Base.Unicode.isspace(c_before) + punct_before = Base.Unicode.ispunct(c_before) + + left_flanking = !ws_after && (!punct_after || ws_before || punct_before) + right_flanking = !ws_before && (!punct_before || ws_after || punct_after) + can_open, can_close = if c == '_' + (left_flanking && (!right_flanking || punct_before)), + (right_flanking && (!left_flanking || punct_after)) + elseif c in (''', '"') + (left_flanking && !right_flanking), right_flanking + else + left_flanking, right_flanking + end + + seek(parser, startpos) + return numdelims, can_open, can_close +end + +function handle_delim(parser::InlineParser, cc::AbstractChar, block::Node) + numdelims, can_open, can_close = scan_delims(parser, cc) + numdelims === 0 && return false + + startpos = position(parser) + + seek(parser, position(parser) + numdelims) # `cc` is ASCII. + contents = cc == ''' ? "\u2019" : cc == '"' ? "\u201C" : cc^numdelims + + node = text(contents) + append_child(block, node) + + # Add entry to stack for this opener + parser.delimiters = Delimiter( + cc, + numdelims, + numdelims, + node, + parser.delimiters, + nothing, + can_open, + can_close, + ) + if parser.delimiters.previous !== nothing + parser.delimiters.previous.next = parser.delimiters + end + return true +end + +function remove_delimiter(parser::InlineParser, delim::Delimiter) + if delim.previous !== nothing + delim.previous.next = delim.next + end + if delim.next === nothing + parser.delimiters = delim.previous # Top of stack. + else + delim.next.previous = delim.previous + end + return nothing +end + +function remove_delimiters_between(bottom::Delimiter, top::Delimiter) + if bottom.next !== top + bottom.next = top + top.previous = bottom + end + return nothing +end + +function process_emphasis(parser::InlineParser, stack_bottom) + openers_bottom = Dict{Char,Union{Nothing,Delimiter}}( + '_' => stack_bottom, + '*' => stack_bottom, + ''' => stack_bottom, + '"' => stack_bottom, + ) + odd_match = false + use_delims = 0 + + # Find first closer above `stack_bottom`. + closer = parser.delimiters + while closer !== nothing && closer.previous !== stack_bottom + closer = closer.previous + end + + # Move forward, looking for closers, and handling each. + while closer !== nothing + if !closer.can_close + closer = closer.next + else + # Found emphasis closer. Now look back for first matching opener. + opener = closer.previous + opener_found = false + closercc = closer.cc + while ( + opener !== nothing && + opener !== stack_bottom && + opener !== openers_bottom[closercc] + ) + odd_match = + (closer.can_open || opener.can_close) && + closer.origdelims % 3 != 0 && + (opener.origdelims + closer.origdelims) % 3 == 0 + if opener.cc == closercc && opener.can_open && !odd_match + opener_found = true + break + end + opener = opener.previous + end + old_closer = closer + + if closercc in ('*', '_') + if !opener_found + closer = closer.next + else + # Calculate actual number of delimiters used from closer. + use_delims = (closer.numdelims ≥ 2 && opener.numdelims ≥ 2) ? 2 : 1 + + opener_inl = opener.node + closer_inl = closer.node + + # Remove used delimiters from stack elements and inlines. + opener.numdelims -= use_delims + closer.numdelims -= use_delims + opener_inl.literal = + opener_inl.literal[1:length(opener_inl.literal)-use_delims] + closer_inl.literal = + closer_inl.literal[1:length(closer_inl.literal)-use_delims] + + # Build contents for new Emph or Strong element. + emph = use_delims == 1 ? Node(Emph()) : Node(Strong()) + emph.literal = closercc^use_delims + + tmp = opener_inl.nxt + while !isnull(tmp) && tmp !== closer_inl + nxt = tmp.nxt + unlink(tmp) + append_child(emph, tmp) + tmp = nxt + end + insert_after(opener_inl, emph) + + # Remove elts between opener and closer in delimiters stack. + remove_delimiters_between(opener, closer) + + # If opener has 0 delims, remove it and the inline. + if opener.numdelims == 0 + unlink(opener_inl) + remove_delimiter(parser, opener) + end + + if closer.numdelims == 0 + unlink(closer_inl) + tempstack = closer.next + remove_delimiter(parser, closer) + closer = tempstack + end + end + elseif closercc == ''' + closer.node.literal = "\u2019" + opener_found && (opener.node.literal = "\u2018") + closer = closer.next + elseif closercc == '"' + closer.node.literal = "\u201D" + opener_found && (opener.node.literal = "\u201C") + closer = closer.next + end + + if !opener_found && !odd_match + # Set lower bound for future searches for openers We don't do + # this with odd_match because a ** that doesn't match an + # earlier * might turn into an opener, and the * might be + # matched by something else. + openers_bottom[closercc] = old_closer.previous + # We can remove a closer that can't be an opener, once we've + # seen there's no matching opener. + old_closer.can_open || remove_delimiter(parser, old_closer) + end + end + end + # Remove all delimiters + while parser.delimiters !== nothing && parser.delimiters !== stack_bottom + remove_delimiter(parser, parser.delimiters) + end +end +process_emphasis(parser::InlineParser, ::Node) = process_emphasis(parser, nothing) + +struct AsteriskEmphasisRule end +inline_rule(::AsteriskEmphasisRule) = Rule(parse_asterisk, 1, "*") +inline_modifier(::AsteriskEmphasisRule) = Rule(process_emphasis, 1) + +struct UnderscoreEmphasisRule end +inline_rule(::UnderscoreEmphasisRule) = Rule(parse_underscore, 1, "_") +inline_modifier(::UnderscoreEmphasisRule) = Rule(process_emphasis, 1) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/escapes.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/escapes.jl new file mode 100644 index 0000000..2a2a5dd --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/escapes.jl @@ -0,0 +1,22 @@ +function parse_backslash(parser::InlineParser, block::Node) + @assert read(parser, Char) === '\\' + char = trypeek(parser, Char) + if char === '\n' + read(parser, Char) + node = Node(LineBreak()) + append_child(block, Node(Backslash())) + append_child(block, node) + elseif char in ESCAPABLE + read(parser, Char) + append_child(block, Node(Backslash())) + append_child(block, text(char)) + else + append_child(block, text('\\')) + end + return true +end + +struct Backslash <: AbstractInline end + +struct BackslashEscapeRule end +inline_rule(::BackslashEscapeRule) = Rule(parse_backslash, 1, "\\") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/html.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/html.jl new file mode 100644 index 0000000..46758ab --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/html.jl @@ -0,0 +1,23 @@ +struct HtmlInline <: AbstractInline end + +function parse_html_tag(parser::InlineParser, block::Node) + m = consume(parser, match(reHtmlTag, parser)) + m === nothing && return false + node = Node(HtmlInline()) + node.literal = m.match + append_child(block, node) + return true +end + +function parse_entity(parser::InlineParser, block::Node) + m = consume(parser, match(reEntityHere, parser)) + m === nothing && return false + append_child(block, text(HTMLunescape(m.match))) + return true +end + +struct HtmlInlineRule end +inline_rule(::HtmlInlineRule) = Rule(parse_html_tag, 2, "<") + +struct HtmlEntityRule end +inline_rule(::HtmlEntityRule) = Rule(parse_entity, 1, "&") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/links.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/links.jl new file mode 100644 index 0000000..b25d8bb --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/links.jl @@ -0,0 +1,276 @@ +mutable struct Link <: AbstractInline + destination::String + title::String + Link() = new("", "") +end + +is_container(::Link) = true + +mutable struct Image <: AbstractInline + destination::String + title::String + Image() = new("", "") +end + +is_container(::Image) = true + +chomp_ws(parser::InlineParser) = (consume(parser, match(reSpnl, parser)); true) + +function parse_link_title(parser::InlineParser) + title = consume(parser, match(reLinkTitle, parser)) + title === nothing && return nothing + # Chop off quotes from title and unescape. + return unescape_string(chop(title.match; head = 1, tail = 1)) +end + +function parse_link_destination(parser::InlineParser) + res = consume(parser, match(reLinkDestinationBraces, parser)) + if res === nothing + trypeek(parser, Char) === '<' && return nothing + savepos = position(parser) + openparens = 0 + c = trypeek(parser, Char) + while true + c = trypeek(parser, Char) + if c === nothing + break + end + if c == '\\' && trynext(parser, Char) in ESCAPABLE + @assert read(parser, Char) === '\\' + if trypeek(parser, Char) !== nothing + read(parser, Char) + end + elseif c == '(' + @assert read(parser, Char) === '(' + openparens += 1 + elseif c == ')' + if openparens < 1 + break + else + @assert read(parser, Char) === ')' + openparens -= 1 + end + elseif c in WHITESPACECHAR + break + else + read(parser, Char) + end + end + if position(parser) === savepos && c !== ')' + return nothing + end + res = String(bytes(parser, savepos, position(parser) - 1)) + return normalize_uri(unescape_string(res)) + else + # Chop off surrounding <..>. + return normalize_uri(unescape_string(chop(res.match; head = 1, tail = 1))) + end +end + +function parse_link_label(parser::InlineParser) + m = consume(parser, match(reLinkLabel, parser)) + return (m === nothing || length(m.match) ≥ 1000) ? 0 : ncodeunits(m.match) +end + +function parse_open_bracket(parser::InlineParser, block::Node) + startpos = position(parser) + @assert read(parser, Char) === '[' + node = text("[") + append_child(block, node) + # Add entry to stack for this opener. + add_bracket!(parser, node, startpos, false) + return true +end + +function parse_bang(parser::InlineParser, block::Node) + startpos = position(parser) + @assert read(parser, Char) === '!' + if trypeek(parser, Char) === '[' + @assert read(parser, Char) === '[' + node = text("![") + append_child(block, node) + # Add entry to stack for this openeer. + add_bracket!(parser, node, startpos + 1, true) + else + append_child(block, text("!")) + end + return true +end + +function parse_close_bracket(parser::InlineParser, block::Node) + title = nothing + matched = false + @assert read(parser, Char) === ']' + startpos = position(parser) + # Get last [ or ![. + opener = parser.brackets + if opener === nothing + # No matched opener, just return a literal. + append_child(block, text("]")) + return true + end + if !opener.active + # No matched opener, just return a literal. + append_child(block, text("]")) + # Take opener off brackets stack. + remove_bracket!(parser) + return true + end + # If we got here, opener is a potential opener. + is_image = opener.image + # Check to see if we have a link/image. + savepos = position(parser) + # Inline link? + if trypeek(parser, Char, '\0') === '(' + @assert read(parser, Char) === '(' + chomp_ws(parser) + dest = parse_link_destination(parser) + if dest !== nothing && chomp_ws(parser) + # Make sure there's a space before the title. + if prev(parser, Char) in WHITESPACECHAR + title = parse_link_title(parser) + end + if chomp_ws(parser) && trypeek(parser, Char, '\0') === ')' + @assert read(parser, Char) === ')' + matched = true + end + else + seek(parser, savepos) + end + end + if !matched + # Next, see if there's a link label. + beforelabel = position(parser) + n = parse_link_label(parser) + reflabel = "" + if n > 2 + reflabel = String(bytes(parser, beforelabel, beforelabel + n - 1)) + elseif !opener.bracket_after + # Empty or missing second label means to use the first label as the + # reference. The reference must not contain a bracket. If we know + # there's a bracket, we don't even bother checking it. + reflabel = String(bytes(parser, opener.index, startpos - 1)) + end + if n == 0 + # If shortcut reference link, rewind before spaces we skipped. + seek(parser, savepos) + end + if !isempty(reflabel) + # Lookup rawlabel in refmap. + link = get(parser.refmap, normalize_reference(reflabel), nothing) + if link !== nothing + dest, title = link + matched = true + end + end + end + if matched + node = Node(is_image ? Image() : Link()) + node.t.destination = dest + node.t.title = title === nothing ? "" : title + tmp = opener.node.nxt + while !isnull(tmp) + nxt = tmp.nxt + unlink(tmp) + append_child(node, tmp) + tmp = nxt + end + append_child(block, node) + process_emphasis(parser, opener.previousDelimiter) + remove_bracket!(parser) + unlink(opener.node) + # We remove this bracket and process_emphasis will remove later + # delimiters. Now, for a link, we also deactivate earlier link openers. + # (no links in links). + if !is_image + opener = parser.brackets + while opener !== nothing + if !opener.image + # Deactivate this opener. + opener.active = false + end + opener = opener.previous + end + end + return true + else + # No match remove this opener from stack. + remove_bracket!(parser) + seek(parser, startpos) + append_child(block, text("]")) + return true + end +end + +function add_bracket!(p::InlineParser, node::Node, index::Integer, img::Bool) + if p.brackets !== nothing + p.brackets.bracket_after = true + end + p.brackets = Bracket(node, p.brackets, p.delimiters, index, img, true, false) +end + +remove_bracket!(p::InlineParser) = p.brackets = p.brackets.previous + +function parse_reference(parser::InlineParser, s::AbstractString, refmap::Dict) + parser.buf = s + seek(parser, 1) + startpos = position(parser) + + # Label. + match_chars = parse_link_label(parser) + match_chars in (0, 2) && return 0 + rawlabel = String(bytes(parser, 1, match_chars)) + + # Colon. + trypeek(parser, Char) === ':' || (seek(parser, startpos); return 0) + @assert read(parser, Char) === ':' + + # Link URL. + chomp_ws(parser) + dest = parse_link_destination(parser) + dest === nothing && (seek(parser, startpos); return 0) + + beforetitle = position(parser) + chomp_ws(parser) + title = nothing + if position(parser) !== beforetitle + title = parse_link_title(parser) + end + if title === nothing + title = "" + # Rewind before spaces. + seek(parser, beforetitle) + end + + # Make sure we're at line end. + at_line_end = true + if consume(parser, match(reSpaceAtEndOfLine, parser)) === nothing + if title == "" + at_line_end = false + else + # The potential title we found is not at the line end, but it could + # still be a legal link reference if we discard the title. + title == "" + # Rewind to before spaces. + seek(parser, beforetitle) + # Or instead check if the link URL is at the line end. + at_line_end = consume(parser, match(reSpaceAtEndOfLine, parser)) !== nothing + end + end + + at_line_end || (seek(parser, startpos); return 0) + + normlabel = normalize_reference(rawlabel) + normlabel == "[]" && (seek(parser, startpos); return 0) + + haskey(refmap, normlabel) || (refmap[normlabel] = (dest, title)) + parser.refmap = refmap + return position(parser) - startpos +end + +struct LinkRule end +inline_rule(::LinkRule) = + (Rule(parse_open_bracket, 1, "["), Rule(parse_close_bracket, 1, "]")) + +struct ImageRule end +inline_rule(::ImageRule) = (Rule(parse_bang, 1, "!"), inline_rule(LinkRule())...) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/text.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/text.jl new file mode 100644 index 0000000..1868cdc --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/inlines/text.jl @@ -0,0 +1,110 @@ +struct SoftBreak <: AbstractInline end +struct LineBreak <: AbstractInline end + +function parse_string(parser::InlineParser, block::Node) + start = position(parser) + while true + char = trypeek(parser, Char, '\0') + if char === '\0' || haskey(parser.inline_parsers, char) + # Stop scanning once we've hit a trigger character. + break + end + read(parser, Char) + end + start === position(parser) && return false + append_child(block, text(String(bytes(parser, start, position(parser) - 1)))) + return true +end + +struct TextRule end +inline_rule(::TextRule) = Rule(parse_string, 1, "") + +function parse_newline(parser::InlineParser, block::Node) + @assert read(parser, Char) === '\n' + lastc = block.last_child + if !isnull(lastc) && lastc.t isa Text && endswith(lastc.literal, ' ') + child = Node(endswith(lastc.literal, " ") ? LineBreak() : SoftBreak()) + lastc.literal = rstrip(lastc.literal) + append_child(block, child) + else + append_child(block, Node(SoftBreak())) + end + # Gobble leading spaces in next line. + consume(parser, match(reInitialSpace, parser)) + return true +end + +struct NewlineRule end +inline_rule(::NewlineRule) = Rule(parse_newline, 1, "\n") + +struct TypographyRule + double_quotes::Bool + single_quotes::Bool + ellipses::Bool + dashes::Bool + + function TypographyRule(; kwargs...) + return new( + get(kwargs, :double_quotes, true), + get(kwargs, :single_quotes, true), + get(kwargs, :ellipses, true), + get(kwargs, :dashes, true), + ) + end +end + +function inline_rule(tr::TypographyRule) + return ( + tr.double_quotes ? Rule(parse_double_quote, 1, "\"") : nothing, + tr.single_quotes ? Rule(parse_single_quote, 1, "'") : nothing, + tr.ellipses ? Rule(parse_ellipsis, 1, ".") : nothing, + tr.dashes ? Rule(parse_dashes, 1, "-") : nothing, + ) +end + +function inline_modifier(tr::TypographyRule) + return (tr.double_quotes || tr.single_quotes) ? Rule(process_emphasis, 1) : nothing +end + +parse_single_quote(parser, block) = handle_delim(parser, ''', block) +parse_double_quote(parser, block) = handle_delim(parser, '"', block) + +function parse_ellipsis(parser::InlineParser, block::Node) + m = consume(parser, match(r"^\.{3}", parser)) + return m === nothing ? false : (append_child(block, text("\u2026")); true) +end + +function parse_dashes(parser::InlineParser, block::Node) + m = consume(parser, match(r"^-+", parser)) + append_child(block, text(smart_dashes(m.match))) + return true +end + +function smart_dashes(chars::AbstractString) + en_count, em_count, n = 0, 0, length(chars) + if n === 1 + return chars + elseif n % 3 === 0 + # If divisible by 3, use all em dashes. + em_count = n ÷ 3 + elseif n % 2 === 0 + # If divisble by 2, use all en dashes. + en_count = n ÷ 2 + elseif n % 3 === 2 + # If 2 extra dashes, use en-dash for last 2; em-dashes for rest. + en_count, em_count = 1, (n - 2) ÷ 3 + else + # Use en-dashes for last 4 hyphens; em-dashes for rest. + en_count, em_count = 2, (n - 4) ÷ 3 + end + return '\u2014'^em_count * '\u2013'^en_count +end + +struct Text <: AbstractInline end + +function text(s::AbstractString) + node = Node(Text()) + node.literal = s + return node +end +text(c::AbstractChar) = text(string(c)) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/parsers/rules.jl b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/rules.jl new file mode 100644 index 0000000..e49d5b1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/parsers/rules.jl @@ -0,0 +1,77 @@ +block_rule(::Any) = nothing +block_modifier(::Any) = nothing +inline_rule(::Any) = nothing +inline_modifier(::Any) = nothing + +struct Rule + fn::Function + priority::Float64 + triggers::String + + Rule(fn, priority, triggers = "") = new(fn, priority, triggers) +end + +# Two parsing rules are generally considered the same (for the purposes of enabling and +# disabling them in the parser) if the types match --- the values on any fields do not +# matter. In case this is not correct for a rule, the two-argument is_same_rule should be +# appropriately overloaded. Some possible cases where this might be necessary: +# (1) A rule with type parameters, where even when the type parameter values are +# different, the rules should still be considered the same. +# (2) A rule which can be included multiple times if some field has a different value. +is_same_rule(x, y) = typeof(x) == typeof(y) +is_same_rule(x) = y -> is_same_rule(x, y) +ruleoccursin(needle, haystack) = any(is_same_rule(needle), haystack) +ruleoccursin(haystack) = needle -> ruleoccursin(needle, haystack) + +function enable!(p::AbstractParser, fn, rule::Rule) + p.priorities[rule.fn] = rule.priority + for trigger in (isempty(rule.triggers) ? "\0" : rule.triggers) + λs = get_funcs(p, fn, trigger) + if rule.fn ∉ λs + push!(λs, rule.fn) + sort!(λs; by = λ -> p.priorities[λ]) + end + end + return p +end +enable!(p::AbstractParser, fn, ::Nothing) = p +enable!(p::AbstractParser, fn, rules::Union{Tuple,Vector}) = + (foreach(r -> enable!(p, fn, r), rules); p) +enable!(p::AbstractParser, fn, rule) = enable!(p, fn, fn(rule)) + +function enable!(p::AbstractParser, rule) + if ruleoccursin(rule, p.rules) + error("$rule is already enabled in the parser") + end + enable!(p, inline_rule, rule) + enable!(p, inline_modifier, rule) + enable!(p, block_rule, rule) + enable!(p, block_modifier, rule) + push!(p.rules, rule) + return p +end + +enable!(p::AbstractParser, rules::Union{Tuple,Vector}) = + (foreach(r -> enable!(p, r), rules); p) + +get_funcs(p, ::typeof(block_rule), c) = get!(() -> Function[], p.block_starts, c) +get_funcs(p, ::typeof(inline_rule), c) = + get!(() -> Function[], p.inline_parser.inline_parsers, c) + +get_funcs(p, ::typeof(block_modifier), _) = p.modifiers +get_funcs(p, ::typeof(inline_modifier), _) = p.inline_parser.modifiers + +function disable!(p::AbstractParser, rules::Union{Tuple,Vector}) + rules_kept = filter(!ruleoccursin(rules), p.rules) + empty!(p.priorities) + empty!(p.block_starts) + empty!(p.modifiers) + empty!(p.inline_parser.inline_parsers) + empty!(p.inline_parser.modifiers) + empty!(p.rules) + return enable!(p, rules_kept) +end +disable!(p::AbstractParser, rule) = disable!(p, [rule]) + +reset_rules!(p::AbstractParser) = (foreach(reset_rule!, p.rules); p) +reset_rule!(rule) = nothing diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/precompile.jl b/.julia-depot/packages/CommonMark/lmLkP/src/precompile.jl new file mode 100644 index 0000000..ffc1510 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/precompile.jl @@ -0,0 +1,29 @@ +using PrecompileTools + +@setup_workload begin + # All non-default rules + extension_rules = [ + AdmonitionRule, + AttributeRule, + AutoIdentifierRule, + CitationRule, + DollarMathRule, + FootnoteRule, + FrontMatterRule, + MathRule, + RawContentRule, + TableRule, + TypographyRule, + ] + writers = [html, latex, term, markdown, notebook] + @compile_workload begin + parser = Parser() + for rule in extension_rules + enable!(parser, rule()) + end + ast = parser("Hello *world*") + for writer in writers + writer(ast) + end + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils.jl b/.julia-depot/packages/CommonMark/lmLkP/src/utils.jl new file mode 100644 index 0000000..051150e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils.jl @@ -0,0 +1,3 @@ +include("utils/common.jl") +include("utils/normalize_reference.jl") +include("utils/entitytrans.jl") diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils/common.jl b/.julia-depot/packages/CommonMark/lmLkP/src/utils/common.jl new file mode 100644 index 0000000..540a9dc --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils/common.jl @@ -0,0 +1,47 @@ +# TODO: entity regex #[0-9]{1,8} not technically correct, should be #[0-9]{1,7} +# but this seems to be required for passing one of the sample cases from cmark. +const ENTITY = "&(?:#x[a-f0-9]{1,6}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});" +const TAGNAME = "[A-Za-z][A-Za-z0-9-]*" +const ATTRIBUTENAME = "[a-zA-Z_:][a-zA-Z0-9:._-]*" +const UNQUOTEDVALUE = "[^\"'=<>`\\x00-\\x20]+" +const SINGLEQUOTEDVALUE = "'[^']*'" +const DOUBLEQUOTEDVALUE = "\"[^\"]*\"" +const ATTRIBUTEVALUE = "(?:$(UNQUOTEDVALUE)|$(SINGLEQUOTEDVALUE)|$(DOUBLEQUOTEDVALUE))" +const ATTRIBUTEVALUESPEC = "(?:\\s*=\\s*$(ATTRIBUTEVALUE))" +const ATTRIBUTE = "(?:\\s+$(ATTRIBUTENAME)$(ATTRIBUTEVALUESPEC)?)" +const OPENTAG = "<$(TAGNAME)$(ATTRIBUTE)*\\s*/?>" +const CLOSETAG = "]" +const HTMLCOMMENT = "|" +const PROCESSINGINSTRUCTION = "[<][?].*?[?][>]" +const DECLARATION = "]*>" +const CDATA = "" +const HTMLTAG = "(?:$(OPENTAG)|$(CLOSETAG)|$(HTMLCOMMENT)|$(PROCESSINGINSTRUCTION)|$(DECLARATION)|$(CDATA))" +const ESCAPABLE = "[!\"#\$%&\'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]" +const XMLSPECIAL = "[&<>\"]" + +const reHtmlTag = Regex("^$(HTMLTAG)", "i") +const reBackslashOrAmp = r"[\\&]" +const reEntityOrEscapedChar = Regex("\\\\$(ESCAPABLE)|$(ENTITY)", "i") +const reXmlSpecial = Regex(XMLSPECIAL) + +unescape_char(s) = s[1] == '\\' ? s[2] : HTMLunescape(s) + +unescape_string(s) = + occursin(reBackslashOrAmp, s) ? replace(s, reEntityOrEscapedChar => unescape_char) : s + +@inline issafe(c::Char) = + c in "?:/,-+@._()#=*&%" || (isascii(c) && (isletter(c) || isnumeric(c))) +normalize_uri(s::AbstractString) = _escapeuri(s, issafe) + +# Copied over from URIs.jl. +_escapeuri(c::Char) = string('%', uppercase(string(Int(c), base = 16, pad = 2))) +_escapeuri(str::AbstractString, safe::Function = issafe) = + join(safe(Char(c)) ? Char(c) : _escapeuri(Char(c)) for c in codeunits(str)) + +const UNSAFE_MAP = Dict("&" => "&", "<" => "<", ">" => ">", "\"" => """) +replace_unsafe_char(s::AbstractString) = get(UNSAFE_MAP, s, s) + +escape_xml(::Nothing) = "" +escape_xml(c::AbstractChar) = escape_xml(string(c)) +escape_xml(s::AbstractString) = + occursin(reXmlSpecial, s) ? replace(s, reXmlSpecial => replace_unsafe_char) : s diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.jl b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.jl new file mode 100644 index 0000000..3e78eb1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.jl @@ -0,0 +1,2233 @@ +const ENTITY_DATA = Dict( + "Æ" => "Æ", + "Æ" => "Æ", + "&" => "&", + "&" => "&", + "Á" => "Á", + "Á" => "Á", + "Ă" => "Ă", + "Â" => "Â", + "Â" => "Â", + "А" => "А", + "𝔄" => "𝔄", + "À" => "À", + "À" => "À", + "Α" => "Α", + "Ā" => "Ā", + "⩓" => "⩓", + "Ą" => "Ą", + "𝔸" => "𝔸", + "⁡" => "\u2061", + "Å" => "Å", + "Å" => "Å", + "𝒜" => "𝒜", + "≔" => "≔", + "Ã" => "Ã", + "Ã" => "Ã", + "Ä" => "Ä", + "Ä" => "Ä", + "∖" => "∖", + "⫧" => "⫧", + "⌆" => "⌆", + "Б" => "Б", + "∵" => "∵", + "ℬ" => "ℬ", + "Β" => "Β", + "𝔅" => "𝔅", + "𝔹" => "𝔹", + "˘" => "˘", + "ℬ" => "ℬ", + "≎" => "≎", + "Ч" => "Ч", + "©" => "©", + "©" => "©", + "Ć" => "Ć", + "⋒" => "⋒", + "ⅅ" => "ⅅ", + "ℭ" => "ℭ", + "Č" => "Č", + "Ç" => "Ç", + "Ç" => "Ç", + "Ĉ" => "Ĉ", + "∰" => "∰", + "Ċ" => "Ċ", + "¸" => "¸", + "·" => "·", + "ℭ" => "ℭ", + "Χ" => "Χ", + "⊙" => "⊙", + "⊖" => "⊖", + "⊕" => "⊕", + "⊗" => "⊗", + "∲" => "∲", + "”" => "”", + "’" => "’", + "∷" => "∷", + "⩴" => "⩴", + "≡" => "≡", + "∯" => "∯", + "∮" => "∮", + "ℂ" => "ℂ", + "∐" => "∐", + "∳" => "∳", + "⨯" => "⨯", + "𝒞" => "𝒞", + "⋓" => "⋓", + "≍" => "≍", + "ⅅ" => "ⅅ", + "⤑" => "⤑", + "Ђ" => "Ђ", + "Ѕ" => "Ѕ", + "Џ" => "Џ", + "‡" => "‡", + "↡" => "↡", + "⫤" => "⫤", + "Ď" => "Ď", + "Д" => "Д", + "∇" => "∇", + "Δ" => "Δ", + "𝔇" => "𝔇", + "´" => "´", + "˙" => "˙", + "˝" => "˝", + "`" => "`", + "˜" => "˜", + "⋄" => "⋄", + "ⅆ" => "ⅆ", + "𝔻" => "𝔻", + "¨" => "¨", + "⃜" => "⃜", + "≐" => "≐", + "∯" => "∯", + "¨" => "¨", + "⇓" => "⇓", + "⇐" => "⇐", + "⇔" => "⇔", + "⫤" => "⫤", + "⟸" => "⟸", + "⟺" => "⟺", + "⟹" => "⟹", + "⇒" => "⇒", + "⊨" => "⊨", + "⇑" => "⇑", + "⇕" => "⇕", + "∥" => "∥", + "↓" => "↓", + "⤓" => "⤓", + "⇵" => "⇵", + "̑" => "̑", + "⥐" => "⥐", + "⥞" => "⥞", + "↽" => "↽", + "⥖" => "⥖", + "⥟" => "⥟", + "⇁" => "⇁", + "⥗" => "⥗", + "⊤" => "⊤", + "↧" => "↧", + "⇓" => "⇓", + "𝒟" => "𝒟", + "Đ" => "Đ", + "Ŋ" => "Ŋ", + "Ð" => "Ð", + "Ð" => "Ð", + "É" => "É", + "É" => "É", + "Ě" => "Ě", + "Ê" => "Ê", + "Ê" => "Ê", + "Э" => "Э", + "Ė" => "Ė", + "𝔈" => "𝔈", + "È" => "È", + "È" => "È", + "∈" => "∈", + "Ē" => "Ē", + "◻" => "◻", + "▫" => "▫", + "Ę" => "Ę", + "𝔼" => "𝔼", + "Ε" => "Ε", + "⩵" => "⩵", + "≂" => "≂", + "⇌" => "⇌", + "ℰ" => "ℰ", + "⩳" => "⩳", + "Η" => "Η", + "Ë" => "Ë", + "Ë" => "Ë", + "∃" => "∃", + "ⅇ" => "ⅇ", + "Ф" => "Ф", + "𝔉" => "𝔉", + "◼" => "◼", + "▪" => "▪", + "𝔽" => "𝔽", + "∀" => "∀", + "ℱ" => "ℱ", + "ℱ" => "ℱ", + "Ѓ" => "Ѓ", + ">" => ">", + ">" => ">", + "Γ" => "Γ", + "Ϝ" => "Ϝ", + "Ğ" => "Ğ", + "Ģ" => "Ģ", + "Ĝ" => "Ĝ", + "Г" => "Г", + "Ġ" => "Ġ", + "𝔊" => "𝔊", + "⋙" => "⋙", + "𝔾" => "𝔾", + "≥" => "≥", + "⋛" => "⋛", + "≧" => "≧", + "⪢" => "⪢", + "≷" => "≷", + "⩾" => "⩾", + "≳" => "≳", + "𝒢" => "𝒢", + "≫" => "≫", + "Ъ" => "Ъ", + "ˇ" => "ˇ", + "^" => "^", + "Ĥ" => "Ĥ", + "ℌ" => "ℌ", + "ℋ" => "ℋ", + "ℍ" => "ℍ", + "─" => "─", + "ℋ" => "ℋ", + "Ħ" => "Ħ", + "≎" => "≎", + "≏" => "≏", + "Е" => "Е", + "IJ" => "IJ", + "Ё" => "Ё", + "Í" => "Í", + "Í" => "Í", + "Î" => "Î", + "Î" => "Î", + "И" => "И", + "İ" => "İ", + "ℑ" => "ℑ", + "Ì" => "Ì", + "Ì" => "Ì", + "ℑ" => "ℑ", + "Ī" => "Ī", + "ⅈ" => "ⅈ", + "⇒" => "⇒", + "∬" => "∬", + "∫" => "∫", + "⋂" => "⋂", + "⁣" => "\u2063", + "⁢" => "\u2062", + "Į" => "Į", + "𝕀" => "𝕀", + "Ι" => "Ι", + "ℐ" => "ℐ", + "Ĩ" => "Ĩ", + "І" => "І", + "Ï" => "Ï", + "Ï" => "Ï", + "Ĵ" => "Ĵ", + "Й" => "Й", + "𝔍" => "𝔍", + "𝕁" => "𝕁", + "𝒥" => "𝒥", + "Ј" => "Ј", + "Є" => "Є", + "Х" => "Х", + "Ќ" => "Ќ", + "Κ" => "Κ", + "Ķ" => "Ķ", + "К" => "К", + "𝔎" => "𝔎", + "𝕂" => "𝕂", + "𝒦" => "𝒦", + "Љ" => "Љ", + "<" => "<", + "<" => "<", + "Ĺ" => "Ĺ", + "Λ" => "Λ", + "⟪" => "⟪", + "ℒ" => "ℒ", + "↞" => "↞", + "Ľ" => "Ľ", + "Ļ" => "Ļ", + "Л" => "Л", + "⟨" => "⟨", + "←" => "←", + "⇤" => "⇤", + "⇆" => "⇆", + "⌈" => "⌈", + "⟦" => "⟦", + "⥡" => "⥡", + "⇃" => "⇃", + "⥙" => "⥙", + "⌊" => "⌊", + "↔" => "↔", + "⥎" => "⥎", + "⊣" => "⊣", + "↤" => "↤", + "⥚" => "⥚", + "⊲" => "⊲", + "⧏" => "⧏", + "⊴" => "⊴", + "⥑" => "⥑", + "⥠" => "⥠", + "↿" => "↿", + "⥘" => "⥘", + "↼" => "↼", + "⥒" => "⥒", + "⇐" => "⇐", + "⇔" => "⇔", + "⋚" => "⋚", + "≦" => "≦", + "≶" => "≶", + "⪡" => "⪡", + "⩽" => "⩽", + "≲" => "≲", + "𝔏" => "𝔏", + "⋘" => "⋘", + "⇚" => "⇚", + "Ŀ" => "Ŀ", + "⟵" => "⟵", + "⟷" => "⟷", + "⟶" => "⟶", + "⟸" => "⟸", + "⟺" => "⟺", + "⟹" => "⟹", + "𝕃" => "𝕃", + "↙" => "↙", + "↘" => "↘", + "ℒ" => "ℒ", + "↰" => "↰", + "Ł" => "Ł", + "≪" => "≪", + "⤅" => "⤅", + "М" => "М", + " " => " ", + "ℳ" => "ℳ", + "𝔐" => "𝔐", + "∓" => "∓", + "𝕄" => "𝕄", + "ℳ" => "ℳ", + "Μ" => "Μ", + "Њ" => "Њ", + "Ń" => "Ń", + "Ň" => "Ň", + "Ņ" => "Ņ", + "Н" => "Н", + "​" => "\u200b", + "​" => "\u200b", + "​" => "\u200b", + "​" => "\u200b", + "≫" => "≫", + "≪" => "≪", + " " => "\n", + "𝔑" => "𝔑", + "⁠" => "\u2060", + " " => " ", + "ℕ" => "ℕ", + "⫬" => "⫬", + "≢" => "≢", + "≭" => "≭", + "∦" => "∦", + "∉" => "∉", + "≠" => "≠", + "≂̸" => "≂̸", + "∄" => "∄", + "≯" => "≯", + "≱" => "≱", + "≧̸" => "≧̸", + "≫̸" => "≫̸", + "≹" => "≹", + "⩾̸" => "⩾̸", + "≵" => "≵", + "≎̸" => "≎̸", + "≏̸" => "≏̸", + "⋪" => "⋪", + "⧏̸" => "⧏̸", + "⋬" => "⋬", + "≮" => "≮", + "≰" => "≰", + "≸" => "≸", + "≪̸" => "≪̸", + "⩽̸" => "⩽̸", + "≴" => "≴", + "⪢̸" => "⪢̸", + "⪡̸" => "⪡̸", + "⊀" => "⊀", + "⪯̸" => "⪯̸", + "⋠" => "⋠", + "∌" => "∌", + "⋫" => "⋫", + "⧐̸" => "⧐̸", + "⋭" => "⋭", + "⊏̸" => "⊏̸", + "⋢" => "⋢", + "⊐̸" => "⊐̸", + "⋣" => "⋣", + "⊂⃒" => "⊂⃒", + "⊈" => "⊈", + "⊁" => "⊁", + "⪰̸" => "⪰̸", + "⋡" => "⋡", + "≿̸" => "≿̸", + "⊃⃒" => "⊃⃒", + "⊉" => "⊉", + "≁" => "≁", + "≄" => "≄", + "≇" => "≇", + "≉" => "≉", + "∤" => "∤", + "𝒩" => "𝒩", + "Ñ" => "Ñ", + "Ñ" => "Ñ", + "Ν" => "Ν", + "Œ" => "Œ", + "Ó" => "Ó", + "Ó" => "Ó", + "Ô" => "Ô", + "Ô" => "Ô", + "О" => "О", + "Ő" => "Ő", + "𝔒" => "𝔒", + "Ò" => "Ò", + "Ò" => "Ò", + "Ō" => "Ō", + "Ω" => "Ω", + "Ο" => "Ο", + "𝕆" => "𝕆", + "“" => "“", + "‘" => "‘", + "⩔" => "⩔", + "𝒪" => "𝒪", + "Ø" => "Ø", + "Ø" => "Ø", + "Õ" => "Õ", + "Õ" => "Õ", + "⨷" => "⨷", + "Ö" => "Ö", + "Ö" => "Ö", + "‾" => "‾", + "⏞" => "⏞", + "⎴" => "⎴", + "⏜" => "⏜", + "∂" => "∂", + "П" => "П", + "𝔓" => "𝔓", + "Φ" => "Φ", + "Π" => "Π", + "±" => "±", + "ℌ" => "ℌ", + "ℙ" => "ℙ", + "⪻" => "⪻", + "≺" => "≺", + "⪯" => "⪯", + "≼" => "≼", + "≾" => "≾", + "″" => "″", + "∏" => "∏", + "∷" => "∷", + "∝" => "∝", + "𝒫" => "𝒫", + "Ψ" => "Ψ", + """ => "\"", + """ => "\"", + "𝔔" => "𝔔", + "ℚ" => "ℚ", + "𝒬" => "𝒬", + "⤐" => "⤐", + "®" => "®", + "®" => "®", + "Ŕ" => "Ŕ", + "⟫" => "⟫", + "↠" => "↠", + "⤖" => "⤖", + "Ř" => "Ř", + "Ŗ" => "Ŗ", + "Р" => "Р", + "ℜ" => "ℜ", + "∋" => "∋", + "⇋" => "⇋", + "⥯" => "⥯", + "ℜ" => "ℜ", + "Ρ" => "Ρ", + "⟩" => "⟩", + "→" => "→", + "⇥" => "⇥", + "⇄" => "⇄", + "⌉" => "⌉", + "⟧" => "⟧", + "⥝" => "⥝", + "⇂" => "⇂", + "⥕" => "⥕", + "⌋" => "⌋", + "⊢" => "⊢", + "↦" => "↦", + "⥛" => "⥛", + "⊳" => "⊳", + "⧐" => "⧐", + "⊵" => "⊵", + "⥏" => "⥏", + "⥜" => "⥜", + "↾" => "↾", + "⥔" => "⥔", + "⇀" => "⇀", + "⥓" => "⥓", + "⇒" => "⇒", + "ℝ" => "ℝ", + "⥰" => "⥰", + "⇛" => "⇛", + "ℛ" => "ℛ", + "↱" => "↱", + "⧴" => "⧴", + "Щ" => "Щ", + "Ш" => "Ш", + "Ь" => "Ь", + "Ś" => "Ś", + "⪼" => "⪼", + "Š" => "Š", + "Ş" => "Ş", + "Ŝ" => "Ŝ", + "С" => "С", + "𝔖" => "𝔖", + "↓" => "↓", + "←" => "←", + "→" => "→", + "↑" => "↑", + "Σ" => "Σ", + "∘" => "∘", + "𝕊" => "𝕊", + "√" => "√", + "□" => "□", + "⊓" => "⊓", + "⊏" => "⊏", + "⊑" => "⊑", + "⊐" => "⊐", + "⊒" => "⊒", + "⊔" => "⊔", + "𝒮" => "𝒮", + "⋆" => "⋆", + "⋐" => "⋐", + "⋐" => "⋐", + "⊆" => "⊆", + "≻" => "≻", + "⪰" => "⪰", + "≽" => "≽", + "≿" => "≿", + "∋" => "∋", + "∑" => "∑", + "⋑" => "⋑", + "⊃" => "⊃", + "⊇" => "⊇", + "⋑" => "⋑", + "Þ" => "Þ", + "Þ" => "Þ", + "™" => "™", + "Ћ" => "Ћ", + "Ц" => "Ц", + " " => "\t", + "Τ" => "Τ", + "Ť" => "Ť", + "Ţ" => "Ţ", + "Т" => "Т", + "𝔗" => "𝔗", + "∴" => "∴", + "Θ" => "Θ", + "  " => "  ", + " " => " ", + "∼" => "∼", + "≃" => "≃", + "≅" => "≅", + "≈" => "≈", + "𝕋" => "𝕋", + "⃛" => "⃛", + "𝒯" => "𝒯", + "Ŧ" => "Ŧ", + "Ú" => "Ú", + "Ú" => "Ú", + "↟" => "↟", + "⥉" => "⥉", + "Ў" => "Ў", + "Ŭ" => "Ŭ", + "Û" => "Û", + "Û" => "Û", + "У" => "У", + "Ű" => "Ű", + "𝔘" => "𝔘", + "Ù" => "Ù", + "Ù" => "Ù", + "Ū" => "Ū", + "_" => "_", + "⏟" => "⏟", + "⎵" => "⎵", + "⏝" => "⏝", + "⋃" => "⋃", + "⊎" => "⊎", + "Ų" => "Ų", + "𝕌" => "𝕌", + "↑" => "↑", + "⤒" => "⤒", + "⇅" => "⇅", + "↕" => "↕", + "⥮" => "⥮", + "⊥" => "⊥", + "↥" => "↥", + "⇑" => "⇑", + "⇕" => "⇕", + "↖" => "↖", + "↗" => "↗", + "ϒ" => "ϒ", + "Υ" => "Υ", + "Ů" => "Ů", + "𝒰" => "𝒰", + "Ũ" => "Ũ", + "Ü" => "Ü", + "Ü" => "Ü", + "⊫" => "⊫", + "⫫" => "⫫", + "В" => "В", + "⊩" => "⊩", + "⫦" => "⫦", + "⋁" => "⋁", + "‖" => "‖", + "‖" => "‖", + "∣" => "∣", + "|" => "|", + "❘" => "❘", + "≀" => "≀", + " " => " ", + "𝔙" => "𝔙", + "𝕍" => "𝕍", + "𝒱" => "𝒱", + "⊪" => "⊪", + "Ŵ" => "Ŵ", + "⋀" => "⋀", + "𝔚" => "𝔚", + "𝕎" => "𝕎", + "𝒲" => "𝒲", + "𝔛" => "𝔛", + "Ξ" => "Ξ", + "𝕏" => "𝕏", + "𝒳" => "𝒳", + "Я" => "Я", + "Ї" => "Ї", + "Ю" => "Ю", + "Ý" => "Ý", + "Ý" => "Ý", + "Ŷ" => "Ŷ", + "Ы" => "Ы", + "𝔜" => "𝔜", + "𝕐" => "𝕐", + "𝒴" => "𝒴", + "Ÿ" => "Ÿ", + "Ж" => "Ж", + "Ź" => "Ź", + "Ž" => "Ž", + "З" => "З", + "Ż" => "Ż", + "​" => "\u200b", + "Ζ" => "Ζ", + "ℨ" => "ℨ", + "ℤ" => "ℤ", + "𝒵" => "𝒵", + "á" => "á", + "á" => "á", + "ă" => "ă", + "∾" => "∾", + "∾̳" => "∾̳", + "∿" => "∿", + "â" => "â", + "â" => "â", + "´" => "´", + "´" => "´", + "а" => "а", + "æ" => "æ", + "æ" => "æ", + "⁡" => "\u2061", + "𝔞" => "𝔞", + "à" => "à", + "à" => "à", + "ℵ" => "ℵ", + "ℵ" => "ℵ", + "α" => "α", + "ā" => "ā", + "⨿" => "⨿", + "&" => "&", + "&" => "&", + "∧" => "∧", + "⩕" => "⩕", + "⩜" => "⩜", + "⩘" => "⩘", + "⩚" => "⩚", + "∠" => "∠", + "⦤" => "⦤", + "∠" => "∠", + "∡" => "∡", + "⦨" => "⦨", + "⦩" => "⦩", + "⦪" => "⦪", + "⦫" => "⦫", + "⦬" => "⦬", + "⦭" => "⦭", + "⦮" => "⦮", + "⦯" => "⦯", + "∟" => "∟", + "⊾" => "⊾", + "⦝" => "⦝", + "∢" => "∢", + "Å" => "Å", + "⍼" => "⍼", + "ą" => "ą", + "𝕒" => "𝕒", + "≈" => "≈", + "⩰" => "⩰", + "⩯" => "⩯", + "≊" => "≊", + "≋" => "≋", + "'" => "'", + "≈" => "≈", + "≊" => "≊", + "å" => "å", + "å" => "å", + "𝒶" => "𝒶", + "*" => "*", + "≈" => "≈", + "≍" => "≍", + "ã" => "ã", + "ã" => "ã", + "ä" => "ä", + "ä" => "ä", + "∳" => "∳", + "⨑" => "⨑", + "⫭" => "⫭", + "≌" => "≌", + "϶" => "϶", + "‵" => "‵", + "∽" => "∽", + "⋍" => "⋍", + "⊽" => "⊽", + "⌅" => "⌅", + "⌅" => "⌅", + "⎵" => "⎵", + "⎶" => "⎶", + "≌" => "≌", + "б" => "б", + "„" => "„", + "∵" => "∵", + "∵" => "∵", + "⦰" => "⦰", + "϶" => "϶", + "ℬ" => "ℬ", + "β" => "β", + "ℶ" => "ℶ", + "≬" => "≬", + "𝔟" => "𝔟", + "⋂" => "⋂", + "◯" => "◯", + "⋃" => "⋃", + "⨀" => "⨀", + "⨁" => "⨁", + "⨂" => "⨂", + "⨆" => "⨆", + "★" => "★", + "▽" => "▽", + "△" => "△", + "⨄" => "⨄", + "⋁" => "⋁", + "⋀" => "⋀", + "⤍" => "⤍", + "⧫" => "⧫", + "▪" => "▪", + "▴" => "▴", + "▾" => "▾", + "◂" => "◂", + "▸" => "▸", + "␣" => "␣", + "▒" => "▒", + "░" => "░", + "▓" => "▓", + "█" => "█", + "=⃥" => "=⃥", + "≡⃥" => "≡⃥", + "⌐" => "⌐", + "𝕓" => "𝕓", + "⊥" => "⊥", + "⊥" => "⊥", + "⋈" => "⋈", + "╗" => "╗", + "╔" => "╔", + "╖" => "╖", + "╓" => "╓", + "═" => "═", + "╦" => "╦", + "╩" => "╩", + "╤" => "╤", + "╧" => "╧", + "╝" => "╝", + "╚" => "╚", + "╜" => "╜", + "╙" => "╙", + "║" => "║", + "╬" => "╬", + "╣" => "╣", + "╠" => "╠", + "╫" => "╫", + "╢" => "╢", + "╟" => "╟", + "⧉" => "⧉", + "╕" => "╕", + "╒" => "╒", + "┐" => "┐", + "┌" => "┌", + "─" => "─", + "╥" => "╥", + "╨" => "╨", + "┬" => "┬", + "┴" => "┴", + "⊟" => "⊟", + "⊞" => "⊞", + "⊠" => "⊠", + "╛" => "╛", + "╘" => "╘", + "┘" => "┘", + "└" => "└", + "│" => "│", + "╪" => "╪", + "╡" => "╡", + "╞" => "╞", + "┼" => "┼", + "┤" => "┤", + "├" => "├", + "‵" => "‵", + "˘" => "˘", + "¦" => "¦", + "¦" => "¦", + "𝒷" => "𝒷", + "⁏" => "⁏", + "∽" => "∽", + "⋍" => "⋍", + "\" => "\\", + "⧅" => "⧅", + "⟈" => "⟈", + "•" => "•", + "•" => "•", + "≎" => "≎", + "⪮" => "⪮", + "≏" => "≏", + "≏" => "≏", + "ć" => "ć", + "∩" => "∩", + "⩄" => "⩄", + "⩉" => "⩉", + "⩋" => "⩋", + "⩇" => "⩇", + "⩀" => "⩀", + "∩︀" => "∩︀", + "⁁" => "⁁", + "ˇ" => "ˇ", + "⩍" => "⩍", + "č" => "č", + "ç" => "ç", + "ç" => "ç", + "ĉ" => "ĉ", + "⩌" => "⩌", + "⩐" => "⩐", + "ċ" => "ċ", + "¸" => "¸", + "¸" => "¸", + "⦲" => "⦲", + "¢" => "¢", + "¢" => "¢", + "·" => "·", + "𝔠" => "𝔠", + "ч" => "ч", + "✓" => "✓", + "✓" => "✓", + "χ" => "χ", + "○" => "○", + "⧃" => "⧃", + "ˆ" => "ˆ", + "≗" => "≗", + "↺" => "↺", + "↻" => "↻", + "®" => "®", + "Ⓢ" => "Ⓢ", + "⊛" => "⊛", + "⊚" => "⊚", + "⊝" => "⊝", + "≗" => "≗", + "⨐" => "⨐", + "⫯" => "⫯", + "⧂" => "⧂", + "♣" => "♣", + "♣" => "♣", + ":" => ":", + "≔" => "≔", + "≔" => "≔", + "," => ",", + "@" => "@", + "∁" => "∁", + "∘" => "∘", + "∁" => "∁", + "ℂ" => "ℂ", + "≅" => "≅", + "⩭" => "⩭", + "∮" => "∮", + "𝕔" => "𝕔", + "∐" => "∐", + "©" => "©", + "©" => "©", + "℗" => "℗", + "↵" => "↵", + "✗" => "✗", + "𝒸" => "𝒸", + "⫏" => "⫏", + "⫑" => "⫑", + "⫐" => "⫐", + "⫒" => "⫒", + "⋯" => "⋯", + "⤸" => "⤸", + "⤵" => "⤵", + "⋞" => "⋞", + "⋟" => "⋟", + "↶" => "↶", + "⤽" => "⤽", + "∪" => "∪", + "⩈" => "⩈", + "⩆" => "⩆", + "⩊" => "⩊", + "⊍" => "⊍", + "⩅" => "⩅", + "∪︀" => "∪︀", + "↷" => "↷", + "⤼" => "⤼", + "⋞" => "⋞", + "⋟" => "⋟", + "⋎" => "⋎", + "⋏" => "⋏", + "¤" => "¤", + "¤" => "¤", + "↶" => "↶", + "↷" => "↷", + "⋎" => "⋎", + "⋏" => "⋏", + "∲" => "∲", + "∱" => "∱", + "⌭" => "⌭", + "⇓" => "⇓", + "⥥" => "⥥", + "†" => "†", + "ℸ" => "ℸ", + "↓" => "↓", + "‐" => "‐", + "⊣" => "⊣", + "⤏" => "⤏", + "˝" => "˝", + "ď" => "ď", + "д" => "д", + "ⅆ" => "ⅆ", + "‡" => "‡", + "⇊" => "⇊", + "⩷" => "⩷", + "°" => "°", + "°" => "°", + "δ" => "δ", + "⦱" => "⦱", + "⥿" => "⥿", + "𝔡" => "𝔡", + "⇃" => "⇃", + "⇂" => "⇂", + "⋄" => "⋄", + "⋄" => "⋄", + "♦" => "♦", + "♦" => "♦", + "¨" => "¨", + "ϝ" => "ϝ", + "⋲" => "⋲", + "÷" => "÷", + "÷" => "÷", + "÷" => "÷", + "⋇" => "⋇", + "⋇" => "⋇", + "ђ" => "ђ", + "⌞" => "⌞", + "⌍" => "⌍", + "$" => "\$", + "𝕕" => "𝕕", + "˙" => "˙", + "≐" => "≐", + "≑" => "≑", + "∸" => "∸", + "∔" => "∔", + "⊡" => "⊡", + "⌆" => "⌆", + "↓" => "↓", + "⇊" => "⇊", + "⇃" => "⇃", + "⇂" => "⇂", + "⤐" => "⤐", + "⌟" => "⌟", + "⌌" => "⌌", + "𝒹" => "𝒹", + "ѕ" => "ѕ", + "⧶" => "⧶", + "đ" => "đ", + "⋱" => "⋱", + "▿" => "▿", + "▾" => "▾", + "⇵" => "⇵", + "⥯" => "⥯", + "⦦" => "⦦", + "џ" => "џ", + "⟿" => "⟿", + "⩷" => "⩷", + "≑" => "≑", + "é" => "é", + "é" => "é", + "⩮" => "⩮", + "ě" => "ě", + "≖" => "≖", + "ê" => "ê", + "ê" => "ê", + "≕" => "≕", + "э" => "э", + "ė" => "ė", + "ⅇ" => "ⅇ", + "≒" => "≒", + "𝔢" => "𝔢", + "⪚" => "⪚", + "è" => "è", + "è" => "è", + "⪖" => "⪖", + "⪘" => "⪘", + "⪙" => "⪙", + "⏧" => "⏧", + "ℓ" => "ℓ", + "⪕" => "⪕", + "⪗" => "⪗", + "ē" => "ē", + "∅" => "∅", + "∅" => "∅", + "∅" => "∅", + " " => " ", + " " => " ", + " " => " ", + "ŋ" => "ŋ", + " " => " ", + "ę" => "ę", + "𝕖" => "𝕖", + "⋕" => "⋕", + "⧣" => "⧣", + "⩱" => "⩱", + "ε" => "ε", + "ε" => "ε", + "ϵ" => "ϵ", + "≖" => "≖", + "≕" => "≕", + "≂" => "≂", + "⪖" => "⪖", + "⪕" => "⪕", + "=" => "=", + "≟" => "≟", + "≡" => "≡", + "⩸" => "⩸", + "⧥" => "⧥", + "≓" => "≓", + "⥱" => "⥱", + "ℯ" => "ℯ", + "≐" => "≐", + "≂" => "≂", + "η" => "η", + "ð" => "ð", + "ð" => "ð", + "ë" => "ë", + "ë" => "ë", + "€" => "€", + "!" => "!", + "∃" => "∃", + "ℰ" => "ℰ", + "ⅇ" => "ⅇ", + "≒" => "≒", + "ф" => "ф", + "♀" => "♀", + "ffi" => "ffi", + "ff" => "ff", + "ffl" => "ffl", + "𝔣" => "𝔣", + "fi" => "fi", + "fj" => "fj", + "♭" => "♭", + "fl" => "fl", + "▱" => "▱", + "ƒ" => "ƒ", + "𝕗" => "𝕗", + "∀" => "∀", + "⋔" => "⋔", + "⫙" => "⫙", + "⨍" => "⨍", + "½" => "½", + "½" => "½", + "⅓" => "⅓", + "¼" => "¼", + "¼" => "¼", + "⅕" => "⅕", + "⅙" => "⅙", + "⅛" => "⅛", + "⅔" => "⅔", + "⅖" => "⅖", + "¾" => "¾", + "¾" => "¾", + "⅗" => "⅗", + "⅜" => "⅜", + "⅘" => "⅘", + "⅚" => "⅚", + "⅝" => "⅝", + "⅞" => "⅞", + "⁄" => "⁄", + "⌢" => "⌢", + "𝒻" => "𝒻", + "≧" => "≧", + "⪌" => "⪌", + "ǵ" => "ǵ", + "γ" => "γ", + "ϝ" => "ϝ", + "⪆" => "⪆", + "ğ" => "ğ", + "ĝ" => "ĝ", + "г" => "г", + "ġ" => "ġ", + "≥" => "≥", + "⋛" => "⋛", + "≥" => "≥", + "≧" => "≧", + "⩾" => "⩾", + "⩾" => "⩾", + "⪩" => "⪩", + "⪀" => "⪀", + "⪂" => "⪂", + "⪄" => "⪄", + "⋛︀" => "⋛︀", + "⪔" => "⪔", + "𝔤" => "𝔤", + "≫" => "≫", + "⋙" => "⋙", + "ℷ" => "ℷ", + "ѓ" => "ѓ", + "≷" => "≷", + "⪒" => "⪒", + "⪥" => "⪥", + "⪤" => "⪤", + "≩" => "≩", + "⪊" => "⪊", + "⪊" => "⪊", + "⪈" => "⪈", + "⪈" => "⪈", + "≩" => "≩", + "⋧" => "⋧", + "𝕘" => "𝕘", + "`" => "`", + "ℊ" => "ℊ", + "≳" => "≳", + "⪎" => "⪎", + "⪐" => "⪐", + ">" => ">", + ">" => ">", + "⪧" => "⪧", + "⩺" => "⩺", + "⋗" => "⋗", + "⦕" => "⦕", + "⩼" => "⩼", + "⪆" => "⪆", + "⥸" => "⥸", + "⋗" => "⋗", + "⋛" => "⋛", + "⪌" => "⪌", + "≷" => "≷", + "≳" => "≳", + "≩︀" => "≩︀", + "≩︀" => "≩︀", + "⇔" => "⇔", + " " => " ", + "½" => "½", + "ℋ" => "ℋ", + "ъ" => "ъ", + "↔" => "↔", + "⥈" => "⥈", + "↭" => "↭", + "ℏ" => "ℏ", + "ĥ" => "ĥ", + "♥" => "♥", + "♥" => "♥", + "…" => "…", + "⊹" => "⊹", + "𝔥" => "𝔥", + "⤥" => "⤥", + "⤦" => "⤦", + "⇿" => "⇿", + "∻" => "∻", + "↩" => "↩", + "↪" => "↪", + "𝕙" => "𝕙", + "―" => "―", + "𝒽" => "𝒽", + "ℏ" => "ℏ", + "ħ" => "ħ", + "⁃" => "⁃", + "‐" => "‐", + "í" => "í", + "í" => "í", + "⁣" => "\u2063", + "î" => "î", + "î" => "î", + "и" => "и", + "е" => "е", + "¡" => "¡", + "¡" => "¡", + "⇔" => "⇔", + "𝔦" => "𝔦", + "ì" => "ì", + "ì" => "ì", + "ⅈ" => "ⅈ", + "⨌" => "⨌", + "∭" => "∭", + "⧜" => "⧜", + "℩" => "℩", + "ij" => "ij", + "ī" => "ī", + "ℑ" => "ℑ", + "ℐ" => "ℐ", + "ℑ" => "ℑ", + "ı" => "ı", + "⊷" => "⊷", + "Ƶ" => "Ƶ", + "∈" => "∈", + "℅" => "℅", + "∞" => "∞", + "⧝" => "⧝", + "ı" => "ı", + "∫" => "∫", + "⊺" => "⊺", + "ℤ" => "ℤ", + "⊺" => "⊺", + "⨗" => "⨗", + "⨼" => "⨼", + "ё" => "ё", + "į" => "į", + "𝕚" => "𝕚", + "ι" => "ι", + "⨼" => "⨼", + "¿" => "¿", + "¿" => "¿", + "𝒾" => "𝒾", + "∈" => "∈", + "⋹" => "⋹", + "⋵" => "⋵", + "⋴" => "⋴", + "⋳" => "⋳", + "∈" => "∈", + "⁢" => "\u2062", + "ĩ" => "ĩ", + "і" => "і", + "ï" => "ï", + "ï" => "ï", + "ĵ" => "ĵ", + "й" => "й", + "𝔧" => "𝔧", + "ȷ" => "ȷ", + "𝕛" => "𝕛", + "𝒿" => "𝒿", + "ј" => "ј", + "є" => "є", + "κ" => "κ", + "ϰ" => "ϰ", + "ķ" => "ķ", + "к" => "к", + "𝔨" => "𝔨", + "ĸ" => "ĸ", + "х" => "х", + "ќ" => "ќ", + "𝕜" => "𝕜", + "𝓀" => "𝓀", + "⇚" => "⇚", + "⇐" => "⇐", + "⤛" => "⤛", + "⤎" => "⤎", + "≦" => "≦", + "⪋" => "⪋", + "⥢" => "⥢", + "ĺ" => "ĺ", + "⦴" => "⦴", + "ℒ" => "ℒ", + "λ" => "λ", + "⟨" => "⟨", + "⦑" => "⦑", + "⟨" => "⟨", + "⪅" => "⪅", + "«" => "«", + "«" => "«", + "←" => "←", + "⇤" => "⇤", + "⤟" => "⤟", + "⤝" => "⤝", + "↩" => "↩", + "↫" => "↫", + "⤹" => "⤹", + "⥳" => "⥳", + "↢" => "↢", + "⪫" => "⪫", + "⤙" => "⤙", + "⪭" => "⪭", + "⪭︀" => "⪭︀", + "⤌" => "⤌", + "❲" => "❲", + "{" => "{", + "[" => "[", + "⦋" => "⦋", + "⦏" => "⦏", + "⦍" => "⦍", + "ľ" => "ľ", + "ļ" => "ļ", + "⌈" => "⌈", + "{" => "{", + "л" => "л", + "⤶" => "⤶", + "“" => "“", + "„" => "„", + "⥧" => "⥧", + "⥋" => "⥋", + "↲" => "↲", + "≤" => "≤", + "←" => "←", + "↢" => "↢", + "↽" => "↽", + "↼" => "↼", + "⇇" => "⇇", + "↔" => "↔", + "⇆" => "⇆", + "⇋" => "⇋", + "↭" => "↭", + "⋋" => "⋋", + "⋚" => "⋚", + "≤" => "≤", + "≦" => "≦", + "⩽" => "⩽", + "⩽" => "⩽", + "⪨" => "⪨", + "⩿" => "⩿", + "⪁" => "⪁", + "⪃" => "⪃", + "⋚︀" => "⋚︀", + "⪓" => "⪓", + "⪅" => "⪅", + "⋖" => "⋖", + "⋚" => "⋚", + "⪋" => "⪋", + "≶" => "≶", + "≲" => "≲", + "⥼" => "⥼", + "⌊" => "⌊", + "𝔩" => "𝔩", + "≶" => "≶", + "⪑" => "⪑", + "↽" => "↽", + "↼" => "↼", + "⥪" => "⥪", + "▄" => "▄", + "љ" => "љ", + "≪" => "≪", + "⇇" => "⇇", + "⌞" => "⌞", + "⥫" => "⥫", + "◺" => "◺", + "ŀ" => "ŀ", + "⎰" => "⎰", + "⎰" => "⎰", + "≨" => "≨", + "⪉" => "⪉", + "⪉" => "⪉", + "⪇" => "⪇", + "⪇" => "⪇", + "≨" => "≨", + "⋦" => "⋦", + "⟬" => "⟬", + "⇽" => "⇽", + "⟦" => "⟦", + "⟵" => "⟵", + "⟷" => "⟷", + "⟼" => "⟼", + "⟶" => "⟶", + "↫" => "↫", + "↬" => "↬", + "⦅" => "⦅", + "𝕝" => "𝕝", + "⨭" => "⨭", + "⨴" => "⨴", + "∗" => "∗", + "_" => "_", + "◊" => "◊", + "◊" => "◊", + "⧫" => "⧫", + "(" => "(", + "⦓" => "⦓", + "⇆" => "⇆", + "⌟" => "⌟", + "⇋" => "⇋", + "⥭" => "⥭", + "‎" => "\u200e", + "⊿" => "⊿", + "‹" => "‹", + "𝓁" => "𝓁", + "↰" => "↰", + "≲" => "≲", + "⪍" => "⪍", + "⪏" => "⪏", + "[" => "[", + "‘" => "‘", + "‚" => "‚", + "ł" => "ł", + "<" => "<", + "<" => "<", + "⪦" => "⪦", + "⩹" => "⩹", + "⋖" => "⋖", + "⋋" => "⋋", + "⋉" => "⋉", + "⥶" => "⥶", + "⩻" => "⩻", + "⦖" => "⦖", + "◃" => "◃", + "⊴" => "⊴", + "◂" => "◂", + "⥊" => "⥊", + "⥦" => "⥦", + "≨︀" => "≨︀", + "≨︀" => "≨︀", + "∺" => "∺", + "¯" => "¯", + "¯" => "¯", + "♂" => "♂", + "✠" => "✠", + "✠" => "✠", + "↦" => "↦", + "↦" => "↦", + "↧" => "↧", + "↤" => "↤", + "↥" => "↥", + "▮" => "▮", + "⨩" => "⨩", + "м" => "м", + "—" => "—", + "∡" => "∡", + "𝔪" => "𝔪", + "℧" => "℧", + "µ" => "µ", + "µ" => "µ", + "∣" => "∣", + "*" => "*", + "⫰" => "⫰", + "·" => "·", + "·" => "·", + "−" => "−", + "⊟" => "⊟", + "∸" => "∸", + "⨪" => "⨪", + "⫛" => "⫛", + "…" => "…", + "∓" => "∓", + "⊧" => "⊧", + "𝕞" => "𝕞", + "∓" => "∓", + "𝓂" => "𝓂", + "∾" => "∾", + "μ" => "μ", + "⊸" => "⊸", + "⊸" => "⊸", + "⋙̸" => "⋙̸", + "≫⃒" => "≫⃒", + "≫̸" => "≫̸", + "⇍" => "⇍", + "⇎" => "⇎", + "⋘̸" => "⋘̸", + "≪⃒" => "≪⃒", + "≪̸" => "≪̸", + "⇏" => "⇏", + "⊯" => "⊯", + "⊮" => "⊮", + "∇" => "∇", + "ń" => "ń", + "∠⃒" => "∠⃒", + "≉" => "≉", + "⩰̸" => "⩰̸", + "≋̸" => "≋̸", + "ʼn" => "ʼn", + "≉" => "≉", + "♮" => "♮", + "♮" => "♮", + "ℕ" => "ℕ", + " " => " ", + " " => " ", + "≎̸" => "≎̸", + "≏̸" => "≏̸", + "⩃" => "⩃", + "ň" => "ň", + "ņ" => "ņ", + "≇" => "≇", + "⩭̸" => "⩭̸", + "⩂" => "⩂", + "н" => "н", + "–" => "–", + "≠" => "≠", + "⇗" => "⇗", + "⤤" => "⤤", + "↗" => "↗", + "↗" => "↗", + "≐̸" => "≐̸", + "≢" => "≢", + "⤨" => "⤨", + "≂̸" => "≂̸", + "∄" => "∄", + "∄" => "∄", + "𝔫" => "𝔫", + "≧̸" => "≧̸", + "≱" => "≱", + "≱" => "≱", + "≧̸" => "≧̸", + "⩾̸" => "⩾̸", + "⩾̸" => "⩾̸", + "≵" => "≵", + "≯" => "≯", + "≯" => "≯", + "⇎" => "⇎", + "↮" => "↮", + "⫲" => "⫲", + "∋" => "∋", + "⋼" => "⋼", + "⋺" => "⋺", + "∋" => "∋", + "њ" => "њ", + "⇍" => "⇍", + "≦̸" => "≦̸", + "↚" => "↚", + "‥" => "‥", + "≰" => "≰", + "↚" => "↚", + "↮" => "↮", + "≰" => "≰", + "≦̸" => "≦̸", + "⩽̸" => "⩽̸", + "⩽̸" => "⩽̸", + "≮" => "≮", + "≴" => "≴", + "≮" => "≮", + "⋪" => "⋪", + "⋬" => "⋬", + "∤" => "∤", + "𝕟" => "𝕟", + "¬" => "¬", + "¬" => "¬", + "∉" => "∉", + "⋹̸" => "⋹̸", + "⋵̸" => "⋵̸", + "∉" => "∉", + "⋷" => "⋷", + "⋶" => "⋶", + "∌" => "∌", + "∌" => "∌", + "⋾" => "⋾", + "⋽" => "⋽", + "∦" => "∦", + "∦" => "∦", + "⫽⃥" => "⫽⃥", + "∂̸" => "∂̸", + "⨔" => "⨔", + "⊀" => "⊀", + "⋠" => "⋠", + "⪯̸" => "⪯̸", + "⊀" => "⊀", + "⪯̸" => "⪯̸", + "⇏" => "⇏", + "↛" => "↛", + "⤳̸" => "⤳̸", + "↝̸" => "↝̸", + "↛" => "↛", + "⋫" => "⋫", + "⋭" => "⋭", + "⊁" => "⊁", + "⋡" => "⋡", + "⪰̸" => "⪰̸", + "𝓃" => "𝓃", + "∤" => "∤", + "∦" => "∦", + "≁" => "≁", + "≄" => "≄", + "≄" => "≄", + "∤" => "∤", + "∦" => "∦", + "⋢" => "⋢", + "⋣" => "⋣", + "⊄" => "⊄", + "⫅̸" => "⫅̸", + "⊈" => "⊈", + "⊂⃒" => "⊂⃒", + "⊈" => "⊈", + "⫅̸" => "⫅̸", + "⊁" => "⊁", + "⪰̸" => "⪰̸", + "⊅" => "⊅", + "⫆̸" => "⫆̸", + "⊉" => "⊉", + "⊃⃒" => "⊃⃒", + "⊉" => "⊉", + "⫆̸" => "⫆̸", + "≹" => "≹", + "ñ" => "ñ", + "ñ" => "ñ", + "≸" => "≸", + "⋪" => "⋪", + "⋬" => "⋬", + "⋫" => "⋫", + "⋭" => "⋭", + "ν" => "ν", + "#" => "#", + "№" => "№", + " " => " ", + "⊭" => "⊭", + "⤄" => "⤄", + "≍⃒" => "≍⃒", + "⊬" => "⊬", + "≥⃒" => "≥⃒", + ">⃒" => ">⃒", + "⧞" => "⧞", + "⤂" => "⤂", + "≤⃒" => "≤⃒", + "<⃒" => "<⃒", + "⊴⃒" => "⊴⃒", + "⤃" => "⤃", + "⊵⃒" => "⊵⃒", + "∼⃒" => "∼⃒", + "⇖" => "⇖", + "⤣" => "⤣", + "↖" => "↖", + "↖" => "↖", + "⤧" => "⤧", + "Ⓢ" => "Ⓢ", + "ó" => "ó", + "ó" => "ó", + "⊛" => "⊛", + "⊚" => "⊚", + "ô" => "ô", + "ô" => "ô", + "о" => "о", + "⊝" => "⊝", + "ő" => "ő", + "⨸" => "⨸", + "⊙" => "⊙", + "⦼" => "⦼", + "œ" => "œ", + "⦿" => "⦿", + "𝔬" => "𝔬", + "˛" => "˛", + "ò" => "ò", + "ò" => "ò", + "⧁" => "⧁", + "⦵" => "⦵", + "Ω" => "Ω", + "∮" => "∮", + "↺" => "↺", + "⦾" => "⦾", + "⦻" => "⦻", + "‾" => "‾", + "⧀" => "⧀", + "ō" => "ō", + "ω" => "ω", + "ο" => "ο", + "⦶" => "⦶", + "⊖" => "⊖", + "𝕠" => "𝕠", + "⦷" => "⦷", + "⦹" => "⦹", + "⊕" => "⊕", + "∨" => "∨", + "↻" => "↻", + "⩝" => "⩝", + "ℴ" => "ℴ", + "ℴ" => "ℴ", + "ª" => "ª", + "ª" => "ª", + "º" => "º", + "º" => "º", + "⊶" => "⊶", + "⩖" => "⩖", + "⩗" => "⩗", + "⩛" => "⩛", + "ℴ" => "ℴ", + "ø" => "ø", + "ø" => "ø", + "⊘" => "⊘", + "õ" => "õ", + "õ" => "õ", + "⊗" => "⊗", + "⨶" => "⨶", + "ö" => "ö", + "ö" => "ö", + "⌽" => "⌽", + "∥" => "∥", + "¶" => "¶", + "¶" => "¶", + "∥" => "∥", + "⫳" => "⫳", + "⫽" => "⫽", + "∂" => "∂", + "п" => "п", + "%" => "%", + "." => ".", + "‰" => "‰", + "⊥" => "⊥", + "‱" => "‱", + "𝔭" => "𝔭", + "φ" => "φ", + "ϕ" => "ϕ", + "ℳ" => "ℳ", + "☎" => "☎", + "π" => "π", + "⋔" => "⋔", + "ϖ" => "ϖ", + "ℏ" => "ℏ", + "ℎ" => "ℎ", + "ℏ" => "ℏ", + "+" => "+", + "⨣" => "⨣", + "⊞" => "⊞", + "⨢" => "⨢", + "∔" => "∔", + "⨥" => "⨥", + "⩲" => "⩲", + "±" => "±", + "±" => "±", + "⨦" => "⨦", + "⨧" => "⨧", + "±" => "±", + "⨕" => "⨕", + "𝕡" => "𝕡", + "£" => "£", + "£" => "£", + "≺" => "≺", + "⪳" => "⪳", + "⪷" => "⪷", + "≼" => "≼", + "⪯" => "⪯", + "≺" => "≺", + "⪷" => "⪷", + "≼" => "≼", + "⪯" => "⪯", + "⪹" => "⪹", + "⪵" => "⪵", + "⋨" => "⋨", + "≾" => "≾", + "′" => "′", + "ℙ" => "ℙ", + "⪵" => "⪵", + "⪹" => "⪹", + "⋨" => "⋨", + "∏" => "∏", + "⌮" => "⌮", + "⌒" => "⌒", + "⌓" => "⌓", + "∝" => "∝", + "∝" => "∝", + "≾" => "≾", + "⊰" => "⊰", + "𝓅" => "𝓅", + "ψ" => "ψ", + " " => " ", + "𝔮" => "𝔮", + "⨌" => "⨌", + "𝕢" => "𝕢", + "⁗" => "⁗", + "𝓆" => "𝓆", + "ℍ" => "ℍ", + "⨖" => "⨖", + "?" => "?", + "≟" => "≟", + """ => "\"", + """ => "\"", + "⇛" => "⇛", + "⇒" => "⇒", + "⤜" => "⤜", + "⤏" => "⤏", + "⥤" => "⥤", + "∽̱" => "∽̱", + "ŕ" => "ŕ", + "√" => "√", + "⦳" => "⦳", + "⟩" => "⟩", + "⦒" => "⦒", + "⦥" => "⦥", + "⟩" => "⟩", + "»" => "»", + "»" => "»", + "→" => "→", + "⥵" => "⥵", + "⇥" => "⇥", + "⤠" => "⤠", + "⤳" => "⤳", + "⤞" => "⤞", + "↪" => "↪", + "↬" => "↬", + "⥅" => "⥅", + "⥴" => "⥴", + "↣" => "↣", + "↝" => "↝", + "⤚" => "⤚", + "∶" => "∶", + "ℚ" => "ℚ", + "⤍" => "⤍", + "❳" => "❳", + "}" => "}", + "]" => "]", + "⦌" => "⦌", + "⦎" => "⦎", + "⦐" => "⦐", + "ř" => "ř", + "ŗ" => "ŗ", + "⌉" => "⌉", + "}" => "}", + "р" => "р", + "⤷" => "⤷", + "⥩" => "⥩", + "”" => "”", + "”" => "”", + "↳" => "↳", + "ℜ" => "ℜ", + "ℛ" => "ℛ", + "ℜ" => "ℜ", + "ℝ" => "ℝ", + "▭" => "▭", + "®" => "®", + "®" => "®", + "⥽" => "⥽", + "⌋" => "⌋", + "𝔯" => "𝔯", + "⇁" => "⇁", + "⇀" => "⇀", + "⥬" => "⥬", + "ρ" => "ρ", + "ϱ" => "ϱ", + "→" => "→", + "↣" => "↣", + "⇁" => "⇁", + "⇀" => "⇀", + "⇄" => "⇄", + "⇌" => "⇌", + "⇉" => "⇉", + "↝" => "↝", + "⋌" => "⋌", + "˚" => "˚", + "≓" => "≓", + "⇄" => "⇄", + "⇌" => "⇌", + "‏" => "\u200f", + "⎱" => "⎱", + "⎱" => "⎱", + "⫮" => "⫮", + "⟭" => "⟭", + "⇾" => "⇾", + "⟧" => "⟧", + "⦆" => "⦆", + "𝕣" => "𝕣", + "⨮" => "⨮", + "⨵" => "⨵", + ")" => ")", + "⦔" => "⦔", + "⨒" => "⨒", + "⇉" => "⇉", + "›" => "›", + "𝓇" => "𝓇", + "↱" => "↱", + "]" => "]", + "’" => "’", + "’" => "’", + "⋌" => "⋌", + "⋊" => "⋊", + "▹" => "▹", + "⊵" => "⊵", + "▸" => "▸", + "⧎" => "⧎", + "⥨" => "⥨", + "℞" => "℞", + "ś" => "ś", + "‚" => "‚", + "≻" => "≻", + "⪴" => "⪴", + "⪸" => "⪸", + "š" => "š", + "≽" => "≽", + "⪰" => "⪰", + "ş" => "ş", + "ŝ" => "ŝ", + "⪶" => "⪶", + "⪺" => "⪺", + "⋩" => "⋩", + "⨓" => "⨓", + "≿" => "≿", + "с" => "с", + "⋅" => "⋅", + "⊡" => "⊡", + "⩦" => "⩦", + "⇘" => "⇘", + "⤥" => "⤥", + "↘" => "↘", + "↘" => "↘", + "§" => "§", + "§" => "§", + ";" => ";", + "⤩" => "⤩", + "∖" => "∖", + "∖" => "∖", + "✶" => "✶", + "𝔰" => "𝔰", + "⌢" => "⌢", + "♯" => "♯", + "щ" => "щ", + "ш" => "ш", + "∣" => "∣", + "∥" => "∥", + "­" => "\uad", + "­" => "\uad", + "σ" => "σ", + "ς" => "ς", + "ς" => "ς", + "∼" => "∼", + "⩪" => "⩪", + "≃" => "≃", + "≃" => "≃", + "⪞" => "⪞", + "⪠" => "⪠", + "⪝" => "⪝", + "⪟" => "⪟", + "≆" => "≆", + "⨤" => "⨤", + "⥲" => "⥲", + "←" => "←", + "∖" => "∖", + "⨳" => "⨳", + "⧤" => "⧤", + "∣" => "∣", + "⌣" => "⌣", + "⪪" => "⪪", + "⪬" => "⪬", + "⪬︀" => "⪬︀", + "ь" => "ь", + "/" => "/", + "⧄" => "⧄", + "⌿" => "⌿", + "𝕤" => "𝕤", + "♠" => "♠", + "♠" => "♠", + "∥" => "∥", + "⊓" => "⊓", + "⊓︀" => "⊓︀", + "⊔" => "⊔", + "⊔︀" => "⊔︀", + "⊏" => "⊏", + "⊑" => "⊑", + "⊏" => "⊏", + "⊑" => "⊑", + "⊐" => "⊐", + "⊒" => "⊒", + "⊐" => "⊐", + "⊒" => "⊒", + "□" => "□", + "□" => "□", + "▪" => "▪", + "▪" => "▪", + "→" => "→", + "𝓈" => "𝓈", + "∖" => "∖", + "⌣" => "⌣", + "⋆" => "⋆", + "☆" => "☆", + "★" => "★", + "ϵ" => "ϵ", + "ϕ" => "ϕ", + "¯" => "¯", + "⊂" => "⊂", + "⫅" => "⫅", + "⪽" => "⪽", + "⊆" => "⊆", + "⫃" => "⫃", + "⫁" => "⫁", + "⫋" => "⫋", + "⊊" => "⊊", + "⪿" => "⪿", + "⥹" => "⥹", + "⊂" => "⊂", + "⊆" => "⊆", + "⫅" => "⫅", + "⊊" => "⊊", + "⫋" => "⫋", + "⫇" => "⫇", + "⫕" => "⫕", + "⫓" => "⫓", + "≻" => "≻", + "⪸" => "⪸", + "≽" => "≽", + "⪰" => "⪰", + "⪺" => "⪺", + "⪶" => "⪶", + "⋩" => "⋩", + "≿" => "≿", + "∑" => "∑", + "♪" => "♪", + "¹" => "¹", + "¹" => "¹", + "²" => "²", + "²" => "²", + "³" => "³", + "³" => "³", + "⊃" => "⊃", + "⫆" => "⫆", + "⪾" => "⪾", + "⫘" => "⫘", + "⊇" => "⊇", + "⫄" => "⫄", + "⟉" => "⟉", + "⫗" => "⫗", + "⥻" => "⥻", + "⫂" => "⫂", + "⫌" => "⫌", + "⊋" => "⊋", + "⫀" => "⫀", + "⊃" => "⊃", + "⊇" => "⊇", + "⫆" => "⫆", + "⊋" => "⊋", + "⫌" => "⫌", + "⫈" => "⫈", + "⫔" => "⫔", + "⫖" => "⫖", + "⇙" => "⇙", + "⤦" => "⤦", + "↙" => "↙", + "↙" => "↙", + "⤪" => "⤪", + "ß" => "ß", + "ß" => "ß", + "⌖" => "⌖", + "τ" => "τ", + "⎴" => "⎴", + "ť" => "ť", + "ţ" => "ţ", + "т" => "т", + "⃛" => "⃛", + "⌕" => "⌕", + "𝔱" => "𝔱", + "∴" => "∴", + "∴" => "∴", + "θ" => "θ", + "ϑ" => "ϑ", + "ϑ" => "ϑ", + "≈" => "≈", + "∼" => "∼", + " " => " ", + "≈" => "≈", + "∼" => "∼", + "þ" => "þ", + "þ" => "þ", + "˜" => "˜", + "×" => "×", + "×" => "×", + "⊠" => "⊠", + "⨱" => "⨱", + "⨰" => "⨰", + "∭" => "∭", + "⤨" => "⤨", + "⊤" => "⊤", + "⌶" => "⌶", + "⫱" => "⫱", + "𝕥" => "𝕥", + "⫚" => "⫚", + "⤩" => "⤩", + "‴" => "‴", + "™" => "™", + "▵" => "▵", + "▿" => "▿", + "◃" => "◃", + "⊴" => "⊴", + "≜" => "≜", + "▹" => "▹", + "⊵" => "⊵", + "◬" => "◬", + "≜" => "≜", + "⨺" => "⨺", + "⨹" => "⨹", + "⧍" => "⧍", + "⨻" => "⨻", + "⏢" => "⏢", + "𝓉" => "𝓉", + "ц" => "ц", + "ћ" => "ћ", + "ŧ" => "ŧ", + "≬" => "≬", + "↞" => "↞", + "↠" => "↠", + "⇑" => "⇑", + "⥣" => "⥣", + "ú" => "ú", + "ú" => "ú", + "↑" => "↑", + "ў" => "ў", + "ŭ" => "ŭ", + "û" => "û", + "û" => "û", + "у" => "у", + "⇅" => "⇅", + "ű" => "ű", + "⥮" => "⥮", + "⥾" => "⥾", + "𝔲" => "𝔲", + "ù" => "ù", + "ù" => "ù", + "↿" => "↿", + "↾" => "↾", + "▀" => "▀", + "⌜" => "⌜", + "⌜" => "⌜", + "⌏" => "⌏", + "◸" => "◸", + "ū" => "ū", + "¨" => "¨", + "¨" => "¨", + "ų" => "ų", + "𝕦" => "𝕦", + "↑" => "↑", + "↕" => "↕", + "↿" => "↿", + "↾" => "↾", + "⊎" => "⊎", + "υ" => "υ", + "ϒ" => "ϒ", + "υ" => "υ", + "⇈" => "⇈", + "⌝" => "⌝", + "⌝" => "⌝", + "⌎" => "⌎", + "ů" => "ů", + "◹" => "◹", + "𝓊" => "𝓊", + "⋰" => "⋰", + "ũ" => "ũ", + "▵" => "▵", + "▴" => "▴", + "⇈" => "⇈", + "ü" => "ü", + "ü" => "ü", + "⦧" => "⦧", + "⇕" => "⇕", + "⫨" => "⫨", + "⫩" => "⫩", + "⊨" => "⊨", + "⦜" => "⦜", + "ϵ" => "ϵ", + "ϰ" => "ϰ", + "∅" => "∅", + "ϕ" => "ϕ", + "ϖ" => "ϖ", + "∝" => "∝", + "↕" => "↕", + "ϱ" => "ϱ", + "ς" => "ς", + "⊊︀" => "⊊︀", + "⫋︀" => "⫋︀", + "⊋︀" => "⊋︀", + "⫌︀" => "⫌︀", + "ϑ" => "ϑ", + "⊲" => "⊲", + "⊳" => "⊳", + "в" => "в", + "⊢" => "⊢", + "∨" => "∨", + "⊻" => "⊻", + "≚" => "≚", + "⋮" => "⋮", + "|" => "|", + "|" => "|", + "𝔳" => "𝔳", + "⊲" => "⊲", + "⊂⃒" => "⊂⃒", + "⊃⃒" => "⊃⃒", + "𝕧" => "𝕧", + "∝" => "∝", + "⊳" => "⊳", + "𝓋" => "𝓋", + "⫋︀" => "⫋︀", + "⊊︀" => "⊊︀", + "⫌︀" => "⫌︀", + "⊋︀" => "⊋︀", + "⦚" => "⦚", + "ŵ" => "ŵ", + "⩟" => "⩟", + "∧" => "∧", + "≙" => "≙", + "℘" => "℘", + "𝔴" => "𝔴", + "𝕨" => "𝕨", + "℘" => "℘", + "≀" => "≀", + "≀" => "≀", + "𝓌" => "𝓌", + "⋂" => "⋂", + "◯" => "◯", + "⋃" => "⋃", + "▽" => "▽", + "𝔵" => "𝔵", + "⟺" => "⟺", + "⟷" => "⟷", + "ξ" => "ξ", + "⟸" => "⟸", + "⟵" => "⟵", + "⟼" => "⟼", + "⋻" => "⋻", + "⨀" => "⨀", + "𝕩" => "𝕩", + "⨁" => "⨁", + "⨂" => "⨂", + "⟹" => "⟹", + "⟶" => "⟶", + "𝓍" => "𝓍", + "⨆" => "⨆", + "⨄" => "⨄", + "△" => "△", + "⋁" => "⋁", + "⋀" => "⋀", + "ý" => "ý", + "ý" => "ý", + "я" => "я", + "ŷ" => "ŷ", + "ы" => "ы", + "¥" => "¥", + "¥" => "¥", + "𝔶" => "𝔶", + "ї" => "ї", + "𝕪" => "𝕪", + "𝓎" => "𝓎", + "ю" => "ю", + "ÿ" => "ÿ", + "ÿ" => "ÿ", + "ź" => "ź", + "ž" => "ž", + "з" => "з", + "ż" => "ż", + "ℨ" => "ℨ", + "ζ" => "ζ", + "𝔷" => "𝔷", + "ж" => "ж", + "⇝" => "⇝", + "𝕫" => "𝕫", + "𝓏" => "𝓏", + "‍" => "\u200d", + "‌" => "\u200c", +) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.json b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.json new file mode 100644 index 0000000..557170b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entities.json @@ -0,0 +1,2233 @@ +{ + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "Æ": { "codepoints": [198], "characters": "\u00C6" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Á": { "codepoints": [193], "characters": "\u00C1" }, + "Ă": { "codepoints": [258], "characters": "\u0102" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "Â": { "codepoints": [194], "characters": "\u00C2" }, + "А": { "codepoints": [1040], "characters": "\u0410" }, + "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "À": { "codepoints": [192], "characters": "\u00C0" }, + "Α": { "codepoints": [913], "characters": "\u0391" }, + "Ā": { "codepoints": [256], "characters": "\u0100" }, + "⩓": { "codepoints": [10835], "characters": "\u2A53" }, + "Ą": { "codepoints": [260], "characters": "\u0104" }, + "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ã": { "codepoints": [195], "characters": "\u00C3" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "Ä": { "codepoints": [196], "characters": "\u00C4" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⫧": { "codepoints": [10983], "characters": "\u2AE7" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "Б": { "codepoints": [1041], "characters": "\u0411" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "Β": { "codepoints": [914], "characters": "\u0392" }, + "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" }, + "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "Ч": { "codepoints": [1063], "characters": "\u0427" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "Ć": { "codepoints": [262], "characters": "\u0106" }, + "⋒": { "codepoints": [8914], "characters": "\u22D2" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Č": { "codepoints": [268], "characters": "\u010C" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ç": { "codepoints": [199], "characters": "\u00C7" }, + "Ĉ": { "codepoints": [264], "characters": "\u0108" }, + "∰": { "codepoints": [8752], "characters": "\u2230" }, + "Ċ": { "codepoints": [266], "characters": "\u010A" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "ℭ": { "codepoints": [8493], "characters": "\u212D" }, + "Χ": { "codepoints": [935], "characters": "\u03A7" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "⩴": { "codepoints": [10868], "characters": "\u2A74" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨯": { "codepoints": [10799], "characters": "\u2A2F" }, + "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" }, + "⋓": { "codepoints": [8915], "characters": "\u22D3" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ⅅ": { "codepoints": [8517], "characters": "\u2145" }, + "⤑": { "codepoints": [10513], "characters": "\u2911" }, + "Ђ": { "codepoints": [1026], "characters": "\u0402" }, + "Ѕ": { "codepoints": [1029], "characters": "\u0405" }, + "Џ": { "codepoints": [1039], "characters": "\u040F" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "↡": { "codepoints": [8609], "characters": "\u21A1" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "Ď": { "codepoints": [270], "characters": "\u010E" }, + "Д": { "codepoints": [1044], "characters": "\u0414" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "Δ": { "codepoints": [916], "characters": "\u0394" }, + "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⃜": { "codepoints": [8412], "characters": "\u20DC" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "∯": { "codepoints": [8751], "characters": "\u222F" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⫤": { "codepoints": [10980], "characters": "\u2AE4" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⤓": { "codepoints": [10515], "characters": "\u2913" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "̑": { "codepoints": [785], "characters": "\u0311" }, + "⥐": { "codepoints": [10576], "characters": "\u2950" }, + "⥞": { "codepoints": [10590], "characters": "\u295E" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "⥖": { "codepoints": [10582], "characters": "\u2956" }, + "⥟": { "codepoints": [10591], "characters": "\u295F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⥗": { "codepoints": [10583], "characters": "\u2957" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" }, + "Đ": { "codepoints": [272], "characters": "\u0110" }, + "Ŋ": { "codepoints": [330], "characters": "\u014A" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "Ð": { "codepoints": [208], "characters": "\u00D0" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "É": { "codepoints": [201], "characters": "\u00C9" }, + "Ě": { "codepoints": [282], "characters": "\u011A" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Ê": { "codepoints": [202], "characters": "\u00CA" }, + "Э": { "codepoints": [1069], "characters": "\u042D" }, + "Ė": { "codepoints": [278], "characters": "\u0116" }, + "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "È": { "codepoints": [200], "characters": "\u00C8" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "Ē": { "codepoints": [274], "characters": "\u0112" }, + "◻": { "codepoints": [9723], "characters": "\u25FB" }, + "▫": { "codepoints": [9643], "characters": "\u25AB" }, + "Ę": { "codepoints": [280], "characters": "\u0118" }, + "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" }, + "Ε": { "codepoints": [917], "characters": "\u0395" }, + "⩵": { "codepoints": [10869], "characters": "\u2A75" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "⩳": { "codepoints": [10867], "characters": "\u2A73" }, + "Η": { "codepoints": [919], "characters": "\u0397" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "Ë": { "codepoints": [203], "characters": "\u00CB" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "Ф": { "codepoints": [1060], "characters": "\u0424" }, + "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" }, + "◼": { "codepoints": [9724], "characters": "\u25FC" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "ℱ": { "codepoints": [8497], "characters": "\u2131" }, + "Ѓ": { "codepoints": [1027], "characters": "\u0403" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "Γ": { "codepoints": [915], "characters": "\u0393" }, + "Ϝ": { "codepoints": [988], "characters": "\u03DC" }, + "Ğ": { "codepoints": [286], "characters": "\u011E" }, + "Ģ": { "codepoints": [290], "characters": "\u0122" }, + "Ĝ": { "codepoints": [284], "characters": "\u011C" }, + "Г": { "codepoints": [1043], "characters": "\u0413" }, + "Ġ": { "codepoints": [288], "characters": "\u0120" }, + "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪢": { "codepoints": [10914], "characters": "\u2AA2" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "Ъ": { "codepoints": [1066], "characters": "\u042A" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "^": { "codepoints": [94], "characters": "\u005E" }, + "Ĥ": { "codepoints": [292], "characters": "\u0124" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "Ħ": { "codepoints": [294], "characters": "\u0126" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "Е": { "codepoints": [1045], "characters": "\u0415" }, + "IJ": { "codepoints": [306], "characters": "\u0132" }, + "Ё": { "codepoints": [1025], "characters": "\u0401" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Í": { "codepoints": [205], "characters": "\u00CD" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "Î": { "codepoints": [206], "characters": "\u00CE" }, + "И": { "codepoints": [1048], "characters": "\u0418" }, + "İ": { "codepoints": [304], "characters": "\u0130" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "Ì": { "codepoints": [204], "characters": "\u00CC" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "Ī": { "codepoints": [298], "characters": "\u012A" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "∬": { "codepoints": [8748], "characters": "\u222C" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "Į": { "codepoints": [302], "characters": "\u012E" }, + "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" }, + "Ι": { "codepoints": [921], "characters": "\u0399" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "Ĩ": { "codepoints": [296], "characters": "\u0128" }, + "І": { "codepoints": [1030], "characters": "\u0406" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ï": { "codepoints": [207], "characters": "\u00CF" }, + "Ĵ": { "codepoints": [308], "characters": "\u0134" }, + "Й": { "codepoints": [1049], "characters": "\u0419" }, + "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" }, + "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" }, + "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" }, + "Ј": { "codepoints": [1032], "characters": "\u0408" }, + "Є": { "codepoints": [1028], "characters": "\u0404" }, + "Х": { "codepoints": [1061], "characters": "\u0425" }, + "Ќ": { "codepoints": [1036], "characters": "\u040C" }, + "Κ": { "codepoints": [922], "characters": "\u039A" }, + "Ķ": { "codepoints": [310], "characters": "\u0136" }, + "К": { "codepoints": [1050], "characters": "\u041A" }, + "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" }, + "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" }, + "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" }, + "Љ": { "codepoints": [1033], "characters": "\u0409" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "Ĺ": { "codepoints": [313], "characters": "\u0139" }, + "Λ": { "codepoints": [923], "characters": "\u039B" }, + "⟪": { "codepoints": [10218], "characters": "\u27EA" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "Ľ": { "codepoints": [317], "characters": "\u013D" }, + "Ļ": { "codepoints": [315], "characters": "\u013B" }, + "Л": { "codepoints": [1051], "characters": "\u041B" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⥡": { "codepoints": [10593], "characters": "\u2961" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⥙": { "codepoints": [10585], "characters": "\u2959" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥎": { "codepoints": [10574], "characters": "\u294E" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "⥚": { "codepoints": [10586], "characters": "\u295A" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⧏": { "codepoints": [10703], "characters": "\u29CF" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "⥑": { "codepoints": [10577], "characters": "\u2951" }, + "⥠": { "codepoints": [10592], "characters": "\u2960" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "⥘": { "codepoints": [10584], "characters": "\u2958" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥒": { "codepoints": [10578], "characters": "\u2952" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪡": { "codepoints": [10913], "characters": "\u2AA1" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" }, + "⋘": { "codepoints": [8920], "characters": "\u22D8" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "Ŀ": { "codepoints": [319], "characters": "\u013F" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "Ł": { "codepoints": [321], "characters": "\u0141" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⤅": { "codepoints": [10501], "characters": "\u2905" }, + "М": { "codepoints": [1052], "characters": "\u041C" }, + " ": { "codepoints": [8287], "characters": "\u205F" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "Μ": { "codepoints": [924], "characters": "\u039C" }, + "Њ": { "codepoints": [1034], "characters": "\u040A" }, + "Ń": { "codepoints": [323], "characters": "\u0143" }, + "Ň": { "codepoints": [327], "characters": "\u0147" }, + "Ņ": { "codepoints": [325], "characters": "\u0145" }, + "Н": { "codepoints": [1053], "characters": "\u041D" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + " ": { "codepoints": [10], "characters": "\u000A" }, + "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" }, + "⁠": { "codepoints": [8288], "characters": "\u2060" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + "⫬": { "codepoints": [10988], "characters": "\u2AEC" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "≭": { "codepoints": [8813], "characters": "\u226D" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" }, + "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ñ": { "codepoints": [209], "characters": "\u00D1" }, + "Ν": { "codepoints": [925], "characters": "\u039D" }, + "Œ": { "codepoints": [338], "characters": "\u0152" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ó": { "codepoints": [211], "characters": "\u00D3" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "Ô": { "codepoints": [212], "characters": "\u00D4" }, + "О": { "codepoints": [1054], "characters": "\u041E" }, + "Ő": { "codepoints": [336], "characters": "\u0150" }, + "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ò": { "codepoints": [210], "characters": "\u00D2" }, + "Ō": { "codepoints": [332], "characters": "\u014C" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "Ο": { "codepoints": [927], "characters": "\u039F" }, + "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "⩔": { "codepoints": [10836], "characters": "\u2A54" }, + "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Ø": { "codepoints": [216], "characters": "\u00D8" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "Õ": { "codepoints": [213], "characters": "\u00D5" }, + "⨷": { "codepoints": [10807], "characters": "\u2A37" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "Ö": { "codepoints": [214], "characters": "\u00D6" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⏞": { "codepoints": [9182], "characters": "\u23DE" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "⏜": { "codepoints": [9180], "characters": "\u23DC" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "П": { "codepoints": [1055], "characters": "\u041F" }, + "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" }, + "Φ": { "codepoints": [934], "characters": "\u03A6" }, + "Π": { "codepoints": [928], "characters": "\u03A0" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "ℌ": { "codepoints": [8460], "characters": "\u210C" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪻": { "codepoints": [10939], "characters": "\u2ABB" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "″": { "codepoints": [8243], "characters": "\u2033" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "∷": { "codepoints": [8759], "characters": "\u2237" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" }, + "Ψ": { "codepoints": [936], "characters": "\u03A8" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ŕ": { "codepoints": [340], "characters": "\u0154" }, + "⟫": { "codepoints": [10219], "characters": "\u27EB" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⤖": { "codepoints": [10518], "characters": "\u2916" }, + "Ř": { "codepoints": [344], "characters": "\u0158" }, + "Ŗ": { "codepoints": [342], "characters": "\u0156" }, + "Р": { "codepoints": [1056], "characters": "\u0420" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "Ρ": { "codepoints": [929], "characters": "\u03A1" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⥝": { "codepoints": [10589], "characters": "\u295D" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⥕": { "codepoints": [10581], "characters": "\u2955" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "⥛": { "codepoints": [10587], "characters": "\u295B" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "⧐": { "codepoints": [10704], "characters": "\u29D0" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "⥏": { "codepoints": [10575], "characters": "\u294F" }, + "⥜": { "codepoints": [10588], "characters": "\u295C" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⥔": { "codepoints": [10580], "characters": "\u2954" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥓": { "codepoints": [10579], "characters": "\u2953" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "⥰": { "codepoints": [10608], "characters": "\u2970" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "⧴": { "codepoints": [10740], "characters": "\u29F4" }, + "Щ": { "codepoints": [1065], "characters": "\u0429" }, + "Ш": { "codepoints": [1064], "characters": "\u0428" }, + "Ь": { "codepoints": [1068], "characters": "\u042C" }, + "Ś": { "codepoints": [346], "characters": "\u015A" }, + "⪼": { "codepoints": [10940], "characters": "\u2ABC" }, + "Š": { "codepoints": [352], "characters": "\u0160" }, + "Ş": { "codepoints": [350], "characters": "\u015E" }, + "Ŝ": { "codepoints": [348], "characters": "\u015C" }, + "С": { "codepoints": [1057], "characters": "\u0421" }, + "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "Σ": { "codepoints": [931], "characters": "\u03A3" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⋐": { "codepoints": [8912], "characters": "\u22D0" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⋑": { "codepoints": [8913], "characters": "\u22D1" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "Þ": { "codepoints": [222], "characters": "\u00DE" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "Ћ": { "codepoints": [1035], "characters": "\u040B" }, + "Ц": { "codepoints": [1062], "characters": "\u0426" }, + " ": { "codepoints": [9], "characters": "\u0009" }, + "Τ": { "codepoints": [932], "characters": "\u03A4" }, + "Ť": { "codepoints": [356], "characters": "\u0164" }, + "Ţ": { "codepoints": [354], "characters": "\u0162" }, + "Т": { "codepoints": [1058], "characters": "\u0422" }, + "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "Θ": { "codepoints": [920], "characters": "\u0398" }, + "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" }, + "Ŧ": { "codepoints": [358], "characters": "\u0166" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "Ú": { "codepoints": [218], "characters": "\u00DA" }, + "↟": { "codepoints": [8607], "characters": "\u219F" }, + "⥉": { "codepoints": [10569], "characters": "\u2949" }, + "Ў": { "codepoints": [1038], "characters": "\u040E" }, + "Ŭ": { "codepoints": [364], "characters": "\u016C" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "Û": { "codepoints": [219], "characters": "\u00DB" }, + "У": { "codepoints": [1059], "characters": "\u0423" }, + "Ű": { "codepoints": [368], "characters": "\u0170" }, + "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ù": { "codepoints": [217], "characters": "\u00D9" }, + "Ū": { "codepoints": [362], "characters": "\u016A" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "⏟": { "codepoints": [9183], "characters": "\u23DF" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⏝": { "codepoints": [9181], "characters": "\u23DD" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "Ų": { "codepoints": [370], "characters": "\u0172" }, + "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "⤒": { "codepoints": [10514], "characters": "\u2912" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "Υ": { "codepoints": [933], "characters": "\u03A5" }, + "Ů": { "codepoints": [366], "characters": "\u016E" }, + "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" }, + "Ũ": { "codepoints": [360], "characters": "\u0168" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "Ü": { "codepoints": [220], "characters": "\u00DC" }, + "⊫": { "codepoints": [8875], "characters": "\u22AB" }, + "⫫": { "codepoints": [10987], "characters": "\u2AEB" }, + "В": { "codepoints": [1042], "characters": "\u0412" }, + "⊩": { "codepoints": [8873], "characters": "\u22A9" }, + "⫦": { "codepoints": [10982], "characters": "\u2AE6" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "‖": { "codepoints": [8214], "characters": "\u2016" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "❘": { "codepoints": [10072], "characters": "\u2758" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" }, + "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" }, + "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" }, + "⊪": { "codepoints": [8874], "characters": "\u22AA" }, + "Ŵ": { "codepoints": [372], "characters": "\u0174" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" }, + "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" }, + "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" }, + "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" }, + "Ξ": { "codepoints": [926], "characters": "\u039E" }, + "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" }, + "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" }, + "Я": { "codepoints": [1071], "characters": "\u042F" }, + "Ї": { "codepoints": [1031], "characters": "\u0407" }, + "Ю": { "codepoints": [1070], "characters": "\u042E" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ý": { "codepoints": [221], "characters": "\u00DD" }, + "Ŷ": { "codepoints": [374], "characters": "\u0176" }, + "Ы": { "codepoints": [1067], "characters": "\u042B" }, + "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" }, + "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" }, + "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" }, + "Ÿ": { "codepoints": [376], "characters": "\u0178" }, + "Ж": { "codepoints": [1046], "characters": "\u0416" }, + "Ź": { "codepoints": [377], "characters": "\u0179" }, + "Ž": { "codepoints": [381], "characters": "\u017D" }, + "З": { "codepoints": [1047], "characters": "\u0417" }, + "Ż": { "codepoints": [379], "characters": "\u017B" }, + "​": { "codepoints": [8203], "characters": "\u200B" }, + "Ζ": { "codepoints": [918], "characters": "\u0396" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "á": { "codepoints": [225], "characters": "\u00E1" }, + "ă": { "codepoints": [259], "characters": "\u0103" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" }, + "∿": { "codepoints": [8767], "characters": "\u223F" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "â": { "codepoints": [226], "characters": "\u00E2" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "´": { "codepoints": [180], "characters": "\u00B4" }, + "а": { "codepoints": [1072], "characters": "\u0430" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "æ": { "codepoints": [230], "characters": "\u00E6" }, + "⁡": { "codepoints": [8289], "characters": "\u2061" }, + "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "à": { "codepoints": [224], "characters": "\u00E0" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "ℵ": { "codepoints": [8501], "characters": "\u2135" }, + "α": { "codepoints": [945], "characters": "\u03B1" }, + "ā": { "codepoints": [257], "characters": "\u0101" }, + "⨿": { "codepoints": [10815], "characters": "\u2A3F" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "&": { "codepoints": [38], "characters": "\u0026" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "⩕": { "codepoints": [10837], "characters": "\u2A55" }, + "⩜": { "codepoints": [10844], "characters": "\u2A5C" }, + "⩘": { "codepoints": [10840], "characters": "\u2A58" }, + "⩚": { "codepoints": [10842], "characters": "\u2A5A" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "⦤": { "codepoints": [10660], "characters": "\u29A4" }, + "∠": { "codepoints": [8736], "characters": "\u2220" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "⦨": { "codepoints": [10664], "characters": "\u29A8" }, + "⦩": { "codepoints": [10665], "characters": "\u29A9" }, + "⦪": { "codepoints": [10666], "characters": "\u29AA" }, + "⦫": { "codepoints": [10667], "characters": "\u29AB" }, + "⦬": { "codepoints": [10668], "characters": "\u29AC" }, + "⦭": { "codepoints": [10669], "characters": "\u29AD" }, + "⦮": { "codepoints": [10670], "characters": "\u29AE" }, + "⦯": { "codepoints": [10671], "characters": "\u29AF" }, + "∟": { "codepoints": [8735], "characters": "\u221F" }, + "⊾": { "codepoints": [8894], "characters": "\u22BE" }, + "⦝": { "codepoints": [10653], "characters": "\u299D" }, + "∢": { "codepoints": [8738], "characters": "\u2222" }, + "Å": { "codepoints": [197], "characters": "\u00C5" }, + "⍼": { "codepoints": [9084], "characters": "\u237C" }, + "ą": { "codepoints": [261], "characters": "\u0105" }, + "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "⩰": { "codepoints": [10864], "characters": "\u2A70" }, + "⩯": { "codepoints": [10863], "characters": "\u2A6F" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "≋": { "codepoints": [8779], "characters": "\u224B" }, + "'": { "codepoints": [39], "characters": "\u0027" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≊": { "codepoints": [8778], "characters": "\u224A" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "å": { "codepoints": [229], "characters": "\u00E5" }, + "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "≍": { "codepoints": [8781], "characters": "\u224D" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ã": { "codepoints": [227], "characters": "\u00E3" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "ä": { "codepoints": [228], "characters": "\u00E4" }, + "∳": { "codepoints": [8755], "characters": "\u2233" }, + "⨑": { "codepoints": [10769], "characters": "\u2A11" }, + "⫭": { "codepoints": [10989], "characters": "\u2AED" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "⊽": { "codepoints": [8893], "characters": "\u22BD" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⌅": { "codepoints": [8965], "characters": "\u2305" }, + "⎵": { "codepoints": [9141], "characters": "\u23B5" }, + "⎶": { "codepoints": [9142], "characters": "\u23B6" }, + "≌": { "codepoints": [8780], "characters": "\u224C" }, + "б": { "codepoints": [1073], "characters": "\u0431" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "∵": { "codepoints": [8757], "characters": "\u2235" }, + "⦰": { "codepoints": [10672], "characters": "\u29B0" }, + "϶": { "codepoints": [1014], "characters": "\u03F6" }, + "ℬ": { "codepoints": [8492], "characters": "\u212C" }, + "β": { "codepoints": [946], "characters": "\u03B2" }, + "ℶ": { "codepoints": [8502], "characters": "\u2136" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "␣": { "codepoints": [9251], "characters": "\u2423" }, + "▒": { "codepoints": [9618], "characters": "\u2592" }, + "░": { "codepoints": [9617], "characters": "\u2591" }, + "▓": { "codepoints": [9619], "characters": "\u2593" }, + "█": { "codepoints": [9608], "characters": "\u2588" }, + "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" }, + "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" }, + "⌐": { "codepoints": [8976], "characters": "\u2310" }, + "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "⋈": { "codepoints": [8904], "characters": "\u22C8" }, + "╗": { "codepoints": [9559], "characters": "\u2557" }, + "╔": { "codepoints": [9556], "characters": "\u2554" }, + "╖": { "codepoints": [9558], "characters": "\u2556" }, + "╓": { "codepoints": [9555], "characters": "\u2553" }, + "═": { "codepoints": [9552], "characters": "\u2550" }, + "╦": { "codepoints": [9574], "characters": "\u2566" }, + "╩": { "codepoints": [9577], "characters": "\u2569" }, + "╤": { "codepoints": [9572], "characters": "\u2564" }, + "╧": { "codepoints": [9575], "characters": "\u2567" }, + "╝": { "codepoints": [9565], "characters": "\u255D" }, + "╚": { "codepoints": [9562], "characters": "\u255A" }, + "╜": { "codepoints": [9564], "characters": "\u255C" }, + "╙": { "codepoints": [9561], "characters": "\u2559" }, + "║": { "codepoints": [9553], "characters": "\u2551" }, + "╬": { "codepoints": [9580], "characters": "\u256C" }, + "╣": { "codepoints": [9571], "characters": "\u2563" }, + "╠": { "codepoints": [9568], "characters": "\u2560" }, + "╫": { "codepoints": [9579], "characters": "\u256B" }, + "╢": { "codepoints": [9570], "characters": "\u2562" }, + "╟": { "codepoints": [9567], "characters": "\u255F" }, + "⧉": { "codepoints": [10697], "characters": "\u29C9" }, + "╕": { "codepoints": [9557], "characters": "\u2555" }, + "╒": { "codepoints": [9554], "characters": "\u2552" }, + "┐": { "codepoints": [9488], "characters": "\u2510" }, + "┌": { "codepoints": [9484], "characters": "\u250C" }, + "─": { "codepoints": [9472], "characters": "\u2500" }, + "╥": { "codepoints": [9573], "characters": "\u2565" }, + "╨": { "codepoints": [9576], "characters": "\u2568" }, + "┬": { "codepoints": [9516], "characters": "\u252C" }, + "┴": { "codepoints": [9524], "characters": "\u2534" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "╛": { "codepoints": [9563], "characters": "\u255B" }, + "╘": { "codepoints": [9560], "characters": "\u2558" }, + "┘": { "codepoints": [9496], "characters": "\u2518" }, + "└": { "codepoints": [9492], "characters": "\u2514" }, + "│": { "codepoints": [9474], "characters": "\u2502" }, + "╪": { "codepoints": [9578], "characters": "\u256A" }, + "╡": { "codepoints": [9569], "characters": "\u2561" }, + "╞": { "codepoints": [9566], "characters": "\u255E" }, + "┼": { "codepoints": [9532], "characters": "\u253C" }, + "┤": { "codepoints": [9508], "characters": "\u2524" }, + "├": { "codepoints": [9500], "characters": "\u251C" }, + "‵": { "codepoints": [8245], "characters": "\u2035" }, + "˘": { "codepoints": [728], "characters": "\u02D8" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "¦": { "codepoints": [166], "characters": "\u00A6" }, + "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" }, + "⁏": { "codepoints": [8271], "characters": "\u204F" }, + "∽": { "codepoints": [8765], "characters": "\u223D" }, + "⋍": { "codepoints": [8909], "characters": "\u22CD" }, + "\": { "codepoints": [92], "characters": "\u005C" }, + "⧅": { "codepoints": [10693], "characters": "\u29C5" }, + "⟈": { "codepoints": [10184], "characters": "\u27C8" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "•": { "codepoints": [8226], "characters": "\u2022" }, + "≎": { "codepoints": [8782], "characters": "\u224E" }, + "⪮": { "codepoints": [10926], "characters": "\u2AAE" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "≏": { "codepoints": [8783], "characters": "\u224F" }, + "ć": { "codepoints": [263], "characters": "\u0107" }, + "∩": { "codepoints": [8745], "characters": "\u2229" }, + "⩄": { "codepoints": [10820], "characters": "\u2A44" }, + "⩉": { "codepoints": [10825], "characters": "\u2A49" }, + "⩋": { "codepoints": [10827], "characters": "\u2A4B" }, + "⩇": { "codepoints": [10823], "characters": "\u2A47" }, + "⩀": { "codepoints": [10816], "characters": "\u2A40" }, + "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" }, + "⁁": { "codepoints": [8257], "characters": "\u2041" }, + "ˇ": { "codepoints": [711], "characters": "\u02C7" }, + "⩍": { "codepoints": [10829], "characters": "\u2A4D" }, + "č": { "codepoints": [269], "characters": "\u010D" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ç": { "codepoints": [231], "characters": "\u00E7" }, + "ĉ": { "codepoints": [265], "characters": "\u0109" }, + "⩌": { "codepoints": [10828], "characters": "\u2A4C" }, + "⩐": { "codepoints": [10832], "characters": "\u2A50" }, + "ċ": { "codepoints": [267], "characters": "\u010B" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "¸": { "codepoints": [184], "characters": "\u00B8" }, + "⦲": { "codepoints": [10674], "characters": "\u29B2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "¢": { "codepoints": [162], "characters": "\u00A2" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" }, + "ч": { "codepoints": [1095], "characters": "\u0447" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "✓": { "codepoints": [10003], "characters": "\u2713" }, + "χ": { "codepoints": [967], "characters": "\u03C7" }, + "○": { "codepoints": [9675], "characters": "\u25CB" }, + "⧃": { "codepoints": [10691], "characters": "\u29C3" }, + "ˆ": { "codepoints": [710], "characters": "\u02C6" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "≗": { "codepoints": [8791], "characters": "\u2257" }, + "⨐": { "codepoints": [10768], "characters": "\u2A10" }, + "⫯": { "codepoints": [10991], "characters": "\u2AEF" }, + "⧂": { "codepoints": [10690], "characters": "\u29C2" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + "♣": { "codepoints": [9827], "characters": "\u2663" }, + ":": { "codepoints": [58], "characters": "\u003A" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + "≔": { "codepoints": [8788], "characters": "\u2254" }, + ",": { "codepoints": [44], "characters": "\u002C" }, + "@": { "codepoints": [64], "characters": "\u0040" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "∘": { "codepoints": [8728], "characters": "\u2218" }, + "∁": { "codepoints": [8705], "characters": "\u2201" }, + "ℂ": { "codepoints": [8450], "characters": "\u2102" }, + "≅": { "codepoints": [8773], "characters": "\u2245" }, + "⩭": { "codepoints": [10861], "characters": "\u2A6D" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" }, + "∐": { "codepoints": [8720], "characters": "\u2210" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "©": { "codepoints": [169], "characters": "\u00A9" }, + "℗": { "codepoints": [8471], "characters": "\u2117" }, + "↵": { "codepoints": [8629], "characters": "\u21B5" }, + "✗": { "codepoints": [10007], "characters": "\u2717" }, + "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" }, + "⫏": { "codepoints": [10959], "characters": "\u2ACF" }, + "⫑": { "codepoints": [10961], "characters": "\u2AD1" }, + "⫐": { "codepoints": [10960], "characters": "\u2AD0" }, + "⫒": { "codepoints": [10962], "characters": "\u2AD2" }, + "⋯": { "codepoints": [8943], "characters": "\u22EF" }, + "⤸": { "codepoints": [10552], "characters": "\u2938" }, + "⤵": { "codepoints": [10549], "characters": "\u2935" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "⤽": { "codepoints": [10557], "characters": "\u293D" }, + "∪": { "codepoints": [8746], "characters": "\u222A" }, + "⩈": { "codepoints": [10824], "characters": "\u2A48" }, + "⩆": { "codepoints": [10822], "characters": "\u2A46" }, + "⩊": { "codepoints": [10826], "characters": "\u2A4A" }, + "⊍": { "codepoints": [8845], "characters": "\u228D" }, + "⩅": { "codepoints": [10821], "characters": "\u2A45" }, + "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⤼": { "codepoints": [10556], "characters": "\u293C" }, + "⋞": { "codepoints": [8926], "characters": "\u22DE" }, + "⋟": { "codepoints": [8927], "characters": "\u22DF" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "¤": { "codepoints": [164], "characters": "\u00A4" }, + "↶": { "codepoints": [8630], "characters": "\u21B6" }, + "↷": { "codepoints": [8631], "characters": "\u21B7" }, + "⋎": { "codepoints": [8910], "characters": "\u22CE" }, + "⋏": { "codepoints": [8911], "characters": "\u22CF" }, + "∲": { "codepoints": [8754], "characters": "\u2232" }, + "∱": { "codepoints": [8753], "characters": "\u2231" }, + "⌭": { "codepoints": [9005], "characters": "\u232D" }, + "⇓": { "codepoints": [8659], "characters": "\u21D3" }, + "⥥": { "codepoints": [10597], "characters": "\u2965" }, + "†": { "codepoints": [8224], "characters": "\u2020" }, + "ℸ": { "codepoints": [8504], "characters": "\u2138" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "⊣": { "codepoints": [8867], "characters": "\u22A3" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "˝": { "codepoints": [733], "characters": "\u02DD" }, + "ď": { "codepoints": [271], "characters": "\u010F" }, + "д": { "codepoints": [1076], "characters": "\u0434" }, + "ⅆ": { "codepoints": [8518], "characters": "\u2146" }, + "‡": { "codepoints": [8225], "characters": "\u2021" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "°": { "codepoints": [176], "characters": "\u00B0" }, + "δ": { "codepoints": [948], "characters": "\u03B4" }, + "⦱": { "codepoints": [10673], "characters": "\u29B1" }, + "⥿": { "codepoints": [10623], "characters": "\u297F" }, + "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "⋄": { "codepoints": [8900], "characters": "\u22C4" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "♦": { "codepoints": [9830], "characters": "\u2666" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⋲": { "codepoints": [8946], "characters": "\u22F2" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "÷": { "codepoints": [247], "characters": "\u00F7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "⋇": { "codepoints": [8903], "characters": "\u22C7" }, + "ђ": { "codepoints": [1106], "characters": "\u0452" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⌍": { "codepoints": [8973], "characters": "\u230D" }, + "$": { "codepoints": [36], "characters": "\u0024" }, + "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" }, + "˙": { "codepoints": [729], "characters": "\u02D9" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⌆": { "codepoints": [8966], "characters": "\u2306" }, + "↓": { "codepoints": [8595], "characters": "\u2193" }, + "⇊": { "codepoints": [8650], "characters": "\u21CA" }, + "⇃": { "codepoints": [8643], "characters": "\u21C3" }, + "⇂": { "codepoints": [8642], "characters": "\u21C2" }, + "⤐": { "codepoints": [10512], "characters": "\u2910" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⌌": { "codepoints": [8972], "characters": "\u230C" }, + "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" }, + "ѕ": { "codepoints": [1109], "characters": "\u0455" }, + "⧶": { "codepoints": [10742], "characters": "\u29F6" }, + "đ": { "codepoints": [273], "characters": "\u0111" }, + "⋱": { "codepoints": [8945], "characters": "\u22F1" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "▾": { "codepoints": [9662], "characters": "\u25BE" }, + "⇵": { "codepoints": [8693], "characters": "\u21F5" }, + "⥯": { "codepoints": [10607], "characters": "\u296F" }, + "⦦": { "codepoints": [10662], "characters": "\u29A6" }, + "џ": { "codepoints": [1119], "characters": "\u045F" }, + "⟿": { "codepoints": [10239], "characters": "\u27FF" }, + "⩷": { "codepoints": [10871], "characters": "\u2A77" }, + "≑": { "codepoints": [8785], "characters": "\u2251" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "é": { "codepoints": [233], "characters": "\u00E9" }, + "⩮": { "codepoints": [10862], "characters": "\u2A6E" }, + "ě": { "codepoints": [283], "characters": "\u011B" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "ê": { "codepoints": [234], "characters": "\u00EA" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "э": { "codepoints": [1101], "characters": "\u044D" }, + "ė": { "codepoints": [279], "characters": "\u0117" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" }, + "⪚": { "codepoints": [10906], "characters": "\u2A9A" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "è": { "codepoints": [232], "characters": "\u00E8" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪘": { "codepoints": [10904], "characters": "\u2A98" }, + "⪙": { "codepoints": [10905], "characters": "\u2A99" }, + "⏧": { "codepoints": [9191], "characters": "\u23E7" }, + "ℓ": { "codepoints": [8467], "characters": "\u2113" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "⪗": { "codepoints": [10903], "characters": "\u2A97" }, + "ē": { "codepoints": [275], "characters": "\u0113" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + " ": { "codepoints": [8196], "characters": "\u2004" }, + " ": { "codepoints": [8197], "characters": "\u2005" }, + " ": { "codepoints": [8195], "characters": "\u2003" }, + "ŋ": { "codepoints": [331], "characters": "\u014B" }, + " ": { "codepoints": [8194], "characters": "\u2002" }, + "ę": { "codepoints": [281], "characters": "\u0119" }, + "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" }, + "⋕": { "codepoints": [8917], "characters": "\u22D5" }, + "⧣": { "codepoints": [10723], "characters": "\u29E3" }, + "⩱": { "codepoints": [10865], "characters": "\u2A71" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ε": { "codepoints": [949], "characters": "\u03B5" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "≖": { "codepoints": [8790], "characters": "\u2256" }, + "≕": { "codepoints": [8789], "characters": "\u2255" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "⪖": { "codepoints": [10902], "characters": "\u2A96" }, + "⪕": { "codepoints": [10901], "characters": "\u2A95" }, + "=": { "codepoints": [61], "characters": "\u003D" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + "≡": { "codepoints": [8801], "characters": "\u2261" }, + "⩸": { "codepoints": [10872], "characters": "\u2A78" }, + "⧥": { "codepoints": [10725], "characters": "\u29E5" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⥱": { "codepoints": [10609], "characters": "\u2971" }, + "ℯ": { "codepoints": [8495], "characters": "\u212F" }, + "≐": { "codepoints": [8784], "characters": "\u2250" }, + "≂": { "codepoints": [8770], "characters": "\u2242" }, + "η": { "codepoints": [951], "characters": "\u03B7" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ð": { "codepoints": [240], "characters": "\u00F0" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "ë": { "codepoints": [235], "characters": "\u00EB" }, + "€": { "codepoints": [8364], "characters": "\u20AC" }, + "!": { "codepoints": [33], "characters": "\u0021" }, + "∃": { "codepoints": [8707], "characters": "\u2203" }, + "ℰ": { "codepoints": [8496], "characters": "\u2130" }, + "ⅇ": { "codepoints": [8519], "characters": "\u2147" }, + "≒": { "codepoints": [8786], "characters": "\u2252" }, + "ф": { "codepoints": [1092], "characters": "\u0444" }, + "♀": { "codepoints": [9792], "characters": "\u2640" }, + "ffi": { "codepoints": [64259], "characters": "\uFB03" }, + "ff": { "codepoints": [64256], "characters": "\uFB00" }, + "ffl": { "codepoints": [64260], "characters": "\uFB04" }, + "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" }, + "fi": { "codepoints": [64257], "characters": "\uFB01" }, + "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" }, + "♭": { "codepoints": [9837], "characters": "\u266D" }, + "fl": { "codepoints": [64258], "characters": "\uFB02" }, + "▱": { "codepoints": [9649], "characters": "\u25B1" }, + "ƒ": { "codepoints": [402], "characters": "\u0192" }, + "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" }, + "∀": { "codepoints": [8704], "characters": "\u2200" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "⫙": { "codepoints": [10969], "characters": "\u2AD9" }, + "⨍": { "codepoints": [10765], "characters": "\u2A0D" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "⅓": { "codepoints": [8531], "characters": "\u2153" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "¼": { "codepoints": [188], "characters": "\u00BC" }, + "⅕": { "codepoints": [8533], "characters": "\u2155" }, + "⅙": { "codepoints": [8537], "characters": "\u2159" }, + "⅛": { "codepoints": [8539], "characters": "\u215B" }, + "⅔": { "codepoints": [8532], "characters": "\u2154" }, + "⅖": { "codepoints": [8534], "characters": "\u2156" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "¾": { "codepoints": [190], "characters": "\u00BE" }, + "⅗": { "codepoints": [8535], "characters": "\u2157" }, + "⅜": { "codepoints": [8540], "characters": "\u215C" }, + "⅘": { "codepoints": [8536], "characters": "\u2158" }, + "⅚": { "codepoints": [8538], "characters": "\u215A" }, + "⅝": { "codepoints": [8541], "characters": "\u215D" }, + "⅞": { "codepoints": [8542], "characters": "\u215E" }, + "⁄": { "codepoints": [8260], "characters": "\u2044" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "ǵ": { "codepoints": [501], "characters": "\u01F5" }, + "γ": { "codepoints": [947], "characters": "\u03B3" }, + "ϝ": { "codepoints": [989], "characters": "\u03DD" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "ğ": { "codepoints": [287], "characters": "\u011F" }, + "ĝ": { "codepoints": [285], "characters": "\u011D" }, + "г": { "codepoints": [1075], "characters": "\u0433" }, + "ġ": { "codepoints": [289], "characters": "\u0121" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "≥": { "codepoints": [8805], "characters": "\u2265" }, + "≧": { "codepoints": [8807], "characters": "\u2267" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⩾": { "codepoints": [10878], "characters": "\u2A7E" }, + "⪩": { "codepoints": [10921], "characters": "\u2AA9" }, + "⪀": { "codepoints": [10880], "characters": "\u2A80" }, + "⪂": { "codepoints": [10882], "characters": "\u2A82" }, + "⪄": { "codepoints": [10884], "characters": "\u2A84" }, + "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" }, + "⪔": { "codepoints": [10900], "characters": "\u2A94" }, + "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" }, + "≫": { "codepoints": [8811], "characters": "\u226B" }, + "⋙": { "codepoints": [8921], "characters": "\u22D9" }, + "ℷ": { "codepoints": [8503], "characters": "\u2137" }, + "ѓ": { "codepoints": [1107], "characters": "\u0453" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "⪒": { "codepoints": [10898], "characters": "\u2A92" }, + "⪥": { "codepoints": [10917], "characters": "\u2AA5" }, + "⪤": { "codepoints": [10916], "characters": "\u2AA4" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪊": { "codepoints": [10890], "characters": "\u2A8A" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "⪈": { "codepoints": [10888], "characters": "\u2A88" }, + "≩": { "codepoints": [8809], "characters": "\u2269" }, + "⋧": { "codepoints": [8935], "characters": "\u22E7" }, + "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" }, + "`": { "codepoints": [96], "characters": "\u0060" }, + "ℊ": { "codepoints": [8458], "characters": "\u210A" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "⪎": { "codepoints": [10894], "characters": "\u2A8E" }, + "⪐": { "codepoints": [10896], "characters": "\u2A90" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + ">": { "codepoints": [62], "characters": "\u003E" }, + "⪧": { "codepoints": [10919], "characters": "\u2AA7" }, + "⩺": { "codepoints": [10874], "characters": "\u2A7A" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⦕": { "codepoints": [10645], "characters": "\u2995" }, + "⩼": { "codepoints": [10876], "characters": "\u2A7C" }, + "⪆": { "codepoints": [10886], "characters": "\u2A86" }, + "⥸": { "codepoints": [10616], "characters": "\u2978" }, + "⋗": { "codepoints": [8919], "characters": "\u22D7" }, + "⋛": { "codepoints": [8923], "characters": "\u22DB" }, + "⪌": { "codepoints": [10892], "characters": "\u2A8C" }, + "≷": { "codepoints": [8823], "characters": "\u2277" }, + "≳": { "codepoints": [8819], "characters": "\u2273" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + " ": { "codepoints": [8202], "characters": "\u200A" }, + "½": { "codepoints": [189], "characters": "\u00BD" }, + "ℋ": { "codepoints": [8459], "characters": "\u210B" }, + "ъ": { "codepoints": [1098], "characters": "\u044A" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⥈": { "codepoints": [10568], "characters": "\u2948" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ĥ": { "codepoints": [293], "characters": "\u0125" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "♥": { "codepoints": [9829], "characters": "\u2665" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "⊹": { "codepoints": [8889], "characters": "\u22B9" }, + "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "⇿": { "codepoints": [8703], "characters": "\u21FF" }, + "∻": { "codepoints": [8763], "characters": "\u223B" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" }, + "―": { "codepoints": [8213], "characters": "\u2015" }, + "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ħ": { "codepoints": [295], "characters": "\u0127" }, + "⁃": { "codepoints": [8259], "characters": "\u2043" }, + "‐": { "codepoints": [8208], "characters": "\u2010" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "í": { "codepoints": [237], "characters": "\u00ED" }, + "⁣": { "codepoints": [8291], "characters": "\u2063" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "î": { "codepoints": [238], "characters": "\u00EE" }, + "и": { "codepoints": [1080], "characters": "\u0438" }, + "е": { "codepoints": [1077], "characters": "\u0435" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "¡": { "codepoints": [161], "characters": "\u00A1" }, + "⇔": { "codepoints": [8660], "characters": "\u21D4" }, + "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ì": { "codepoints": [236], "characters": "\u00EC" }, + "ⅈ": { "codepoints": [8520], "characters": "\u2148" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⧜": { "codepoints": [10716], "characters": "\u29DC" }, + "℩": { "codepoints": [8489], "characters": "\u2129" }, + "ij": { "codepoints": [307], "characters": "\u0133" }, + "ī": { "codepoints": [299], "characters": "\u012B" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ℐ": { "codepoints": [8464], "characters": "\u2110" }, + "ℑ": { "codepoints": [8465], "characters": "\u2111" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "⊷": { "codepoints": [8887], "characters": "\u22B7" }, + "Ƶ": { "codepoints": [437], "characters": "\u01B5" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "℅": { "codepoints": [8453], "characters": "\u2105" }, + "∞": { "codepoints": [8734], "characters": "\u221E" }, + "⧝": { "codepoints": [10717], "characters": "\u29DD" }, + "ı": { "codepoints": [305], "characters": "\u0131" }, + "∫": { "codepoints": [8747], "characters": "\u222B" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "ℤ": { "codepoints": [8484], "characters": "\u2124" }, + "⊺": { "codepoints": [8890], "characters": "\u22BA" }, + "⨗": { "codepoints": [10775], "characters": "\u2A17" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "ё": { "codepoints": [1105], "characters": "\u0451" }, + "į": { "codepoints": [303], "characters": "\u012F" }, + "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" }, + "ι": { "codepoints": [953], "characters": "\u03B9" }, + "⨼": { "codepoints": [10812], "characters": "\u2A3C" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "¿": { "codepoints": [191], "characters": "\u00BF" }, + "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⋹": { "codepoints": [8953], "characters": "\u22F9" }, + "⋵": { "codepoints": [8949], "characters": "\u22F5" }, + "⋴": { "codepoints": [8948], "characters": "\u22F4" }, + "⋳": { "codepoints": [8947], "characters": "\u22F3" }, + "∈": { "codepoints": [8712], "characters": "\u2208" }, + "⁢": { "codepoints": [8290], "characters": "\u2062" }, + "ĩ": { "codepoints": [297], "characters": "\u0129" }, + "і": { "codepoints": [1110], "characters": "\u0456" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ï": { "codepoints": [239], "characters": "\u00EF" }, + "ĵ": { "codepoints": [309], "characters": "\u0135" }, + "й": { "codepoints": [1081], "characters": "\u0439" }, + "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" }, + "ȷ": { "codepoints": [567], "characters": "\u0237" }, + "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" }, + "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" }, + "ј": { "codepoints": [1112], "characters": "\u0458" }, + "є": { "codepoints": [1108], "characters": "\u0454" }, + "κ": { "codepoints": [954], "characters": "\u03BA" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "ķ": { "codepoints": [311], "characters": "\u0137" }, + "к": { "codepoints": [1082], "characters": "\u043A" }, + "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" }, + "ĸ": { "codepoints": [312], "characters": "\u0138" }, + "х": { "codepoints": [1093], "characters": "\u0445" }, + "ќ": { "codepoints": [1116], "characters": "\u045C" }, + "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" }, + "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" }, + "⇚": { "codepoints": [8666], "characters": "\u21DA" }, + "⇐": { "codepoints": [8656], "characters": "\u21D0" }, + "⤛": { "codepoints": [10523], "characters": "\u291B" }, + "⤎": { "codepoints": [10510], "characters": "\u290E" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "⥢": { "codepoints": [10594], "characters": "\u2962" }, + "ĺ": { "codepoints": [314], "characters": "\u013A" }, + "⦴": { "codepoints": [10676], "characters": "\u29B4" }, + "ℒ": { "codepoints": [8466], "characters": "\u2112" }, + "λ": { "codepoints": [955], "characters": "\u03BB" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⦑": { "codepoints": [10641], "characters": "\u2991" }, + "⟨": { "codepoints": [10216], "characters": "\u27E8" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "«": { "codepoints": [171], "characters": "\u00AB" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "⇤": { "codepoints": [8676], "characters": "\u21E4" }, + "⤟": { "codepoints": [10527], "characters": "\u291F" }, + "⤝": { "codepoints": [10525], "characters": "\u291D" }, + "↩": { "codepoints": [8617], "characters": "\u21A9" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "⤹": { "codepoints": [10553], "characters": "\u2939" }, + "⥳": { "codepoints": [10611], "characters": "\u2973" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "⪫": { "codepoints": [10923], "characters": "\u2AAB" }, + "⤙": { "codepoints": [10521], "characters": "\u2919" }, + "⪭": { "codepoints": [10925], "characters": "\u2AAD" }, + "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" }, + "⤌": { "codepoints": [10508], "characters": "\u290C" }, + "❲": { "codepoints": [10098], "characters": "\u2772" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "⦋": { "codepoints": [10635], "characters": "\u298B" }, + "⦏": { "codepoints": [10639], "characters": "\u298F" }, + "⦍": { "codepoints": [10637], "characters": "\u298D" }, + "ľ": { "codepoints": [318], "characters": "\u013E" }, + "ļ": { "codepoints": [316], "characters": "\u013C" }, + "⌈": { "codepoints": [8968], "characters": "\u2308" }, + "{": { "codepoints": [123], "characters": "\u007B" }, + "л": { "codepoints": [1083], "characters": "\u043B" }, + "⤶": { "codepoints": [10550], "characters": "\u2936" }, + "“": { "codepoints": [8220], "characters": "\u201C" }, + "„": { "codepoints": [8222], "characters": "\u201E" }, + "⥧": { "codepoints": [10599], "characters": "\u2967" }, + "⥋": { "codepoints": [10571], "characters": "\u294B" }, + "↲": { "codepoints": [8626], "characters": "\u21B2" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "↢": { "codepoints": [8610], "characters": "\u21A2" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "↔": { "codepoints": [8596], "characters": "\u2194" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "↭": { "codepoints": [8621], "characters": "\u21AD" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "≤": { "codepoints": [8804], "characters": "\u2264" }, + "≦": { "codepoints": [8806], "characters": "\u2266" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⩽": { "codepoints": [10877], "characters": "\u2A7D" }, + "⪨": { "codepoints": [10920], "characters": "\u2AA8" }, + "⩿": { "codepoints": [10879], "characters": "\u2A7F" }, + "⪁": { "codepoints": [10881], "characters": "\u2A81" }, + "⪃": { "codepoints": [10883], "characters": "\u2A83" }, + "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" }, + "⪓": { "codepoints": [10899], "characters": "\u2A93" }, + "⪅": { "codepoints": [10885], "characters": "\u2A85" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋚": { "codepoints": [8922], "characters": "\u22DA" }, + "⪋": { "codepoints": [10891], "characters": "\u2A8B" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⥼": { "codepoints": [10620], "characters": "\u297C" }, + "⌊": { "codepoints": [8970], "characters": "\u230A" }, + "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" }, + "≶": { "codepoints": [8822], "characters": "\u2276" }, + "⪑": { "codepoints": [10897], "characters": "\u2A91" }, + "↽": { "codepoints": [8637], "characters": "\u21BD" }, + "↼": { "codepoints": [8636], "characters": "\u21BC" }, + "⥪": { "codepoints": [10602], "characters": "\u296A" }, + "▄": { "codepoints": [9604], "characters": "\u2584" }, + "љ": { "codepoints": [1113], "characters": "\u0459" }, + "≪": { "codepoints": [8810], "characters": "\u226A" }, + "⇇": { "codepoints": [8647], "characters": "\u21C7" }, + "⌞": { "codepoints": [8990], "characters": "\u231E" }, + "⥫": { "codepoints": [10603], "characters": "\u296B" }, + "◺": { "codepoints": [9722], "characters": "\u25FA" }, + "ŀ": { "codepoints": [320], "characters": "\u0140" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "⎰": { "codepoints": [9136], "characters": "\u23B0" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪉": { "codepoints": [10889], "characters": "\u2A89" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "⪇": { "codepoints": [10887], "characters": "\u2A87" }, + "≨": { "codepoints": [8808], "characters": "\u2268" }, + "⋦": { "codepoints": [8934], "characters": "\u22E6" }, + "⟬": { "codepoints": [10220], "characters": "\u27EC" }, + "⇽": { "codepoints": [8701], "characters": "\u21FD" }, + "⟦": { "codepoints": [10214], "characters": "\u27E6" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "↫": { "codepoints": [8619], "characters": "\u21AB" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⦅": { "codepoints": [10629], "characters": "\u2985" }, + "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" }, + "⨭": { "codepoints": [10797], "characters": "\u2A2D" }, + "⨴": { "codepoints": [10804], "characters": "\u2A34" }, + "∗": { "codepoints": [8727], "characters": "\u2217" }, + "_": { "codepoints": [95], "characters": "\u005F" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "◊": { "codepoints": [9674], "characters": "\u25CA" }, + "⧫": { "codepoints": [10731], "characters": "\u29EB" }, + "(": { "codepoints": [40], "characters": "\u0028" }, + "⦓": { "codepoints": [10643], "characters": "\u2993" }, + "⇆": { "codepoints": [8646], "characters": "\u21C6" }, + "⌟": { "codepoints": [8991], "characters": "\u231F" }, + "⇋": { "codepoints": [8651], "characters": "\u21CB" }, + "⥭": { "codepoints": [10605], "characters": "\u296D" }, + "‎": { "codepoints": [8206], "characters": "\u200E" }, + "⊿": { "codepoints": [8895], "characters": "\u22BF" }, + "‹": { "codepoints": [8249], "characters": "\u2039" }, + "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" }, + "↰": { "codepoints": [8624], "characters": "\u21B0" }, + "≲": { "codepoints": [8818], "characters": "\u2272" }, + "⪍": { "codepoints": [10893], "characters": "\u2A8D" }, + "⪏": { "codepoints": [10895], "characters": "\u2A8F" }, + "[": { "codepoints": [91], "characters": "\u005B" }, + "‘": { "codepoints": [8216], "characters": "\u2018" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "ł": { "codepoints": [322], "characters": "\u0142" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "<": { "codepoints": [60], "characters": "\u003C" }, + "⪦": { "codepoints": [10918], "characters": "\u2AA6" }, + "⩹": { "codepoints": [10873], "characters": "\u2A79" }, + "⋖": { "codepoints": [8918], "characters": "\u22D6" }, + "⋋": { "codepoints": [8907], "characters": "\u22CB" }, + "⋉": { "codepoints": [8905], "characters": "\u22C9" }, + "⥶": { "codepoints": [10614], "characters": "\u2976" }, + "⩻": { "codepoints": [10875], "characters": "\u2A7B" }, + "⦖": { "codepoints": [10646], "characters": "\u2996" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "◂": { "codepoints": [9666], "characters": "\u25C2" }, + "⥊": { "codepoints": [10570], "characters": "\u294A" }, + "⥦": { "codepoints": [10598], "characters": "\u2966" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" }, + "∺": { "codepoints": [8762], "characters": "\u223A" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "♂": { "codepoints": [9794], "characters": "\u2642" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "✠": { "codepoints": [10016], "characters": "\u2720" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↦": { "codepoints": [8614], "characters": "\u21A6" }, + "↧": { "codepoints": [8615], "characters": "\u21A7" }, + "↤": { "codepoints": [8612], "characters": "\u21A4" }, + "↥": { "codepoints": [8613], "characters": "\u21A5" }, + "▮": { "codepoints": [9646], "characters": "\u25AE" }, + "⨩": { "codepoints": [10793], "characters": "\u2A29" }, + "м": { "codepoints": [1084], "characters": "\u043C" }, + "—": { "codepoints": [8212], "characters": "\u2014" }, + "∡": { "codepoints": [8737], "characters": "\u2221" }, + "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" }, + "℧": { "codepoints": [8487], "characters": "\u2127" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "µ": { "codepoints": [181], "characters": "\u00B5" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "*": { "codepoints": [42], "characters": "\u002A" }, + "⫰": { "codepoints": [10992], "characters": "\u2AF0" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "·": { "codepoints": [183], "characters": "\u00B7" }, + "−": { "codepoints": [8722], "characters": "\u2212" }, + "⊟": { "codepoints": [8863], "characters": "\u229F" }, + "∸": { "codepoints": [8760], "characters": "\u2238" }, + "⨪": { "codepoints": [10794], "characters": "\u2A2A" }, + "⫛": { "codepoints": [10971], "characters": "\u2ADB" }, + "…": { "codepoints": [8230], "characters": "\u2026" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "⊧": { "codepoints": [8871], "characters": "\u22A7" }, + "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" }, + "∓": { "codepoints": [8723], "characters": "\u2213" }, + "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" }, + "∾": { "codepoints": [8766], "characters": "\u223E" }, + "μ": { "codepoints": [956], "characters": "\u03BC" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⊸": { "codepoints": [8888], "characters": "\u22B8" }, + "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" }, + "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" }, + "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" }, + "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" }, + "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "⊯": { "codepoints": [8879], "characters": "\u22AF" }, + "⊮": { "codepoints": [8878], "characters": "\u22AE" }, + "∇": { "codepoints": [8711], "characters": "\u2207" }, + "ń": { "codepoints": [324], "characters": "\u0144" }, + "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" }, + "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" }, + "ʼn": { "codepoints": [329], "characters": "\u0149" }, + "≉": { "codepoints": [8777], "characters": "\u2249" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "♮": { "codepoints": [9838], "characters": "\u266E" }, + "ℕ": { "codepoints": [8469], "characters": "\u2115" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + " ": { "codepoints": [160], "characters": "\u00A0" }, + "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" }, + "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" }, + "⩃": { "codepoints": [10819], "characters": "\u2A43" }, + "ň": { "codepoints": [328], "characters": "\u0148" }, + "ņ": { "codepoints": [326], "characters": "\u0146" }, + "≇": { "codepoints": [8775], "characters": "\u2247" }, + "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" }, + "⩂": { "codepoints": [10818], "characters": "\u2A42" }, + "н": { "codepoints": [1085], "characters": "\u043D" }, + "–": { "codepoints": [8211], "characters": "\u2013" }, + "≠": { "codepoints": [8800], "characters": "\u2260" }, + "⇗": { "codepoints": [8663], "characters": "\u21D7" }, + "⤤": { "codepoints": [10532], "characters": "\u2924" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "↗": { "codepoints": [8599], "characters": "\u2197" }, + "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" }, + "≢": { "codepoints": [8802], "characters": "\u2262" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "∄": { "codepoints": [8708], "characters": "\u2204" }, + "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≱": { "codepoints": [8817], "characters": "\u2271" }, + "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" }, + "≵": { "codepoints": [8821], "characters": "\u2275" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "≯": { "codepoints": [8815], "characters": "\u226F" }, + "⇎": { "codepoints": [8654], "characters": "\u21CE" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "⫲": { "codepoints": [10994], "characters": "\u2AF2" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "⋼": { "codepoints": [8956], "characters": "\u22FC" }, + "⋺": { "codepoints": [8954], "characters": "\u22FA" }, + "∋": { "codepoints": [8715], "characters": "\u220B" }, + "њ": { "codepoints": [1114], "characters": "\u045A" }, + "⇍": { "codepoints": [8653], "characters": "\u21CD" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "‥": { "codepoints": [8229], "characters": "\u2025" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "↚": { "codepoints": [8602], "characters": "\u219A" }, + "↮": { "codepoints": [8622], "characters": "\u21AE" }, + "≰": { "codepoints": [8816], "characters": "\u2270" }, + "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "≴": { "codepoints": [8820], "characters": "\u2274" }, + "≮": { "codepoints": [8814], "characters": "\u226E" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "¬": { "codepoints": [172], "characters": "\u00AC" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" }, + "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" }, + "∉": { "codepoints": [8713], "characters": "\u2209" }, + "⋷": { "codepoints": [8951], "characters": "\u22F7" }, + "⋶": { "codepoints": [8950], "characters": "\u22F6" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "∌": { "codepoints": [8716], "characters": "\u220C" }, + "⋾": { "codepoints": [8958], "characters": "\u22FE" }, + "⋽": { "codepoints": [8957], "characters": "\u22FD" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" }, + "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" }, + "⨔": { "codepoints": [10772], "characters": "\u2A14" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⋠": { "codepoints": [8928], "characters": "\u22E0" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⊀": { "codepoints": [8832], "characters": "\u2280" }, + "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" }, + "⇏": { "codepoints": [8655], "characters": "\u21CF" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" }, + "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" }, + "↛": { "codepoints": [8603], "characters": "\u219B" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⋡": { "codepoints": [8929], "characters": "\u22E1" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "≁": { "codepoints": [8769], "characters": "\u2241" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "≄": { "codepoints": [8772], "characters": "\u2244" }, + "∤": { "codepoints": [8740], "characters": "\u2224" }, + "∦": { "codepoints": [8742], "characters": "\u2226" }, + "⋢": { "codepoints": [8930], "characters": "\u22E2" }, + "⋣": { "codepoints": [8931], "characters": "\u22E3" }, + "⊄": { "codepoints": [8836], "characters": "\u2284" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊈": { "codepoints": [8840], "characters": "\u2288" }, + "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" }, + "⊁": { "codepoints": [8833], "characters": "\u2281" }, + "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" }, + "⊅": { "codepoints": [8837], "characters": "\u2285" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "⊉": { "codepoints": [8841], "characters": "\u2289" }, + "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" }, + "≹": { "codepoints": [8825], "characters": "\u2279" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "ñ": { "codepoints": [241], "characters": "\u00F1" }, + "≸": { "codepoints": [8824], "characters": "\u2278" }, + "⋪": { "codepoints": [8938], "characters": "\u22EA" }, + "⋬": { "codepoints": [8940], "characters": "\u22EC" }, + "⋫": { "codepoints": [8939], "characters": "\u22EB" }, + "⋭": { "codepoints": [8941], "characters": "\u22ED" }, + "ν": { "codepoints": [957], "characters": "\u03BD" }, + "#": { "codepoints": [35], "characters": "\u0023" }, + "№": { "codepoints": [8470], "characters": "\u2116" }, + " ": { "codepoints": [8199], "characters": "\u2007" }, + "⊭": { "codepoints": [8877], "characters": "\u22AD" }, + "⤄": { "codepoints": [10500], "characters": "\u2904" }, + "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" }, + "⊬": { "codepoints": [8876], "characters": "\u22AC" }, + "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" }, + ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" }, + "⧞": { "codepoints": [10718], "characters": "\u29DE" }, + "⤂": { "codepoints": [10498], "characters": "\u2902" }, + "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" }, + "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" }, + "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" }, + "⤃": { "codepoints": [10499], "characters": "\u2903" }, + "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" }, + "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" }, + "⇖": { "codepoints": [8662], "characters": "\u21D6" }, + "⤣": { "codepoints": [10531], "characters": "\u2923" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "↖": { "codepoints": [8598], "characters": "\u2196" }, + "⤧": { "codepoints": [10535], "characters": "\u2927" }, + "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "ó": { "codepoints": [243], "characters": "\u00F3" }, + "⊛": { "codepoints": [8859], "characters": "\u229B" }, + "⊚": { "codepoints": [8858], "characters": "\u229A" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "ô": { "codepoints": [244], "characters": "\u00F4" }, + "о": { "codepoints": [1086], "characters": "\u043E" }, + "⊝": { "codepoints": [8861], "characters": "\u229D" }, + "ő": { "codepoints": [337], "characters": "\u0151" }, + "⨸": { "codepoints": [10808], "characters": "\u2A38" }, + "⊙": { "codepoints": [8857], "characters": "\u2299" }, + "⦼": { "codepoints": [10684], "characters": "\u29BC" }, + "œ": { "codepoints": [339], "characters": "\u0153" }, + "⦿": { "codepoints": [10687], "characters": "\u29BF" }, + "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" }, + "˛": { "codepoints": [731], "characters": "\u02DB" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "ò": { "codepoints": [242], "characters": "\u00F2" }, + "⧁": { "codepoints": [10689], "characters": "\u29C1" }, + "⦵": { "codepoints": [10677], "characters": "\u29B5" }, + "Ω": { "codepoints": [937], "characters": "\u03A9" }, + "∮": { "codepoints": [8750], "characters": "\u222E" }, + "↺": { "codepoints": [8634], "characters": "\u21BA" }, + "⦾": { "codepoints": [10686], "characters": "\u29BE" }, + "⦻": { "codepoints": [10683], "characters": "\u29BB" }, + "‾": { "codepoints": [8254], "characters": "\u203E" }, + "⧀": { "codepoints": [10688], "characters": "\u29C0" }, + "ō": { "codepoints": [333], "characters": "\u014D" }, + "ω": { "codepoints": [969], "characters": "\u03C9" }, + "ο": { "codepoints": [959], "characters": "\u03BF" }, + "⦶": { "codepoints": [10678], "characters": "\u29B6" }, + "⊖": { "codepoints": [8854], "characters": "\u2296" }, + "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" }, + "⦷": { "codepoints": [10679], "characters": "\u29B7" }, + "⦹": { "codepoints": [10681], "characters": "\u29B9" }, + "⊕": { "codepoints": [8853], "characters": "\u2295" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "↻": { "codepoints": [8635], "characters": "\u21BB" }, + "⩝": { "codepoints": [10845], "characters": "\u2A5D" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "ª": { "codepoints": [170], "characters": "\u00AA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "º": { "codepoints": [186], "characters": "\u00BA" }, + "⊶": { "codepoints": [8886], "characters": "\u22B6" }, + "⩖": { "codepoints": [10838], "characters": "\u2A56" }, + "⩗": { "codepoints": [10839], "characters": "\u2A57" }, + "⩛": { "codepoints": [10843], "characters": "\u2A5B" }, + "ℴ": { "codepoints": [8500], "characters": "\u2134" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "ø": { "codepoints": [248], "characters": "\u00F8" }, + "⊘": { "codepoints": [8856], "characters": "\u2298" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "õ": { "codepoints": [245], "characters": "\u00F5" }, + "⊗": { "codepoints": [8855], "characters": "\u2297" }, + "⨶": { "codepoints": [10806], "characters": "\u2A36" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "ö": { "codepoints": [246], "characters": "\u00F6" }, + "⌽": { "codepoints": [9021], "characters": "\u233D" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "¶": { "codepoints": [182], "characters": "\u00B6" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⫳": { "codepoints": [10995], "characters": "\u2AF3" }, + "⫽": { "codepoints": [11005], "characters": "\u2AFD" }, + "∂": { "codepoints": [8706], "characters": "\u2202" }, + "п": { "codepoints": [1087], "characters": "\u043F" }, + "%": { "codepoints": [37], "characters": "\u0025" }, + ".": { "codepoints": [46], "characters": "\u002E" }, + "‰": { "codepoints": [8240], "characters": "\u2030" }, + "⊥": { "codepoints": [8869], "characters": "\u22A5" }, + "‱": { "codepoints": [8241], "characters": "\u2031" }, + "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" }, + "φ": { "codepoints": [966], "characters": "\u03C6" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ℳ": { "codepoints": [8499], "characters": "\u2133" }, + "☎": { "codepoints": [9742], "characters": "\u260E" }, + "π": { "codepoints": [960], "characters": "\u03C0" }, + "⋔": { "codepoints": [8916], "characters": "\u22D4" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "ℎ": { "codepoints": [8462], "characters": "\u210E" }, + "ℏ": { "codepoints": [8463], "characters": "\u210F" }, + "+": { "codepoints": [43], "characters": "\u002B" }, + "⨣": { "codepoints": [10787], "characters": "\u2A23" }, + "⊞": { "codepoints": [8862], "characters": "\u229E" }, + "⨢": { "codepoints": [10786], "characters": "\u2A22" }, + "∔": { "codepoints": [8724], "characters": "\u2214" }, + "⨥": { "codepoints": [10789], "characters": "\u2A25" }, + "⩲": { "codepoints": [10866], "characters": "\u2A72" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨦": { "codepoints": [10790], "characters": "\u2A26" }, + "⨧": { "codepoints": [10791], "characters": "\u2A27" }, + "±": { "codepoints": [177], "characters": "\u00B1" }, + "⨕": { "codepoints": [10773], "characters": "\u2A15" }, + "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "£": { "codepoints": [163], "characters": "\u00A3" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪳": { "codepoints": [10931], "characters": "\u2AB3" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "≺": { "codepoints": [8826], "characters": "\u227A" }, + "⪷": { "codepoints": [10935], "characters": "\u2AB7" }, + "≼": { "codepoints": [8828], "characters": "\u227C" }, + "⪯": { "codepoints": [10927], "characters": "\u2AAF" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "′": { "codepoints": [8242], "characters": "\u2032" }, + "ℙ": { "codepoints": [8473], "characters": "\u2119" }, + "⪵": { "codepoints": [10933], "characters": "\u2AB5" }, + "⪹": { "codepoints": [10937], "characters": "\u2AB9" }, + "⋨": { "codepoints": [8936], "characters": "\u22E8" }, + "∏": { "codepoints": [8719], "characters": "\u220F" }, + "⌮": { "codepoints": [9006], "characters": "\u232E" }, + "⌒": { "codepoints": [8978], "characters": "\u2312" }, + "⌓": { "codepoints": [8979], "characters": "\u2313" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "≾": { "codepoints": [8830], "characters": "\u227E" }, + "⊰": { "codepoints": [8880], "characters": "\u22B0" }, + "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" }, + "ψ": { "codepoints": [968], "characters": "\u03C8" }, + " ": { "codepoints": [8200], "characters": "\u2008" }, + "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" }, + "⨌": { "codepoints": [10764], "characters": "\u2A0C" }, + "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" }, + "⁗": { "codepoints": [8279], "characters": "\u2057" }, + "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" }, + "ℍ": { "codepoints": [8461], "characters": "\u210D" }, + "⨖": { "codepoints": [10774], "characters": "\u2A16" }, + "?": { "codepoints": [63], "characters": "\u003F" }, + "≟": { "codepoints": [8799], "characters": "\u225F" }, + """: { "codepoints": [34], "characters": "\u0022" }, + """: { "codepoints": [34], "characters": "\u0022" }, + "⇛": { "codepoints": [8667], "characters": "\u21DB" }, + "⇒": { "codepoints": [8658], "characters": "\u21D2" }, + "⤜": { "codepoints": [10524], "characters": "\u291C" }, + "⤏": { "codepoints": [10511], "characters": "\u290F" }, + "⥤": { "codepoints": [10596], "characters": "\u2964" }, + "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" }, + "ŕ": { "codepoints": [341], "characters": "\u0155" }, + "√": { "codepoints": [8730], "characters": "\u221A" }, + "⦳": { "codepoints": [10675], "characters": "\u29B3" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "⦒": { "codepoints": [10642], "characters": "\u2992" }, + "⦥": { "codepoints": [10661], "characters": "\u29A5" }, + "⟩": { "codepoints": [10217], "characters": "\u27E9" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "»": { "codepoints": [187], "characters": "\u00BB" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "⥵": { "codepoints": [10613], "characters": "\u2975" }, + "⇥": { "codepoints": [8677], "characters": "\u21E5" }, + "⤠": { "codepoints": [10528], "characters": "\u2920" }, + "⤳": { "codepoints": [10547], "characters": "\u2933" }, + "⤞": { "codepoints": [10526], "characters": "\u291E" }, + "↪": { "codepoints": [8618], "characters": "\u21AA" }, + "↬": { "codepoints": [8620], "characters": "\u21AC" }, + "⥅": { "codepoints": [10565], "characters": "\u2945" }, + "⥴": { "codepoints": [10612], "characters": "\u2974" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⤚": { "codepoints": [10522], "characters": "\u291A" }, + "∶": { "codepoints": [8758], "characters": "\u2236" }, + "ℚ": { "codepoints": [8474], "characters": "\u211A" }, + "⤍": { "codepoints": [10509], "characters": "\u290D" }, + "❳": { "codepoints": [10099], "characters": "\u2773" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "⦌": { "codepoints": [10636], "characters": "\u298C" }, + "⦎": { "codepoints": [10638], "characters": "\u298E" }, + "⦐": { "codepoints": [10640], "characters": "\u2990" }, + "ř": { "codepoints": [345], "characters": "\u0159" }, + "ŗ": { "codepoints": [343], "characters": "\u0157" }, + "⌉": { "codepoints": [8969], "characters": "\u2309" }, + "}": { "codepoints": [125], "characters": "\u007D" }, + "р": { "codepoints": [1088], "characters": "\u0440" }, + "⤷": { "codepoints": [10551], "characters": "\u2937" }, + "⥩": { "codepoints": [10601], "characters": "\u2969" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "”": { "codepoints": [8221], "characters": "\u201D" }, + "↳": { "codepoints": [8627], "characters": "\u21B3" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℛ": { "codepoints": [8475], "characters": "\u211B" }, + "ℜ": { "codepoints": [8476], "characters": "\u211C" }, + "ℝ": { "codepoints": [8477], "characters": "\u211D" }, + "▭": { "codepoints": [9645], "characters": "\u25AD" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "®": { "codepoints": [174], "characters": "\u00AE" }, + "⥽": { "codepoints": [10621], "characters": "\u297D" }, + "⌋": { "codepoints": [8971], "characters": "\u230B" }, + "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⥬": { "codepoints": [10604], "characters": "\u296C" }, + "ρ": { "codepoints": [961], "characters": "\u03C1" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "↣": { "codepoints": [8611], "characters": "\u21A3" }, + "⇁": { "codepoints": [8641], "characters": "\u21C1" }, + "⇀": { "codepoints": [8640], "characters": "\u21C0" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "↝": { "codepoints": [8605], "characters": "\u219D" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "˚": { "codepoints": [730], "characters": "\u02DA" }, + "≓": { "codepoints": [8787], "characters": "\u2253" }, + "⇄": { "codepoints": [8644], "characters": "\u21C4" }, + "⇌": { "codepoints": [8652], "characters": "\u21CC" }, + "‏": { "codepoints": [8207], "characters": "\u200F" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⎱": { "codepoints": [9137], "characters": "\u23B1" }, + "⫮": { "codepoints": [10990], "characters": "\u2AEE" }, + "⟭": { "codepoints": [10221], "characters": "\u27ED" }, + "⇾": { "codepoints": [8702], "characters": "\u21FE" }, + "⟧": { "codepoints": [10215], "characters": "\u27E7" }, + "⦆": { "codepoints": [10630], "characters": "\u2986" }, + "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" }, + "⨮": { "codepoints": [10798], "characters": "\u2A2E" }, + "⨵": { "codepoints": [10805], "characters": "\u2A35" }, + ")": { "codepoints": [41], "characters": "\u0029" }, + "⦔": { "codepoints": [10644], "characters": "\u2994" }, + "⨒": { "codepoints": [10770], "characters": "\u2A12" }, + "⇉": { "codepoints": [8649], "characters": "\u21C9" }, + "›": { "codepoints": [8250], "characters": "\u203A" }, + "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" }, + "↱": { "codepoints": [8625], "characters": "\u21B1" }, + "]": { "codepoints": [93], "characters": "\u005D" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "’": { "codepoints": [8217], "characters": "\u2019" }, + "⋌": { "codepoints": [8908], "characters": "\u22CC" }, + "⋊": { "codepoints": [8906], "characters": "\u22CA" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "▸": { "codepoints": [9656], "characters": "\u25B8" }, + "⧎": { "codepoints": [10702], "characters": "\u29CE" }, + "⥨": { "codepoints": [10600], "characters": "\u2968" }, + "℞": { "codepoints": [8478], "characters": "\u211E" }, + "ś": { "codepoints": [347], "characters": "\u015B" }, + "‚": { "codepoints": [8218], "characters": "\u201A" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪴": { "codepoints": [10932], "characters": "\u2AB4" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "š": { "codepoints": [353], "characters": "\u0161" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "ş": { "codepoints": [351], "characters": "\u015F" }, + "ŝ": { "codepoints": [349], "characters": "\u015D" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "⨓": { "codepoints": [10771], "characters": "\u2A13" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "с": { "codepoints": [1089], "characters": "\u0441" }, + "⋅": { "codepoints": [8901], "characters": "\u22C5" }, + "⊡": { "codepoints": [8865], "characters": "\u22A1" }, + "⩦": { "codepoints": [10854], "characters": "\u2A66" }, + "⇘": { "codepoints": [8664], "characters": "\u21D8" }, + "⤥": { "codepoints": [10533], "characters": "\u2925" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "↘": { "codepoints": [8600], "characters": "\u2198" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + "§": { "codepoints": [167], "characters": "\u00A7" }, + ";": { "codepoints": [59], "characters": "\u003B" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "✶": { "codepoints": [10038], "characters": "\u2736" }, + "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" }, + "⌢": { "codepoints": [8994], "characters": "\u2322" }, + "♯": { "codepoints": [9839], "characters": "\u266F" }, + "щ": { "codepoints": [1097], "characters": "\u0449" }, + "ш": { "codepoints": [1096], "characters": "\u0448" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "­": { "codepoints": [173], "characters": "\u00AD" }, + "σ": { "codepoints": [963], "characters": "\u03C3" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "⩪": { "codepoints": [10858], "characters": "\u2A6A" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "≃": { "codepoints": [8771], "characters": "\u2243" }, + "⪞": { "codepoints": [10910], "characters": "\u2A9E" }, + "⪠": { "codepoints": [10912], "characters": "\u2AA0" }, + "⪝": { "codepoints": [10909], "characters": "\u2A9D" }, + "⪟": { "codepoints": [10911], "characters": "\u2A9F" }, + "≆": { "codepoints": [8774], "characters": "\u2246" }, + "⨤": { "codepoints": [10788], "characters": "\u2A24" }, + "⥲": { "codepoints": [10610], "characters": "\u2972" }, + "←": { "codepoints": [8592], "characters": "\u2190" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⨳": { "codepoints": [10803], "characters": "\u2A33" }, + "⧤": { "codepoints": [10724], "characters": "\u29E4" }, + "∣": { "codepoints": [8739], "characters": "\u2223" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⪪": { "codepoints": [10922], "characters": "\u2AAA" }, + "⪬": { "codepoints": [10924], "characters": "\u2AAC" }, + "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" }, + "ь": { "codepoints": [1100], "characters": "\u044C" }, + "/": { "codepoints": [47], "characters": "\u002F" }, + "⧄": { "codepoints": [10692], "characters": "\u29C4" }, + "⌿": { "codepoints": [9023], "characters": "\u233F" }, + "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "♠": { "codepoints": [9824], "characters": "\u2660" }, + "∥": { "codepoints": [8741], "characters": "\u2225" }, + "⊓": { "codepoints": [8851], "characters": "\u2293" }, + "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" }, + "⊔": { "codepoints": [8852], "characters": "\u2294" }, + "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊏": { "codepoints": [8847], "characters": "\u228F" }, + "⊑": { "codepoints": [8849], "characters": "\u2291" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "⊐": { "codepoints": [8848], "characters": "\u2290" }, + "⊒": { "codepoints": [8850], "characters": "\u2292" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "□": { "codepoints": [9633], "characters": "\u25A1" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "▪": { "codepoints": [9642], "characters": "\u25AA" }, + "→": { "codepoints": [8594], "characters": "\u2192" }, + "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" }, + "∖": { "codepoints": [8726], "characters": "\u2216" }, + "⌣": { "codepoints": [8995], "characters": "\u2323" }, + "⋆": { "codepoints": [8902], "characters": "\u22C6" }, + "☆": { "codepoints": [9734], "characters": "\u2606" }, + "★": { "codepoints": [9733], "characters": "\u2605" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "¯": { "codepoints": [175], "characters": "\u00AF" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⪽": { "codepoints": [10941], "characters": "\u2ABD" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫃": { "codepoints": [10947], "characters": "\u2AC3" }, + "⫁": { "codepoints": [10945], "characters": "\u2AC1" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⪿": { "codepoints": [10943], "characters": "\u2ABF" }, + "⥹": { "codepoints": [10617], "characters": "\u2979" }, + "⊂": { "codepoints": [8834], "characters": "\u2282" }, + "⊆": { "codepoints": [8838], "characters": "\u2286" }, + "⫅": { "codepoints": [10949], "characters": "\u2AC5" }, + "⊊": { "codepoints": [8842], "characters": "\u228A" }, + "⫋": { "codepoints": [10955], "characters": "\u2ACB" }, + "⫇": { "codepoints": [10951], "characters": "\u2AC7" }, + "⫕": { "codepoints": [10965], "characters": "\u2AD5" }, + "⫓": { "codepoints": [10963], "characters": "\u2AD3" }, + "≻": { "codepoints": [8827], "characters": "\u227B" }, + "⪸": { "codepoints": [10936], "characters": "\u2AB8" }, + "≽": { "codepoints": [8829], "characters": "\u227D" }, + "⪰": { "codepoints": [10928], "characters": "\u2AB0" }, + "⪺": { "codepoints": [10938], "characters": "\u2ABA" }, + "⪶": { "codepoints": [10934], "characters": "\u2AB6" }, + "⋩": { "codepoints": [8937], "characters": "\u22E9" }, + "≿": { "codepoints": [8831], "characters": "\u227F" }, + "∑": { "codepoints": [8721], "characters": "\u2211" }, + "♪": { "codepoints": [9834], "characters": "\u266A" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "¹": { "codepoints": [185], "characters": "\u00B9" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "²": { "codepoints": [178], "characters": "\u00B2" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "³": { "codepoints": [179], "characters": "\u00B3" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⪾": { "codepoints": [10942], "characters": "\u2ABE" }, + "⫘": { "codepoints": [10968], "characters": "\u2AD8" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫄": { "codepoints": [10948], "characters": "\u2AC4" }, + "⟉": { "codepoints": [10185], "characters": "\u27C9" }, + "⫗": { "codepoints": [10967], "characters": "\u2AD7" }, + "⥻": { "codepoints": [10619], "characters": "\u297B" }, + "⫂": { "codepoints": [10946], "characters": "\u2AC2" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫀": { "codepoints": [10944], "characters": "\u2AC0" }, + "⊃": { "codepoints": [8835], "characters": "\u2283" }, + "⊇": { "codepoints": [8839], "characters": "\u2287" }, + "⫆": { "codepoints": [10950], "characters": "\u2AC6" }, + "⊋": { "codepoints": [8843], "characters": "\u228B" }, + "⫌": { "codepoints": [10956], "characters": "\u2ACC" }, + "⫈": { "codepoints": [10952], "characters": "\u2AC8" }, + "⫔": { "codepoints": [10964], "characters": "\u2AD4" }, + "⫖": { "codepoints": [10966], "characters": "\u2AD6" }, + "⇙": { "codepoints": [8665], "characters": "\u21D9" }, + "⤦": { "codepoints": [10534], "characters": "\u2926" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "↙": { "codepoints": [8601], "characters": "\u2199" }, + "⤪": { "codepoints": [10538], "characters": "\u292A" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "ß": { "codepoints": [223], "characters": "\u00DF" }, + "⌖": { "codepoints": [8982], "characters": "\u2316" }, + "τ": { "codepoints": [964], "characters": "\u03C4" }, + "⎴": { "codepoints": [9140], "characters": "\u23B4" }, + "ť": { "codepoints": [357], "characters": "\u0165" }, + "ţ": { "codepoints": [355], "characters": "\u0163" }, + "т": { "codepoints": [1090], "characters": "\u0442" }, + "⃛": { "codepoints": [8411], "characters": "\u20DB" }, + "⌕": { "codepoints": [8981], "characters": "\u2315" }, + "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "∴": { "codepoints": [8756], "characters": "\u2234" }, + "θ": { "codepoints": [952], "characters": "\u03B8" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + " ": { "codepoints": [8201], "characters": "\u2009" }, + "≈": { "codepoints": [8776], "characters": "\u2248" }, + "∼": { "codepoints": [8764], "characters": "\u223C" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "þ": { "codepoints": [254], "characters": "\u00FE" }, + "˜": { "codepoints": [732], "characters": "\u02DC" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "×": { "codepoints": [215], "characters": "\u00D7" }, + "⊠": { "codepoints": [8864], "characters": "\u22A0" }, + "⨱": { "codepoints": [10801], "characters": "\u2A31" }, + "⨰": { "codepoints": [10800], "characters": "\u2A30" }, + "∭": { "codepoints": [8749], "characters": "\u222D" }, + "⤨": { "codepoints": [10536], "characters": "\u2928" }, + "⊤": { "codepoints": [8868], "characters": "\u22A4" }, + "⌶": { "codepoints": [9014], "characters": "\u2336" }, + "⫱": { "codepoints": [10993], "characters": "\u2AF1" }, + "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" }, + "⫚": { "codepoints": [10970], "characters": "\u2ADA" }, + "⤩": { "codepoints": [10537], "characters": "\u2929" }, + "‴": { "codepoints": [8244], "characters": "\u2034" }, + "™": { "codepoints": [8482], "characters": "\u2122" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▿": { "codepoints": [9663], "characters": "\u25BF" }, + "◃": { "codepoints": [9667], "characters": "\u25C3" }, + "⊴": { "codepoints": [8884], "characters": "\u22B4" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "▹": { "codepoints": [9657], "characters": "\u25B9" }, + "⊵": { "codepoints": [8885], "characters": "\u22B5" }, + "◬": { "codepoints": [9708], "characters": "\u25EC" }, + "≜": { "codepoints": [8796], "characters": "\u225C" }, + "⨺": { "codepoints": [10810], "characters": "\u2A3A" }, + "⨹": { "codepoints": [10809], "characters": "\u2A39" }, + "⧍": { "codepoints": [10701], "characters": "\u29CD" }, + "⨻": { "codepoints": [10811], "characters": "\u2A3B" }, + "⏢": { "codepoints": [9186], "characters": "\u23E2" }, + "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" }, + "ц": { "codepoints": [1094], "characters": "\u0446" }, + "ћ": { "codepoints": [1115], "characters": "\u045B" }, + "ŧ": { "codepoints": [359], "characters": "\u0167" }, + "≬": { "codepoints": [8812], "characters": "\u226C" }, + "↞": { "codepoints": [8606], "characters": "\u219E" }, + "↠": { "codepoints": [8608], "characters": "\u21A0" }, + "⇑": { "codepoints": [8657], "characters": "\u21D1" }, + "⥣": { "codepoints": [10595], "characters": "\u2963" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "ú": { "codepoints": [250], "characters": "\u00FA" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "ў": { "codepoints": [1118], "characters": "\u045E" }, + "ŭ": { "codepoints": [365], "characters": "\u016D" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "û": { "codepoints": [251], "characters": "\u00FB" }, + "у": { "codepoints": [1091], "characters": "\u0443" }, + "⇅": { "codepoints": [8645], "characters": "\u21C5" }, + "ű": { "codepoints": [369], "characters": "\u0171" }, + "⥮": { "codepoints": [10606], "characters": "\u296E" }, + "⥾": { "codepoints": [10622], "characters": "\u297E" }, + "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "ù": { "codepoints": [249], "characters": "\u00F9" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "▀": { "codepoints": [9600], "characters": "\u2580" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌜": { "codepoints": [8988], "characters": "\u231C" }, + "⌏": { "codepoints": [8975], "characters": "\u230F" }, + "◸": { "codepoints": [9720], "characters": "\u25F8" }, + "ū": { "codepoints": [363], "characters": "\u016B" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "¨": { "codepoints": [168], "characters": "\u00A8" }, + "ų": { "codepoints": [371], "characters": "\u0173" }, + "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" }, + "↑": { "codepoints": [8593], "characters": "\u2191" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "↿": { "codepoints": [8639], "characters": "\u21BF" }, + "↾": { "codepoints": [8638], "characters": "\u21BE" }, + "⊎": { "codepoints": [8846], "characters": "\u228E" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "ϒ": { "codepoints": [978], "characters": "\u03D2" }, + "υ": { "codepoints": [965], "characters": "\u03C5" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌝": { "codepoints": [8989], "characters": "\u231D" }, + "⌎": { "codepoints": [8974], "characters": "\u230E" }, + "ů": { "codepoints": [367], "characters": "\u016F" }, + "◹": { "codepoints": [9721], "characters": "\u25F9" }, + "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" }, + "⋰": { "codepoints": [8944], "characters": "\u22F0" }, + "ũ": { "codepoints": [361], "characters": "\u0169" }, + "▵": { "codepoints": [9653], "characters": "\u25B5" }, + "▴": { "codepoints": [9652], "characters": "\u25B4" }, + "⇈": { "codepoints": [8648], "characters": "\u21C8" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "ü": { "codepoints": [252], "characters": "\u00FC" }, + "⦧": { "codepoints": [10663], "characters": "\u29A7" }, + "⇕": { "codepoints": [8661], "characters": "\u21D5" }, + "⫨": { "codepoints": [10984], "characters": "\u2AE8" }, + "⫩": { "codepoints": [10985], "characters": "\u2AE9" }, + "⊨": { "codepoints": [8872], "characters": "\u22A8" }, + "⦜": { "codepoints": [10652], "characters": "\u299C" }, + "ϵ": { "codepoints": [1013], "characters": "\u03F5" }, + "ϰ": { "codepoints": [1008], "characters": "\u03F0" }, + "∅": { "codepoints": [8709], "characters": "\u2205" }, + "ϕ": { "codepoints": [981], "characters": "\u03D5" }, + "ϖ": { "codepoints": [982], "characters": "\u03D6" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "↕": { "codepoints": [8597], "characters": "\u2195" }, + "ϱ": { "codepoints": [1009], "characters": "\u03F1" }, + "ς": { "codepoints": [962], "characters": "\u03C2" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "ϑ": { "codepoints": [977], "characters": "\u03D1" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "в": { "codepoints": [1074], "characters": "\u0432" }, + "⊢": { "codepoints": [8866], "characters": "\u22A2" }, + "∨": { "codepoints": [8744], "characters": "\u2228" }, + "⊻": { "codepoints": [8891], "characters": "\u22BB" }, + "≚": { "codepoints": [8794], "characters": "\u225A" }, + "⋮": { "codepoints": [8942], "characters": "\u22EE" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "|": { "codepoints": [124], "characters": "\u007C" }, + "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" }, + "⊲": { "codepoints": [8882], "characters": "\u22B2" }, + "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" }, + "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" }, + "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" }, + "∝": { "codepoints": [8733], "characters": "\u221D" }, + "⊳": { "codepoints": [8883], "characters": "\u22B3" }, + "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" }, + "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" }, + "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" }, + "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" }, + "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" }, + "⦚": { "codepoints": [10650], "characters": "\u299A" }, + "ŵ": { "codepoints": [373], "characters": "\u0175" }, + "⩟": { "codepoints": [10847], "characters": "\u2A5F" }, + "∧": { "codepoints": [8743], "characters": "\u2227" }, + "≙": { "codepoints": [8793], "characters": "\u2259" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" }, + "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" }, + "℘": { "codepoints": [8472], "characters": "\u2118" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "≀": { "codepoints": [8768], "characters": "\u2240" }, + "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" }, + "⋂": { "codepoints": [8898], "characters": "\u22C2" }, + "◯": { "codepoints": [9711], "characters": "\u25EF" }, + "⋃": { "codepoints": [8899], "characters": "\u22C3" }, + "▽": { "codepoints": [9661], "characters": "\u25BD" }, + "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" }, + "⟺": { "codepoints": [10234], "characters": "\u27FA" }, + "⟷": { "codepoints": [10231], "characters": "\u27F7" }, + "ξ": { "codepoints": [958], "characters": "\u03BE" }, + "⟸": { "codepoints": [10232], "characters": "\u27F8" }, + "⟵": { "codepoints": [10229], "characters": "\u27F5" }, + "⟼": { "codepoints": [10236], "characters": "\u27FC" }, + "⋻": { "codepoints": [8955], "characters": "\u22FB" }, + "⨀": { "codepoints": [10752], "characters": "\u2A00" }, + "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" }, + "⨁": { "codepoints": [10753], "characters": "\u2A01" }, + "⨂": { "codepoints": [10754], "characters": "\u2A02" }, + "⟹": { "codepoints": [10233], "characters": "\u27F9" }, + "⟶": { "codepoints": [10230], "characters": "\u27F6" }, + "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" }, + "⨆": { "codepoints": [10758], "characters": "\u2A06" }, + "⨄": { "codepoints": [10756], "characters": "\u2A04" }, + "△": { "codepoints": [9651], "characters": "\u25B3" }, + "⋁": { "codepoints": [8897], "characters": "\u22C1" }, + "⋀": { "codepoints": [8896], "characters": "\u22C0" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "ý": { "codepoints": [253], "characters": "\u00FD" }, + "я": { "codepoints": [1103], "characters": "\u044F" }, + "ŷ": { "codepoints": [375], "characters": "\u0177" }, + "ы": { "codepoints": [1099], "characters": "\u044B" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "¥": { "codepoints": [165], "characters": "\u00A5" }, + "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" }, + "ї": { "codepoints": [1111], "characters": "\u0457" }, + "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" }, + "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" }, + "ю": { "codepoints": [1102], "characters": "\u044E" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ÿ": { "codepoints": [255], "characters": "\u00FF" }, + "ź": { "codepoints": [378], "characters": "\u017A" }, + "ž": { "codepoints": [382], "characters": "\u017E" }, + "з": { "codepoints": [1079], "characters": "\u0437" }, + "ż": { "codepoints": [380], "characters": "\u017C" }, + "ℨ": { "codepoints": [8488], "characters": "\u2128" }, + "ζ": { "codepoints": [950], "characters": "\u03B6" }, + "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" }, + "ж": { "codepoints": [1078], "characters": "\u0436" }, + "⇝": { "codepoints": [8669], "characters": "\u21DD" }, + "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" }, + "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" }, + "‍": { "codepoints": [8205], "characters": "\u200D" }, + "‌": { "codepoints": [8204], "characters": "\u200C" } +} diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils/entitytrans.jl b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entitytrans.jl new file mode 100644 index 0000000..c627a7f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils/entitytrans.jl @@ -0,0 +1,37 @@ +#= +# Generated data: + +import JSON +ENTITY_DATA = JSON.Parser.parsefile(joinpath(@__DIR__, "src", "utils", "entities.json")) +open(joinpath(@__DIR__, "src", "utils", "entities.jl"), "w") do io + print(io, "const ENTITY_DATA = Dict(") + for k in sort(collect(keys(ENTITY_DATA))) + v = ENTITY_DATA[k] + print(io, repr(k)) + print(io, "=>") + print(io, repr(v["characters"]), ",") + end + print(io, ")") +end +=# +include("entities.jl") + +function HTMLunescape(s) + @assert startswith(s, '&') + if startswith(s, "&#") + num = if startswith(s, "&#X") || startswith(s, "&#x") + Base.parse(UInt32, s[4:end-1]; base = 16) + else + Base.parse(UInt32, s[3:end-1]) + end + num == 0 && return "\uFFFD" + try + return string(Char(num)) + catch err + err isa Base.CodePointError || rethrow(err) + return "\uFFFD" + end + else + return get(ENTITY_DATA, s, s) + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/utils/normalize_reference.jl b/.julia-depot/packages/CommonMark/lmLkP/src/utils/normalize_reference.jl new file mode 100644 index 0000000..81218b6 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/utils/normalize_reference.jl @@ -0,0 +1,9 @@ +# TODO very hacky, but passes spec. +function normalize_reference(str) + if startswith(str, '[') && endswith(str, ']') + str = chop(str; head = 1, tail = 1) + end + str = lowercase(Base.Unicode.normalize(str)) + str = strip(replace(str, r"\s+" => ' ')) + return isempty(str) ? "[]" : str +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/LICENSE.md b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/LICENSE.md new file mode 100644 index 0000000..e998c34 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/LICENSE.md @@ -0,0 +1,22 @@ +The Crayons.jl package is licensed under the MIT "Expat" License: + +> Copyright (c) 2016: Kristoffer Carlsson. +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. +> diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/Crayons.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/Crayons.jl new file mode 100644 index 0000000..68ecc89 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/Crayons.jl @@ -0,0 +1,12 @@ +module Crayons + +export Crayon, CrayonStack, @crayon_str + +include("crayon.jl") +include("downcasts.jl") +include("crayon_stack.jl") +include("crayon_wrapper.jl") +include("consts.jl") +include("macro.jl") + +end # module diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/consts.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/consts.jl new file mode 100644 index 0000000..23a82f5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/consts.jl @@ -0,0 +1,93 @@ +module Box + +using ..Crayons + +export BLACK_FG, + RED_FG, + GREEN_FG, + YELLOW_FG, + BLUE_FG, + MAGENTA_FG, + CYAN_FG, + LIGHT_GRAY_FG, + DEFAULT_FG, + DARK_GRAY_FG, + LIGHT_RED_FG, + LIGHT_GREEN_FG, + LIGHT_YELLOW_FG, + LIGHT_BLUE_FG, + LIGHT_MAGENTA_FG, + LIGHT_CYAN_FG, + WHITE_FG, + BLACK_BG, + RED_BG, + GREEN_BG, + YELLOW_BG, + BLUE_BG, + MAGENTA_BG, + CYAN_BG, + LIGHT_GRAY_BG, + DEFAULT_BG, + DARK_GRAY_BG, + LIGHT_RED_BG, + LIGHT_GREEN_BG, + LIGHT_YELLOW_BG, + LIGHT_BLUE_BG, + LIGHT_MAGENTA_BG, + LIGHT_CYAN_BG, + WHITE_BG, + BOLD, + FAINT, + ITALICS, + UNDERLINE, + BLINK, + NEGATIVE, + CONCEAL, + STRIKETHROUGH + +const BLACK_FG = Crayon(foreground = :black) +const RED_FG = Crayon(foreground = :red) +const GREEN_FG = Crayon(foreground = :green) +const YELLOW_FG = Crayon(foreground = :yellow) +const BLUE_FG = Crayon(foreground = :blue) +const MAGENTA_FG = Crayon(foreground = :magenta) +const CYAN_FG = Crayon(foreground = :cyan) +const LIGHT_GRAY_FG = Crayon(foreground = :light_gray) +const DEFAULT_FG = Crayon(foreground = :default) +const DARK_GRAY_FG = Crayon(foreground = :dark_gray) +const LIGHT_RED_FG = Crayon(foreground = :light_red) +const LIGHT_GREEN_FG = Crayon(foreground = :light_green) +const LIGHT_YELLOW_FG = Crayon(foreground = :light_yellow) +const LIGHT_BLUE_FG = Crayon(foreground = :light_blue) +const LIGHT_MAGENTA_FG = Crayon(foreground = :light_magenta) +const LIGHT_CYAN_FG = Crayon(foreground = :light_cyan) +const WHITE_FG = Crayon(foreground = :white) + +const BLACK_BG = Crayon(background = :black) +const RED_BG = Crayon(background = :red) +const GREEN_BG = Crayon(background = :green) +const YELLOW_BG = Crayon(background = :yellow) +const BLUE_BG = Crayon(background = :blue) +const MAGENTA_BG = Crayon(background = :magenta) +const CYAN_BG = Crayon(background = :cyan) +const LIGHT_GRAY_BG = Crayon(background = :light_gray) +const DEFAULT_BG = Crayon(background = :default) +const DARK_GRAY_BG = Crayon(background = :dark_gray) +const LIGHT_RED_BG = Crayon(background = :light_red) +const LIGHT_GREEN_BG = Crayon(background = :light_green) +const LIGHT_YELLOW_BG = Crayon(background = :light_yellow) +const LIGHT_BLUE_BG = Crayon(background = :light_blue) +const LIGHT_MAGENTA_BG = Crayon(background = :light_magenta) +const LIGHT_CYAN_BG = Crayon(background = :light_cyan) +const WHITE_BG = Crayon(background = :white) + +const BOLD = Crayon(bold = true) +const FAINT = Crayon(faint = true) +const ITALICS = Crayon(italics = true) +const UNDERLINE = Crayon(underline = true) +const BLINK = Crayon(blink = true) +const NEGATIVE = Crayon(negative = true) +const CONCEAL = Crayon(conceal = true) +const STRIKETHROUGH = Crayon(strikethrough = true) + +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon.jl new file mode 100644 index 0000000..6c1d601 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon.jl @@ -0,0 +1,306 @@ +const FORCE_COLOR = Ref(false) +const FORCE_256_COLORS = Ref(false) +const FORCE_SYSTEM_COLORS = Ref(false) + +force_color(b::Bool) = FORCE_COLOR[] = b +force_256_colors(b::Bool) = FORCE_256_COLORS[] = b +force_system_colors(b::Bool) = FORCE_SYSTEM_COLORS[] = b + +_force_color() = FORCE_COLOR[] || haskey(ENV, "FORCE_COLOR") +_force_256_colors() = FORCE_256_COLORS[] || haskey(ENV, "FORCE_256_COLORS") +_force_system_colors() = FORCE_SYSTEM_COLORS[] || haskey(ENV, "FORCE_SYSTEM_COLORS") + +const CSI = "\e[" +const ESCAPED_CSI = "\\e[" +const END_ANSI = "m" + +# Add 30 to get fg ANSI +# Add 40 to get bg ANSI +const COLORS = Dict( + :black => 0, + :red => 1, + :green => 2, + :yellow => 3, + :blue => 4, + :magenta => 5, + :cyan => 6, + :light_gray => 7, + :default => 9, + :dark_gray => 60, + :light_red => 61, + :light_green => 62, + :light_yellow => 63, + :light_blue => 64, + :light_magenta => 65, + :light_cyan => 66, + :white => 67, +) + +@enum(ColorMode, RESET, COLORS_16, COLORS_256, COLORS_24BIT) + +struct ANSIColor + r::UInt8 # [0-9, 60-69] for 16 colors, 0-255 for 256 colors + g::UInt8 + b::UInt8 + style::ColorMode + active::Bool +end + +ANSIColor(r, g, b, style::ColorMode = COLORS_16, active = true) = + ANSIColor(UInt8(r), UInt8(g), UInt8(b), style, active) +ANSIColor() = ANSIColor(0x0, 0x0, 0x0, COLORS_16, false) +ANSIColor(val::Integer, style::ColorMode, active::Bool = true) = + ANSIColor(UInt8(val), 0, 0, style, active) + +red(x::ANSIColor) = x.r +green(x::ANSIColor) = x.g +blue(x::ANSIColor) = x.b +val(x::ANSIColor) = x.r + +# The inverse sets the color to default. +# No point making active if color already is default +Base.inv(x::ANSIColor) = + ANSIColor(0x9, 0x0, 0x0, COLORS_16, x.active && !(x.style == COLORS_16 && x.r == 9)) + +struct ANSIStyle + on::Bool + active::Bool +end + +ANSIStyle() = ANSIStyle(false, false) +ANSIStyle(v::Bool) = ANSIStyle(v, true) + +# The inverse always sets the thing to false +# No point in setting active if the style is off. +Base.inv(x::ANSIStyle) = ANSIStyle(false, x.active && x.on) + +struct Crayon + fg::ANSIColor + bg::ANSIColor + + reset::ANSIStyle + bold::ANSIStyle + faint::ANSIStyle + italics::ANSIStyle + underline::ANSIStyle + blink::ANSIStyle + negative::ANSIStyle + conceal::ANSIStyle + strikethrough::ANSIStyle +end + +anyactive(x::Crayon) = ( + (x.reset.active && x.reset.on) || + x.fg.active || + x.bg.active || + x.bold.active || + x.faint.active || + x.italics.active || + x.underline.active || + x.blink.active || + x.negative.active || + x.conceal.active || + x.strikethrough.active +) + +Base.inv(c::Crayon) = Crayon( + inv(c.fg), + inv(c.bg), + ANSIStyle(), # no point taking inverse of reset, + inv(c.bold), + inv(c.faint), + inv(c.italics), + inv(c.underline), + inv(c.blink), + inv(c.negative), + inv(c.conceal), + inv(c.strikethrough), +) + +function _have_color() + if isdefined(Base, :get_have_color) + return Base.get_have_color() + else + Base.have_color + end +end +function Base.print(io::IO, x::Crayon) + if anyactive(x) && (_have_color() || _force_color()) + print(io, CSI) + if (x.fg.style == COLORS_24BIT || x.bg.style == COLORS_24BIT) + if _force_256_colors() + x = to_256_colors(x) + elseif _force_system_colors() + x = to_system_colors(x) + end + end + _print(io, x) + print(io, END_ANSI) + end +end + +function Base.show(io::IO, x::Crayon) + if anyactive(x) + print(io, x) + print(io, ESCAPED_CSI) + _print(io, x) + print(io, END_ANSI, CSI, "0", END_ANSI) + end +end + +_ishex(c::Char) = isdigit(c) || ('a' <= c <= 'f') || ('A' <= c <= 'F') + +function _torgb(hex::UInt32)::NTuple{3,UInt8} + (hex << 8 >> 24, hex << 16 >> 24, hex << 24 >> 24) +end + +function _parse_color(c::Union{Integer,Symbol,NTuple{3,Integer},UInt32,Nothing}) + ansicol = ANSIColor() + if c !== nothing + if isa(c, Symbol) + ansicol = ANSIColor(COLORS[c], COLORS_16) + elseif isa(c, UInt32) + r, g, b = _torgb(c) + ansicol = ANSIColor(r, g, b, COLORS_24BIT) + elseif isa(c, Integer) + ansicol = ANSIColor(c, COLORS_256) + elseif isa(c, NTuple{3,Integer}) + ansicol = ANSIColor(c[1], c[2], c[3], COLORS_24BIT) + else + error("should not happen") + end + end + return ansicol +end + +function Crayon(; + foreground::Union{Int,Symbol,NTuple{3,Integer},UInt32,Nothing} = nothing, + background::Union{Int,Symbol,NTuple{3,Integer},UInt32,Nothing} = nothing, + reset::Union{Bool,Nothing} = nothing, + bold::Union{Bool,Nothing} = nothing, + faint::Union{Bool,Nothing} = nothing, + italics::Union{Bool,Nothing} = nothing, + underline::Union{Bool,Nothing} = nothing, + blink::Union{Bool,Nothing} = nothing, + negative::Union{Bool,Nothing} = nothing, + conceal::Union{Bool,Nothing} = nothing, + strikethrough::Union{Bool,Nothing} = nothing, +) + + fgcol = _parse_color(foreground) + bgcol = _parse_color(background) + + _reset = ANSIStyle() + _bold = ANSIStyle() + _faint = ANSIStyle() + _italics = ANSIStyle() + _underline = ANSIStyle() + _blink = ANSIStyle() + _negative = ANSIStyle() + _conceal = ANSIStyle() + _strikethrough = ANSIStyle() + + reset !== nothing && (_reset = ANSIStyle(reset)) + bold !== nothing && (_bold = ANSIStyle(bold)) + faint !== nothing && (_faint = ANSIStyle(faint)) + italics !== nothing && (_italics = ANSIStyle(italics)) + underline !== nothing && (_underline = ANSIStyle(underline)) + blink !== nothing && (_blink = ANSIStyle(blink)) + negative !== nothing && (_negative = ANSIStyle(negative)) + conceal !== nothing && (_conceal = ANSIStyle(conceal)) + strikethrough !== nothing && (_strikethrough = ANSIStyle(strikethrough)) + + return Crayon( + fgcol, + bgcol, + _reset, + _bold, + _faint, + _italics, + _underline, + _blink, + _negative, + _conceal, + _strikethrough, + ) +end + +# Prints the crayon without the inital and terminating ansi escape sequences +function _print(io::IO, c::Crayon) + first_active = true + if c.reset.active && c.reset.on + first_active = false + print(io, "0") + end + + for (col, num) in ((c.fg, 30), (c.bg, 40)) + if col.active + !first_active && print(io, ";") + first_active = false + + col.style == COLORS_16 && print(io, val(col) + num) + col.style == COLORS_256 && print(io, num + 8, ";5;", val(col)) + col.style == COLORS_24BIT && + print(io, num + 8, ";2;", red(col), ";", green(col), ";", blue(col)) + end + end + + for (style, val) in ( + (c.bold, 1), + (c.faint, 2), + (c.italics, 3), + (c.underline, 4), + (c.blink, 5), + (c.negative, 7), + (c.conceal, 8), + (c.strikethrough, 9), + ) + + if style.active + !first_active && print(io, ";") + first_active = false + + style.on && print(io, val) + # Bold off is actually 22 so special case for val == 1 + !style.on && print(io, val == 1 ? val + 21 : val + 20) + end + end + return nothing +end + +function Base.merge(a::Crayon, b::Crayon) + fg = b.fg.active ? b.fg : a.fg + bg = b.bg.active ? b.bg : a.bg + reset = b.reset.active ? b.reset : a.reset + bold = b.bold.active ? b.bold : a.bold + faint = b.faint.active ? b.faint : a.faint + italics = b.italics.active ? b.italics : a.italics + underline = b.underline.active ? b.underline : a.underline + blink = b.blink.active ? b.blink : a.blink + negative = b.negative.active ? b.negative : a.negative + conceal = b.conceal.active ? b.conceal : a.conceal + strikethrough = b.strikethrough.active ? b.strikethrough : a.strikethrough + + return Crayon( + fg, + bg, + reset, + bold, + faint, + italics, + underline, + blink, + negative, + conceal, + strikethrough, + ) +end + +Base.:*(a::Crayon, b::Crayon) = merge(a, b) + +function Base.merge(tok::Crayon, toks::Crayon...) + for tok2 in toks + tok = merge(tok, tok2) + end + return tok +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_stack.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_stack.jl new file mode 100644 index 0000000..883dc49 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_stack.jl @@ -0,0 +1,118 @@ +# Type for pushing and popping text states +struct CrayonStack + incremental::Bool + crayons::Vector{Crayon} +end + +Base.print(io::IO, cs::CrayonStack) = print(io, cs.crayons[end]) + +function CrayonStack(; incremental::Bool = false) + CrayonStack( + incremental, + [ + Crayon( + ANSIColor(0x9, COLORS_16, !incremental), + ANSIColor(0x9, COLORS_16, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ANSIStyle(false, !incremental), + ), + ], + ) +end + +# Checks if equal disregarding active or not +_equal(a::ANSIColor, b::ANSIColor) = + a.r == b.r && a.g == b.g && a.b == b.b && a.style == b.style +_equal(a::ANSIStyle, b::ANSIStyle) = a.on == b.on + + +# Currently we have the crayon a on the stack. +# We now want to push the crayon b. +# If in incremental mode we compute the changes needed to achive the state of b. +function _incremental_add(a::ANSIColor, b::ANSIColor, incremental::Bool) + if b.active + return ANSIColor(b.r, b.g, b.b, b.style, !_equal(a, b) || !incremental) + else + return ANSIColor(a.r, a.g, a.b, a.style, !incremental) + end +end + +# Similar to above +_incremental_add(a::ANSIStyle, b::ANSIStyle, incremental::Bool) = + b.active ? ANSIStyle(b.on, !_equal(a, b) || !incremental) : + ANSIStyle(a.on, !incremental) + +# Have a, going to b +# State should be exactly as b! +# However, we only want to activate those that are needed, that is +# those that are active in a AND are different from b +_incremental_sub(a::ANSIColor, b::ANSIColor, incremental::Bool) = + ANSIColor(b.r, b.g, b.b, b.style, !_equal(a, b) || !incremental) +_incremental_sub(a::ANSIStyle, b::ANSIStyle, incremental::Bool) = + ANSIStyle(b.on, !_equal(a, b) || !incremental) + + +function Base.push!(cs::CrayonStack, c::Crayon) + pc = cs.crayons[end] + push!( + cs.crayons, + Crayon( + _incremental_add(pc.fg, c.fg, cs.incremental), + _incremental_add(pc.bg, c.bg, cs.incremental), + _incremental_add(pc.reset, c.reset, cs.incremental), + _incremental_add(pc.bold, c.bold, cs.incremental), + _incremental_add(pc.faint, c.faint, cs.incremental), + _incremental_add(pc.italics, c.italics, cs.incremental), + _incremental_add(pc.underline, c.underline, cs.incremental), + _incremental_add(pc.blink, c.blink, cs.incremental), + _incremental_add(pc.negative, c.negative, cs.incremental), + _incremental_add(pc.conceal, c.conceal, cs.incremental), + _incremental_add(pc.strikethrough, c.strikethrough, cs.incremental), + ), + ) + return cs +end + +function Base.pop!(cs::CrayonStack) + length(cs.crayons) == 1 && throw(ArgumentError("no more Crayons left in stack")) + + c = pop!(cs.crayons) + pc = cs.crayons[end] + if length(cs.crayons) == 1 + pc = Crayon( + ANSIColor(0x9, COLORS_16, true), + ANSIColor(0x9, COLORS_16, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ANSIStyle(false, true), + ) + end + cs.crayons[end] = Crayon( + _incremental_sub(c.fg, pc.fg, cs.incremental), + _incremental_sub(c.bg, pc.bg, cs.incremental), + _incremental_sub(c.reset, pc.reset, cs.incremental), + _incremental_sub(c.bold, pc.bold, cs.incremental), + _incremental_sub(c.faint, pc.faint, cs.incremental), + _incremental_sub(c.italics, pc.italics, cs.incremental), + _incremental_sub(c.underline, pc.underline, cs.incremental), + _incremental_sub(c.blink, pc.blink, cs.incremental), + _incremental_sub(c.negative, pc.negative, cs.incremental), + _incremental_sub(c.conceal, pc.conceal, cs.incremental), + _incremental_sub(c.strikethrough, pc.strikethrough, cs.incremental), + ) + # Return the currently active crayon so we can use print(pop!(crayonstack), "bla") + return cs +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_wrapper.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_wrapper.jl new file mode 100644 index 0000000..17522ed --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/crayon_wrapper.jl @@ -0,0 +1,27 @@ +struct CrayonWrapper + c::Crayon + v::Vector{Union{CrayonWrapper,String}} +end + +function (c::Crayon)(args::Union{CrayonWrapper,AbstractString}...) + typefix(cw::CrayonWrapper) = cw + typefix(str) = String(str) + + CrayonWrapper(c, typefix.(collect(args))) +end + +Base.show(io::IO, cw::CrayonWrapper) = _show(io, cw, CrayonStack(incremental = true)) + +_show(io::IO, str::String, stack::CrayonStack) = print(io, str) + +function _show(io::IO, cw::CrayonWrapper, stack::CrayonStack) + print(io, push!(stack, cw.c)) + for obj in cw.v + _show(io, obj, stack) + end + length(stack.crayons) > 1 && print(io, pop!(stack)) + return +end + +Base.:*(c::Crayon, cw::CrayonWrapper) = CrayonWrapper(c * cw.c, cw.v) +Base.:*(cw::CrayonWrapper, c::Crayon) = CrayonWrapper(cw.c * c, cw.v) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/downcasts.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/downcasts.jl new file mode 100644 index 0000000..5f7e61b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/downcasts.jl @@ -0,0 +1,95 @@ +function to_256_colors(crayon::Crayon) + fg = crayon.fg + bg = crayon.bg + crayon.fg.style == COLORS_24BIT && (fg = to_256_colors(crayon.fg)) + crayon.bg.style == COLORS_24BIT && (bg = to_256_colors(crayon.bg)) + return Crayon( + fg, + bg, + crayon.reset, + crayon.bold, + crayon.faint, + crayon.italics, + crayon.underline, + crayon.blink, + crayon.negative, + crayon.conceal, + crayon.strikethrough, + ) +end + +function to_256_colors(color::ANSIColor) + @assert color.style == COLORS_24BIT + r, g, b = rgb = color.r, color.g, color.b + ansi = if r == g == b && r % 10 == 8 + 232 + min((r - 8) ÷ 10, 23) # gray level + elseif all(map(c -> (c & 0x1) == 0 && (c > 0 ? c == 128 || c == 192 : true), rgb)) + (r >> 7) + 2(g >> 7) + 4(b >> 7) # primary color + else + r6, g6, b6 = map(c -> c < 48 ? 0 : (c < 114 ? 1 : trunc(Int, (c - 35) / 40)), rgb) + 16 + 36r6 + 6g6 + b6 # cube 6x6x6 + end + return ANSIColor(UInt8(ansi), COLORS_256, color.active) +end + +# 24bit -> 16 system colors +function to_system_colors(crayon::Crayon) + fg = crayon.fg + bg = crayon.bg + crayon.fg.style == COLORS_24BIT && (fg = to_system_colors(crayon.fg)) + crayon.bg.style == COLORS_24BIT && (bg = to_system_colors(crayon.bg)) + return Crayon( + fg, + bg, + crayon.reset, + crayon.bold, + crayon.faint, + crayon.italics, + crayon.underline, + crayon.blink, + crayon.negative, + crayon.conceal, + crayon.strikethrough, + ) +end + +function compute_value(r, g, b) + r′, g′, b′ = (r, g, b) ./ 255 + Cmax = max(r′, g′, b′) + return 100Cmax + #= + # This is not needed + Cmin = min(r′, g′, b′) + Δ = Cmax - Cmin + H = begin + if Cmax == r′ + 60 * (((g′ - b′) / Δ) % 6) + elseif Cmax == g′ + 60 * ((b′ - r′) / Δ + 2) + else + 60 * ((r′ - g′) / Δ + 4) + end + end + + S = Cmax == 0 ? 0 : (Δ / Cmax) + V = Cmax + return H * 360, S * 100, V * 100 + =# +end + +function to_system_colors(color::ANSIColor) + @assert color.style == COLORS_24BIT + r, g, b = color.r, color.g, color.b + value = compute_value(r, g, b) + + value = round(Int, value / 50) + + if (value == 0) + ansi = 0 + else + ansi = + ((round(Int, b / 255) << 2) | (round(Int, g / 255) << 1) | round(Int, r / 255)) + value == 2 && (ansi += 60) + end + return ANSIColor(UInt8(ansi), COLORS_16, color.active) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/macro.jl b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/macro.jl new file mode 100644 index 0000000..dc13980 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/vendor/Crayons/src/macro.jl @@ -0,0 +1,120 @@ +# [[fg:]] [bg:] ([[!]properties], ...) + +macro crayon_str(str::String) + _reset = ANSIStyle() + _bold = ANSIStyle() + _faint = ANSIStyle() + _italics = ANSIStyle() + _underline = ANSIStyle() + _blink = ANSIStyle() + _negative = ANSIStyle() + _conceal = ANSIStyle() + _strikethrough = ANSIStyle() + + fgcol = ANSIColor() + bgcol = ANSIColor() + + for word in split(str, " ") + length(word) == 0 && continue + token = word + enabled = true + parse_state = :style + + if word[1] == '!' + enabled = false + token = word[2:end] + @goto doparse + end + + if ':' in word + ws = split(word, ':') + if length(ws) != 2 + @goto parse_err + end + val, token = ws + if val == "fg" + parse_state = :fg_color + elseif val == "bg" + parse_state = :bg_color + else + @goto parse_err + end + @goto doparse + @label parse_err + throw(ArgumentError("should have the format [fg/bg]:color")) + end + + @label doparse + if parse_state == :fg_color || parse_state == :bg_color + color = _parse_color_string(token) + if parse_state == :fg_color + fgcol = color + else + bgcol = color + end + elseif parse_state == :style + if token == "reset" + _reset = ANSIStyle(enabled) + elseif token == "bold" + _bold = ANSIStyle(enabled) + elseif token == "faint" + _faint = ANSIStyle(enabled) + elseif token == "italics" + _italics = ANSIStyle(enabled) + elseif token == "underline" + _underline = ANSIStyle(enabled) + elseif token == "blink" + _blink = ANSIStyle(enabled) + elseif token == "negative" + _negative = ANSIStyle(enabled) + elseif token == "conceal" + _conceal = ANSIStyle(enabled) + elseif token == "strikethrough" + _strikethrough = ANSIStyle(enabled) + else + fgcol = _parse_color_string(token) + end + end + end + + return Crayon( + fgcol, + bgcol, + _reset, + _bold, + _faint, + _italics, + _underline, + _blink, + _negative, + _conceal, + _strikethrough, + ) +end + +function _parse_color_string(token::AbstractString) + if length(token) >= 6 + tok_hex = token + startswith(token, "#") && (tok_hex = token[2:end]) + !startswith(token, "0x") && (tok_hex = "0x" * tok_hex) + nhex = tryparse(UInt32, tok_hex) + nhex !== nothing && return _parse_color(nhex) + end + + nint = tryparse(Int, token) + nint !== nothing && return _parse_color(nint) + reg = r"\(([0-9]*),([0-9]*),([0-9]*)\)" + m = match(reg, token) + if m !== nothing + r = m.captures[1]::SubString{String} + g = m.captures[2]::SubString{String} + b = m.captures[3]::SubString{String} + return _parse_color(parse.(Int, (r, g, b))) + end + + if Symbol(token) in keys(COLORS) + return _parse_color(Symbol(token)) + end + + throw(ArgumentError("could not parse $token as a color")) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers.jl new file mode 100644 index 0000000..7187fd6 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers.jl @@ -0,0 +1,121 @@ +function writer(mime, file::AbstractString, ast::Node, env = Dict{String,Any}(); kws...) + env = merge(env, Dict("outputfile" => file)) + open(io -> writer(io, mime, ast, env; kws...), file, "w") +end +writer(mime, io::IO, ast::Node, env = nothing; kws...) = writer(io, mime, ast, env; kws...) +function writer(mime, ast::Node, env = nothing; kws...) + io = IOBuffer() + writer(mime, io, ast, env; kws...) + return String(take!(io)) +end + +function writer(io::IO, mime::MIME, ast::Node, env::Dict; kws...) + # Merge all metadata provided, priority is right-to-left. + env = recursive_merge(default_config(), env, frontmatter(ast), ast.meta) + if haskey(env, "template-engine") + temp = template(env, mime_to_str(mime)) + # Empty templates will skip the template rendering step. + if !isempty(temp) + env["body"] = sprint(show, mime, ast, env) + env["template-engine"](io, temp, env; tags = ("\${", "}")) + return nothing + end + end + show(io, mime, ast, env; kws...) +end +writer(io::IO, mime::MIME, ast::Node, ::Nothing; kws...) = show(io, mime, ast; kws...) + +default_config() = Dict{String,Any}( + "authors" => [], + "curdir" => pwd(), + "title" => "", + "subtitle" => "", + "abstract" => "", + "keywords" => [], + "lang" => "en", + "latex" => Dict{String,Any}("documentclass" => "article"), +) + +_smart_link(mime, obj, node, env) = + haskey(env, "smartlink-engine") ? env["smartlink-engine"](mime, obj, node, env) : obj + +function template(env, fmt) + # Template load order: + # + # - .template.string + # - .template.file + # - TEMPLATES[""] + # + config = get(() -> Dict{String,Any}(), env, fmt) + tmp = get(() -> Dict{String,Any}(), config, "template") + get(tmp, "string") do + haskey(tmp, "file") ? read(tmp["file"], String) : + haskey(TEMPLATES, fmt) ? read(TEMPLATES[fmt], String) : "" + end +end +const TEMPLATES = Dict{String,String}() + +recursive_merge(ds::AbstractDict...) = merge(recursive_merge, ds...) +recursive_merge(args...) = last(args) + +frontmatter(n::Node) = has_frontmatter(n) ? n.first_child.t.data : Dict{String,Any}() +has_frontmatter(n::Node) = !isnull(n.first_child) && n.first_child.t isa FrontMatter + +mutable struct Writer{F,I<:IO} + format::F + buffer::I + last::Char + enabled::Bool + context::Dict{Symbol,Any} + env::Dict{String,Any} +end +Writer(format, buffer = IOBuffer(), env = Dict{String,Any}()) = + Writer(format, buffer, '\n', true, Dict{Symbol,Any}(), env) + +Base.get(w::Writer, k::Symbol, default) = get(w.context, k, default) +Base.get!(f::Function, w::Writer, k::Symbol) = get!(f, w.context, k) + +function literal(r::Writer, args...) + if r.enabled + for arg in args + write(r.buffer, arg) + r.last = isempty(arg) ? r.last : last(arg) + end + end + return nothing +end + +function cr(r::Writer) + if r.enabled && r.last != '\n' + r.last = '\n' + write(r.buffer, '\n') + end + return nothing +end + +function _syntax_highlighter(w::Writer, mime::MIME, node::Node, escape = identity) + key = "syntax-highlighter" + return haskey(w.env, key) ? w.env[key](mime, node) : escape(node.literal) +end + +include("writers/html.jl") +include("writers/latex.jl") +include("writers/term.jl") +include("writers/markdown.jl") +include("writers/notebook.jl") +include("writers/typst.jl") + +function ast_dump(io::IO, ast::Node) + indent = -2 + for (node, enter) in ast + T = typeof(node.t).name.name + if is_container(node) + indent += enter ? 2 : -2 + enter && printstyled(io, ' '^indent, T, "\n"; color = :blue) + else + printstyled(io, ' '^(indent + 2), T, "\n"; bold = true, color = :red) + println(io, ' '^(indent + 4), repr(node.literal)) + end + end +end +ast_dump(ast::Node) = ast_dump(stdout, ast) diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/html.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/html.jl new file mode 100644 index 0000000..ec95bab --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/html.jl @@ -0,0 +1,262 @@ +# Public. + +function Base.show(io::IO, ::MIME"text/html", ast::Node, env = Dict{String,Any}(); kws...) + writer = Writer(HTML(; kws...), io, env) + write_html(writer, ast) + return nothing +end +html(args...; kws...) = writer(MIME"text/html"(), args...; kws...) + +# Internals. + +mime_to_str(::MIME"text/html") = "html" + +TEMPLATES["html"] = joinpath(@__DIR__, "templates/html.mustache") + +mutable struct HTML + disable_tags::Int + softbreak::String + safe::Bool + sourcepos::Union{Bool,Function} + + function HTML(; softbreak = "\n", safe = false, sourcepos = false) + format = new() + format.disable_tags = 0 + format.softbreak = softbreak # Set to "
" to for hardbreaks, " " for no wrapping. + format.safe = safe + format.sourcepos = sourcepos + return format + end +end + +function write_html(writer::Writer, ast::Node) + for (node, entering) in ast + write_html(node.t, writer, node, entering) + end +end + +const reUnsafeProtocol = r"^javascript:|vbscript:|file:|data:"i +const reSafeDataProtocol = r"^data:image\/(?:png|gif|jpeg|webp)"i + +potentially_unsafe(url) = + occursin(reUnsafeProtocol, url) && !occursin(reSafeDataProtocol, url) + +function tag(r::Writer, name, attributes = [], self_closing = false) + r.format.disable_tags > 0 && return nothing + literal(r, '<', name) + for (key, value) in attributes + literal(r, " ", key, '=', '"', value, '"') + end + self_closing && literal(r, " /") + literal(r, '>') + r.last = '>' + return nothing +end + +write_html(::Document, r, n, ent) = nothing + +write_html(::Text, r, n, ent) = literal(r, escape_xml(n.literal)) + +write_html(::Backslash, w, node, ent) = nothing + +write_html(::SoftBreak, r, n, ent) = literal(r, r.format.softbreak) + +function write_html(::LineBreak, r, n, ent) + tag(r, "br", attributes(r, n), true) + cr(r) +end + +function write_html(link::Link, r, n, ent) + if ent + attrs = [] + if !(r.format.safe && potentially_unsafe(link.destination)) + link = _smart_link(MIME"text/html"(), link, n, r.env) + push!(attrs, "href" => escape_xml(link.destination)) + end + if !isempty(link.title) + push!(attrs, "title" => escape_xml(link.title)) + end + tag(r, "a", attributes(r, n, attrs)) + else + tag(r, "/a") + end +end + +function write_html(image::Image, r, n, ent) + if ent + if r.format.disable_tags == 0 + if r.format.safe && potentially_unsafe(image.destination) + literal(r, "\"")") + end + end +end + +write_html(::Emph, r, n, ent) = tag(r, ent ? "em" : "/em", ent ? attributes(r, n) : []) + +write_html(::Strong, r, n, ent) = + tag(r, ent ? "strong" : "/strong", ent ? attributes(r, n) : []) + +function write_html(::Paragraph, r, n, ent) + grandparent = n.parent.parent + if !isnull(grandparent) && grandparent.t isa List + if grandparent.t.list_data.tight + return + end + end + if ent + attrs = attributes(r, n) + cr(r) + tag(r, "p", attrs) + else + tag(r, "/p") + cr(r) + end +end + +function write_html(::Heading, r, n, ent) + tagname = "h$(n.t.level)" + if ent + attrs = attributes(r, n) + cr(r) + tag(r, tagname, attrs) + # Insert auto-generated anchor Links for all Headings with IDs. + # The Link is not added to the document's AST. + if haskey(n.meta, "id") + anchor = Node(Link()) + anchor.t.destination = "#" * n.meta["id"] + anchor.meta["class"] = ["anchor"] + write_html(r, anchor) + end + else + tag(r, "/$(tagname)") + cr(r) + end +end + +function write_html(::Code, r, n, ent) + tag(r, "code", attributes(r, n)) + literal(r, escape_xml(n.literal)) + tag(r, "/code") +end + +function write_html(::CodeBlock, r, n, ent) + info_words = split(n.t.info === nothing ? "" : n.t.info) + attrs = attributes(r, n) + if !isempty(info_words) && !isempty(first(info_words)) + push!(attrs, "class" => "language-$(escape_xml(first(info_words)))") + end + cr(r) + tag(r, "pre") + tag(r, "code", attrs) + literal(r, _syntax_highlighter(r, MIME("text/html"), n, escape_xml)) + tag(r, "/code") + tag(r, "/pre") + cr(r) +end + +function write_html(::ThematicBreak, r, n, ent) + attrs = attributes(r, n) + cr(r) + tag(r, "hr", attrs, true) + cr(r) +end + +function write_html(::BlockQuote, r, n, ent) + if ent + attrs = attributes(r, n) + cr(r) + tag(r, "blockquote", attrs) + cr(r) + else + cr(r) + tag(r, "/blockquote") + cr(r) + end +end + +function write_html(::List, r, n, ent) + tagname = n.t.list_data.type === :bullet ? "ul" : "ol" + if ent + attrs = attributes(r, n) + start = n.t.list_data.start + if start !== nothing && start != 1 + push!(attrs, "start" => string(start)) + end + cr(r) + tag(r, tagname, attrs) + cr(r) + else + cr(r) + tag(r, "/$(tagname)") + cr(r) + end +end + +function write_html(::Item, r, n, ent) + if ent + attrs = attributes(r, n) + tag(r, "li", attrs) + else + tag(r, "/li") + cr(r) + end +end + +write_html(::HtmlInline, r, n, ent) = + literal(r, r.format.safe ? "" : n.literal) + +function write_html(::HtmlBlock, r, n, ent) + cr(r) + literal(r, r.format.safe ? "" : n.literal) + cr(r) +end + +function attributes(r, n, out = []) + # Maintain the order of the attributes, but merge duplicates. + order = String[] + dict = Dict{String,Any}() + if _has_sourcepos(r.format.sourcepos) + if n.sourcepos !== nothing + p = n.sourcepos + result = _process_sourcepos(r.format.sourcepos, p) + if isa(result, Pair) + k, v = result + push!(order, k) + dict[k] = v + end + end + end + for each in (out, n.meta) + for (key, value) in each + value = isa(value, AbstractString) ? value : join(value, " ") + if haskey(dict, key) + dict[key] = "$(dict[key]) $value" + else + dict[key] = value + push!(order, key) + end + end + end + return [k => dict[k] for k in order] +end + +_has_sourcepos(sourcepos::Any) = sourcepos === true +_has_sourcepos(sourcepos::Function) = true + + +_process_sourcepos(handler::Function, p) = handler(p) +_process_sourcepos(::Bool, p) = + "data-sourcepos" => "$(p[1][1]):$(p[1][2])-$(p[2][1]):$(p[2][2])" diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/latex.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/latex.jl new file mode 100644 index 0000000..714655f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/latex.jl @@ -0,0 +1,164 @@ +# Public. + +function Base.show(io::IO, ::MIME"text/latex", ast::Node, env = Dict{String,Any}()) + writer = Writer(LaTeX(), io, env) + write_latex(writer, ast) + return nothing +end +latex(args...) = writer(MIME"text/latex"(), args...) + +# Internals. + +mime_to_str(::MIME"text/latex") = "latex" + +TEMPLATES["latex"] = joinpath(@__DIR__, "templates/latex.mustache") + +mutable struct LaTeX + LaTeX() = new() +end + +function write_latex(writer::Writer, ast::Node) + for (node, entering) in ast + if entering + meta = node.meta + if haskey(meta, "id") + literal(writer, "\\protect\\hypertarget{", meta["id"], "}{}") + end + end + write_latex(node.t, writer, node, entering) + end +end + +write_latex(::Document, w, node, ent) = nothing + +write_latex(::Text, w, node, ent) = latex_escape(w, node.literal) + +write_latex(::Backslash, w, node, ent) = nothing + +write_latex(::SoftBreak, w, node, ent) = cr(w) +write_latex(::LineBreak, w, node, ent) = cr(w) + +function write_latex(::Code, w, node, ent) + literal(w, "\\texttt{") + latex_escape(w, node.literal) + literal(w, "}") +end + +write_latex(::HtmlInline, w, node, ent) = nothing + +function write_latex(link::Link, w, node, ent) + if ent + link = _smart_link(MIME"text/latex"(), link, node, w.env) + # Link destinations that begin with a # are taken to be internal to the + # document. LaTeX wants to use a hyperlink rather than an href for + # these, so branch based on it to allow both types of links to be used. + # Generating `\url` commands is not supported. + type, n = startswith(link.destination, '#') ? ("hyperlink", 1) : ("href", 0) + literal(w, "\\$type{$(chop(link.destination; head=n, tail=0))}{") + else + literal(w, "}") + end +end + +function write_latex(image::Image, w, node, ent) + if ent + image = _smart_link(MIME"text/latex"(), image, node, w.env) + cr(w) + literal(w, "\\begin{figure}\n") + literal(w, "\\centering\n") + literal(w, "\\includegraphics[max width=\\linewidth]{", image.destination, "}\n") + literal(w, "\\caption{") + else + literal(w, "}\n") + literal(w, "\\end{figure}") + cr(w) + end +end + +write_latex(::Emph, w, node, ent) = literal(w, ent ? "\\textit{" : "}") + +write_latex(::Strong, w, node, ent) = literal(w, ent ? "\\textbf{" : "}") + +function write_latex(::Paragraph, w, node, ent) + literal(w, ent ? "" : "\\par\n") +end + +function write_latex(::Heading, w, node, ent) + if ent + cr(w) + n = node.t.level + name = n ≤ 3 ? "sub"^(n - 1) * "section" : "sub"^(n - 4) * "paragraph" + literal(w, "\\$name{") + else + literal(w, "}") + cr(w) + end +end + +function write_latex(::BlockQuote, w, node, ent) + cr(w) + literal(w, ent ? "\\begin{quote}" : "\\end{quote}") + cr(w) +end + +function write_latex(list::List, w, node, ent) + cr(w) + command = list.list_data.type === :bullet ? "itemize" : "enumerate" + if ent + literal(w, "\\begin{$command}\n") + if command == "enumerate" + literal(w, "\\def\\labelenumi{\\arabic{enumi}.}\n") + literal(w, "\\setcounter{enumi}{$(list.list_data.start-1)}\n") + end + if list.list_data.tight + literal(w, "\\setlength{\\itemsep}{0pt}\n") + literal(w, "\\setlength{\\parskip}{0pt}\n") + end + else + literal(w, "\\end{$command}") + end + cr(w) +end + +function write_latex(::Item, w, node, ent) + literal(w, ent ? "\\item" : "") + cr(w) +end + +function write_latex(::ThematicBreak, w, node, ent) + cr(w) + literal(w, "\\par\\bigskip\\noindent\\hrulefill\\par\\bigskip") + cr(w) +end + +function write_latex(c::CodeBlock, w, node, ent) + environment = c.is_fenced ? "lstlisting" : "verbatim" + cr(w) + literal(w, "\\begin{$environment}") + cr(w) + literal(w, _syntax_highlighter(w, MIME("text/latex"), node)) + cr(w) + literal(w, "\\end{$environment}") + cr(w) +end + +write_latex(::HtmlBlock, w, node, ent) = nothing + +let chars = Dict('^' => "\\^{}", '\\' => "{\\textbackslash}", '~' => "{\\textasciitilde}") + for c in "&%\$#_{}" + chars[c] = "\\$c" + end + global function latex_escape(w::Writer, s::AbstractString) + for ch in s + literal(w, get(chars, ch, ch)) + end + end + + global function latex_escape(s::AbstractString) + buffer = IOBuffer() + for ch in s + write(buffer, get(chars, ch, ch)) + end + return String(take!(buffer)) + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/markdown.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/markdown.jl new file mode 100644 index 0000000..ef01d38 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/markdown.jl @@ -0,0 +1,191 @@ +# Public. + +function Base.show(io::IO, ::MIME"text/markdown", ast::Node, env = Dict{String,Any}()) + writer = Writer(Markdown(io), io, env) + write_markdown(writer, ast) + return nothing +end +markdown(args...) = writer(MIME"text/markdown"(), args...) + +# Internals. + +mime_to_str(::MIME"text/markdown") = "markdown" + +mutable struct Markdown{I<:IO} + buffer::I + indent::Int + margin::Vector{MarginSegment} + list_depth::Int + list_item_number::Vector{Int} + Markdown(io::I) where {I} = new{I}(io, 0, [], 0, []) +end + +function write_markdown(writer::Writer, ast::Node) + for (node, entering) in ast + write_markdown(node.t, writer, node, entering) + end +end + +function linebreak(w, node) + if !isnull(node.nxt) + print_margin(w) + literal(w, "\n") + end + return nothing +end + +# Writers. + +write_markdown(::Document, w, node, ent) = nothing + +write_markdown(::Text, w, node, ent) = literal(w, node.literal) + +write_markdown(::Backslash, w, node, ent) = literal(w, "\\") + +function write_markdown(::Union{SoftBreak,LineBreak}, w, node, ent) + cr(w) + print_margin(w) +end + +function write_markdown(::Code, w, node, ent) + num = foldl(eachmatch(r"`+", node.literal); init = 0) do a, b + max(a, length(b.match)) + end + literal(w, "`"^(num == 1 ? 3 : 1)) + literal(w, node.literal) + literal(w, "`"^(num == 1 ? 3 : 1)) +end + +write_markdown(::HtmlInline, w, node, ent) = literal(w, node.literal) + +function write_markdown(link::Link, w, node, ent) + if ent + literal(w, "[") + else + link = _smart_link(MIME"text/markdown"(), link, node, w.env) + literal(w, "](", link.destination) + isempty(link.title) || literal(w, " \"", link.title, "\"") + literal(w, ")") + end +end + +function write_markdown(image::Image, w, node, ent) + if ent + literal(w, "![") + else + image = _smart_link(MIME"text/markdown"(), image, node, w.env) + literal(w, "](", image.destination) + isempty(image.title) || literal(w, " \"", image.title, "\"") + literal(w, ")") + end +end + +write_markdown(::Emph, w, node, ent) = literal(w, node.literal) + +write_markdown(::Strong, w, node, ent) = literal(w, node.literal) + +function write_markdown(::Paragraph, w, node, ent) + if ent + print_margin(w) + else + cr(w) + linebreak(w, node) + end +end + +function write_markdown(heading::Heading, w, node, ent) + if ent + print_margin(w) + literal(w, "#"^heading.level, " ") + else + cr(w) + linebreak(w, node) + end +end + +function write_markdown(::BlockQuote, w, node, ent) + if ent + push_margin!(w, ">") + push_margin!(w, " ") + else + pop_margin!(w) + maybe_print_margin(w, node) + pop_margin!(w) + cr(w) + linebreak(w, node) + end +end + +function write_markdown(list::List, w, node, ent) + if ent + w.format.list_depth += 1 + push!(w.format.list_item_number, list.list_data.start) + else + w.format.list_depth -= 1 + pop!(w.format.list_item_number) + cr(w) + linebreak(w, node) + end +end + +function write_markdown(item::Item, w, node, enter) + if enter + if item.list_data.type === :ordered + number = lpad(string(w.format.list_item_number[end], ". "), 4, " ") + w.format.list_item_number[end] += 1 + push_margin!(w, 1, number) + else + bullets = ['-', '+', '*', '-', '+', '*'] + bullet = bullets[min(w.format.list_depth, length(bullets))] + push_margin!(w, 1, lpad("$bullet ", 4, " ")) + end + else + if isnull(node.first_child) + print_margin(w) + linebreak(w, node) + end + pop_margin!(w) + if !item.list_data.tight + cr(w) + linebreak(w, node) + end + end +end + +function write_markdown(::ThematicBreak, w, node, ent) + print_margin(w) + literal(w, "* * *") + cr(w) + linebreak(w, node) +end + +function write_markdown(code::CodeBlock, w, node, ent) + if code.is_fenced + fence = code.fence_char^code.fence_length + print_margin(w) + literal(w, fence, code.info) + cr(w) + for line in eachline(IOBuffer(node.literal); keep = true) + print_margin(w) + literal(w, line) + end + print_margin(w) + literal(w, fence) + cr(w) + else + for line in eachline(IOBuffer(node.literal); keep = true) + print_margin(w) + indent = all(isspace, line) ? 0 : CODE_INDENT + literal(w, ' '^indent, line) + end + end + linebreak(w, node) +end + +function write_markdown(::HtmlBlock, w, node, ent) + for line in eachline(IOBuffer(node.literal); keep = true) + print_margin(w) + literal(w, line) + end + linebreak(w, node) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/notebook.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/notebook.jl new file mode 100644 index 0000000..8404b18 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/notebook.jl @@ -0,0 +1,174 @@ +# Public. + +function Base.show( + io::IO, + ::MIME"application/x-ipynb+json", + ast::Node, + env = Dict{String,Any}(), +) + json = Dict( + "cells" => [], + "metadata" => Dict( + "kernelspec" => Dict( + "display_name" => "Julia $VERSION", + "language" => "julia", + "name" => "julia-$VERSION", + ), + "language_info" => Dict( + "file_extension" => ".jl", + "mimetype" => "application/julia", + "name" => "julia", + "version" => "$VERSION", + ), + ), + "nbformat" => 4, + "nbformat_minor" => 4, + ) + for (node, enter) in ast + write_notebook(json, node, enter, env) + end + _json(io, json) + return nothing +end +notebook(args...) = writer(MIME"application/x-ipynb+json"(), args...) + +# Internal. + +mime_to_str(::MIME"application/x-ipynb+json") = "notebook" + +function write_notebook(json, node, enter, env) + split_lines = str -> collect(eachline(IOBuffer(str); keep = true)) + if !isnull(node) && + node.t isa CodeBlock && + node.parent.t isa Document && + node.t.info == "julia" + # Toplevel Julia codeblocks become code cells. + cell = Dict( + "cell_type" => "code", + "execution_count" => nothing, + "metadata" => Dict(), + "source" => split_lines(rstrip(node.literal, '\n')), + "outputs" => [], + ) + push!(json["cells"], cell) + elseif !isnull(node.parent) && node.parent.t isa Document && enter + # All other toplevel turns into markdown cells. + cells = json["cells"] + if !isempty(cells) && cells[end]["cell_type"] == "markdown" + # When we already have a current markdown cell then append content. + append!(cells[end]["source"], split_lines(markdown(node, env))) + else + # ... otherwise open a new cell. + cell = Dict( + "cell_type" => "markdown", + "metadata" => Dict(), + "source" => split_lines(markdown(node)), + ) + push!(cells, cell) + end + end +end + +struct StringContext{T<:IO} <: IO + io::T +end + +Base.write(io::StringContext, byte::UInt8) = write(io.io, ESCAPED_ARRAY[byte+1]) + +function _json(io::IO, str::AbstractString) + write(io, STRING_DELIM) + print(StringContext(io), str) + write(io, STRING_DELIM) +end +_json(io::IO, ::Nothing) = print(io, "null") +_json(io::IO, num::Real) = print(io, num) + +function _json(io::IO, dict::AbstractDict) + print(io, "{") + for (nth, (key, value)) in enumerate(dict) + if nth > 1 + print(io, ",") + end + _json(io, key) + print(io, ":") + _json(io, value) + end + print(io, "}") +end + +function _json(io::IO, vec::AbstractVector) + print(io, "[") + for (nth, value) in enumerate(vec) + if nth > 1 + print(io, ",") + end + _json(io, value) + end + print(io, "]") +end + +# The following bytes have significant meaning in JSON +const BACKSPACE = UInt8('\b') +const TAB = UInt8('\t') +const NEWLINE = UInt8('\n') +const FORM_FEED = UInt8('\f') +const RETURN = UInt8('\r') +const SPACE = UInt8(' ') +const STRING_DELIM = UInt8('"') +const PLUS_SIGN = UInt8('+') +const DELIMITER = UInt8(',') +const MINUS_SIGN = UInt8('-') +const DECIMAL_POINT = UInt8('.') +const SOLIDUS = UInt8('/') +const DIGIT_ZERO = UInt8('0') +const DIGIT_NINE = UInt8('9') +const SEPARATOR = UInt8(':') +const LATIN_UPPER_A = UInt8('A') +const LATIN_UPPER_E = UInt8('E') +const LATIN_UPPER_F = UInt8('F') +const LATIN_UPPER_I = UInt8('I') +const LATIN_UPPER_N = UInt8('N') +const ARRAY_BEGIN = UInt8('[') +const BACKSLASH = UInt8('\\') +const ARRAY_END = UInt8(']') +const LATIN_A = UInt8('a') +const LATIN_B = UInt8('b') +const LATIN_E = UInt8('e') +const LATIN_F = UInt8('f') +const LATIN_I = UInt8('i') +const LATIN_L = UInt8('l') +const LATIN_N = UInt8('n') +const LATIN_R = UInt8('r') +const LATIN_S = UInt8('s') +const LATIN_T = UInt8('t') +const LATIN_U = UInt8('u') +const LATIN_Y = UInt8('y') +const OBJECT_BEGIN = UInt8('{') +const OBJECT_END = UInt8('}') + +const ESCAPES = Dict( + STRING_DELIM => STRING_DELIM, + BACKSLASH => BACKSLASH, + SOLIDUS => SOLIDUS, + LATIN_B => BACKSPACE, + LATIN_F => FORM_FEED, + LATIN_N => NEWLINE, + LATIN_R => RETURN, + LATIN_T => TAB, +) + +const REVERSE_ESCAPES = Dict(reverse(p) for p in ESCAPES) +const ESCAPED_ARRAY = Vector{Vector{UInt8}}(undef, 256) +for c = 0x00:0xFF + ESCAPED_ARRAY[c+1] = if c == SOLIDUS + [SOLIDUS] # don't escape this one + elseif c ≥ 0x80 + [c] # UTF-8 character copied verbatim + elseif haskey(REVERSE_ESCAPES, c) + [BACKSLASH, REVERSE_ESCAPES[c]] + elseif iscntrl(Char(c)) || !isprint(Char(c)) + UInt8[BACKSLASH, LATIN_U, string(c, base = 16, pad = 4)...] + else + [c] + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/html.mustache b/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/html.mustache new file mode 100644 index 0000000..6f7acc8 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/html.mustache @@ -0,0 +1,24 @@ + + + + + + + + ${#authors} + + ${/authors} + ${title} + ${#html.css} + + ${/html.css} + ${#html.js} + + ${/html.js} + ${{html.header}} + + +${{body}} +${{html.footer}} + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/latex.mustache b/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/latex.mustache new file mode 100644 index 0000000..b4cb104 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/templates/latex.mustache @@ -0,0 +1,38 @@ +\documentclass{${latex.documentclass}} + +\usepackage{fontspec} +\usepackage{amssymb,amsmath} +\defaultfontfeatures{Scale=MatchLowercase} +\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\usepackage{hyperref} + +${#title} +\title{${title}} +${/title} +${#subtitle} +\subtitle{${subtitle}} +${/subtitle} +\author{${#authors}${.}${^.[end]} \and ${/.[end]}${/authors}} +${#date} +\date{${date}} +${/date} + +${{latex.preamble}} + +\begin{document} + +${#title} +\maketitle +${/title} + +${#abstract} +\begin{abstract} +${abstract} +\end{abstract} +${/abstract} + +\tableofcontents + +${{body}} + +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/term.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/term.jl new file mode 100644 index 0000000..e33489f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/term.jl @@ -0,0 +1,416 @@ +# Public. + +function Base.show(io::IO, ::MIME"text/plain", ast::Node, env = Dict{String,Any}()) + writer = Writer(Term(), io, env) + write_term(writer, ast) + # Writing is done to an intermediate buffer and then written to the + # user-provided one once we have traversed the AST so that we can avoid + # noticable lag when displaying on the terminal. + write(writer.buffer, take!(writer.format.buffer)) + return nothing +end +term(args...) = writer(MIME"text/plain"(), args...) + +# Internals. + +mime_to_str(::MIME"text/plain") = "term" + +include("../vendor/Crayons/src/Crayons.jl") +import .Crayons: Crayon, @crayon_str + +mutable struct MarginSegment + text::String + width::Int + count::Int +end + +mutable struct Term + indent::Int + margin::Vector{MarginSegment} + buffer::IOBuffer + wrap::Int + list_depth::Int + list_item_number::Vector{Int} + Term() = new(0, [], IOBuffer(), -1, 0, []) +end + +function write_term(writer::Writer, ast::Node) + for (node, entering) in ast + write_term(node.t, writer, node, entering) + end +end + +# Utilities. + +function padding_between(cols, objects) + count = length(objects) - 1 + nchars = sum(Base.Unicode.textwidth, objects) + return (cols - nchars) ÷ count +end +padding_between(cols, width::Integer) = (cols - width) ÷ 2 + +""" +What is the width of the literal text stored in `node` and all of it's child +nodes. Used to determine alignment for rendering nodes such as centered. +""" +function literal_width(node::Node) + width = 0 + for (node, enter) in node + if enter + width += Base.Unicode.textwidth(node.literal) + end + end + return width +end + +const LEFT_MARGIN = " " + +""" +Given the current indent of the renderer we check to see how much space is left +on the current line. +""" +function available_columns(r::Writer{Term}) + _, cols = displaysize(r.buffer) + return cols - r.format.indent - length(LEFT_MARGIN) +end + +""" +Adds a new segment to the margin buffer. This segment is persistent and thus +will print on every margin print. +""" +function push_margin!(r::Writer, text::AbstractString, style = crayon"") + return push_margin!(r, -1, text, style) +end + +""" +Adds new segmant to the margin buffer. `count` determines how many time +`initial` is printed. After that, the width of `rest` is printed instead. +""" +function push_margin!( + r::Writer, + count::Integer, + initial::AbstractString, + rest::AbstractString, +) + width = Base.Unicode.textwidth(rest) + r.format.indent += width + seg = MarginSegment(initial, width, count) + push!(r.format.margin, seg) + return nothing +end + +""" +Adds a new segment to the margin buffer, but will only print out for the given +number of `count` calls to `print_margin`. After `count` calls it will instead +print out spaces equal to the width of `text`. +""" +function push_margin!(r::Writer, count::Integer, text::AbstractString, style = crayon"") + width = Base.Unicode.textwidth(text) + text = string(style, text, inv(style)) + r.format.indent += width + seg = MarginSegment(text, width, count) + push!(r.format.margin, seg) + return nothing +end + +# Matching call for a `push_margin!`. Must be call on exiting a node where a +# `push_margin!` was used when entering. +function pop_margin!(r::Writer) + seg = pop!(r.format.margin) + r.format.indent -= seg.width + return nothing +end + +function push_inline!(r::Writer, style) + push!(r.format.margin, MarginSegment(string(style), 0, -1)) + pushfirst!(r.format.margin, MarginSegment(string(inv(style)), 0, -1)) + return nothing +end + +function pop_inline!(r::Writer) + pop!(r.format.margin) + popfirst!(r.format.margin) + return nothing +end + +""" +Print out all the current segments present in the margin buffer. + +Each time a segment gets printed it's count is reduced. When a segment has a +count of zero it won't be printed and instead spaces equal to it's width are +printed. For persistent printing a count of -1 should be used. +""" +function print_margin(r::Writer) + for seg in r.format.margin + if seg.count == 0 + # Blank space case. + print(r.format.buffer, ' '^seg.width) + else + # The normal case, where .count is reduced after each print. + print(r.format.buffer, seg.text) + seg.count > 0 && (seg.count -= 1) + end + end +end + +function maybe_print_margin(r, node::Node) + if isnull(node.first_child) + push_margin!(r, "\n") + print_margin(r) + pop_margin!(r) + end + return nothing +end + +""" +Literal printing of a of `parts`. Behaviour depends on when `.wrap` is active +at the moment, which is set in `Paragraph` rendering. +""" +function print_literal(r::Writer{Term}, parts...) + # Ignore printing literals when there isn't much space, stops causing + # stackoverflows and avoids printing badly wrapped lines when there's no + # use printing them. + available_columns(r) < 5 && return + + if r.format.wrap < 0 + # We just print everything normally here, allowing for the possibility + # of bad automatic line wrapping by the terminal. + for part in parts + print(r.format.buffer, part) + end + else + # We're in a `Paragraph` and so want nice line wrapping. + for part in parts + print_literal_part(r, part) + end + end +end + +function print_literal_part(r::Writer{Term}, lit::AbstractString, rec = 0) + width = Base.Unicode.textwidth(lit) + space = (available_columns(r) - r.format.wrap) + ispunct(get(lit, 1, '\0')) + if width < space + print(r.format.buffer, lit) + r.format.wrap += width + else + index = findprev(c -> c in " -–—", lit, space) + index = index === nothing ? (rec > 0 ? space : 0) : index + head = SubString(lit, 1, thisind(lit, index)) + tail = SubString(lit, nextind(lit, index)) + + print(r.format.buffer, rstrip(head), "\n") + + print_margin(r) + r.format.wrap = 0 + + print_literal_part(r, lstrip(tail), rec + 1) + end +end +print_literal_part(r::Writer{Term}, c::Crayon) = print(r.format.buffer, c) + +# Rendering to terminal. + +function write_term(::Document, render, node, enter) + if enter + push_margin!(render, LEFT_MARGIN, crayon"") + else + pop_margin!(render) + end +end + +function write_term(::Text, render, node, enter) + print_literal(render, replace(node.literal, r"\s+" => ' ')) +end + +write_term(::Backslash, w, node, ent) = nothing + +function write_term(::SoftBreak, render, node, enter) + print_literal(render, " ") +end + +function write_term(::LineBreak, render, node, enter) + print(render.format.buffer, "\n") + print_margin(render) + render.format.wrap = render.format.wrap < 0 ? -1 : 0 +end + +function write_term(::Code, render, node, enter) + style = crayon"cyan" + print_literal(render, style) + push_inline!(render, style) + print_literal(render, node.literal) + pop_inline!(render) + print_literal(render, inv(style)) +end + +function write_term(::HtmlInline, render, node, enter) + style = crayon"dark_gray" + print_literal(render, style) + push_inline!(render, style) + print_literal(render, node.literal) + pop_inline!(render) + print_literal(render, inv(style)) +end + +function write_term(::Link, render, node, enter) + style = crayon"blue underline" + if enter + print_literal(render, style) + push_inline!(render, style) + else + pop_inline!(render) + print_literal(render, inv(style)) + end +end + +function write_term(::Image, render, node, enter) + style = crayon"green" + if enter + print_literal(render, style) + push_inline!(render, style) + else + pop_inline!(render) + print_literal(render, inv(style)) + end +end + +function write_term(::Emph, render, node, enter) + style = crayon"italics" + if enter + print_literal(render, style) + push_inline!(render, style) + else + pop_inline!(render) + print_literal(render, inv(style)) + end +end + +function write_term(::Strong, render, node, enter) + style = crayon"bold" + if enter + print_literal(render, style) + push_inline!(render, style) + else + pop_inline!(render) + print_literal(render, inv(style)) + end +end + +function write_term(::Paragraph, render, node, enter) + if enter + render.format.wrap = 0 + print_margin(render) + else + render.format.wrap = -1 + print_literal(render, "\n") + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end + end +end + +function write_term(heading::Heading, render, node, enter) + if enter + print_margin(render) + style = crayon"blue bold" + print_literal(render, style, "#"^heading.level, inv(style), " ") + else + print_literal(render, "\n") + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end + end +end + +function write_term(::BlockQuote, render, node, enter) + if enter + push_margin!(render, "│", crayon"bold") + push_margin!(render, " ", crayon"") + else + pop_margin!(render) + maybe_print_margin(render, node) + pop_margin!(render) + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end + end +end + +function write_term(list::List, render, node, enter) + if enter + render.format.list_depth += 1 + push!(render.format.list_item_number, list.list_data.start) + push_margin!(render, " ", crayon"") + else + render.format.list_depth -= 1 + pop!(render.format.list_item_number) + pop_margin!(render) + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end + end +end + +function write_term(item::Item, render, node, enter) + if enter + if item.list_data.type === :ordered + number = string(render.format.list_item_number[end], ". ") + render.format.list_item_number[end] += 1 + push_margin!(render, 1, number, crayon"") + else + # ● ○ ▶ ▷ ■ □ + bullets = ['\u25CF', '\u25CB', '\u25B6', '\u25B7', '\u25A0', '\u25A1'] + bullet = bullets[min(render.format.list_depth, length(bullets))] + push_margin!(render, 1, "$bullet ", crayon"") + end + else + maybe_print_margin(render, node) + pop_margin!(render) + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end + end +end + +function write_term(::ThematicBreak, render, node, enter) + print_margin(render) + style = crayon"dark_gray" + stars = " § " + padding = '═'^padding_between(available_columns(render), length(stars)) + print_literal(render, style, padding, stars, padding, inv(style), "\n") + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end +end + +function write_term(::CodeBlock, render, node, enter) + pipe = crayon"cyan" + style = crayon"dark_gray" + for line in eachline(IOBuffer(_syntax_highlighter(render, MIME("text/plain"), node))) + print_margin(render) + print_literal(render, " ", pipe, "│", inv(pipe), " ") + print_literal(render, style, line, inv(style), "\n") + end + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end +end + +function write_term(::HtmlBlock, render, node, enter) + style = crayon"dark_gray" + for line in eachline(IOBuffer(node.literal)) + print_margin(render) + print_literal(render, style, line, inv(style), "\n") + end + if !isnull(node.nxt) + print_margin(render) + print_literal(render, "\n") + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/src/writers/typst.jl b/.julia-depot/packages/CommonMark/lmLkP/src/writers/typst.jl new file mode 100644 index 0000000..f0884f4 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/src/writers/typst.jl @@ -0,0 +1,184 @@ +# Public. + +function Base.show(io::IO, ::MIME"text/typst", ast::Node, env = Dict{String,Any}()) + writer = Writer(Typst(io), io, env) + write_typst(writer, ast) + return nothing +end +typst(args...) = writer(MIME"text/typst"(), args...) + +# Internals. + +mime_to_str(::MIME"text/typst") = "typst" + +mutable struct Typst{I<:IO} + buffer::I + indent::Int + margin::Vector{MarginSegment} + list_depth::Int + list_item_number::Vector{Int} + Typst(io::I) where {I} = new{I}(io, 0, [], 0, []) +end + +function write_typst(writer::Writer, ast::Node) + for (node, entering) in ast + write_typst(node.t, writer, node, entering) + end +end + +# Writers. + +write_typst(::Document, w, node, ent) = nothing + +write_typst(::Text, w, node, ent) = typst_escape(w, node.literal) + +write_typst(::Backslash, w, node, ent) = literal(w, "\\") + +function write_typst(::Union{SoftBreak,LineBreak}, w, node, ent) + cr(w) + print_margin(w) +end + +function write_typst(::Code, w, node, ent) + num = foldl(eachmatch(r"`+", node.literal); init = 0) do a, b + max(a, length(b.match)) + end + literal(w, "`"^(num == 1 ? 3 : 1)) + literal(w, node.literal) + literal(w, "`"^(num == 1 ? 3 : 1)) +end + +write_typst(::HtmlInline, w, node, ent) = nothing + +function write_typst(link::Link, w, node, ent) + if ent + link = _smart_link(MIME"text/typst"(), link, node, w.env) + literal(w, "#link(", repr(link.destination), ")[") + else + literal(w, "]") + end +end + +function write_typst(image::Image, w, node, ent) + if ent + image = _smart_link(MIME"text/typst"(), image, node, w.env) + literal(w, "#figure(image(", repr(image.destination), "), caption: [") + else + literal(w, "])") + end +end + +write_typst(::Emph, w, node, ent) = literal(w, ent ? "#emph[" : "]") + +write_typst(::Strong, w, node, ent) = literal(w, ent ? "#strong[" : "]") + +function write_typst(::Paragraph, w, node, ent) + if ent + print_margin(w) + else + cr(w) + linebreak(w, node) + end +end + +function write_typst(heading::Heading, w, node, ent) + if ent + print_margin(w) + literal(w, "="^heading.level, " ") + else + cr(w) + linebreak(w, node) + end +end + +function write_typst(::BlockQuote, w, node, ent) + if ent + literal(w, "#quote(block: true)[") + cr(w) + else + literal(w, "]") + cr(w) + end +end + +function write_typst(list::List, w, node, ent) + if ent + w.format.list_depth += 1 + push!(w.format.list_item_number, list.list_data.start) + else + w.format.list_depth -= 1 + pop!(w.format.list_item_number) + cr(w) + linebreak(w, node) + end +end + +function write_typst(item::Item, w, node, enter) + if enter + if item.list_data.type === :ordered + number = lpad(string(w.format.list_item_number[end], ". "), 4, " ") + w.format.list_item_number[end] += 1 + push_margin!(w, 1, number) + else + push_margin!(w, 1, lpad("- ", 4, " ")) + end + else + if isnull(node.first_child) + print_margin(w) + linebreak(w, node) + end + pop_margin!(w) + if !item.list_data.tight + cr(w) + linebreak(w, node) + end + end +end + +function write_typst(::ThematicBreak, w, node, ent) + literal(w, "#line(start: (25%, 0%), end: (75%, 0%))") + cr(w) + linebreak(w, node) +end + +function write_typst(code::CodeBlock, w, node, ent) + fence = code.is_fenced ? code.fence_char^code.fence_length : "```" + print_margin(w) + literal(w, fence, code.info) + cr(w) + for line in eachline(IOBuffer(node.literal); keep = true) + print_margin(w) + literal(w, line) + end + print_margin(w) + literal(w, fence) + cr(w) + linebreak(w, node) +end + +function write_typst(::HtmlBlock, w, node, ent) + for line in eachline(IOBuffer(node.literal); keep = true) + print_margin(w) + literal(w, line) + end + linebreak(w, node) +end + +let chars = Dict{Char,String}() + for c in "~\$#_" + chars[c] = "\\$c" + end + global function typst_escape(w::Writer, s::AbstractString) + for ch in s + literal(w, get(chars, ch, ch)) + end + end + + global function typst_escape(s::AbstractString) + buffer = IOBuffer() + for ch in s + write(buffer, get(chars, ch, ch)) + end + return String(take!(buffer)) + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/Project.toml b/.julia-depot/packages/CommonMark/lmLkP/test/Project.toml new file mode 100644 index 0000000..0b14c64 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/Project.toml @@ -0,0 +1,6 @@ +[deps] +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Mustache = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/ast.jl b/.julia-depot/packages/CommonMark/lmLkP/test/ast.jl new file mode 100644 index 0000000..34bdca6 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/ast.jl @@ -0,0 +1,25 @@ +@testset "AST" begin + text = CommonMark.text + root = text("root") + + CommonMark.insert_before(root, text("insert_before")) + CommonMark.insert_after(root, text("insert_after")) + @test root.prv.literal == "insert_before" + @test root.nxt.literal == "insert_after" + + CommonMark.append_child(root, text("append_child")) + @test root.first_child.literal == "append_child" + @test root.last_child.literal == "append_child" + + CommonMark.prepend_child(root, text("prepend_child")) + @test root.first_child.literal == "prepend_child" + @test root.last_child.literal == "append_child" + + CommonMark.unlink(root.last_child) + @test root.last_child.literal == "prepend_child" + + root = text("root") + CommonMark.prepend_child(root, text("prepend_child")) + @test root.first_child.literal == "prepend_child" + @test root.last_child.literal == "prepend_child" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions.jl new file mode 100644 index 0000000..96cfe7e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions.jl @@ -0,0 +1,15 @@ +@testset "Extensions" begin + include("extensions/admonitions.jl") + include("extensions/footnotes.jl") + include("extensions/math.jl") + include("extensions/tables.jl") + include("extensions/frontmatter.jl") + include("extensions/typography.jl") + include("extensions/raw.jl") + include("extensions/attributes.jl") + include("extensions/citations.jl") + include("extensions/autoidentifiers.jl") + include("extensions/smartlinks.jl") + include("extensions/highlights.jl") + include("extensions/interpolation.jl") +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/admonitions.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/admonitions.jl new file mode 100644 index 0000000..d638036 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/admonitions.jl @@ -0,0 +1,70 @@ +@testset "Admonitions" begin + p = Parser() + enable!(p, AdmonitionRule()) + + text = """ + !!! warning + + text + """ + ast = p(text) + + @test html(ast) == + "

Warning

\n

text

\n
" + @test latex(ast) == + "\\begin{admonition@warning}{Warning}\ntext\\par\n\\end{admonition@warning}\n" + @test term(ast) == + " \e[33;1m┌ Warning ────────────────────────────────────────────────────────────────────\e[39;22m\n \e[33;1m│\e[39;22m text\n \e[33;1m└─────────────────────────────────────────────────────────────────────────────\e[39;22m\n" + @test markdown(ast) == "!!! warning\n \n text\n" + @test typst(ast) == + "#block(fill: rgb(\"#e5e5e5\"), inset: 8pt, stroke: (left: 2pt + rgb(\"#facc15\"), rest: none), width: 100%)[#strong[Warning] \\\ntext\n]\n" + + text = """ + !!! warning + + \ttext + """ + ast = p(text) + + @test html(ast) == + "

Warning

\n

text

\n
" + @test latex(ast) == + "\\begin{admonition@warning}{Warning}\ntext\\par\n\\end{admonition@warning}\n" + @test term(ast) == + " \e[33;1m┌ Warning ────────────────────────────────────────────────────────────────────\e[39;22m\n \e[33;1m│\e[39;22m text\n \e[33;1m└─────────────────────────────────────────────────────────────────────────────\e[39;22m\n" + @test markdown(ast) == "!!! warning\n \n text\n" + @test typst(ast) == + "#block(fill: rgb(\"#e5e5e5\"), inset: 8pt, stroke: (left: 2pt + rgb(\"#facc15\"), rest: none), width: 100%)[#strong[Warning] \\\ntext\n]\n" + + text = """ + !!! info "Custom Title" + + text + """ + ast = p(text) + + @test html(ast) == + "

Custom Title

\n

text

\n
" + @test latex(ast) == + "\\begin{admonition@info}{Custom Title}\ntext\\par\n\\end{admonition@info}\n" + @test term(ast) == + " \e[36;1m┌ Custom Title ───────────────────────────────────────────────────────────────\e[39;22m\n \e[36;1m│\e[39;22m text\n \e[36;1m└─────────────────────────────────────────────────────────────────────────────\e[39;22m\n" + @test markdown(ast) == "!!! info \"Custom Title\"\n \n text\n" + @test typst(ast) == + "#block(fill: rgb(\"#e5e5e5\"), inset: 8pt, stroke: (left: 2pt + rgb(\"#0ea5e9\"), rest: none), width: 100%)[#strong[Custom Title] \\\ntext\n]\n" + + p = enable!(Parser(), [AdmonitionRule(), AttributeRule()]) + + text = """ + {#id} + !!! warning + + text + """ + ast = p(text) + + @test html(ast) == + "

Warning

\n

text

\n
" + @test latex(ast) == + "\\protect\\hypertarget{id}{}\n\\begin{admonition@warning}{Warning}\ntext\\par\n\\end{admonition@warning}\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/attributes.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/attributes.jl new file mode 100644 index 0000000..0a0283d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/attributes.jl @@ -0,0 +1,157 @@ +@testset "Attributes" begin + p = Parser() + enable!(p, AttributeRule()) + + # Syntax. + + test = function (text, dict) + ast = p(text) + @test ast.first_child.t isa CommonMark.Attributes + @test ast.first_child.t.dict == dict + end + + test("{}", Dict{String,Any}()) + test("{empty}", Dict{String,Any}("empty" => "")) + test("{#id}", Dict{String,Any}("id" => "id")) + test("{empty #id}", Dict{String,Any}("id" => "id", "empty" => "")) + test("{#id empty}", Dict{String,Any}("id" => "id", "empty" => "")) + test("{#one #two}", Dict{String,Any}("id" => "two")) # Only last # is kept. + test("{.class}", Dict{String,Any}("class" => ["class"])) + test("{empty .class}", Dict{String,Any}("class" => ["class"], "empty" => "")) + test("{.one.two}", Dict{String,Any}("class" => ["one", "two"])) # All .s are kept. + test("{:element}", Dict{String,Any}("element" => "element")) + test("{:element empty}", Dict{String,Any}("element" => "element", "empty" => "")) + test("{one=two}", Dict{String,Any}("one" => "two")) + test( + "{empty one=two other}", + Dict{String,Any}("one" => "two", "empty" => "", "other" => ""), + ) + test("{one=two three='four'}", Dict{String,Any}("one" => "two", "three" => "four")) + test( + "{one=two empty three='four'}", + Dict{String,Any}("one" => "two", "three" => "four", "empty" => ""), + ) + test("{one=2 three=4}", Dict{String,Any}("one" => "2", "three" => "4")) + test( + "{#id .class one=two three='four'}", + Dict{String,Any}( + "id" => "id", + "class" => ["class"], + "one" => "two", + "three" => "four", + ), + ) + + # Block metadata attachment. + + test = function (text, T, dict) + ast = p(text) + @test ast.first_child.t isa CommonMark.Attributes + @test ast.first_child.nxt.t isa T + @test ast.first_child.nxt.meta == dict + @test text == markdown(ast) + end + dict = Dict{String,Any}("id" => "id") + + test( + """ + {#id} + # H1 + """, + CommonMark.Heading, + dict, + ) + test( + """ + {#id} + > blockquote + """, + CommonMark.BlockQuote, + dict, + ) + test( + """ + {#id} + ``` + code + ``` + """, + CommonMark.CodeBlock, + dict, + ) + test( + """ + {#id} + - one + - two + - three + """, + CommonMark.List, + dict, + ) + test( + """ + {#id} + paragraph + """, + CommonMark.Paragraph, + dict, + ) + test( + """ + {#id} + * * * + """, + CommonMark.ThematicBreak, + dict, + ) + test( + """ + {.hidden} + - list + """, + CommonMark.List, + Dict{String,Any}("class" => ["hidden"]), + ) + + # Inline metadata attachment. + + test = function (text, T, dict, md = text) + ast = p(text) + @test ast.first_child.first_child.t isa T + @test ast.first_child.first_child.nxt.t isa CommonMark.Attributes + @test ast.first_child.first_child.meta == dict + @test md * "\n" == markdown(ast) # Paragraphs add a newline at end. + end + + test("*word*{#id}", CommonMark.Emph, dict) + test("[word](url){#id}", CommonMark.Link, dict) + test("![word](url){#id}", CommonMark.Image, dict) + test("**word**{#id}", CommonMark.Strong, dict) + test("`word`{#id}", CommonMark.Code, dict) + test( + "{#id}", + CommonMark.Link, + dict, + "[http://www.website.com](http://www.website.com){#id}", + ) + + test = function (input, f, output) + ast = p(input) + @test f(ast) == output + end + + test( + "{#id}\n# H1", + html, + "

H1

\n", + ) + test("{.one.two}\n# H1", html, "

H1

\n") + test("{#id}\n# H1", latex, "\\protect\\hypertarget{id}{}\n\\section{H1}\n") + test("{#id}\n# H1", typst, "= H1\n") + + test("*word*{#id}", html, "

word

\n") + test("*word*{.one.two}", html, "

word

\n") + test("*word*{#id}", latex, "\\protect\\hypertarget{id}{}\\textit{word}\\par\n") + test("*word*{#id}", typst, "#emph[word]\n") +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/autoidentifiers.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/autoidentifiers.jl new file mode 100644 index 0000000..372ab2b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/autoidentifiers.jl @@ -0,0 +1,48 @@ +@testset "Auto-Identifiers" begin + slugs = Dict( + # Examples from pandoc documentation: + "Heading identifiers in HTML" => "heading-identifiers-in-html", + "Maître d'hôtel" => "maître-dhôtel", + "*Dogs*?--in *my* house?" => "dogs--in-my-house", + "[HTML], [S5], or [RTF]?" => "html-s5-or-rtf", + "3. Applications" => "applications", + "33" => "section", + ) + for (k, v) in slugs + @test CommonMark.slugify(k) == v + end + + rule = AutoIdentifierRule() + p = enable!(Parser(), rule) + + text = "# Heading." + ast = p(text) + @test ast.first_child.meta["id"] == "heading" + @test rule.refs[ast]["heading"] == 1 + + rule = AutoIdentifierRule() + p = enable!(Parser(), rule) + + text = "# Heading.\n# heading!" + ast = p(text) + @test ast.first_child.meta["id"] == "heading" + @test ast.first_child.nxt.meta["id"] == "heading-1" + @test rule.refs[ast]["heading"] == 2 + + rule = AutoIdentifierRule() + p = enable!(Parser(), [rule, AttributeRule()]) + + text = "{#refs}\n# Heading.\n# heading!" + ast = p(text) + @test ast.first_child.nxt.meta["id"] == "refs" + @test ast.first_child.nxt.nxt.meta["id"] == "heading" + @test rule.refs[ast]["heading"] == 1 + + rule = AutoIdentifierRule() + p = enable!(Parser(), rule) + + text = "> # Heading." + ast = p(text) + @test ast.first_child.first_child.meta["id"] == "heading" + @test rule.refs[ast]["heading"] == 1 +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.jl new file mode 100644 index 0000000..e2c5639 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.jl @@ -0,0 +1,123 @@ +@testset "Citations" begin + p = enable!(Parser(), CitationRule()) + bib = JSON.parsefile(joinpath(@__DIR__, "citations.json")) + + test = function (bib, ast, _html, _latex, _markdown, _term, _typst) + env = Dict{String,Any}("references" => bib) + @test html(ast, env) == _html + @test latex(ast, env) == _latex + @test markdown(ast, env) == _markdown + @test term(ast, env) == _term + @test typst(ast, env) == _typst + end + + # Unbracketed citations. + + # Missing bibliography data. + test( + bib, + p("@unknown"), + "

@unknown

\n", + "\\protect\\hyperlink{ref-unknown}{@unknown}\\par\n", + "@unknown\n", + " \e[31m@unknown\e[39m\n", + "@unknown\n", + ) + + # Single author. + test( + bib, + p("@innes2018"), + "

Innes 2018

\n", + "\\protect\\hyperlink{ref-innes2018}{Innes 2018}\\par\n", + "@innes2018\n", + " \e[31mInnes 2018\e[39m\n", + "@innes2018\n", + ) + + # Two authors. + test( + bib, + p("@lubin2015"), + "

Dunning and Lubin 2015

\n", + "\\protect\\hyperlink{ref-lubin2015}{Dunning and Lubin 2015}\\par\n", + "@lubin2015\n", + " \e[31mDunning and Lubin 2015\e[39m\n", + "@lubin2015\n", + ) + + # Many authors. + test( + bib, + p("@bezanson2017"), + "

Bezanson et al. 2017

\n", + "\\protect\\hyperlink{ref-bezanson2017}{Bezanson et al. 2017}\\par\n", + "@bezanson2017\n", + " \e[31mBezanson et al. 2017\e[39m\n", + "@bezanson2017\n", + ) + + # Bracketed citations. + + # Missing bibliography data. + test( + bib, + p("[@unknown]"), + "

(@unknown)

\n", + "(\\protect\\hyperlink{ref-unknown}{@unknown})\\par\n", + "[@unknown]\n", + " (\e[31m@unknown\e[39m)\n", + "[@unknown]\n", + ) + + # Single author. + test( + bib, + p("[@innes2018]"), + "

(Innes 2018)

\n", + "(\\protect\\hyperlink{ref-innes2018}{Innes 2018})\\par\n", + "[@innes2018]\n", + " (\e[31mInnes 2018\e[39m)\n", + "[@innes2018]\n", + ) + + # Two authors. + test( + bib, + p("[@lubin2015]"), + "

(Dunning and Lubin 2015)

\n", + "(\\protect\\hyperlink{ref-lubin2015}{Dunning and Lubin 2015})\\par\n", + "[@lubin2015]\n", + " (\e[31mDunning and Lubin 2015\e[39m)\n", + "[@lubin2015]\n", + ) + + # Many authors. + test( + bib, + p("[@bezanson2017]"), + "

(Bezanson et al. 2017)

\n", + "(\\protect\\hyperlink{ref-bezanson2017}{Bezanson et al. 2017})\\par\n", + "[@bezanson2017]\n", + " (\e[31mBezanson et al. 2017\e[39m)\n", + "[@bezanson2017]\n", + ) + + # Reference lists. + p = enable!(Parser(), [CitationRule(), AttributeRule()]) + + text = """ + {#refs} + # The reference list. + """ + test( + bib, + p(text), + # Checked by hand. + "

The reference list.

\n

Aruoba, S. Borağan, and Jesús Fernández-Villaverde. 2015. A comparison of programming languages in macroeconomics.

\n

Ault, Shaun V., Tyler A. Cabutto, Sean P. Heeney, Guifen Mao, and Jin Wang. 2018. An Overview of the Julia Programming Language.

\n

Besard, Tim, Bjorn De Sutter, and Christophe Foket. 2018. Effective extensible programming: Unleashing julia on gpus.

\n

Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2017. Julia: A fresh approach to numerical computing.

\n

Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2012. Julia: A fast dynamic language for technical computing.

\n

Boyd, Stephen, Steven Diamond, Jenny Hong, Karanveer Mohan, Madeleine Udell, and David Zeng. 2014. Convex optimization in Julia. IEEE.

\n

Chen, Jiahao, and Jarrett Revels. 2016. Robust benchmarking in noisy environments.

\n

Cusumano-Towner, Marco F., Alexander K. Lew, Vikash K. Mansinghka, and Feras A. Saad. 2019. Gen: A general-purpose probabilistic programming system with programmable inference. New York, NY, USA: ACM. doi:10.1145/3314221.3314642. http://doi.acm.org/10.1145/3314221.3314642.

\n

Dunning, Iain, and Miles Lubin. 2015. Computing in operations research using Julia.

\n

Edelman, Alan. 2015. Julia: A fresh approach to parallel programming. IEEE.

\n

Elmqvist, Hilding, Toivo Henningsson, and Martin Otter. 2016. Systems modeling and programming in a unified environment based on Julia. Springer.

\n

Fieker, Claus, William Hart, Tommy Hofmann, and Fredrik Johansson. 2017. Nemo/Hecke: computer algebra and number theory packages for the Julia programming language.

\n

Fischer, Keno, Dhairya Gandhi, Michael Innes, Neethu Mariya Joy, Tejan Karmali, Avik Pal, Marco Concetto Rudilosso, Elliot Saba, and Viral Shah. 2018. Fashionable modelling with flux. http://arxiv.org/abs/1811.01457.

\n

Ge, Hong, Zoubin Ghahramani, and Kai Xu. 2018. Turing: a language for flexible probabilistic inference. http://proceedings.mlr.press/v84/ge18b.html.

\n

Innes, Michael. 2018. Don't unroll adjoint: Differentiating SSA-Form programs. http://arxiv.org/abs/1810.07951.

\n

Innes, Mike. 2018. Flux: Elegant machine learning with julia. doi:10.21105/joss.00602.

\n

Masthay, Tyler M., and Saverio Perugini. 2017. Parareal Algorithm Implementation and Simulation in Julia.

\n

Mogensen, Patrick Kofod, and Asbjørn Nilsen Riseth. 2018. Optim: A mathematical optimization package for Julia.

\n

Nie, Qing, and Christopher Rackauckas. 2017. DifferentialEquations.jl – a performant and feature-rich ecosystem for solving differential equations in julia. doi:10.5334/jors.151. https://app.dimensions.ai/details/publication/pub.1085583166.

\n

Novosel, Rok, and Bostjan Slivnik. 2019. Beyond Classical Parallel Programming Frameworks: Chapel vs Julia. Schloss Dagstuhl-Leibniz-Zentrum fuer Informatik.

\n", + "\\protect\\hypertarget{refs}{}\n\\section{The reference list.}\n\\protect\\hypertarget{ref-aruoba2015}{}Aruoba, S. Borağan, and Jesús Fernández-Villaverde. 2015. \\textit{A comparison of programming languages in macroeconomics. }\\par\n\\protect\\hypertarget{ref-cabutto2018}{}Ault, Shaun V., Tyler A. Cabutto, Sean P. Heeney, Guifen Mao, and Jin Wang. 2018. \\textit{An Overview of the Julia Programming Language. }\\par\n\\protect\\hypertarget{ref-besard2018}{}Besard, Tim, Bjorn De Sutter, and Christophe Foket. 2018. \\textit{Effective extensible programming: Unleashing julia on gpus. }\\par\n\\protect\\hypertarget{ref-bezanson2017}{}Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2017. \\textit{Julia: A fresh approach to numerical computing. }\\par\n\\protect\\hypertarget{ref-bezanson2012}{}Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2012. \\textit{Julia: A fast dynamic language for technical computing. }\\par\n\\protect\\hypertarget{ref-udell2014}{}Boyd, Stephen, Steven Diamond, Jenny Hong, Karanveer Mohan, Madeleine Udell, and David Zeng. 2014. \\textit{Convex optimization in Julia. }IEEE. \\par\n\\protect\\hypertarget{ref-chen2016}{}Chen, Jiahao, and Jarrett Revels. 2016. \\textit{Robust benchmarking in noisy environments. }\\par\n\\protect\\hypertarget{ref-cusumano-towner2019}{}Cusumano-Towner, Marco F., Alexander K. Lew, Vikash K. Mansinghka, and Feras A. Saad. 2019. \\textit{Gen: A general-purpose probabilistic programming system with programmable inference. }New York, NY, USA: ACM. doi:10.1145/3314221.3314642. \\href{http://doi.acm.org/10.1145/3314221.3314642}{http://doi.acm.org/10.1145/3314221.3314642}. \\par\n\\protect\\hypertarget{ref-lubin2015}{}Dunning, Iain, and Miles Lubin. 2015. \\textit{Computing in operations research using Julia. }\\par\n\\protect\\hypertarget{ref-edelman2015}{}Edelman, Alan. 2015. \\textit{Julia: A fresh approach to parallel programming. }IEEE. \\par\n\\protect\\hypertarget{ref-elmqvist2016}{}Elmqvist, Hilding, Toivo Henningsson, and Martin Otter. 2016. \\textit{Systems modeling and programming in a unified environment based on Julia. }Springer. \\par\n\\protect\\hypertarget{ref-fieker2017}{}Fieker, Claus, William Hart, Tommy Hofmann, and Fredrik Johansson. 2017. \\textit{Nemo/Hecke: computer algebra and number theory packages for the Julia programming language. }\\par\n\\protect\\hypertarget{ref-innes2018a}{}Fischer, Keno, Dhairya Gandhi, Michael Innes, Neethu Mariya Joy, Tejan Karmali, Avik Pal, Marco Concetto Rudilosso, Elliot Saba, and Viral Shah. 2018. \\textit{Fashionable modelling with flux. }\\href{http://arxiv.org/abs/1811.01457}{http://arxiv.org/abs/1811.01457}. \\par\n\\protect\\hypertarget{ref-ge2018}{}Ge, Hong, Zoubin Ghahramani, and Kai Xu. 2018. \\textit{Turing: a language for flexible probabilistic inference. }\\href{http://proceedings.mlr.press/v84/ge18b.html}{http://proceedings.mlr.press/v84/ge18b.html}. \\par\n\\protect\\hypertarget{ref-innes2018}{}Innes, Michael. 2018. \\textit{Don't unroll adjoint: Differentiating SSA-Form programs. }\\href{http://arxiv.org/abs/1810.07951}{http://arxiv.org/abs/1810.07951}. \\par\n\\protect\\hypertarget{ref-innes2018b}{}Innes, Mike. 2018. \\textit{Flux: Elegant machine learning with julia. }doi:10.21105/joss.00602. \\par\n\\protect\\hypertarget{ref-masthay2017}{}Masthay, Tyler M., and Saverio Perugini. 2017. \\textit{Parareal Algorithm Implementation and Simulation in Julia. }\\par\n\\protect\\hypertarget{ref-mogensen2018}{}Mogensen, Patrick Kofod, and Asbjørn Nilsen Riseth. 2018. \\textit{Optim: A mathematical optimization package for Julia. }\\par\n\\protect\\hypertarget{ref-rackauckas2017}{}Nie, Qing, and Christopher Rackauckas. 2017. \\textit{DifferentialEquations.jl – a performant and feature-rich ecosystem for solving differential equations in julia. }doi:10.5334/jors.151. \\href{https://app.dimensions.ai/details/publication/pub.1085583166}{https://app.dimensions.ai/details/publication/pub.1085583166}. \\par\n\\protect\\hypertarget{ref-novosel2019}{}Novosel, Rok, and Bostjan Slivnik. 2019. \\textit{Beyond Classical Parallel Programming Frameworks: Chapel vs Julia. }Schloss Dagstuhl-Leibniz-Zentrum fuer Informatik. \\par\n", + "{#refs}\n# The reference list.\n\n", + " \e[34;1m#\e[39;22m The reference list.\n \n Aruoba, S. Borağan, and Jesús Fernández-Villaverde. 2015. \e[3mA comparison of\n\e[23m \e[3mprogramming languages in macroeconomics. \e[23m\n \n Ault, Shaun V., Tyler A. Cabutto, Sean P. Heeney, Guifen Mao, and Jin Wang. \n 2018. \e[3mAn Overview of the Julia Programming Language. \e[23m\n \n Besard, Tim, Bjorn De Sutter, and Christophe Foket. 2018. \e[3mEffective\n\e[23m \e[3mextensible programming: Unleashing julia on gpus. \e[23m\n \n Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2017. \e[3m\n\e[23m \e[3mJulia: A fresh approach to numerical computing. \e[23m\n \n Bezanson, Jeff, Alan Edelman, Stefan Karpinski, and Viral B. Shah. 2012. \e[3m\n\e[23m \e[3mJulia: A fast dynamic language for technical computing. \e[23m\n \n Boyd, Stephen, Steven Diamond, Jenny Hong, Karanveer Mohan, Madeleine Udell,\n and David Zeng. 2014. \e[3mConvex optimization in Julia. \e[23mIEEE. \n \n Chen, Jiahao, and Jarrett Revels. 2016. \e[3mRobust benchmarking in noisy\n\e[23m \e[3menvironments. \e[23m\n \n Cusumano-Towner, Marco F., Alexander K. Lew, Vikash K. Mansinghka, and Feras\n A. Saad. 2019. \e[3mGen: A general-purpose probabilistic programming system with\n\e[23m \e[3mprogrammable inference. \e[23mNew York, NY, USA: ACM. doi:10.1145/3314221.3314642. \e[34;4m\n\e[39;24m \e[34;4mhttp://doi.acm.org/10.1145/3314221.3314642\e[39;24m. \n \n Dunning, Iain, and Miles Lubin. 2015. \e[3mComputing in operations research using\n\e[23m \e[3mJulia. \e[23m\n \n Edelman, Alan. 2015. \e[3mJulia: A fresh approach to parallel programming. \e[23mIEEE. \n \n Elmqvist, Hilding, Toivo Henningsson, and Martin Otter. 2016. \e[3mSystems\n\e[23m \e[3mmodeling and programming in a unified environment based on Julia. \e[23mSpringer. \n \n Fieker, Claus, William Hart, Tommy Hofmann, and Fredrik Johansson. 2017. \e[3m\n\e[23m \e[3mNemo/Hecke: computer algebra and number theory packages for the Julia\n\e[23m \e[3mprogramming language. \e[23m\n \n Fischer, Keno, Dhairya Gandhi, Michael Innes, Neethu Mariya Joy, Tejan\n Karmali, Avik Pal, Marco Concetto Rudilosso, Elliot Saba, and Viral Shah. \n 2018. \e[3mFashionable modelling with flux. \e[23m\e[34;4mhttp://arxiv.org/abs/1811.01457\e[39;24m. \n \n Ge, Hong, Zoubin Ghahramani, and Kai Xu. 2018. \e[3mTuring: a language for\n\e[23m \e[3mflexible probabilistic inference. \e[23m\e[34;4mhttp://proceedings.mlr.press/v84/ge18b.html\e[39;24m.\n \n \n Innes, Michael. 2018. \e[3mDon't unroll adjoint: Differentiating SSA-Form\n\e[23m \e[3mprograms. \e[23m\e[34;4mhttp://arxiv.org/abs/1810.07951\e[39;24m. \n \n Innes, Mike. 2018. \e[3mFlux: Elegant machine learning with julia. \e[23m\n doi:10.21105/joss.00602. \n \n Masthay, Tyler M., and Saverio Perugini. 2017. \e[3mParareal Algorithm\n\e[23m \e[3mImplementation and Simulation in Julia. \e[23m\n \n Mogensen, Patrick Kofod, and Asbjørn Nilsen Riseth. 2018. \e[3mOptim: A\n\e[23m \e[3mmathematical optimization package for Julia. \e[23m\n \n Nie, Qing, and Christopher Rackauckas. 2017. \e[3mDifferentialEquations.jl – a\n\e[23m \e[3mperformant and feature-rich ecosystem for solving differential equations in\n\e[23m \e[3mjulia. \e[23mdoi:10.5334/jors.151. \e[34;4m\n\e[39;24m \e[34;4mhttps://app.dimensions.ai/details/publication/pub.1085583166\e[39;24m. \n \n Novosel, Rok, and Bostjan Slivnik. 2019. \e[3mBeyond Classical Parallel\n\e[23m \e[3mProgramming Frameworks: Chapel vs Julia. \e[23mSchloss Dagstuhl-Leibniz-Zentrum\n fuer Informatik. \n", + "= The reference list.\n\n", + ) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.json b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.json new file mode 100644 index 0000000..436279c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/citations.json @@ -0,0 +1,609 @@ +[ + { + "id": "bezanson2017", + "type": "article-journal", + "container-title": "SIAM review", + "issue": "1", + "note": "publisher: SIAM", + "page": "65–98", + "title": "Julia: A fresh approach to numerical computing", + "title-short": "Julia", + "volume": "59", + "author": [ + { + "family": "Bezanson", + "given": "Jeff" + }, + { + "family": "Edelman", + "given": "Alan" + }, + { + "family": "Karpinski", + "given": "Stefan" + }, + { + "family": "Shah", + "given": "Viral B." + } + ], + "issued": { + "date-parts": [ + [ + "2017" + ] + ] + } + }, + { + "id": "edelman2015", + "type": "paper-conference", + "container-title": "2015 IEEE International Parallel and Distributed Processing Symposium", + "page": "517–517", + "publisher": "IEEE", + "title": "Julia: A fresh approach to parallel programming", + "title-short": "Julia", + "author": [ + { + "family": "Edelman", + "given": "Alan" + } + ], + "issued": { + "date-parts": [ + [ + "2015" + ] + ] + } + }, + { + "id": "cabutto2018", + "type": "paper-conference", + "container-title": "Proceedings of the 2018 International Conference on Computing and Big Data", + "page": "87–91", + "title": "An Overview of the Julia Programming Language", + "author": [ + { + "family": "Cabutto", + "given": "Tyler A." + }, + { + "family": "Heeney", + "given": "Sean P." + }, + { + "family": "Ault", + "given": "Shaun V." + }, + { + "family": "Mao", + "given": "Guifen" + }, + { + "family": "Wang", + "given": "Jin" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "novosel2019", + "type": "paper-conference", + "container-title": "8th Symposium on Languages, Applications and Technologies (SLATE 2019)", + "publisher": "Schloss Dagstuhl-Leibniz-Zentrum fuer Informatik", + "title": "Beyond Classical Parallel Programming Frameworks: Chapel vs Julia", + "title-short": "Beyond Classical Parallel Programming Frameworks", + "author": [ + { + "family": "Novosel", + "given": "Rok" + }, + { + "family": "Slivnik", + "given": "Bostjan" + } + ], + "issued": { + "date-parts": [ + [ + "2019" + ] + ] + } + }, + { + "id": "aruoba2015", + "type": "article-journal", + "container-title": "Journal of Economic Dynamics and Control", + "note": "publisher: Elsevier", + "page": "265–273", + "title": "A comparison of programming languages in macroeconomics", + "volume": "58", + "author": [ + { + "family": "Aruoba", + "given": "S. Borağan" + }, + { + "family": "Fernández-Villaverde", + "given": "Jesús" + } + ], + "issued": { + "date-parts": [ + [ + "2015" + ] + ] + } + }, + { + "id": "elmqvist2016", + "type": "paper-conference", + "container-title": "International Symposium on Leveraging Applications of Formal Methods", + "page": "198–217", + "publisher": "Springer", + "title": "Systems modeling and programming in a unified environment based on Julia", + "author": [ + { + "family": "Elmqvist", + "given": "Hilding" + }, + { + "family": "Henningsson", + "given": "Toivo" + }, + { + "family": "Otter", + "given": "Martin" + } + ], + "issued": { + "date-parts": [ + [ + "2016" + ] + ] + } + }, + { + "id": "masthay2017", + "type": "article-journal", + "container-title": "arXiv preprint arXiv:1706.08569", + "title": "Parareal Algorithm Implementation and Simulation in Julia", + "author": [ + { + "family": "Masthay", + "given": "Tyler M." + }, + { + "family": "Perugini", + "given": "Saverio" + } + ], + "issued": { + "date-parts": [ + [ + "2017" + ] + ] + } + }, + { + "id": "lubin2015", + "type": "article-journal", + "container-title": "INFORMS Journal on Computing", + "issue": "2", + "note": "publisher: INFORMS", + "page": "238–248", + "title": "Computing in operations research using Julia", + "volume": "27", + "author": [ + { + "family": "Lubin", + "given": "Miles" + }, + { + "family": "Dunning", + "given": "Iain" + } + ], + "issued": { + "date-parts": [ + [ + "2015" + ] + ] + } + }, + { + "id": "fieker2017", + "type": "paper-conference", + "container-title": "Proceedings of the 2017 acm on international symposium on symbolic and algebraic computation", + "page": "157–164", + "title": "Nemo/Hecke: computer algebra and number theory packages for the Julia programming language", + "title-short": "Nemo/Hecke", + "author": [ + { + "family": "Fieker", + "given": "Claus" + }, + { + "family": "Hart", + "given": "William" + }, + { + "family": "Hofmann", + "given": "Tommy" + }, + { + "family": "Johansson", + "given": "Fredrik" + } + ], + "issued": { + "date-parts": [ + [ + "2017" + ] + ] + } + }, + { + "id": "mogensen2018", + "type": "article-journal", + "container-title": "Journal of Open Source Software", + "issue": "24", + "note": "publisher: Open Journals", + "title": "Optim: A mathematical optimization package for Julia", + "title-short": "Optim", + "volume": "3", + "author": [ + { + "family": "Mogensen", + "given": "Patrick Kofod" + }, + { + "family": "Riseth", + "given": "Asbjørn Nilsen" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "bezanson2012", + "type": "article-journal", + "container-title": "arXiv preprint arXiv:1209.5145", + "title": "Julia: A fast dynamic language for technical computing", + "title-short": "Julia", + "author": [ + { + "family": "Bezanson", + "given": "Jeff" + }, + { + "family": "Karpinski", + "given": "Stefan" + }, + { + "family": "Shah", + "given": "Viral B." + }, + { + "family": "Edelman", + "given": "Alan" + } + ], + "issued": { + "date-parts": [ + [ + "2012" + ] + ] + } + }, + { + "id": "besard2018", + "type": "article-journal", + "container-title": "IEEE Transactions on Parallel and Distributed Systems", + "issue": "4", + "note": "publisher: IEEE", + "page": "827–841", + "title": "Effective extensible programming: Unleashing julia on gpus", + "title-short": "Effective extensible programming", + "volume": "30", + "author": [ + { + "family": "Besard", + "given": "Tim" + }, + { + "family": "Foket", + "given": "Christophe" + }, + { + "family": "De Sutter", + "given": "Bjorn" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "udell2014", + "type": "paper-conference", + "container-title": "2014 First Workshop for High Performance Technical Computing in Dynamic Languages", + "page": "18–28", + "publisher": "IEEE", + "title": "Convex optimization in Julia", + "author": [ + { + "family": "Udell", + "given": "Madeleine" + }, + { + "family": "Mohan", + "given": "Karanveer" + }, + { + "family": "Zeng", + "given": "David" + }, + { + "family": "Hong", + "given": "Jenny" + }, + { + "family": "Diamond", + "given": "Steven" + }, + { + "family": "Boyd", + "given": "Stephen" + } + ], + "issued": { + "date-parts": [ + [ + "2014" + ] + ] + } + }, + { + "id": "rackauckas2017", + "type": "article-journal", + "container-title": "The Journal of Open Research Software", + "DOI": "10.5334/jors.151", + "issue": "1", + "title": "DifferentialEquations.jl – a performant and feature-rich ecosystem for solving differential equations in julia", + "URL": "https://app.dimensions.ai/details/publication/pub.1085583166", + "volume": "5", + "author": [ + { + "family": "Rackauckas", + "given": "Christopher" + }, + { + "family": "Nie", + "given": "Qing" + } + ], + "issued": { + "date-parts": [ + [ + "2017" + ] + ] + } + }, + { + "id": "cusumano-towner2019", + "type": "paper-conference", + "collection-title": "PLDI 2019", + "container-title": "Proceedings of the 40th ACM SIGPLAN conference on programming language design and implementation", + "DOI": "10.1145/3314221.3314642", + "event-place": "New York, NY, USA", + "ISBN": "978-1-4503-6712-7", + "note": "number-of-pages: 16\npublisher-place: Phoenix, AZ, USA\ntex.acmid: 3314642", + "page": "221–236", + "publisher": "ACM", + "publisher-place": "New York, NY, USA", + "title": "Gen: A general-purpose probabilistic programming system with programmable inference", + "URL": "http://doi.acm.org/10.1145/3314221.3314642", + "author": [ + { + "family": "Cusumano-Towner", + "given": "Marco F." + }, + { + "family": "Saad", + "given": "Feras A." + }, + { + "family": "Lew", + "given": "Alexander K." + }, + { + "family": "Mansinghka", + "given": "Vikash K." + } + ], + "issued": { + "date-parts": [ + [ + "2019" + ] + ] + } + }, + { + "id": "ge2018", + "type": "paper-conference", + "container-title": "International conference on artificial intelligence and statistics, AISTATS 2018, 9-11 april 2018, playa blanca, lanzarote, canary islands, spain", + "note": "tex.biburl: https://dblp.org/rec/bib/conf/aistats/GeXG18", + "page": "1682–1690", + "title": "Turing: a language for flexible probabilistic inference", + "URL": "http://proceedings.mlr.press/v84/ge18b.html", + "author": [ + { + "family": "Ge", + "given": "Hong" + }, + { + "family": "Xu", + "given": "Kai" + }, + { + "family": "Ghahramani", + "given": "Zoubin" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "chen2016", + "type": "article-journal", + "container-title": "arXiv e-prints", + "note": "arXiv: 1608.04295 [cs.PF]\ntex.adsnote: Provided by the SAO/NASA Astrophysics Data System\ntex.adsurl: https://ui.adsabs.harvard.edu/abs/2016arXiv160804295C\ntex.eid: arXiv:1608.04295", + "title": "Robust benchmarking in noisy environments", + "author": [ + { + "family": "Chen", + "given": "Jiahao" + }, + { + "family": "Revels", + "given": "Jarrett" + } + ], + "issued": { + "date-parts": [ + [ + "2016", + 8 + ] + ] + } + }, + { + "id": "innes2018a", + "type": "article-journal", + "container-title": "CoRR", + "note": "arXiv: 1811.01457\ntex.bibsource: dblp computer science bibliography, https://dblp.org\ntex.biburl: https://dblp.org/rec/bib/journals/corr/abs-1811-01457\ntex.timestamp: Thu, 22 Nov 2018 17:58:30 +0100", + "title": "Fashionable modelling with flux", + "URL": "http://arxiv.org/abs/1811.01457", + "volume": "abs/1811.01457", + "author": [ + { + "family": "Innes", + "given": "Michael" + }, + { + "family": "Saba", + "given": "Elliot" + }, + { + "family": "Fischer", + "given": "Keno" + }, + { + "family": "Gandhi", + "given": "Dhairya" + }, + { + "family": "Rudilosso", + "given": "Marco Concetto" + }, + { + "family": "Joy", + "given": "Neethu Mariya" + }, + { + "family": "Karmali", + "given": "Tejan" + }, + { + "family": "Pal", + "given": "Avik" + }, + { + "family": "Shah", + "given": "Viral" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "innes2018b", + "type": "article-journal", + "container-title": "Journal of Open Source Software", + "DOI": "10.21105/joss.00602", + "title": "Flux: Elegant machine learning with julia", + "author": [ + { + "family": "Innes", + "given": "Mike" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + }, + { + "id": "innes2018", + "type": "article-journal", + "container-title": "CoRR", + "note": "arXiv: 1810.07951\ntex.bibsource: dblp computer science bibliography, https://dblp.org\ntex.biburl: https://dblp.org/rec/bib/journals/corr/abs-1810-07951\ntex.timestamp: Tue, 30 Oct 2018 20:39:56 +0100", + "title": "Don't unroll adjoint: Differentiating SSA-Form programs", + "URL": "http://arxiv.org/abs/1810.07951", + "volume": "abs/1810.07951", + "author": [ + { + "family": "Innes", + "given": "Michael" + } + ], + "issued": { + "date-parts": [ + [ + "2018" + ] + ] + } + } +] diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/footnotes.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/footnotes.jl new file mode 100644 index 0000000..4a31d4c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/footnotes.jl @@ -0,0 +1,84 @@ +@testset "Footnotes" begin + p = Parser() + enable!(p, FootnoteRule()) + + # Links + text = "text[^1]" + ast = p(text) + + @test html(ast) == "

text1

\n" + @test latex(ast) == "text\\par\n" # No definition so not displayed in LaTeX. + @test typst(ast) == "text\n" # No definition so not displayed in Typst. + @test term(ast) == " text\e[31m[^1]\e[39m\n" + @test markdown(ast) == "text[^1]\n" + + # Definitions + text = "[^1]: text" + ast = p(text) + + @test html(ast) == + "

1

\n

text

\n
" + @test latex(ast) == "" # Definitions vanish in LaTeX since they are inlined. + @test typst(ast) == "" # Definitions vanish in Typst since they are inlined. + @test term(ast) == + " \e[31m┌ [^1] ───────────────────────────────────────────────────────────────────────\e[39m\n \e[31m│\e[39m text\n \e[31m└─────────────────────────────────────────────────────────────────────────────\e[39m\n" + @test markdown(ast) == "[^1]: text\n" + + text = "text[^1].\n\n[^1]: text" + ast = p(text) + @test latex(ast) == "text\\footnote{text\\par\n\\label{fn:1}}.\\par\n" + @test typst(ast) == "text#footnote[text\n] .\n\n" + @test markdown(ast) == "text[^1].\n\n[^1]: text\n" + + p = enable!(Parser(), [FootnoteRule(), AttributeRule()]) + + text = "text[^1]{#id}" + ast = p(text) + + @test html(ast) == + "

text1

\n" + + text = """ + {key="value"} + [^1]: text + """ + ast = p(text) + + @test html(ast) == + "

1

\n

text

\n
" + + text = """ + text[^1]{#id}. + + {key="value"} + [^1]: text + """ + ast = p(text) + @test html(ast) == + "

text1.

\n

1

\n

text

\n
" + @test latex(ast) == + "text\\protect\\hypertarget{id}{}\\footnote{text\\par\n\\label{fn:1}}.\\par\n" + @test typst(ast) == "text#footnote[text\n] .\n\n" + + text = "[^1]:\n\n text" + ast = p(text) + + @test html(ast) == + "

1

\n

text

\n
" + @test latex(ast) == "" # Definitions vanish in LaTeX since they are inlined. + @test term(ast) == + " \e[31m┌ [^1] ───────────────────────────────────────────────────────────────────────\e[39m\n \e[31m│\e[39m text\n \e[31m└─────────────────────────────────────────────────────────────────────────────\e[39m\n" + @test markdown(ast) == "[^1]: text\n" + @test typst(ast) == "" # Definitions vanish in Typst since they are inlined. + + text = "[^1]:\n\n\ttext" + ast = p(text) + + @test html(ast) == + "

1

\n

text

\n
" + @test latex(ast) == "" # Definitions vanish in LaTeX since they are inlined. + @test typst(ast) == "" # Definitions vanish in Typst since they are inlined. + @test term(ast) == + " \e[31m┌ [^1] ───────────────────────────────────────────────────────────────────────\e[39m\n \e[31m│\e[39m text\n \e[31m└─────────────────────────────────────────────────────────────────────────────\e[39m\n" + @test markdown(ast) == "[^1]: text\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/frontmatter.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/frontmatter.jl new file mode 100644 index 0000000..330f17b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/frontmatter.jl @@ -0,0 +1,73 @@ +@testset "Frontmatter" begin + p = Parser() + enable!( + p, + FrontMatterRule(json = JSON.Parser.parse, toml = TOML.parse, yaml = YAML.load), + ) + + test = function (text, expected) + ast = p(text) + data = frontmatter(ast) + @test length(data) == 1 + @test data["field"] == "data" + @test html(ast) == expected + end + + # JSON + test( + """ + ;;; + {"field": "data"} + ;;; + ;;; + """, + "

;;;

\n", + ) + + # TOML + test( + """ + +++ + field = "data" + +++ + +++ + """, + "

+++

\n", + ) + + # YAML + test( + """ + --- + field: data + --- + --- + """, + "
\n", + ) + + # Unclosed frontmatter. Runs on until EOF. + text = """ + +++ + one = 1 + two = 2 + """ + ast = p(text) + data = frontmatter(ast) + @test data["one"] == 1 + @test data["two"] == 2 + + # Frontmatter must begin on the first line of the file. Otherwise it's a literal. + text = "\n+++" + ast = p(text) + @test html(ast) == "

+++

\n" + + text = """ + --- + field: data + --- + """ + ast = p(text) + @test markdown(ast) == "---\nfield: data\n---\n" + @test markdown(p(markdown(ast))) == markdown(ast) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/highlights.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/highlights.jl new file mode 100644 index 0000000..af1138a --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/highlights.jl @@ -0,0 +1,20 @@ +@testset "Highlights" begin + highlighter(::MIME"text/html", node) = "NO HTML HIGHLIGHTING" + highlighter(::MIME"text/latex", node) = "NO LATEX HIGHLIGHTING" + highlighter(::MIME"text/plain", node) = "NO TERM HIGHLIGHTING" + + p = Parser() + env = Dict("syntax-highlighter" => highlighter) + + ast = p(""" + ```julia + code + ``` + """) + @test html(ast, env) == + "
NO HTML HIGHLIGHTING
\n" + @test latex(ast, env) == + "\\begin{lstlisting}\nNO LATEX HIGHLIGHTING\n\\end{lstlisting}\n" + @test term(ast, env) == " \e[36m│\e[39m \e[90mNO TERM HIGHLIGHTING\e[39m\n" + @test markdown(ast, env) == "```julia\ncode\n```\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/interpolation.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/interpolation.jl new file mode 100644 index 0000000..0a662e9 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/interpolation.jl @@ -0,0 +1,167 @@ +function custom_parser() + p = Parser() + enable!(p, MathRule()) + return p +end + +@testset "Interpolation" begin + ast = cm"" + @test html(ast) == "" + @test latex(ast) == "" + @test markdown(ast) == "" + @test term(ast) == "" + @test typst(ast) == "" + + ast = cm"no interpolation" + @test html(ast) == "

no interpolation

\n" + @test latex(ast) == "no interpolation\\par\n" + @test markdown(ast) == "no interpolation\n" + @test term(ast) == " no interpolation\n" + @test typst(ast) == "no interpolation\n" + + value = :interpolation + ast = cm"'some' $value $(value)" + @test html(ast) == + "

‘some’ interpolation interpolation

\n" + @test latex(ast) == "‘some’ interpolation interpolation\\par\n" + @test markdown(ast) == "‘some’ \$(value) \$(value)\n" + @test term(ast) == " ‘some’ \e[33minterpolation\e[39m \e[33minterpolation\e[39m\n" + @test typst(ast) == "‘some’ interpolation interpolation\n" + + ast = cm"*expressions* $(1 + 2) and $(2 + 3)" + @test html(ast) == + "

expressions 3 and 5

\n" + @test latex(ast) == "\\textit{expressions} 3 and 5\\par\n" + @test markdown(ast) == "*expressions* \$(1 + 2) and \$(2 + 3)\n" + @test term(ast) == " \e[3mexpressions\e[23m \e[33m3\e[39m and \e[33m5\e[39m\n" + @test typst(ast) == "#emph[expressions] 3 and 5\n" + + ast = cm"> *expressions* $(1 + 2) and $(2 + 3)" + @test html(ast) == + "
\n

expressions 3 and 5

\n
\n" + @test latex(ast) == "\\begin{quote}\n\\textit{expressions} 3 and 5\\par\n\\end{quote}\n" + @test markdown(ast) == "> *expressions* \$(1 + 2) and \$(2 + 3)\n" + @test term(ast) == + " \e[1m│\e[22m \e[3mexpressions\e[23m \e[33m3\e[39m and \e[33m5\e[39m\n" + @test typst(ast) == "#quote(block: true)[\n#emph[expressions] 3 and 5\n]\n" + + value = :interpolation + ast = cm"'some' $value $(value)"basic + @test html(ast) == + "

'some' interpolation interpolation

\n" + @test latex(ast) == "'some' interpolation interpolation\\par\n" + @test markdown(ast) == "'some' \$(value) \$(value)\n" + @test term(ast) == " 'some' \e[33minterpolation\e[39m \e[33minterpolation\e[39m\n" + @test typst(ast) == "'some' interpolation interpolation\n" + + value = :interpolation + ast = cm"'some' ``math`` $value $(value)"custom_parser + @test html(ast) == + "

'some' \\(math\\) interpolation interpolation

\n" + @test latex(ast) == "'some' \\(math\\) interpolation interpolation\\par\n" + @test markdown(ast) == "'some' ``math`` \$(value) \$(value)\n" + @test term(ast) == + " 'some' \e[35mmath\e[39m \e[33minterpolation\e[39m \e[33minterpolation\e[39m\n" + @test typst(ast) == "'some' \$math\$ interpolation interpolation\n" + + value = 1 + ast = cm"$(value) $(value + 1) $(value += 1) $(value += 1)" + @test html(ast) == + "

1 2 2 3

\n" + @test latex(ast) == "1 2 2 3\\par\n" + @test markdown(ast) == "\$(value) \$(value + 1) \$(value += 1) \$(value += 1)\n" + @test term(ast) == " \e[33m1\e[39m \e[33m2\e[39m \e[33m2\e[39m \e[33m3\e[39m\n" + @test typst(ast) == "1 2 2 3\n" + + # A case that can fail if the @cm_str macro relies on evaluating the passed expressions in argument + # lists (like the constructor of a vector). + # https://github.com/JuliaLang/julia/issues/46251 + let + global value_global + value_global = 1 + ast = + cm"$(value_global) $(value_global + 1) $(value_global += 1) $(value_global += 1)" + @test latex(ast) == "1 2 2 3\\par\n" + end + + # Interpolated strings are not markdown-interpreted + ast = cm"""*expressions* $("**test**")""" + @test html(ast) == + "

expressions **test**

\n" + @test latex(ast) == "\\textit{expressions} **test**\\par\n" + @test markdown(ast) == "*expressions* \$(**test**)\n" + @test term(ast) == " \e[3mexpressions\e[23m \e[33m**test**\e[39m\n" + @test typst(ast) == "#emph[expressions] **test**\n" + + # Interpolated values are not linked to their macroexpansion origin. + asts = [cm"Value = **$(each)**" for each = 1:3] + @test html(asts[1]) == + "

Value = 1

\n" + @test html(asts[2]) == + "

Value = 2

\n" + @test html(asts[3]) == + "

Value = 3

\n" + + # Interpolating collections. + worlds = [HTML("
world $i
") for i = 1:3] + @test html(cm"Hello $(worlds)") == + "

Hello

world 1
world 2
world 3

\n" + + worlds = (HTML("
world $i
") for i = 1:3) + @test html(cm"Hello $(worlds)") == + "

Hello

world 1
world 2
world 3

\n" + + worlds = Tuple(HTML("
world $i
") for i = 1:3) + @test html(cm"Hello $(worlds)") == + "

Hello

world 1
world 2
world 3

\n" + + # Make sure that the evaluation of values happens at runtime. + f(x) = cm"if x = $(x), then x² = $(x^2)" + let ast = f(2) + @test markdown(ast) == "if x = \$(x), then x² = \$(x ^ 2)\n" + @test term(ast) == " if x = \e[33m2\e[39m, then x² = \e[33m4\e[39m\n" + end + let ast = f(-3) + @test markdown(ast) == "if x = \$(x), then x² = \$(x ^ 2)\n" + @test term(ast) == " if x = \e[33m-3\e[39m, then x² = \e[33m9\e[39m\n" + end + + # Make sure that a variable that evaluates to different values in different positions + # gets interpolated correctly. + let x = 1 + function f!() + x += 1 + 42 + end # closure that updates the local `x` variable + ast = cm"$(x), $(f!()), $(x)" + @test markdown(ast) == "\$(x), \$(f!()), \$(x)\n" + @test term(ast) == " \e[33m1\e[39m, \e[33m42\e[39m, \e[33m2\e[39m\n" + end + + # IOContext passthrough + struct MyInterpolatedType end + + function Base.show(io::IO, m::MIME"text/html", x::MyInterpolatedType) + write(io, get(io, :secret, "not found")) + end + + value = MyInterpolatedType() + ast = cm"hello $(value)" + out1 = repr(MIME"text/html"(), ast) + out2 = repr(MIME"text/html"(), ast; context = (:secret => "🙊")) + @test out1 == "

hello not found

\n" + @test out2 == "

hello 🙊

\n" + + # ASTs containing JuliaExpression elements + p = Parser() + enable!(p, CommonMark.JuliaInterpolationRule()) + ast = p("foo: \$(foo), \$(x ^ 2), \$1234") + @test html(ast) == + "

foo: \$(foo), \$(x ^ 2), \$(1234)

\n" + @test latex(ast) == + "foo: \\texttt{\\\$(foo)}, \\texttt{\\\$(x \\^{} 2)}, \\texttt{\\\$(1234)}\\par\n" + @test markdown(ast) == "foo: \$(foo), \$(x ^ 2), \$(1234)\n" + @test term(ast) == + " foo: \e[33m\$(foo)\e[39m, \e[33m\$(x ^ 2)\e[39m, \e[33m\$(1234)\e[39m\n" + @test typst(ast) == "foo: foo, x ^ 2, 1234\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/math.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/math.jl new file mode 100644 index 0000000..eaf31df --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/math.jl @@ -0,0 +1,85 @@ +@testset "Math" begin + p = Parser() + enable!(p, MathRule()) + + # Inline + text = "Some ``math``." + ast = p(text) + + @test html(ast) == "

Some \\(math\\).

\n" + @test latex(ast) == "Some \\(math\\).\\par\n" + @test typst(ast) == "Some \$math\$.\n" + @test term(ast) == " Some \e[35mmath\e[39m.\n" + @test markdown(ast) == "Some ``math``.\n" + + ast = p("`x`") + @test html(ast) == "

x

\n" + + # Display + text = "```math\nmath\n```" + ast = p(text) + + @test html(ast) == "
\\[math\\]
" + @test latex(ast) == "\\begin{equation*}\nmath\n\\end{equation*}\n" + @test typst(ast) == "\$ math \$\n" + @test term(ast) == " \e[35m│\e[39m \e[90mmath\e[39m\n" + @test markdown(ast) == "```math\nmath\n```\n" + + p = enable!(Parser(), [MathRule(), AttributeRule()]) + text = "Some ``math``{key='value'}." + ast = p(text) + + @test html(ast) == + "

Some \\(math\\).

\n" + + text = """ + {#id} + ```math + math + ``` + """ + ast = p(text) + + @test html(ast) == "
\\[math\\]
" + @test latex(ast) == + "\\protect\\hypertarget{id}{}\\begin{equation*}\nmath\n\\end{equation*}\n" + + text = """ + {.red} + ```math + E=mc^2 + ``` + """ + ast = p(text) + + @test html(ast) == "
\\[E=mc^2\\]
" + + text = """ + {#id .red} + ```math + E=mc^2 + ``` + """ + ast = p(text) + + @test html(ast) == "
\\[E=mc^2\\]
" + + # Dollar math + p = enable!(Parser(), DollarMathRule()) + + text = raw"Some $math$." + ast = p(text) + @test html(ast) == "

Some \\(math\\).

\n" + @test latex(ast) == "Some \\(math\\).\\par\n" + @test typst(ast) == "Some \$math\$.\n" + @test markdown(ast) == "Some ``math``.\n" + @test term(ast) == " Some \e[35mmath\e[39m.\n" + + text = raw"$$display math$$" + ast = p(text) + @test html(ast) == "
\\[display math\\]
" + @test latex(ast) == "\\begin{equation*}\ndisplay math\n\\end{equation*}\n" + @test typst(ast) == "\$ display math \$\n" + @test markdown(ast) == "```math\ndisplay math\n```\n" + @test term(ast) == " \e[35m│\e[39m \e[90mdisplay math\e[39m\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/raw.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/raw.jl new file mode 100644 index 0000000..53e6b46 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/raw.jl @@ -0,0 +1,46 @@ +@testset "Raw Content" begin + p = Parser() + enable!(p, RawContentRule()) + + text = "`html`{=html}`latex`{=latex}`typst`{=typst}" + ast = p(text) + + @test html(ast) == "

html

\n" + @test latex(ast) == "latex\\par\n" + @test term(ast) == " \e[90mhtml\e[39m\e[90mlatex\e[39m\e[90mtypst\e[39m\n" + @test markdown(ast) == "html`latex`{=latex}`typst`{=typst}\n" # TODO: should we pass through a literal instead for html? + + text = """ + ```{=html} +
+
+ ``` + ```{=latex} + \\begin{tikzpicture} + ... + \\end{tikzpicture} + ``` + ```{=typst} + #let name = "Typst" + ``` + """ + ast = p(text) + + @test html(ast) == "
\n
\n" + @test latex(ast) == "\\begin{tikzpicture}\n...\n\\end{tikzpicture}\n" + @test term(ast) == + " \e[90m
\e[39m\n \e[90m
\e[39m\n \n \e[90m\\begin{tikzpicture}\e[39m\n \e[90m...\e[39m\n \e[90m\\end{tikzpicture}\e[39m\n \n \e[90m#let name = \"Typst\"\e[39m\n" + @test markdown(ast) == + "
\n
\n\n```{=latex}\n\\begin{tikzpicture}\n...\n\\end{tikzpicture}\n```\n\n```{=typst}\n#let name = \"Typst\"\n```\n" + + p = Parser() + enable!(p, RawContentRule(text_inline = CommonMark.Text)) + + text = "`**not bold**`{=text}" + ast = p(text) + + @test html(ast) == "

**not bold**

\n" + @test latex(ast) == "**not bold**\\par\n" + @test term(ast) == " **not bold**\n" + @test markdown(ast) == "**not bold**\n" # TODO: pass through raw content. +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/smartlinks.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/smartlinks.jl new file mode 100644 index 0000000..cad4bab --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/smartlinks.jl @@ -0,0 +1,27 @@ +@testset "Smart Links" begin + function handler(::MIME"text/html", obj::CommonMark.Link, node::CommonMark.Node, env) + name, _ = splitext(obj.destination) + obj = deepcopy(obj) + obj.destination = join([env["root"], "$name.html"], "/") + return obj + end + handler(mime, obj, node, env) = obj + + p = Parser() + env = Dict("root" => "/root", "smartlink-engine" => handler) + + ast = p("[link](url.md)") + @test html(ast, env) == "

link

\n" + @test latex(ast, env) == "\\href{url.md}{link}\\par\n" + @test term(ast, env) == " \e[34;4mlink\e[39;24m\n" + @test markdown(ast, env) == "[link](url.md)\n" + @test typst(ast, env) == "#link(\"url.md\")[link]\n" + + ast = p("![link](url.img)") + @test html(ast, env) == "

\"link\"

\n" + @test latex(ast, env) == + "\\begin{figure}\n\\centering\n\\includegraphics[max width=\\linewidth]{url.img}\n\\caption{link}\n\\end{figure}\n\\par\n" + @test term(ast, env) == " \e[32mlink\e[39m\n" + @test markdown(ast, env) == "![link](url.img)\n" + @test typst(ast, env) == "#figure(image(\"url.img\"), caption: [link])\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/tables.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/tables.jl new file mode 100644 index 0000000..5fc4e0b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/tables.jl @@ -0,0 +1,161 @@ +@testset "Tables" begin + p = Parser() + enable!(p, TableRule()) + + text = """ + | 1 | 10 | 100 | + | - | --:|:---:| + | x | y | z | + """ + ast = p(text) + + # HTML + @test html(ast) == + "
110100
xyz
" + @test latex(ast) == + "\\begin{longtable}[]{@{}lrc@{}}\n\\hline\n1 & 10 & 100\\tabularnewline\n\\hline\n\\endfirsthead\nx & y & z\\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "#table(align: (left, right, center), columns: 3, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[1],[10],[100],\n),\n[x],[y],[z],\n)\n" + @test term(ast) == + " ┏━━━┯━━━━┯━━━━━┓\n ┃ 1 │ 10 │ 100 ┃\n ┠───┼────┼─────┨\n ┃ x │ y │ z ┃\n ┗━━━┷━━━━┷━━━━━┛\n" + @test markdown(ast) == "| 1 | 10 | 100 |\n|:- | --:|:---:|\n| x | y | z |\n" + @test markdown(p(markdown(ast))) == + "| 1 | 10 | 100 |\n|:- | --:|:---:|\n| x | y | z |\n" + + # Mis-aligned table pipes: + text = """ + |1|10|100| + | - | --:|:---:| + |x|y|z| + """ + ast = p(text) + @test html(ast) == + "
110100
xyz
" + + p = enable!(Parser(), [TableRule(), AttributeRule()]) + + text = """ + {#id} + | 1 | 10 | 100 | + | - | --:|:---:| + | x | y | z | + """ + ast = p(text) + + # HTML + @test html(ast) == + "
110100
xyz
" + @test latex(ast) == + "\\protect\\hypertarget{id}{}\\begin{longtable}[]{@{}lrc@{}}\n\\hline\n1 & 10 & 100\\tabularnewline\n\\hline\n\\endfirsthead\nx & y & z\\tabularnewline\n\\hline\n\\end{longtable}\n" + + # Internal pipes: + text = """ + |1|10|`|`| + | -:| - |:-:| + |*|*|![|](url)| + |1|2|3|4| + """ + ast = p(text) + + @test html(ast) == + "
110|
|\"|\"
123
" + @test latex(ast) == + "\\begin{longtable}[]{@{}rlc@{}}\n\\hline\n1 & 10 & \\texttt{|}\\tabularnewline\n\\hline\n\\endfirsthead\n\\textit{|} & \n\\begin{figure}\n\\centering\n\\includegraphics[max width=\\linewidth]{url}\n\\caption{|}\n\\end{figure}\n & \\tabularnewline\n1 & 2 & 3\\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "#table(align: (right, left, center), columns: 3, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[1],[10],[`|`],\n),\n[#emph[|]],[#figure(image(\"url\"), caption: [|])],[],\n[1],[2],[3],\n)\n" + @test term(ast) == + " ┏━━━┯━━━━┯━━━┓\n ┃ 1 │ 10 │ \e[36m|\e[39m ┃\n ┠───┼────┼───┨\n ┃ \e[3m|\e[23m │ \e[32m|\e[39m │ ┃\n ┃ 1 │ 2 │ 3 ┃\n ┗━━━┷━━━━┷━━━┛\n" + @test markdown(ast) == + "| 1 | 10 | `|` |\n| ---:|:--------- |:---:|\n| *|* | ![|](url) | |\n| 1 | 2 | 3 |\n" + + # Empty columns: + text = """ + ||| + |-|-| + ||| + """ + ast = p(text) + + @test html(ast) == + "
" + @test latex(ast) == + "\\begin{longtable}[]{@{}ll@{}}\n\\hline\n & \\tabularnewline\n\\hline\n\\endfirsthead\n & \\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "#table(align: (left, left), columns: 2, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[],[],\n),\n[],[],\n)\n" + @test term(ast) == " ┏━━━┯━━━┓\n ┃ │ ┃\n ┠───┼───┨\n ┃ │ ┃\n ┗━━━┷━━━┛\n" + @test markdown(ast) == "| | |\n|:- |:- |\n| | |\n" + + text = """ + # Header + + | table | + | ----- | + | content | + """ + ast = p(text) + + @test html(ast) == + "

Header

\n
table
content
" + @test latex(ast) == + "\\section{Header}\n\\begin{longtable}[]{@{}l@{}}\n\\hline\ntable\\tabularnewline\n\\hline\n\\endfirsthead\ncontent\\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "= Header\n\n#table(align: (left), columns: 1, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[table],\n),\n[content],\n)\n" + @test term(ast) == + " \e[34;1m#\e[39;22m Header\n \n ┏━━━━━━━━━┓\n ┃ table ┃\n ┠─────────┨\n ┃ content ┃\n ┗━━━━━━━━━┛\n" + @test markdown(ast) == "# Header\n\n| table |\n|:------- |\n| content |\n" + + # 'messy' tables + + text = """ + # Messy tables + + | table + | :-: | + | *|* + """ + ast = p(text) + + @test html(ast) == + "

Messy tables

\n
table
|
" + @test latex(ast) == + "\\section{Messy tables}\n\\begin{longtable}[]{@{}c@{}}\n\\hline\ntable\\tabularnewline\n\\hline\n\\endfirsthead\n\\textit{|}\\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "= Messy tables\n\n#table(align: (center), columns: 1, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[table],\n),\n[#emph[|]],\n)\n" + @test term(ast) == + " \e[34;1m#\e[39;22m Messy tables\n \n ┏━━━━━━━┓\n ┃ table ┃\n ┠───────┨\n ┃ \e[3m|\e[23m ┃\n ┗━━━━━━━┛\n" + @test markdown(ast) == "# Messy tables\n\n| table |\n|:-----:|\n| *|* |\n" + + + # tables with lots of whitespace + + text = """ + # whitespace (#38) + + | 1 | 2 | 3 | 4 | + | :--: | :-- | --- | -: | + | one | two | three | four | + """ + ast = p(text) + + @test html(ast) == + "

whitespace (#38)

\n
1234
onetwothreefour
" + @test latex(ast) == + "\\section{whitespace (\\#38)}\n\\begin{longtable}[]{@{}cllr@{}}\n\\hline\n1 & 2 & 3 & 4\\tabularnewline\n\\hline\n\\endfirsthead\none & two & three & four\\tabularnewline\n\\hline\n\\end{longtable}\n" + @test typst(ast) == + "= whitespace (\\#38)\n\n#table(align: (center, left, left, right), columns: 4, fill: (x, y) => if y == 0 { rgb(\"#e5e7eb\") },\ntable.header(\n[1],[2],[3],[4],\n),\n[one],[two],[three],[four],\n)\n" + @test term(ast) == + " \e[34;1m#\e[39;22m whitespace (#38)\n \n ┏━━━━━┯━━━━━┯━━━━━━━┯━━━━━━┓\n ┃ 1 │ 2 │ 3 │ 4 ┃\n ┠─────┼─────┼───────┼──────┨\n ┃ one │ two │ three │ four ┃\n ┗━━━━━┷━━━━━┷━━━━━━━┷━━━━━━┛\n" + @test markdown(ast) == + "# whitespace (#38)\n\n| 1 | 2 | 3 | 4 |\n|:---:|:--- |:----- | ----:|\n| one | two | three | four |\n" + + + text = """ + | Tables | Are | Cool | + |----------|-------------|------| + | col 3 is | right-aligned δεδομέ | 1 | + """ + ast = p(text) + @test html(ast) == + "
TablesAreCool
col 3 isright-aligned δεδομέ1
" + +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/extensions/typography.jl b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/typography.jl new file mode 100644 index 0000000..40e3afb --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/extensions/typography.jl @@ -0,0 +1,13 @@ +@testset "Typography" begin + p = Parser() + enable!(p, TypographyRule()) + + text = "\"Double quotes\", 'single quotes', ellipses...., and-- dashes---" + ast = p(text) + + @test html(ast) == "

“Double quotes”, ‘single quotes’, ellipses…., and– dashes—

\n" + @test latex(ast) == "“Double quotes”, ‘single quotes’, ellipses…., and– dashes—\\par\n" + @test term(ast) == " “Double quotes”, ‘single quotes’, ellipses…., and– dashes—\n" + @test markdown(ast) == "“Double quotes”, ‘single quotes’, ellipses…., and– dashes—\n" + @test typst(ast) == "“Double quotes”, ‘single quotes’, ellipses…., and– dashes—\n" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/integration.jl b/.julia-depot/packages/CommonMark/lmLkP/test/integration.jl new file mode 100644 index 0000000..d1ea034 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/integration.jl @@ -0,0 +1,21 @@ +@testset "Multiple Extensions" begin + extensions = [ + AdmonitionRule(), + AttributeRule(), + AutoIdentifierRule(), + CitationRule(), + FootnoteRule(), + FrontMatterRule(yaml = YAML.load), + MathRule(), + RawContentRule(), + TableRule(), + TypographyRule(), + ] + p = enable!(Parser(), extensions) + ast = open(p, joinpath(@__DIR__, "integration.md")) + @test !isempty(html(ast)) + @test !isempty(latex(ast)) + @test !isempty(term(ast)) + @test markdown(ast) == + replace(read(joinpath(@__DIR__, "integration_output.md"), String), "\r" => "") +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/integration.md b/.julia-depot/packages/CommonMark/lmLkP/test/integration.md new file mode 100644 index 0000000..6c2da45 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/integration.md @@ -0,0 +1,54 @@ +--- +front: matter +--- + +# Integration Tests + +!!! danger + + Warning [@cite] admonition[^1]... + + ```math + maths + ``` + + {.class} + [^1]: 1 + + footnote content + +!!! warning + + "Warning" [@cite] admonition[^2]. + + | table | + | - | + | content | + + [^2]: 2 + +!!! info + + 'Tip' [@cite] 'admonition'[^3]. + + [^3]: ``x`` + +!!! note + + Note [@cite] "admonition"[^4]. + + ```{=latex} + latex + ``` + + [^4]: 4 + +!!! tip + + Tip [@cite] admonition[^5]. + + [^5]: 5 + +{#refs} +## References + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/integration_output.md b/.julia-depot/packages/CommonMark/lmLkP/test/integration_output.md new file mode 100644 index 0000000..37f9d06 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/integration_output.md @@ -0,0 +1,54 @@ +--- +front: matter +--- + +# Integration Tests + +!!! danger + + Warning [@cite] admonition[^1]… + + ```math + maths + ``` + + {.class} + [^1]: 1 + + footnote content + +!!! warning + + “Warning” [@cite] admonition[^2]. + + | table | + |:------- | + | content | + + [^2]: 2 + +!!! info + + ‘Tip’ [@cite] ‘admonition’[^3]. + + [^3]: ``x`` + +!!! note + + Note [@cite] “admonition”[^4]. + + ```{=latex} + latex + ``` + + [^4]: 4 + +!!! tip + + Tip [@cite] admonition[^5]. + + [^5]: 5 + +{#refs} +## References + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/parsing.jl b/.julia-depot/packages/CommonMark/lmLkP/test/parsing.jl new file mode 100644 index 0000000..31bda88 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/parsing.jl @@ -0,0 +1,103 @@ +@testset "Parsing" begin + # AST metadata via keywords. + p = Parser() + ast = p(""; empty = true) + @test ast.meta["empty"] == true + + # Parsing file contents. + readme = joinpath(@__DIR__, "../README.md") + ast = open(p, readme) + @test ast.meta["source"] == readme + @test ast.first_child.t isa CommonMark.Heading + + # Parsing contents of a buffer. + buffer = IOBuffer("# heading") + ast = p(buffer) + @test ast.first_child.t isa CommonMark.Heading + @test markdown(ast) == "# heading\n" + + # Disabling parser rules. + p = disable!(Parser(), CommonMark.AtxHeadingRule()) + ast = p("# *not a header*") + @test ast.first_child.t isa CommonMark.Paragraph + @test ast.first_child.first_child.nxt.t isa CommonMark.Emph + @test markdown(ast) == "# *not a header*\n" + + # Make sure that enable! or disable! do not create duplicate rules + # https://github.com/MichaelHatherly/CommonMark.jl/issues/45 + @test CommonMark.is_same_rule(LinkRule(), LinkRule()) + @test CommonMark.is_same_rule(FootnoteRule(), FootnoteRule()) + @test !CommonMark.is_same_rule(FootnoteRule(), LinkRule()) + let fn = CommonMark.is_same_rule(LinkRule()) + @test fn(LinkRule()) + @test !fn(FootnoteRule()) + end + let fnrule1 = FootnoteRule(), fnrule2 = FootnoteRule() + @test CommonMark.is_same_rule(fnrule1, fnrule2) + fnrule1.cache["foo"] = CommonMark.Node() + @test CommonMark.is_same_rule(fnrule1, fnrule2) + fnrule2.cache["bar"] = CommonMark.Node() + @test CommonMark.is_same_rule(fnrule1, fnrule2) + end + + are_rules_unique(p::Parser) = p.rules == unique(p.rules) + let p = Parser() + @test CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = enable!(Parser(), TableRule()) + @test CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = enable!(Parser(), [TableRule(), FootnoteRule()]) + @test CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test CommonMark.ruleoccursin(TableRule(), p.rules) + @test CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + @test_throws ErrorException enable!(Parser(), LinkRule()) + @test_throws ErrorException enable!(Parser(), [LinkRule(), ImageRule()]) + @test_throws ErrorException enable!(Parser(), [LinkRule(), FootnoteRule()]) + let p = disable!(Parser(), LinkRule()) + @test !CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = disable!(Parser(), [LinkRule(), ImageRule()]) + @test !CommonMark.ruleoccursin(LinkRule(), p.rules) + @test !CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = disable!(Parser(), TableRule()) + @test CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = disable!(Parser(), [TableRule(), FootnoteRule()]) + @test CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end + let p = disable!(Parser(), [LinkRule(), FootnoteRule()]) + @test !CommonMark.ruleoccursin(LinkRule(), p.rules) + @test CommonMark.ruleoccursin(ImageRule(), p.rules) + @test !CommonMark.ruleoccursin(TableRule(), p.rules) + @test !CommonMark.ruleoccursin(FootnoteRule(), p.rules) + @test are_rules_unique(p) + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/runtests.jl b/.julia-depot/packages/CommonMark/lmLkP/test/runtests.jl new file mode 100644 index 0000000..a4da35c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/runtests.jl @@ -0,0 +1,53 @@ +using CommonMark, Test, JSON, Pkg.TOML, Mustache, YAML + +@testset "CommonMark" begin + # Ensure no method ambiguities. + @test isempty(Test.detect_ambiguities(Base, Core, CommonMark; recursive = true)) + + # Do we pass the CommonMark spec -- version 0.29.0. + @testset "Spec" begin + for case in JSON.Parser.parsefile(joinpath(@__DIR__, "spec.json")) + p = Parser() + ast = p(case["markdown"]) + @test case["html"] == html(ast) + # The following just make sure we don't throw on the other + # rendering. Proper tests are found below. + latex(ast) + term(ast) + end + end + + include("spec.jl") + include("ast.jl") + include("parsing.jl") + include("writers.jl") + include("extensions.jl") + include("templates.jl") + include("sourcepos.jl") + include("integration.jl") + + include("unicodes.jl") + + # Basics: just make sure the parsing and rendering doesn't throw or hang. + @testset "Samples" begin + for (root, dirs, files) in walkdir(joinpath(@__DIR__, "samples")) + for file in files + if endswith(file, ".md") + name = joinpath(root, file) + expected = + replace(read(splitext(name)[1] * ".html", String), "\r\n" => "\n") + + p = Parser() + ast = p(read(name, String)) + + @testset "$file" begin + @test html(ast) == expected + # TODO: just renders, no checks. + latex(ast) + term(ast) + end + end + end + end + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.html new file mode 100644 index 0000000..c47d8de --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.html @@ -0,0 +1,13 @@ +
+

the simple example of a blockquote +the simple example of a blockquote +the simple example of a blockquote +the simple example of a blockquote +... continuation +... continuation +... continuation +... continuation

+
+

empty blockquote:

+
+
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.md new file mode 100644 index 0000000..33e382a --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-flat.md @@ -0,0 +1,16 @@ +> the simple example of a blockquote +> the simple example of a blockquote +> the simple example of a blockquote +> the simple example of a blockquote +... continuation +... continuation +... continuation +... continuation + +empty blockquote: + +> +> +> +> + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.html new file mode 100644 index 0000000..2d99458 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.html @@ -0,0 +1,36 @@ +
+
+
+
+
+
+

deeply nested blockquote +deeply nested blockquote +deeply nested blockquote +deeply nested blockquote +deeply nested blockquote +deeply nested blockquote

+
+
+
+
+
+
+
+

deeply nested blockquote

+
+

deeply nested blockquote

+
+

deeply nested blockquote

+
+

deeply nested blockquote

+
+

deeply nested blockquote

+
+

deeply nested blockquote

+
+
+
+
+
+
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.md new file mode 100644 index 0000000..7ddcffa --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-bq-nested.md @@ -0,0 +1,13 @@ +>>>>>> deeply nested blockquote +>>>>> deeply nested blockquote +>>>> deeply nested blockquote +>>> deeply nested blockquote +>> deeply nested blockquote +> deeply nested blockquote + +> deeply nested blockquote +>> deeply nested blockquote +>>> deeply nested blockquote +>>>> deeply nested blockquote +>>>>> deeply nested blockquote +>>>>>> deeply nested blockquote diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.html new file mode 100644 index 0000000..3b1f404 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.html @@ -0,0 +1,10 @@ +
    an
+    example
+
+    of
+
+
+
+    a code
+    block
+
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.md new file mode 100644 index 0000000..2b1554f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-code.md @@ -0,0 +1,11 @@ + + an + example + + of + + + + a code + block + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.html new file mode 100644 index 0000000..b9ecb3c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.html @@ -0,0 +1,11 @@ +
an
+example
+```
+of
+
+
+a fenced
+```
+code
+block
+
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.md new file mode 100644 index 0000000..5fe8b3c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-fences.md @@ -0,0 +1,14 @@ + +``````````text +an +example +``` +of + + +a fenced +``` +code +block +`````````` + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.html new file mode 100644 index 0000000..e2ae871 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.html @@ -0,0 +1,7 @@ +

heading

+

heading

+
heading
+

heading

+

heading

+
heading ##########
+

############ not a heading

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.md new file mode 100644 index 0000000..fd98558 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-heading.md @@ -0,0 +1,9 @@ +# heading +### heading +##### heading + +# heading # +### heading ### +##### heading \#\#\#\#\###### + +############ not a heading diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.html new file mode 100644 index 0000000..2ccb137 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.html @@ -0,0 +1,4 @@ +
+
+
+

************************* text

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.md new file mode 100644 index 0000000..e1bad6f --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-hr.md @@ -0,0 +1,10 @@ + + * * * * * + + - - - - - + + ________ + + + ************************* text + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.html new file mode 100644 index 0000000..b611858 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.html @@ -0,0 +1,23 @@ +
+

blah blah

+
+ + + + +
+ **test** +
+ + +
<td>
+
+  test
+
+</td>
+
+ +
+ diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.md new file mode 100644 index 0000000..ff7f8fa --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-html.md @@ -0,0 +1,32 @@ +
+ +blah blah + +
+ + + + + +
+ **test** +
+ + + + + + + + + +
+ + test + +
+ + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.html new file mode 100644 index 0000000..c56b1b9 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.html @@ -0,0 +1,4 @@ +

heading

+

heading

+

not a heading +----------------------------------- text

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.md new file mode 100644 index 0000000..e5c0d99 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-lheading.md @@ -0,0 +1,8 @@ +heading +--- + +heading +=================================== + +not a heading +----------------------------------- text diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.html new file mode 100644 index 0000000..fd8539e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.html @@ -0,0 +1,99 @@ +
    +
  • +

    tidy

    +
  • +
  • +

    bullet

    +
  • +
  • +

    list

    +
  • +
  • +

    loose

    +
  • +
  • +

    bullet

    +
  • +
  • +

    list

    +
  • +
+
    +
  1. ordered
  2. +
  3. list
  4. +
  5. example
  6. +
+
    +
  • +
  • +
  • +
  • +
+
    +
  1. +
  2. +
  3. +
+
    +
  • +

    an example +of a list item +with a continuation

    +

    this part is inside the list

    +
  • +
+

this part is just a paragraph

+
    +
  1. test
  2. +
+
    +
  • test
  • +
+
    +
  1. test
  2. +
+
    +
  • test
  • +
+

111111111111111111111111111111111111111111. is this a valid bullet?

+
    +
  • +
    +
  • +
  • +

    this

    +
  • +
  • +

    is

    +

    a

    +

    long

    +
  • +
  • +

    loose

    +
  • +
  • +

    list

    +
  • +
  • +

    with

    +
  • +
  • +

    some

    +

    tidy

    +
  • +
  • +

    list

    +
  • +
  • +

    items

    +
  • +
  • +

    in

    +
  • +
  • +

    between

    +
  • +
  • +
    +
  • +
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.md new file mode 100644 index 0000000..14149db --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-flat.md @@ -0,0 +1,67 @@ + - tidy + - bullet + - list + + + - loose + + - bullet + + - list + + + 0. ordered + 1. list + 2. example + + + - + - + - + - + + + 1. + 2. + 3. + + + - an example +of a list item + with a continuation + + this part is inside the list + + this part is just a paragraph + + + 1. test + - test + 1. test + - test + + +111111111111111111111111111111111111111111. is this a valid bullet? + + - _________________________ + + - this + - is + + a + + long + - loose + - list + + - with + - some + + tidy + + - list + - items + - in + + - between + - _________________________ diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.html new file mode 100644 index 0000000..b2fffa1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.html @@ -0,0 +1,98 @@ +
    +
  • this +
      +
    • is +
        +
      • a +
          +
        • deeply +
            +
          • nested +
              +
            • bullet +
                +
              • list
              • +
              +
            • +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    +
  • +
+
    +
  1. this +2. is +3. a +4. deeply +5. nested +6. unordered +7. list
  2. +
+
    +
  • +

    1

    +
  • +
  • +

    2

    +
  • +
  • +

    3 +- 4

    +
      +
    • 5
    • +
    • 6
    • +
    • 7
    • +
    • 6
    • +
    • 5 +- 4
    • +
    +
  • +
  • +

    3

    +
  • +
  • +

    2

    +
  • +
  • +

    1

    +
  • +
  • +
      +
    • +
        +
      • +
          +
        • +
            +
          • +
              +
            • +
                +
              • +
                  +
                • +
                    +
                  • deeply-nested one-element item
                  • +
                  +
                • +
                +
              • +
              +
            • +
            +
          • +
          +
        • +
        +
      • +
      +
    • +
    +
  • +
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.md new file mode 100644 index 0000000..d30aed3 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-list-nested.md @@ -0,0 +1,36 @@ + + - this + - is + - a + - deeply + - nested + - bullet + - list + + + 1. this + 2. is + 3. a + 4. deeply + 5. nested + 6. unordered + 7. list + + + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + + + - - - - - - - - - deeply-nested one-element item + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.html new file mode 100644 index 0000000..d266aa5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.html @@ -0,0 +1,5 @@ +

1 2 3 1 2 3

+

looooooooooooooooooooooooooooooooooooooooooooooooooong label

+

[[[[[[[[[[[[[[[[[[[[ this should not slow down anything ]]]]]]]]]]]]]]]]]]]]: q +(as long as it is not referenced anywhere)

+

[[[[[[[[[[[[[[[[[[[[]: this is not a valid reference

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.md new file mode 100644 index 0000000..c83dccb --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-flat.md @@ -0,0 +1,15 @@ +[1] [2] [3] [1] [2] [3] + +[looooooooooooooooooooooooooooooooooooooooooooooooooong label] + + [1]: + [2]: http://something.example.com/foo/bar 'test' + [3]: + http://foo/bar + [ looooooooooooooooooooooooooooooooooooooooooooooooooong label ]: + 111 + 'test' + [[[[[[[[[[[[[[[[[[[[ this should not slow down anything ]]]]]]]]]]]]]]]]]]]]: q + (as long as it is not referenced anywhere) + + [[[[[[[[[[[[[[[[[[[[]: this is not a valid reference diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.html new file mode 100644 index 0000000..8f05964 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.html @@ -0,0 +1,14 @@ +

[[[[[[[foo]]]]]]]

+

[[[[[[[foo]]]]]]]: bar +[[[[[[foo]]]]]]: bar +[[[[[foo]]]]]: bar +[[[[foo]]]]: bar +[[[foo]]]: bar +[[foo]]: bar +[foo]: bar

+

[[[[[foo]]]]]

+

[[[[[foo]]]]]: bar +[[[[foo]]]]: bar +[[[foo]]]: bar +[[foo]]: bar +[foo]: bar

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.md new file mode 100644 index 0000000..1e10a8c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/block-ref-nested.md @@ -0,0 +1,17 @@ +[[[[[[[foo]]]]]]] + +[[[[[[[foo]]]]]]]: bar +[[[[[[foo]]]]]]: bar +[[[[[foo]]]]]: bar +[[[[foo]]]]: bar +[[[foo]]]: bar +[[foo]]: bar +[foo]: bar + +[*[*[*[*[foo]*]*]*]*] + +[*[*[*[*[foo]*]*]*]*]: bar +[*[*[*[foo]*]*]*]: bar +[*[*[foo]*]*]: bar +[*[foo]*]: bar +[foo]: bar diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.html new file mode 100644 index 0000000..0f1ee55 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.html @@ -0,0 +1,11 @@ +

closed (valid) autolinks:

+

ftp://1.2.3.4:21/path/foo +http://foo.bar.baz?q=hello&id=22&boolean +http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink/ +teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com

+

these are not autolinks:

+

<ftp://1.2.3.4:21/path/foo +<http://foo.bar.baz?q=hello&id=22&boolean +<http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink +<teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com +< http://foo.bar.baz?q=hello&id=22&boolean >

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.md new file mode 100644 index 0000000..0f71482 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-autolink.md @@ -0,0 +1,14 @@ +closed (valid) autolinks: + + + + + + +these are not autolinks: + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.html new file mode 100644 index 0000000..2652336 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.html @@ -0,0 +1,2 @@ +

lotsofbackticks

+

iwonderhowthiswillbeparsed

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.md new file mode 100644 index 0000000..a6ec6e1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-backticks.md @@ -0,0 +1,3 @@ +`lots`of`backticks` + +``i``wonder``how``this``will``be``parsed`` diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.html new file mode 100644 index 0000000..449947d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.html @@ -0,0 +1,3 @@ +

this is your basic boring emphasis

+

this is your basic boring emphasis

+

this is your basic boring emphasis

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.md new file mode 100644 index 0000000..b7668a5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-flat.md @@ -0,0 +1,5 @@ +*this* *is* *your* *basic* *boring* *emphasis* + +_this_ _is_ _your_ _basic_ _boring_ _emphasis_ + +**this** **is** **your** **basic** **boring** **emphasis** diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.html new file mode 100644 index 0000000..45fec27 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.html @@ -0,0 +1,3 @@ +

this is a bunch of nested emphases

+

this is a bunch of nested emphases

+

this is a bunch of nested emphases

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.md new file mode 100644 index 0000000..6bb0a0d --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-nested.md @@ -0,0 +1,5 @@ +*this *is *a *bunch* of* nested* emphases* + +__this __is __a __bunch__ of__ nested__ emphases__ + +***this ***is ***a ***bunch*** of*** nested*** emphases*** diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.html new file mode 100644 index 0000000..fe61f03 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.html @@ -0,0 +1,3 @@ +

*this *is *a *worst *case *for *em *backtracking

+

__this __is __a __worst __case __for __em __backtracking

+

***this ***is ***a ***worst ***case ***for ***em ***backtracking

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.md new file mode 100644 index 0000000..b6d21da --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-em-worst.md @@ -0,0 +1,5 @@ +*this *is *a *worst *case *for *em *backtracking + +__this __is __a __worst __case __for __em __backtracking + +***this ***is ***a ***worst ***case ***for ***em ***backtracking diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.html new file mode 100644 index 0000000..fc0a901 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.html @@ -0,0 +1,6 @@ +

entities:

+

  & © Æ Ď ¾ ℋ ⅆ ∲

+

# Ӓ Ϡ �

+

non-entities:

+

&18900987654321234567890; &1234567890098765432123456789009876543212345678987654;

+

&qwertyuioppoiuytrewqwer; &oiuytrewqwertyuioiuytrewqwertyuioytrewqwertyuiiuytri;

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.md new file mode 100644 index 0000000..da095ed --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-entity.md @@ -0,0 +1,11 @@ +entities: + +  & © Æ Ď ¾ ℋ ⅆ ∲ + +# Ӓ Ϡ � + +non-entities: + +&18900987654321234567890; &1234567890098765432123456789009876543212345678987654; + +&qwertyuioppoiuytrewqwer; &oiuytrewqwertyuioiuytrewqwertyuioytrewqwertyuiiuytri; diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.html new file mode 100644 index 0000000..e43b953 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.html @@ -0,0 +1,9 @@ +

\t\e\s\t\i\n\g \e\s\c\a\p\e \s\e\q\u\e\n\c\e\s

+

!\"#$%&'()*+,./:;<=>?

+

@ [ ] ^ _ ` { | } ~ - '

+


+\ +\
+\\ +\\\

+

<this> <is> <not> <html>

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.md new file mode 100644 index 0000000..4e1bb39 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-escape.md @@ -0,0 +1,15 @@ + +\t\e\s\t\i\n\g \e\s\c\a\p\e \s\e\q\u\e\n\c\e\s + +\!\\\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\? + +\@ \[ \] \^ \_ \` \{ \| \} \~ \- \' + +\ +\\ +\\\ +\\\\ +\\\\\ + +\ \ \ \ + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.html new file mode 100644 index 0000000..cf8f842 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.html @@ -0,0 +1,25 @@ +

Taking commonmark tests from the spec for benchmarking here:

+

+

+

+

+

<33> <__>

+

<a h*#ref="hi">

+

<a href="hi'> <a href=hi'>

+

< a>< +foo><bar/ >

+

<a href='bar'title=title>

+
+ +

</a href="foo">

+

foo

+

foo <!-- not a comment -- two hyphens -->

+

foo

+

foo

+

foo &<]]>

+ + +

<a href=""">

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.md new file mode 100644 index 0000000..f6e6341 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-html.md @@ -0,0 +1,44 @@ +Taking commonmark tests from the spec for benchmarking here: + +
+ + + + + + + +<33> <__> + + + + + +foo + +foo + +foo + +foo + +foo &<]]> + + + + + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.html new file mode 100644 index 0000000..64eacbd --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.html @@ -0,0 +1,15 @@ +

Valid links:

+

this is a link +this is a link +this is a link +this is an image +this is an image +this is an image

+

escape test +escape test ]]]]]]]]]]]]]]]]

+

Invalid links:

+

[this is not a link

+

[this is not a link](

+

[this is not a link](http://something.example.com/foo/bar 'test'

+

[this is not a link](((((((((((((((((((((((((((((((((((((((((((((((

+

[this is not a link]((((((((((()))))))))) (((((((((()))))))))))

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.md new file mode 100644 index 0000000..5117db8 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-flat.md @@ -0,0 +1,23 @@ +Valid links: + + [this is a link]() + [this is a link]() + [this is a link](http://something.example.com/foo/bar 'test') + ![this is an image]() + ![this is an image]() + ![this is an image](http://something.example.com/foo/bar 'test') + + [escape test](<\>\>\>\>\>\>\>\>\>\>\>\>\>\>> '\'\'\'\'\'\'\'\'\'\'\'\'\'\'') + [escape test \]\]\]\]\]\]\]\]\]\]\]\]\]\]\]\]](\)\)\)\)\)\)\)\)\)\)\)\)\)\)) + +Invalid links: + + [this is not a link + + [this is not a link]( + + [this is not a link](http://something.example.com/foo/bar 'test' + + [this is not a link]((((((((((((((((((((((((((((((((((((((((((((((( + + [this is not a link]((((((((((()))))))))) (((((((((())))))))))) diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.html new file mode 100644 index 0000000..064b015 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.html @@ -0,0 +1,7 @@ +

Valid links:

+

[[[[[[[](test)](test)](test)](test)](test)](test)]

+

[ [[[[[[[[[[[[[[[[[[ ]]]]]]]]]]]]]]]]]] ](test)

+

Invalid links:

+

[[[[[[[[[

+

[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [

+

![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.md new file mode 100644 index 0000000..4e7dc85 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-links-nested.md @@ -0,0 +1,13 @@ +Valid links: + +[[[[[[[[](test)](test)](test)](test)](test)](test)](test)] + +[ [[[[[[[[[[[[[[[[[[ [](test) ]]]]]]]]]]]]]]]]]] ](test) + +Invalid links: + +[[[[[[[[[ + +[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ + +![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![ diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.html new file mode 100644 index 0000000..860448e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.html @@ -0,0 +1,20 @@ +

this
+should
+be
+separated
+by
+newlines

+

this
+should
+be
+separated
+by
+newlines
+too

+

this +should +not +be +separated +by +newlines

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.md new file mode 100644 index 0000000..068a807 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/inline-newlines.md @@ -0,0 +1,24 @@ + +this\ +should\ +be\ +separated\ +by\ +newlines + +this +should +be +separated +by +newlines +too + +this +should +not +be +separated +by +newlines + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.html new file mode 100644 index 0000000..d2494c8 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.html @@ -0,0 +1,6 @@ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet nec erat ac condimentum. Nulla vel rutrum ligula. Sed hendrerit interdum orci a posuere. Vivamus ut velit aliquet, mollis purus eget, iaculis nisl. Proin posuere malesuada ante. Proin auctor orci eros, ac molestie lorem dictum nec. Vestibulum sit amet erat est. Morbi luctus sed elit ac luctus. Proin blandit, enim vitae egestas posuere, neque elit ultricies dui, vel mattis nibh enim ac lorem. Maecenas molestie nisl sit amet velit dictum lobortis. Aliquam erat volutpat.

+

Vivamus sagittis, diam in vehicula lobortis, sapien arcu mattis erat, vel aliquet sem urna et risus. Ut feugiat sapien vitae mi elementum laoreet. Suspendisse potenti. Aliquam erat nisl, aliquam pretium libero aliquet, sagittis eleifend nunc. In hac habitasse platea dictumst. Integer turpis augue, tincidunt dignissim mauris id, rhoncus dapibus purus. Maecenas et enim odio. Nullam massa metus, varius quis vehicula sed, pharetra mollis erat. In quis viverra velit. Vivamus placerat, est nec hendrerit varius, enim dui hendrerit magna, ut pulvinar nibh lorem vel lacus. Mauris a orci iaculis, hendrerit eros sed, gravida leo. In dictum mauris vel augue varius, ac ullamcorper nisl ornare. In eu posuere velit, ac fermentum arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam sed malesuada leo, at interdum elit.

+

Nullam ut tincidunt nunc. Pellentesque metus lacus, commodo eget justo ut, rutrum varius nunc. Sed non rhoncus risus. Morbi sodales gravida pulvinar. Duis malesuada, odio volutpat elementum vulputate, massa magna scelerisque ante, et accumsan tellus nunc in sem. Donec mattis arcu et velit aliquet, non sagittis justo vestibulum. Suspendisse volutpat felis lectus, nec consequat ipsum mattis id. Donec dapibus vehicula facilisis. In tincidunt mi nisi, nec faucibus tortor euismod nec. Suspendisse ante ligula, aliquet vitae libero eu, vulputate dapibus libero. Sed bibendum, sapien at posuere interdum, libero est sollicitudin magna, ac gravida tellus purus eu ipsum. Proin ut quam arcu.

+

Suspendisse potenti. Donec ante velit, ornare at augue quis, tristique laoreet sem. Etiam in ipsum elit. Nullam cursus dolor sit amet nulla feugiat tristique. Phasellus ac tellus tincidunt, imperdiet purus eget, ullamcorper ipsum. Cras eu tincidunt sem. Nullam sed dapibus magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id venenatis tortor. In consectetur sollicitudin pharetra. Etiam convallis nisi nunc, et aliquam turpis viverra sit amet. Maecenas faucibus sodales tortor. Suspendisse lobortis mi eu leo viverra volutpat. Pellentesque velit ante, vehicula sodales congue ut, elementum a urna. Cras tempor, ipsum eget luctus rhoncus, arcu ligula fermentum urna, vulputate pharetra enim enim non libero.

+

Proin diam quam, elementum in eleifend id, elementum et metus. Cras in justo consequat justo semper ultrices. Sed dignissim lectus a ante mollis, nec vulputate ante molestie. Proin in porta nunc. Etiam pulvinar turpis sed velit porttitor, vel adipiscing velit fringilla. Cras ac tellus vitae purus pharetra tincidunt. Sed cursus aliquet aliquet. Cras eleifend commodo malesuada. In turpis turpis, ullamcorper ut tincidunt a, ullamcorper a nunc. Etiam luctus tellus ac dapibus gravida. Ut nec lacus laoreet neque ullamcorper volutpat.

+

Nunc et leo erat. Aenean mattis ultrices lorem, eget adipiscing dolor ultricies eu. In hac habitasse platea dictumst. Vivamus cursus feugiat sapien quis aliquam. Mauris quam libero, porta vel volutpat ut, blandit a purus. Vivamus vestibulum dui vel tortor molestie, sit amet feugiat sem commodo. Nulla facilisi. Sed molestie arcu eget tellus vestibulum tristique.

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.md new file mode 100644 index 0000000..eccb898 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/lorem1.md @@ -0,0 +1,13 @@ +Lorem ipsum dolor sit amet, __consectetur__ adipiscing elit. Cras imperdiet nec erat ac condimentum. Nulla vel rutrum ligula. Sed hendrerit interdum orci a posuere. Vivamus ut velit aliquet, mollis purus eget, iaculis nisl. Proin posuere malesuada ante. Proin auctor orci eros, ac molestie lorem dictum nec. Vestibulum sit amet erat est. Morbi luctus sed elit ac luctus. Proin blandit, enim vitae egestas posuere, neque elit ultricies dui, vel mattis nibh enim ac lorem. Maecenas molestie nisl sit amet velit dictum lobortis. Aliquam erat volutpat. + +Vivamus sagittis, diam in [vehicula](https://github.com/markdown-it/markdown-it) lobortis, sapien arcu mattis erat, vel aliquet sem urna et risus. Ut feugiat sapien vitae mi elementum laoreet. Suspendisse potenti. Aliquam erat nisl, aliquam pretium libero aliquet, sagittis eleifend nunc. In hac habitasse platea dictumst. Integer turpis augue, tincidunt dignissim mauris id, rhoncus dapibus purus. Maecenas et enim odio. Nullam massa metus, varius quis vehicula sed, pharetra mollis erat. In quis viverra velit. Vivamus placerat, est nec hendrerit varius, enim dui hendrerit magna, ut pulvinar nibh lorem vel lacus. Mauris a orci iaculis, hendrerit eros sed, gravida leo. In dictum mauris vel augue varius, ac ullamcorper nisl ornare. In eu posuere velit, ac fermentum arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam sed malesuada leo, at interdum elit. + +Nullam ut tincidunt nunc. [Pellentesque][1] metus lacus, commodo eget justo ut, rutrum varius nunc. Sed non rhoncus risus. Morbi sodales gravida pulvinar. Duis malesuada, odio volutpat elementum vulputate, massa magna scelerisque ante, et accumsan tellus nunc in sem. Donec mattis arcu et velit aliquet, non sagittis justo vestibulum. Suspendisse volutpat felis lectus, nec consequat ipsum mattis id. Donec dapibus vehicula facilisis. In tincidunt mi nisi, nec faucibus tortor euismod nec. Suspendisse ante ligula, aliquet vitae libero eu, vulputate dapibus libero. Sed bibendum, sapien at posuere interdum, libero est sollicitudin magna, ac gravida tellus purus eu ipsum. Proin ut quam arcu. + +Suspendisse potenti. Donec ante velit, ornare at augue quis, tristique laoreet sem. Etiam in ipsum elit. Nullam cursus dolor sit amet nulla feugiat tristique. Phasellus ac tellus tincidunt, imperdiet purus eget, ullamcorper ipsum. Cras eu tincidunt sem. Nullam sed dapibus magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id venenatis tortor. In consectetur sollicitudin pharetra. Etiam convallis nisi nunc, et aliquam turpis viverra sit amet. Maecenas faucibus sodales tortor. Suspendisse lobortis mi eu leo viverra volutpat. Pellentesque velit ante, vehicula sodales congue ut, elementum a urna. Cras tempor, ipsum eget luctus rhoncus, arcu ligula fermentum urna, vulputate pharetra enim enim non libero. + +Proin diam quam, elementum in eleifend id, elementum et metus. Cras in justo consequat justo semper ultrices. Sed dignissim lectus a ante mollis, nec vulputate ante molestie. Proin in porta nunc. Etiam pulvinar turpis sed velit porttitor, vel adipiscing velit fringilla. Cras ac tellus vitae purus pharetra tincidunt. Sed cursus aliquet aliquet. Cras eleifend commodo malesuada. In turpis turpis, ullamcorper ut tincidunt a, ullamcorper a nunc. Etiam luctus tellus ac dapibus gravida. Ut nec lacus laoreet neque ullamcorper volutpat. + +Nunc et leo erat. Aenean mattis ultrices lorem, eget adipiscing dolor ultricies eu. In hac habitasse platea dictumst. Vivamus cursus feugiat sapien quis aliquam. Mauris quam libero, porta vel volutpat ut, blandit a purus. Vivamus vestibulum dui vel tortor molestie, sit amet feugiat sem commodo. Nulla facilisi. Sed molestie arcu eget tellus vestibulum tristique. + +[1]: https://github.com/markdown-it diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.html new file mode 100644 index 0000000..c017d49 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.html @@ -0,0 +1,11 @@ +

this is a test for tab expansion, be careful not to replace them with spaces

+

1 4444 +22 333 +333 22 +4444 1

+
tab-indented line
+space-indented line
+tab-indented line
+
+

a lot of spaces in between here

+

a lot of tabs in between here

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.md new file mode 100644 index 0000000..dc989ea --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/rawtabs.md @@ -0,0 +1,18 @@ + +this is a test for tab expansion, be careful not to replace them with spaces + +1 4444 +22 333 +333 22 +4444 1 + + + tab-indented line + space-indented line + tab-indented line + + +a lot of spaces in between here + +a lot of tabs in between here + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.html b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.html new file mode 100644 index 0000000..b53bc4e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.html @@ -0,0 +1,7140 @@ +
+

title: CommonMark Spec +author: John MacFarlane +version: 0.29 +date: '2019-04-06' +license: 'CC-BY-SA 4.0' +...

+

Introduction

+

What is Markdown?

+

Markdown is a plain text format for writing structured documents, +based on conventions for indicating formatting in email +and usenet posts. It was developed by John Gruber (with +help from Aaron Swartz) and released in 2004 in the form of a +syntax description +and a Perl script (Markdown.pl) for converting Markdown to +HTML. In the next decade, dozens of implementations were +developed in many languages. Some extended the original +Markdown syntax with conventions for footnotes, tables, and +other document elements. Some allowed Markdown documents to be +rendered in formats other than HTML. Websites like Reddit, +StackOverflow, and GitHub had millions of people using Markdown. +And Markdown started to be used beyond the web, to author books, +articles, slide shows, letters, and lecture notes.

+

What distinguishes Markdown from many other lightweight markup +syntaxes, which are often easier to write, is its readability. +As Gruber writes:

+
+

The overriding design goal for Markdown's formatting syntax is +to make it as readable as possible. The idea is that a +Markdown-formatted document should be publishable as-is, as +plain text, without looking like it's been marked up with tags +or formatting instructions. +(http://daringfireball.net/projects/markdown/)

+
+

The point can be illustrated by comparing a sample of +AsciiDoc with +an equivalent sample of Markdown. Here is a sample of +AsciiDoc from the AsciiDoc manual:

+
1. List item one.
++
+List item one continued with a second paragraph followed by an
+Indented block.
++
+.................
+$ ls *.sh
+$ mv *.sh ~/tmp
+.................
++
+List item continued with a third paragraph.
+
+2. List item two continued with an open block.
++
+--
+This paragraph is part of the preceding list item.
+
+a. This list is nested and does not require explicit item
+continuation.
++
+This paragraph is part of the preceding list item.
+
+b. List item b.
+
+This paragraph belongs to item two of the outer list.
+--
+
+

And here is the equivalent in Markdown:

+
1.  List item one.
+
+    List item one continued with a second paragraph followed by an
+    Indented block.
+
+        $ ls *.sh
+        $ mv *.sh ~/tmp
+
+    List item continued with a third paragraph.
+
+2.  List item two continued with an open block.
+
+    This paragraph is part of the preceding list item.
+
+    1. This list is nested and does not require explicit item continuation.
+
+       This paragraph is part of the preceding list item.
+
+    2. List item b.
+
+    This paragraph belongs to item two of the outer list.
+
+

The AsciiDoc version is, arguably, easier to write. You don't need +to worry about indentation. But the Markdown version is much easier +to read. The nesting of list items is apparent to the eye in the +source, not just in the processed document.

+

Why is a spec needed?

+

John Gruber's canonical description of Markdown's +syntax +does not specify the syntax unambiguously. Here are some examples of +questions it does not answer:

+
    +
  1. +

    How much indentation is needed for a sublist? The spec says that +continuation paragraphs need to be indented four spaces, but is +not fully explicit about sublists. It is natural to think that +they, too, must be indented four spaces, but Markdown.pl does +not require that. This is hardly a "corner case," and divergences +between implementations on this issue often lead to surprises for +users in real documents. (See this comment by John +Gruber.)

    +
  2. +
  3. +

    Is a blank line needed before a block quote or heading? +Most implementations do not require the blank line. However, +this can lead to unexpected results in hard-wrapped text, and +also to ambiguities in parsing (note that some implementations +put the heading inside the blockquote, while others do not). +(John Gruber has also spoken in favor of requiring the blank +lines.)

    +
  4. +
  5. +

    Is a blank line needed before an indented code block? +(Markdown.pl requires it, but this is not mentioned in the +documentation, and some implementations do not require it.)

    +
    paragraph
    +    code?
    +
    +
  6. +
  7. +

    What is the exact rule for determining when list items get +wrapped in <p> tags? Can a list be partially "loose" and partially +"tight"? What should we do with a list like this?

    +
    1. one
    +
    +2. two
    +3. three
    +
    +

    Or this?

    +
    1.  one
    +    - a
    +
    +    - b
    +2.  two
    +
    +

    (There are some relevant comments by John Gruber +here.)

    +
  8. +
  9. +

    Can list markers be indented? Can ordered list markers be right-aligned?

    +
     8. item 1
    + 9. item 2
    +10. item 2a
    +
    +
  10. +
  11. +

    Is this one list with a thematic break in its second item, +or two lists separated by a thematic break?

    +
    * a
    +* * * * *
    +* b
    +
    +
  12. +
  13. +

    When list markers change from numbers to bullets, do we have +two lists or one? (The Markdown syntax description suggests two, +but the perl scripts and many other implementations produce one.)

    +
    1. fee
    +2. fie
    +-  foe
    +-  fum
    +
    +
  14. +
  15. +

    What are the precedence rules for the markers of inline structure? +For example, is the following a valid link, or does the code span +take precedence ?

    +
    [a backtick (`)](/url) and [another backtick (`)](/url).
    +
    +
  16. +
  17. +

    What are the precedence rules for markers of emphasis and strong +emphasis? For example, how should the following be parsed?

    +
    *foo *bar* baz*
    +
    +
  18. +
  19. +

    What are the precedence rules between block-level and inline-level +structure? For example, how should the following be parsed?

    +
    - `a long code span can contain a hyphen like this
    +  - and it can screw things up`
    +
    +
  20. +
  21. +

    Can list items include section headings? (Markdown.pl does not +allow this, but does allow blockquotes to include headings.)

    +
    - # Heading
    +
    +
  22. +
  23. +

    Can list items be empty?

    +
    * a
    +*
    +* b
    +
    +
  24. +
  25. +

    Can link references be defined inside block quotes or list items?

    +
    > Blockquote [foo].
    +>
    +> [foo]: /url
    +
    +
  26. +
  27. +

    If there are multiple definitions for the same reference, which takes +precedence?

    +
    [foo]: /url1
    +[foo]: /url2
    +
    +[foo][]
    +
    +
  28. +
+

In the absence of a spec, early implementers consulted Markdown.pl +to resolve these ambiguities. But Markdown.pl was quite buggy, and +gave manifestly bad results in many cases, so it was not a +satisfactory replacement for a spec.

+

Because there is no unambiguous spec, implementations have diverged +considerably. As a result, users are often surprised to find that +a document that renders one way on one system (say, a GitHub wiki) +renders differently on another (say, converting to docbook using +pandoc). To make matters worse, because nothing in Markdown counts +as a "syntax error," the divergence often isn't discovered right away.

+

About this document

+

This document attempts to specify Markdown syntax unambiguously. +It contains many examples with side-by-side Markdown and +HTML. These are intended to double as conformance tests. An +accompanying script spec_tests.py can be used to run the tests +against any Markdown program:

+
python test/spec_tests.py --spec spec.txt --program PROGRAM
+
+

Since this document describes how Markdown is to be parsed into +an abstract syntax tree, it would have made sense to use an abstract +representation of the syntax tree instead of HTML. But HTML is capable +of representing the structural distinctions we need to make, and the +choice of HTML for the tests makes it possible to run the tests against +an implementation without writing an abstract syntax tree renderer.

+

This document is generated from a text file, spec.txt, written +in Markdown with a small extension for the side-by-side tests. +The script tools/makespec.py can be used to convert spec.txt into +HTML or CommonMark (which can then be converted into other formats).

+

In the examples, the character is used to represent tabs.

+

Preliminaries

+

Characters and lines

+

Any sequence of [characters] is a valid CommonMark +document.

+

A character is a Unicode code point. Although some +code points (for example, combining accents) do not correspond to +characters in an intuitive sense, all code points count as characters +for purposes of this spec.

+

This spec does not specify an encoding; it thinks of lines as composed +of [characters] rather than bytes. A conforming parser may be limited +to a certain encoding.

+

A line is a sequence of zero or more [characters] +other than newline (U+000A) or carriage return (U+000D), +followed by a [line ending] or by the end of file.

+

A line ending is a newline (U+000A), a carriage return +(U+000D) not followed by a newline, or a carriage return and a +following newline.

+

A line containing no characters, or a line containing only spaces +(U+0020) or tabs (U+0009), is called a blank line.

+

The following definitions of character classes will be used in this spec:

+

A whitespace character is a space +(U+0020), tab (U+0009), newline (U+000A), line tabulation (U+000B), +form feed (U+000C), or carriage return (U+000D).

+

Whitespace is a sequence of one or more [whitespace +characters].

+

A Unicode whitespace character is +any code point in the Unicode Zs general category, or a tab (U+0009), +carriage return (U+000D), newline (U+000A), or form feed +(U+000C).

+

Unicode whitespace is a sequence of one +or more [Unicode whitespace characters].

+

A space is U+0020.

+

A non-whitespace character is any character +that is not a [whitespace character].

+

An ASCII control character is a character between U+0000–1F (both +including) or U+007F.

+

An ASCII punctuation character +is !, ", #, $, %, &, ', (, ), +*, +, ,, -, ., / (U+0021–2F), +:, ;, <, =, >, ?, @ (U+003A–0040), +[, \, ], ^, _, ` (U+005B–0060), +{, |, }, or ~ (U+007B–007E).

+

A punctuation character is an [ASCII +punctuation character] or anything in +the general Unicode categories Pc, Pd, Pe, Pf, Pi, Po, or Ps.

+

Tabs

+

Tabs in lines are not expanded to [spaces]. However, +in contexts where whitespace helps to define block structure, +tabs behave as if they were replaced by spaces with a tab stop +of 4 characters.

+

Thus, for example, a tab can be used instead of four spaces +in an indented code block. (Note, however, that internal +tabs are passed through as literal tabs, not expanded to +spaces.)

+
→foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+
+
  →foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+
+
    a→a
+    ὐ→a
+.
+<pre><code>a→a
+ὐ→a
+</code></pre>
+
+

In the following example, a continuation paragraph of a list +item is indented with a tab; this has exactly the same effect +as indentation with four spaces would:

+
  - foo
+
+→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+
+
- foo
+
+→→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code>  bar
+</code></pre>
+</li>
+</ul>
+
+

Normally the > that begins a block quote may be followed +optionally by a space, which is not considered part of the +content. In the following case > is followed by a tab, +which is treated as if it were expanded into three spaces. +Since one of these spaces is considered part of the +delimiter, foo is considered to be indented six spaces +inside the block quote context, so we get an indented +code block starting with two spaces.

+
>→→foo
+.
+<blockquote>
+<pre><code>  foo
+</code></pre>
+</blockquote>
+
+
-→→foo
+.
+<ul>
+<li>
+<pre><code>  foo
+</code></pre>
+</li>
+</ul>
+
+
    foo
+→bar
+.
+<pre><code>foo
+bar
+</code></pre>
+
+
 - foo
+   - bar
+→ - baz
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+
#→Foo
+.
+<h1>Foo</h1>
+
+
*→*→*→
+.
+<hr />
+
+

Insecure characters

+

For security reasons, the Unicode character U+0000 must be replaced +with the REPLACEMENT CHARACTER (U+FFFD).

+

Backslash escapes

+

Any ASCII punctuation character may be backslash-escaped:

+
\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
+.
+<p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
+
+

Backslashes before other characters are treated as literal +backslashes:

+
\→\A\a\ \3\φ\«
+.
+<p>\→\A\a\ \3\φ\«</p>
+
+

Escaped characters are treated as regular characters and do +not have their usual Markdown meanings:

+
\*not emphasized*
+\<br/> not a tag
+\[not a link](/foo)
+\`not code`
+1\. not a list
+\* not a list
+\# not a heading
+\[foo]: /url "not a reference"
+\&ouml; not a character entity
+.
+<p>*not emphasized*
+&lt;br/&gt; not a tag
+[not a link](/foo)
+`not code`
+1. not a list
+* not a list
+# not a heading
+[foo]: /url &quot;not a reference&quot;
+&amp;ouml; not a character entity</p>
+
+

If a backslash is itself escaped, the following character is not:

+
\\*emphasis*
+.
+<p>\<em>emphasis</em></p>
+
+

A backslash at the end of the line is a [hard line break]:

+
foo\
+bar
+.
+<p>foo<br />
+bar</p>
+
+

Backslash escapes do not work in code blocks, code spans, autolinks, or +raw HTML:

+
`` \[\` ``
+.
+<p><code>\[\`</code></p>
+
+
    \[\]
+.
+<pre><code>\[\]
+</code></pre>
+
+
~~~
+\[\]
+~~~
+.
+<pre><code>\[\]
+</code></pre>
+
+
<http://example.com?find=\*>
+.
+<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
+
+
<a href="/bar\/)">
+.
+<a href="/bar\/)">
+
+

But they work in all other contexts, including URLs and link titles, +link references, and [info strings] in [fenced code blocks]:

+
[foo](/bar\* "ti\*tle")
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+
+
[foo]
+
+[foo]: /bar\* "ti\*tle"
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+
+
``` foo\+bar
+foo
+```
+.
+<pre><code class="language-foo+bar">foo
+</code></pre>
+
+

Entity and numeric character references

+

Valid HTML entity references and numeric character references +can be used in place of the corresponding Unicode character, +with the following exceptions:

+
    +
  • +

    Entity and character references are not recognized in code +blocks and code spans.

    +
  • +
  • +

    Entity and character references cannot stand in place of +special characters that define structural elements in +CommonMark. For example, although &#42; can be used +in place of a literal * character, &#42; cannot replace +* in emphasis delimiters, bullet list markers, or thematic +breaks.

    +
  • +
+

Conforming CommonMark parsers need not store information about +whether a particular character was represented in the source +using a Unicode character or an entity reference.

+

Entity references consist of & + any of the valid +HTML5 entity names + ;. The +document https://html.spec.whatwg.org/entities.json +is used as an authoritative source for the valid entity +references and their corresponding code points.

+
&nbsp; &amp; &copy; &AElig; &Dcaron;
+&frac34; &HilbertSpace; &DifferentialD;
+&ClockwiseContourIntegral; &ngE;
+.
+<p>  &amp; © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸</p>
+
+

Decimal numeric character +references +consist of &# + a string of 1--7 arabic digits + ;. A +numeric character reference is parsed as the corresponding +Unicode character. Invalid Unicode code points will be replaced by +the REPLACEMENT CHARACTER (U+FFFD). For security reasons, +the code point U+0000 will also be replaced by U+FFFD.

+
&#35; &#1234; &#992; &#0;
+.
+<p># Ӓ Ϡ �</p>
+
+

Hexadecimal numeric character +references consist of &# + +either X or x + a string of 1-6 hexadecimal digits + ;. +They too are parsed as the corresponding Unicode character (this +time specified with a hexadecimal numeral instead of decimal).

+
&#X22; &#XD06; &#xcab;
+.
+<p>&quot; ആ ಫ</p>
+
+

Here are some nonentities:

+
&nbsp &x; &#; &#x;
+&#87654321;
+&#abcdef0;
+&ThisIsNotDefined; &hi?;
+.
+<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
+&amp;#87654321;
+&amp;#abcdef0;
+&amp;ThisIsNotDefined; &amp;hi?;</p>
+
+

Although HTML5 does accept some entity references +without a trailing semicolon (such as &copy), these are not +recognized here, because it makes the grammar too ambiguous:

+
&copy
+.
+<p>&amp;copy</p>
+
+

Strings that are not on the list of HTML5 named entities are not +recognized as entity references either:

+
&MadeUpEntity;
+.
+<p>&amp;MadeUpEntity;</p>
+
+

Entity and numeric character references are recognized in any +context besides code spans or code blocks, including +URLs, [link titles], and [fenced code block][] [info strings]:

+
<a href="&ouml;&ouml;.html">
+.
+<a href="&ouml;&ouml;.html">
+
+
[foo](/f&ouml;&ouml; "f&ouml;&ouml;")
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+
+
[foo]
+
+[foo]: /f&ouml;&ouml; "f&ouml;&ouml;"
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+
+
``` f&ouml;&ouml;
+foo
+```
+.
+<pre><code class="language-föö">foo
+</code></pre>
+
+

Entity and numeric character references are treated as literal +text in code spans and code blocks:

+
`f&ouml;&ouml;`
+.
+<p><code>f&amp;ouml;&amp;ouml;</code></p>
+
+
    f&ouml;f&ouml;
+.
+<pre><code>f&amp;ouml;f&amp;ouml;
+</code></pre>
+
+

Entity and numeric character references cannot be used +in place of symbols indicating structure in CommonMark +documents.

+
&#42;foo&#42;
+*foo*
+.
+<p>*foo*
+<em>foo</em></p>
+
+
&#42; foo
+
+* foo
+.
+<p>* foo</p>
+<ul>
+<li>foo</li>
+</ul>
+
+
foo&#10;&#10;bar
+.
+<p>foo
+
+bar</p>
+
+
&#9;foo
+.
+<p>→foo</p>
+
+
[a](url &quot;tit&quot;)
+.
+<p>[a](url &quot;tit&quot;)</p>
+
+

Blocks and inlines

+

We can think of a document as a sequence of +blocks---structural elements like paragraphs, block +quotations, lists, headings, rules, and code blocks. Some blocks (like +block quotes and list items) contain other blocks; others (like +headings and paragraphs) contain inline content---text, +links, emphasized text, images, code spans, and so on.

+

Precedence

+

Indicators of block structure always take precedence over indicators +of inline structure. So, for example, the following is a list with +two items, not a list with one item containing a code span:

+
- `one
+- two`
+.
+<ul>
+<li>`one</li>
+<li>two`</li>
+</ul>
+
+

This means that parsing can proceed in two steps: first, the block +structure of the document can be discerned; second, text lines inside +paragraphs, headings, and other block constructs can be parsed for inline +structure. The second step requires information about link reference +definitions that will be available only at the end of the first +step. Note that the first step requires processing lines in sequence, +but the second can be parallelized, since the inline parsing of +one block element does not affect the inline parsing of any other.

+

Container blocks and leaf blocks

+

We can divide blocks into two types: +container blocks, +which can contain other blocks, and leaf blocks, +which cannot.

+

Leaf blocks

+

This section describes the different kinds of leaf block that make up a +Markdown document.

+

Thematic breaks

+

A line consisting of 0-3 spaces of indentation, followed by a sequence +of three or more matching -, _, or * characters, each followed +optionally by any number of spaces or tabs, forms a +thematic break.

+
***
+---
+___
+.
+<hr />
+<hr />
+<hr />
+
+

Wrong characters:

+
+++
+.
+<p>+++</p>
+
+
===
+.
+<p>===</p>
+
+

Not enough characters:

+
--
+**
+__
+.
+<p>--
+**
+__</p>
+
+

One to three spaces indent are allowed:

+
 ***
+  ***
+   ***
+.
+<hr />
+<hr />
+<hr />
+
+

Four spaces is too many:

+
    ***
+.
+<pre><code>***
+</code></pre>
+
+
Foo
+    ***
+.
+<p>Foo
+***</p>
+
+

More than three characters may be used:

+
_____________________________________
+.
+<hr />
+
+

Spaces are allowed between the characters:

+
 - - -
+.
+<hr />
+
+
 **  * ** * ** * **
+.
+<hr />
+
+
-     -      -      -
+.
+<hr />
+
+

Spaces are allowed at the end:

+
- - - -    
+.
+<hr />
+
+

However, no other characters may occur in the line:

+
_ _ _ _ a
+
+a------
+
+---a---
+.
+<p>_ _ _ _ a</p>
+<p>a------</p>
+<p>---a---</p>
+
+

It is required that all of the [non-whitespace characters] be the same. +So, this is not a thematic break:

+
 *-*
+.
+<p><em>-</em></p>
+
+

Thematic breaks do not need blank lines before or after:

+
- foo
+***
+- bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+<ul>
+<li>bar</li>
+</ul>
+
+

Thematic breaks can interrupt a paragraph:

+
Foo
+***
+bar
+.
+<p>Foo</p>
+<hr />
+<p>bar</p>
+
+

If a line of dashes that meets the above conditions for being a +thematic break could also be interpreted as the underline of a [setext +heading], the interpretation as a +[setext heading] takes precedence. Thus, for example, +this is a setext heading, not a paragraph followed by a thematic break:

+
Foo
+---
+bar
+.
+<h2>Foo</h2>
+<p>bar</p>
+
+

When both a thematic break and a list item are possible +interpretations of a line, the thematic break takes precedence:

+
* Foo
+* * *
+* Bar
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+<ul>
+<li>Bar</li>
+</ul>
+
+

If you want a thematic break in a list item, use a different bullet:

+
- Foo
+- * * *
+.
+<ul>
+<li>Foo</li>
+<li>
+<hr />
+</li>
+</ul>
+
+

ATX headings

+

An ATX heading +consists of a string of characters, parsed as inline content, between an +opening sequence of 1--6 unescaped # characters and an optional +closing sequence of any number of unescaped # characters. +The opening sequence of # characters must be followed by a +[space] or by the end of line. The optional closing sequence of #s must be +preceded by a [space] and may be followed by spaces only. The opening +# character may be indented 0-3 spaces. The raw contents of the +heading are stripped of leading and trailing spaces before being parsed +as inline content. The heading level is equal to the number of # +characters in the opening sequence.

+

Simple headings:

+
# foo
+## foo
+### foo
+#### foo
+##### foo
+###### foo
+.
+<h1>foo</h1>
+<h2>foo</h2>
+<h3>foo</h3>
+<h4>foo</h4>
+<h5>foo</h5>
+<h6>foo</h6>
+
+

More than six # characters is not a heading:

+
####### foo
+.
+<p>####### foo</p>
+
+

At least one space is required between the # characters and the +heading's contents, unless the heading is empty. Note that many +implementations currently do not require the space. However, the +space was required by the +original ATX implementation, +and it helps prevent things like the following from being parsed as +headings:

+
#5 bolt
+
+#hashtag
+.
+<p>#5 bolt</p>
+<p>#hashtag</p>
+
+

This is not a heading, because the first # is escaped:

+
\## foo
+.
+<p>## foo</p>
+
+

Contents are parsed as inlines:

+
# foo *bar* \*baz\*
+.
+<h1>foo <em>bar</em> *baz*</h1>
+
+

Leading and trailing [whitespace] is ignored in parsing inline content:

+
#                  foo                     
+.
+<h1>foo</h1>
+
+

One to three spaces indentation are allowed:

+
 ### foo
+  ## foo
+   # foo
+.
+<h3>foo</h3>
+<h2>foo</h2>
+<h1>foo</h1>
+
+

Four spaces are too much:

+
    # foo
+.
+<pre><code># foo
+</code></pre>
+
+
foo
+    # bar
+.
+<p>foo
+# bar</p>
+
+

A closing sequence of # characters is optional:

+
## foo ##
+  ###   bar    ###
+.
+<h2>foo</h2>
+<h3>bar</h3>
+
+

It need not be the same length as the opening sequence:

+
# foo ##################################
+##### foo ##
+.
+<h1>foo</h1>
+<h5>foo</h5>
+
+

Spaces are allowed after the closing sequence:

+
### foo ###     
+.
+<h3>foo</h3>
+
+

A sequence of # characters with anything but [spaces] following it +is not a closing sequence, but counts as part of the contents of the +heading:

+
### foo ### b
+.
+<h3>foo ### b</h3>
+
+

The closing sequence must be preceded by a space:

+
# foo#
+.
+<h1>foo#</h1>
+
+

Backslash-escaped # characters do not count as part +of the closing sequence:

+
### foo \###
+## foo #\##
+# foo \#
+.
+<h3>foo ###</h3>
+<h2>foo ###</h2>
+<h1>foo #</h1>
+
+

ATX headings need not be separated from surrounding content by blank +lines, and they can interrupt paragraphs:

+
****
+## foo
+****
+.
+<hr />
+<h2>foo</h2>
+<hr />
+
+
Foo bar
+# baz
+Bar foo
+.
+<p>Foo bar</p>
+<h1>baz</h1>
+<p>Bar foo</p>
+
+

ATX headings can be empty:

+
## 
+#
+### ###
+.
+<h2></h2>
+<h1></h1>
+<h3></h3>
+
+

Setext headings

+

A setext heading consists of one or more +lines of text, each containing at least one [non-whitespace +character], with no more than 3 spaces indentation, followed by +a [setext heading underline]. The lines of text must be such +that, were they not followed by the setext heading underline, +they would be interpreted as a paragraph: they cannot be +interpretable as a [code fence], [ATX heading][ATX headings], +[block quote][block quotes], [thematic break][thematic breaks], +[list item][list items], or [HTML block][HTML blocks].

+

A setext heading underline is a sequence of += characters or a sequence of - characters, with no more than 3 +spaces indentation and any number of trailing spaces. If a line +containing a single - can be interpreted as an +empty [list items], it should be interpreted this way +and not as a [setext heading underline].

+

The heading is a level 1 heading if = characters are used in +the [setext heading underline], and a level 2 heading if - +characters are used. The contents of the heading are the result +of parsing the preceding lines of text as CommonMark inline +content.

+

In general, a setext heading need not be preceded or followed by a +blank line. However, it cannot interrupt a paragraph, so when a +setext heading comes after a paragraph, a blank line is needed between +them.

+

Simple examples:

+
Foo *bar*
+=========
+
+Foo *bar*
+---------
+.
+<h1>Foo <em>bar</em></h1>
+<h2>Foo <em>bar</em></h2>
+
+

The content of the header may span more than one line:

+
Foo *bar
+baz*
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+
+

The contents are the result of parsing the headings's raw +content as inlines. The heading's raw content is formed by +concatenating the lines and removing initial and final +[whitespace].

+
  Foo *bar
+baz*→
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+
+

The underlining can be any length:

+
Foo
+-------------------------
+
+Foo
+=
+.
+<h2>Foo</h2>
+<h1>Foo</h1>
+
+

The heading content can be indented up to three spaces, and need +not line up with the underlining:

+
   Foo
+---
+
+  Foo
+-----
+
+  Foo
+  ===
+.
+<h2>Foo</h2>
+<h2>Foo</h2>
+<h1>Foo</h1>
+
+

Four spaces indent is too much:

+
    Foo
+    ---
+
+    Foo
+---
+.
+<pre><code>Foo
+---
+
+Foo
+</code></pre>
+<hr />
+
+

The setext heading underline can be indented up to three spaces, and +may have trailing spaces:

+
Foo
+   ----      
+.
+<h2>Foo</h2>
+
+

Four spaces is too much:

+
Foo
+    ---
+.
+<p>Foo
+---</p>
+
+

The setext heading underline cannot contain internal spaces:

+
Foo
+= =
+
+Foo
+--- -
+.
+<p>Foo
+= =</p>
+<p>Foo</p>
+<hr />
+
+

Trailing spaces in the content line do not cause a line break:

+
Foo  
+-----
+.
+<h2>Foo</h2>
+
+

Nor does a backslash at the end:

+
Foo\
+----
+.
+<h2>Foo\</h2>
+
+

Since indicators of block structure take precedence over +indicators of inline structure, the following are setext headings:

+
`Foo
+----
+`
+
+<a title="a lot
+---
+of dashes"/>
+.
+<h2>`Foo</h2>
+<p>`</p>
+<h2>&lt;a title=&quot;a lot</h2>
+<p>of dashes&quot;/&gt;</p>
+
+

The setext heading underline cannot be a [lazy continuation +line] in a list item or block quote:

+
> Foo
+---
+.
+<blockquote>
+<p>Foo</p>
+</blockquote>
+<hr />
+
+
> foo
+bar
+===
+.
+<blockquote>
+<p>foo
+bar
+===</p>
+</blockquote>
+
+
- Foo
+---
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+
+

A blank line is needed between a paragraph and a following +setext heading, since otherwise the paragraph becomes part +of the heading's content:

+
Foo
+Bar
+---
+.
+<h2>Foo
+Bar</h2>
+
+

But in general a blank line is not required before or after +setext headings:

+
---
+Foo
+---
+Bar
+---
+Baz
+.
+<hr />
+<h2>Foo</h2>
+<h2>Bar</h2>
+<p>Baz</p>
+
+

Setext headings cannot be empty:

+

+====
+.
+<p>====</p>
+
+

Setext heading text lines must not be interpretable as block +constructs other than paragraphs. So, the line of dashes +in these examples gets interpreted as a thematic break:

+
---
+---
+.
+<hr />
+<hr />
+
+
- foo
+-----
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+
+
    foo
+---
+.
+<pre><code>foo
+</code></pre>
+<hr />
+
+
> foo
+-----
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+
+

If you want a heading with > foo as its literal text, you can +use backslash escapes:

+
\> foo
+------
+.
+<h2>&gt; foo</h2>
+
+

Compatibility note: Most existing Markdown implementations +do not allow the text of setext headings to span multiple lines. +But there is no consensus about how to interpret

+
Foo
+bar
+---
+baz
+
+

One can find four different interpretations:

+
    +
  1. paragraph "Foo", heading "bar", paragraph "baz"
  2. +
  3. paragraph "Foo bar", thematic break, paragraph "baz"
  4. +
  5. paragraph "Foo bar --- baz"
  6. +
  7. heading "Foo bar", paragraph "baz"
  8. +
+

We find interpretation 4 most natural, and interpretation 4 +increases the expressive power of CommonMark, by allowing +multiline headings. Authors who want interpretation 1 can +put a blank line after the first paragraph:

+
Foo
+
+bar
+---
+baz
+.
+<p>Foo</p>
+<h2>bar</h2>
+<p>baz</p>
+
+

Authors who want interpretation 2 can put blank lines around +the thematic break,

+
Foo
+bar
+
+---
+
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+
+

or use a thematic break that cannot count as a [setext heading +underline], such as

+
Foo
+bar
+* * *
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+
+

Authors who want interpretation 3 can use backslash escapes:

+
Foo
+bar
+\---
+baz
+.
+<p>Foo
+bar
+---
+baz</p>
+
+

Indented code blocks

+

An indented code block is composed of one or more +[indented chunks] separated by blank lines. +An indented chunk is a sequence of non-blank lines, +each indented four or more spaces. The contents of the code block are +the literal contents of the lines, including trailing +[line endings], minus four spaces of indentation. +An indented code block has no [info string].

+

An indented code block cannot interrupt a paragraph, so there must be +a blank line between a paragraph and a following indented code block. +(A blank line is not needed, however, between a code block and a following +paragraph.)

+
    a simple
+      indented code block
+.
+<pre><code>a simple
+  indented code block
+</code></pre>
+
+

If there is any ambiguity between an interpretation of indentation +as a code block and as indicating that material belongs to a [list +item][list items], the list item interpretation takes precedence:

+
  - foo
+
+    bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+
+
1.  foo
+
+    - bar
+.
+<ol>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+
+

The contents of a code block are literal text, and do not get parsed +as Markdown:

+
    <a/>
+    *hi*
+
+    - one
+.
+<pre><code>&lt;a/&gt;
+*hi*
+
+- one
+</code></pre>
+
+

Here we have three chunks separated by blank lines:

+
    chunk1
+
+    chunk2
+  
+ 
+ 
+    chunk3
+.
+<pre><code>chunk1
+
+chunk2
+
+
+
+chunk3
+</code></pre>
+
+

Any initial spaces beyond four will be included in the content, even +in interior blank lines:

+
    chunk1
+      
+      chunk2
+.
+<pre><code>chunk1
+  
+  chunk2
+</code></pre>
+
+

An indented code block cannot interrupt a paragraph. (This +allows hanging indents and the like.)

+
Foo
+    bar
+
+.
+<p>Foo
+bar</p>
+
+

However, any non-blank line with fewer than four leading spaces ends +the code block immediately. So a paragraph may occur immediately +after indented code:

+
    foo
+bar
+.
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+
+

And indented code can occur immediately before and after other kinds of +blocks:

+
# Heading
+    foo
+Heading
+------
+    foo
+----
+.
+<h1>Heading</h1>
+<pre><code>foo
+</code></pre>
+<h2>Heading</h2>
+<pre><code>foo
+</code></pre>
+<hr />
+
+

The first line can be indented more than four spaces:

+
        foo
+    bar
+.
+<pre><code>    foo
+bar
+</code></pre>
+
+

Blank lines preceding or following an indented code block +are not included in it:

+

+    
+    foo
+    
+
+.
+<pre><code>foo
+</code></pre>
+
+

Trailing spaces are included in the code block's content:

+
    foo  
+.
+<pre><code>foo  
+</code></pre>
+
+

Fenced code blocks

+

A code fence is a sequence +of at least three consecutive backtick characters (`) or +tildes (~). (Tildes and backticks cannot be mixed.) +A fenced code block +begins with a code fence, indented no more than three spaces.

+

The line with the opening code fence may optionally contain some text +following the code fence; this is trimmed of leading and trailing +whitespace and called the info string. If the [info string] comes +after a backtick fence, it may not contain any backtick +characters. (The reason for this restriction is that otherwise +some inline code would be incorrectly interpreted as the +beginning of a fenced code block.)

+

The content of the code block consists of all subsequent lines, until +a closing [code fence] of the same type as the code block +began with (backticks or tildes), and with at least as many backticks +or tildes as the opening code fence. If the leading code fence is +indented N spaces, then up to N spaces of indentation are removed from +each line of the content (if present). (If a content line is not +indented, it is preserved unchanged. If it is indented less than N +spaces, all of the indentation is removed.)

+

The closing code fence may be indented up to three spaces, and may be +followed only by spaces, which are ignored. If the end of the +containing block (or document) is reached and no closing code fence +has been found, the code block contains all of the lines after the +opening code fence until the end of the containing block (or +document). (An alternative spec would require backtracking in the +event that a closing code fence is not found. But this makes parsing +much less efficient, and there seems to be no real down side to the +behavior described here.)

+

A fenced code block may interrupt a paragraph, and does not require +a blank line either before or after.

+

The content of a code fence is treated as literal text, not parsed +as inlines. The first word of the [info string] is typically used to +specify the language of the code sample, and rendered in the class +attribute of the code tag. However, this spec does not mandate any +particular treatment of the [info string].

+

Here is a simple example with backticks:

+
```
+<
+ >
+```
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+
+

With tildes:

+
~~~
+<
+ >
+~~~
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+
+

Fewer than three backticks is not enough:

+
``
+foo
+``
+.
+<p><code>foo</code></p>
+
+

The closing code fence must use the same character as the opening +fence:

+
```
+aaa
+~~~
+```
+.
+<pre><code>aaa
+~~~
+</code></pre>
+
+
~~~
+aaa
+```
+~~~
+.
+<pre><code>aaa
+```
+</code></pre>
+
+

The closing code fence must be at least as long as the opening fence:

+
````
+aaa
+```
+``````
+.
+<pre><code>aaa
+```
+</code></pre>
+
+
~~~~
+aaa
+~~~
+~~~~
+.
+<pre><code>aaa
+~~~
+</code></pre>
+
+

Unclosed code blocks are closed by the end of the document +(or the enclosing [block quote][block quotes] or [list item][list items]):

+
```
+.
+<pre><code></code></pre>
+
+
`````
+
+```
+aaa
+.
+<pre><code>
+```
+aaa
+</code></pre>
+
+
> ```
+> aaa
+
+bbb
+.
+<blockquote>
+<pre><code>aaa
+</code></pre>
+</blockquote>
+<p>bbb</p>
+
+

A code block can have all empty lines as its content:

+
```
+
+  
+```
+.
+<pre><code>
+  
+</code></pre>
+
+

A code block can be empty:

+
```
+```
+.
+<pre><code></code></pre>
+
+

Fences can be indented. If the opening fence is indented, +content lines will have equivalent opening indentation removed, +if present:

+
 ```
+ aaa
+aaa
+```
+.
+<pre><code>aaa
+aaa
+</code></pre>
+
+
  ```
+aaa
+  aaa
+aaa
+  ```
+.
+<pre><code>aaa
+aaa
+aaa
+</code></pre>
+
+
   ```
+   aaa
+    aaa
+  aaa
+   ```
+.
+<pre><code>aaa
+ aaa
+aaa
+</code></pre>
+
+

Four spaces indentation produces an indented code block:

+
    ```
+    aaa
+    ```
+.
+<pre><code>```
+aaa
+```
+</code></pre>
+
+

Closing fences may be indented by 0-3 spaces, and their indentation +need not match that of the opening fence:

+
```
+aaa
+  ```
+.
+<pre><code>aaa
+</code></pre>
+
+
   ```
+aaa
+  ```
+.
+<pre><code>aaa
+</code></pre>
+
+

This is not a closing fence, because it is indented 4 spaces:

+
```
+aaa
+    ```
+.
+<pre><code>aaa
+    ```
+</code></pre>
+
+

Code fences (opening and closing) cannot contain internal spaces:

+
``` ```
+aaa
+.
+<p><code> </code>
+aaa</p>
+
+
~~~~~~
+aaa
+~~~ ~~
+.
+<pre><code>aaa
+~~~ ~~
+</code></pre>
+
+

Fenced code blocks can interrupt paragraphs, and can be followed +directly by paragraphs, without a blank line between:

+
foo
+```
+bar
+```
+baz
+.
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+
+

Other blocks can also occur before and after fenced code blocks +without an intervening blank line:

+
foo
+---
+~~~
+bar
+~~~
+# baz
+.
+<h2>foo</h2>
+<pre><code>bar
+</code></pre>
+<h1>baz</h1>
+
+

An [info string] can be provided after the opening code fence. +Although this spec doesn't mandate any particular treatment of +the info string, the first word is typically used to specify +the language of the code block. In HTML output, the language is +normally indicated by adding a class to the code element consisting +of language- followed by the language name.

+
```ruby
+def foo(x)
+  return 3
+end
+```
+.
+<pre><code class="language-ruby">def foo(x)
+  return 3
+end
+</code></pre>
+
+
~~~~    ruby startline=3 $%@#$
+def foo(x)
+  return 3
+end
+~~~~~~~
+.
+<pre><code class="language-ruby">def foo(x)
+  return 3
+end
+</code></pre>
+
+
````;
+````
+.
+<pre><code class="language-;"></code></pre>
+
+

[Info strings] for backtick code blocks cannot contain backticks:

+
``` aa ```
+foo
+.
+<p><code>aa</code>
+foo</p>
+
+

[Info strings] for tilde code blocks can contain backticks and tildes:

+
~~~ aa ``` ~~~
+foo
+~~~
+.
+<pre><code class="language-aa">foo
+</code></pre>
+
+

Closing code fences cannot have [info strings]:

+
```
+``` aaa
+```
+.
+<pre><code>``` aaa
+</code></pre>
+
+

HTML blocks

+

An HTML block is a group of lines that is treated +as raw HTML (and will not be escaped in HTML output).

+

There are seven kinds of [HTML block], which can be defined by their +start and end conditions. The block begins with a line that meets a +start condition (after up to three spaces optional indentation). +It ends with the first subsequent line that meets a matching end +condition, or the last line of the document, or the last line of +the container block containing the current HTML +block, if no line is encountered that meets the [end condition]. If +the first line meets both the [start condition] and the [end +condition], the block will contain just that line.

+
    +
  1. +

    Start condition: line begins with the string <script, +<pre, or <style (case-insensitive), followed by whitespace, +the string >, or the end of the line.
    +End condition: line contains an end tag +</script>, </pre>, or </style> (case-insensitive; it +need not match the start tag).

    +
  2. +
  3. +

    Start condition: line begins with the string <!--.
    +End condition: line contains the string -->.

    +
  4. +
  5. +

    Start condition: line begins with the string <?.
    +End condition: line contains the string ?>.

    +
  6. +
  7. +

    Start condition: line begins with the string <! +followed by an ASCII letter.
    +End condition: line contains the character >.

    +
  8. +
  9. +

    Start condition: line begins with the string +<![CDATA[.
    +End condition: line contains the string ]]>.

    +
  10. +
  11. +

    Start condition: line begins the string < or </ +followed by one of the strings (case-insensitive) address, +article, aside, base, basefont, blockquote, body, +caption, center, col, colgroup, dd, details, dialog, +dir, div, dl, dt, fieldset, figcaption, figure, +footer, form, frame, frameset, +h1, h2, h3, h4, h5, h6, head, header, hr, +html, iframe, legend, li, link, main, menu, menuitem, +nav, noframes, ol, optgroup, option, p, param, +section, source, summary, table, tbody, td, +tfoot, th, thead, title, tr, track, ul, followed +by [whitespace], the end of the line, the string >, or +the string />.
    +End condition: line is followed by a [blank line].

    +
  12. +
  13. +

    Start condition: line begins with a complete [open tag] +(with any [tag name] other than script, +style, or pre) or a complete [closing tag], +followed only by [whitespace] or the end of the line.
    +End condition: line is followed by a [blank line].

    +
  14. +
+

HTML blocks continue until they are closed by their appropriate +[end condition], or the last line of the document or other container +block. This means any HTML within an HTML +block that might otherwise be recognised as a start condition will +be ignored by the parser and passed through as-is, without changing +the parser's state.

+

For instance, <pre> within a HTML block started by <table> will not affect +the parser state; as the HTML block was started in by start condition 6, it +will end at any blank line. This can be surprising:

+
<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+.
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+
+

In this case, the HTML block is terminated by the newline — the **Hello** +text remains verbatim — and regular parsing resumes, with a paragraph, +emphasised world and inline and block HTML following.

+

All types of [HTML blocks] except type 7 may interrupt +a paragraph. Blocks of type 7 may not interrupt a paragraph. +(This restriction is intended to prevent unwanted interpretation +of long tags inside a wrapped paragraph as starting HTML blocks.)

+

Some simple examples follow. Here are some basic HTML blocks +of type 6:

+
<table>
+  <tr>
+    <td>
+           hi
+    </td>
+  </tr>
+</table>
+
+okay.
+.
+<table>
+  <tr>
+    <td>
+           hi
+    </td>
+  </tr>
+</table>
+<p>okay.</p>
+
+
 <div>
+  *hello*
+         <foo><a>
+.
+ <div>
+  *hello*
+         <foo><a>
+
+

A block can also start with a closing tag:

+
</div>
+*foo*
+.
+</div>
+*foo*
+
+

Here we have two HTML blocks with a Markdown paragraph between them:

+
<DIV CLASS="foo">
+
+*Markdown*
+
+</DIV>
+.
+<DIV CLASS="foo">
+<p><em>Markdown</em></p>
+</DIV>
+
+

The tag on the first line can be partial, as long +as it is split where there would be whitespace:

+
<div id="foo"
+  class="bar">
+</div>
+.
+<div id="foo"
+  class="bar">
+</div>
+
+
<div id="foo" class="bar
+  baz">
+</div>
+.
+<div id="foo" class="bar
+  baz">
+</div>
+
+

An open tag need not be closed:

+
<div>
+*foo*
+
+*bar*
+.
+<div>
+*foo*
+<p><em>bar</em></p>
+
+

A partial tag need not even be completed (garbage +in, garbage out):

+
<div id="foo"
+*hi*
+.
+<div id="foo"
+*hi*
+
+
<div class
+foo
+.
+<div class
+foo
+
+

The initial tag doesn't even need to be a valid +tag, as long as it starts like one:

+
<div *???-&&&-<---
+*foo*
+.
+<div *???-&&&-<---
+*foo*
+
+

In type 6 blocks, the initial tag need not be on a line by +itself:

+
<div><a href="bar">*foo*</a></div>
+.
+<div><a href="bar">*foo*</a></div>
+
+
<table><tr><td>
+foo
+</td></tr></table>
+.
+<table><tr><td>
+foo
+</td></tr></table>
+
+

Everything until the next blank line or end of document +gets included in the HTML block. So, in the following +example, what looks like a Markdown code block +is actually part of the HTML block, which continues until a blank +line or the end of the document is reached:

+
<div></div>
+``` c
+int x = 33;
+```
+.
+<div></div>
+``` c
+int x = 33;
+```
+
+

To start an [HTML block] with a tag that is not in the +list of block-level tags in (6), you must put the tag by +itself on the first line (and it must be complete):

+
<a href="foo">
+*bar*
+</a>
+.
+<a href="foo">
+*bar*
+</a>
+
+

In type 7 blocks, the [tag name] can be anything:

+
<Warning>
+*bar*
+</Warning>
+.
+<Warning>
+*bar*
+</Warning>
+
+
<i class="foo">
+*bar*
+</i>
+.
+<i class="foo">
+*bar*
+</i>
+
+
</ins>
+*bar*
+.
+</ins>
+*bar*
+
+

These rules are designed to allow us to work with tags that +can function as either block-level or inline-level tags. +The <del> tag is a nice example. We can surround content with +<del> tags in three different ways. In this case, we get a raw +HTML block, because the <del> tag is on a line by itself:

+
<del>
+*foo*
+</del>
+.
+<del>
+*foo*
+</del>
+
+

In this case, we get a raw HTML block that just includes +the <del> tag (because it ends with the following blank +line). So the contents get interpreted as CommonMark:

+
<del>
+
+*foo*
+
+</del>
+.
+<del>
+<p><em>foo</em></p>
+</del>
+
+

Finally, in this case, the <del> tags are interpreted +as [raw HTML] inside the CommonMark paragraph. (Because +the tag is not on a line by itself, we get inline HTML +rather than an [HTML block].)

+
<del>*foo*</del>
+.
+<p><del><em>foo</em></del></p>
+
+

HTML tags designed to contain literal content +(script, style, pre), comments, processing instructions, +and declarations are treated somewhat differently. +Instead of ending at the first blank line, these blocks +end at the first line containing a corresponding end tag. +As a result, these blocks can contain blank lines:

+

A pre tag (type 1):

+
<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+okay
+.
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+<p>okay</p>
+
+

A script tag (type 1):

+
<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+okay
+.
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+<p>okay</p>
+
+

A style tag (type 1):

+
<style
+  type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+okay
+.
+<style
+  type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+<p>okay</p>
+
+

If there is no matching end tag, the block will end at the +end of the document (or the enclosing [block quote][block quotes] +or [list item][list items]):

+
<style
+  type="text/css">
+
+foo
+.
+<style
+  type="text/css">
+
+foo
+
+
> <div>
+> foo
+
+bar
+.
+<blockquote>
+<div>
+foo
+</blockquote>
+<p>bar</p>
+
+
- <div>
+- foo
+.
+<ul>
+<li>
+<div>
+</li>
+<li>foo</li>
+</ul>
+
+

The end tag can occur on the same line as the start tag:

+
<style>p{color:red;}</style>
+*foo*
+.
+<style>p{color:red;}</style>
+<p><em>foo</em></p>
+
+
<!-- foo -->*bar*
+*baz*
+.
+<!-- foo -->*bar*
+<p><em>baz</em></p>
+
+

Note that anything on the last line after the +end tag will be included in the [HTML block]:

+
<script>
+foo
+</script>1. *bar*
+.
+<script>
+foo
+</script>1. *bar*
+
+

A comment (type 2):

+
<!-- Foo
+
+bar
+   baz -->
+okay
+.
+<!-- Foo
+
+bar
+   baz -->
+<p>okay</p>
+
+

A processing instruction (type 3):

+
<?php
+
+  echo '>';
+
+?>
+okay
+.
+<?php
+
+  echo '>';
+
+?>
+<p>okay</p>
+
+

A declaration (type 4):

+
<!DOCTYPE html>
+.
+<!DOCTYPE html>
+
+

CDATA (type 5):

+
<![CDATA[
+function matchwo(a,b)
+{
+  if (a < b && a < 0) then {
+    return 1;
+
+  } else {
+
+    return 0;
+  }
+}
+]]>
+okay
+.
+<![CDATA[
+function matchwo(a,b)
+{
+  if (a < b && a < 0) then {
+    return 1;
+
+  } else {
+
+    return 0;
+  }
+}
+]]>
+<p>okay</p>
+
+

The opening tag can be indented 1-3 spaces, but not 4:

+
  <!-- foo -->
+
+    <!-- foo -->
+.
+  <!-- foo -->
+<pre><code>&lt;!-- foo --&gt;
+</code></pre>
+
+
  <div>
+
+    <div>
+.
+  <div>
+<pre><code>&lt;div&gt;
+</code></pre>
+
+

An HTML block of types 1--6 can interrupt a paragraph, and need not be +preceded by a blank line.

+
Foo
+<div>
+bar
+</div>
+.
+<p>Foo</p>
+<div>
+bar
+</div>
+
+

However, a following blank line is needed, except at the end of +a document, and except for blocks of types 1--5, [above][HTML +block]:

+
<div>
+bar
+</div>
+*foo*
+.
+<div>
+bar
+</div>
+*foo*
+
+

HTML blocks of type 7 cannot interrupt a paragraph:

+
Foo
+<a href="bar">
+baz
+.
+<p>Foo
+<a href="bar">
+baz</p>
+
+

This rule differs from John Gruber's original Markdown syntax +specification, which says:

+
+

The only restrictions are that block-level HTML elements — +e.g. <div>, <table>, <pre>, <p>, etc. — must be separated from +surrounding content by blank lines, and the start and end tags of the +block should not be indented with tabs or spaces.

+
+

In some ways Gruber's rule is more restrictive than the one given +here:

+
    +
  • It requires that an HTML block be preceded by a blank line.
  • +
  • It does not allow the start tag to be indented.
  • +
  • It requires a matching end tag, which it also does not allow to +be indented.
  • +
+

Most Markdown implementations (including some of Gruber's own) do not +respect all of these restrictions.

+

There is one respect, however, in which Gruber's rule is more liberal +than the one given here, since it allows blank lines to occur inside +an HTML block. There are two reasons for disallowing them here. +First, it removes the need to parse balanced tags, which is +expensive and can require backtracking from the end of the document +if no matching end tag is found. Second, it provides a very simple +and flexible way of including Markdown content inside HTML tags: +simply separate the Markdown from the HTML using blank lines:

+

Compare:

+
<div>
+
+*Emphasized* text.
+
+</div>
+.
+<div>
+<p><em>Emphasized</em> text.</p>
+</div>
+
+
<div>
+*Emphasized* text.
+</div>
+.
+<div>
+*Emphasized* text.
+</div>
+
+

Some Markdown implementations have adopted a convention of +interpreting content inside tags as text if the open tag has +the attribute markdown=1. The rule given above seems a simpler and +more elegant way of achieving the same expressive power, which is also +much simpler to parse.

+

The main potential drawback is that one can no longer paste HTML +blocks into Markdown documents with 100% reliability. However, +in most cases this will work fine, because the blank lines in +HTML are usually followed by HTML block tags. For example:

+
<table>
+
+<tr>
+
+<td>
+Hi
+</td>
+
+</tr>
+
+</table>
+.
+<table>
+<tr>
+<td>
+Hi
+</td>
+</tr>
+</table>
+
+

There are problems, however, if the inner tags are indented +and separated by spaces, as then they will be interpreted as +an indented code block:

+
<table>
+
+  <tr>
+
+    <td>
+      Hi
+    </td>
+
+  </tr>
+
+</table>
+.
+<table>
+  <tr>
+<pre><code>&lt;td&gt;
+  Hi
+&lt;/td&gt;
+</code></pre>
+  </tr>
+</table>
+
+

Fortunately, blank lines are usually not necessary and can be +deleted. The exception is inside <pre> tags, but as described +[above][HTML blocks], raw HTML blocks starting with <pre> +can contain blank lines.

+

Link reference definitions

+

A link reference definition +consists of a [link label], indented up to three spaces, followed +by a colon (:), optional [whitespace] (including up to one +[line ending]), a [link destination], +optional [whitespace] (including up to one +[line ending]), and an optional [link +title], which if it is present must be separated +from the [link destination] by [whitespace]. +No further [non-whitespace characters] may occur on the line.

+

A [link reference definition] +does not correspond to a structural element of a document. Instead, it +defines a label which can be used in [reference links] +and reference-style [images] elsewhere in the document. [Link +reference definitions] can come either before or after the links that use +them.

+
[foo]: /url "title"
+
+[foo]
+.
+<p><a href="/url" title="title">foo</a></p>
+
+
   [foo]: 
+      /url  
+           'the title'  
+
+[foo]
+.
+<p><a href="/url" title="the title">foo</a></p>
+
+
[Foo*bar\]]:my_(url) 'title (with parens)'
+
+[Foo*bar\]]
+.
+<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+
+
[Foo bar]:
+<my url>
+'title'
+
+[Foo bar]
+.
+<p><a href="my%20url" title="title">Foo bar</a></p>
+
+

The title may extend over multiple lines:

+
[foo]: /url '
+title
+line1
+line2
+'
+
+[foo]
+.
+<p><a href="/url" title="
+title
+line1
+line2
+">foo</a></p>
+
+

However, it may not contain a [blank line]:

+
[foo]: /url 'title
+
+with blank line'
+
+[foo]
+.
+<p>[foo]: /url 'title</p>
+<p>with blank line'</p>
+<p>[foo]</p>
+
+

The title may be omitted:

+
[foo]:
+/url
+
+[foo]
+.
+<p><a href="/url">foo</a></p>
+
+

The link destination may not be omitted:

+
[foo]:
+
+[foo]
+.
+<p>[foo]:</p>
+<p>[foo]</p>
+
+

However, an empty link destination may be specified using +angle brackets:

+
[foo]: <>
+
+[foo]
+.
+<p><a href="">foo</a></p>
+
+

The title must be separated from the link destination by +whitespace:

+
[foo]: <bar>(baz)
+
+[foo]
+.
+<p>[foo]: <bar>(baz)</p>
+<p>[foo]</p>
+
+

Both title and destination can contain backslash escapes +and literal backslashes:

+
[foo]: /url\bar\*baz "foo\"bar\baz"
+
+[foo]
+.
+<p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
+
+

A link can come before its corresponding definition:

+
[foo]
+
+[foo]: url
+.
+<p><a href="url">foo</a></p>
+
+

If there are several matching definitions, the first one takes +precedence:

+
[foo]
+
+[foo]: first
+[foo]: second
+.
+<p><a href="first">foo</a></p>
+
+

As noted in the section on [Links], matching of labels is +case-insensitive (see [matches]).

+
[FOO]: /url
+
+[Foo]
+.
+<p><a href="/url">Foo</a></p>
+
+
[ΑΓΩ]: /φου
+
+[αγω]
+.
+<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+
+

Here is a link reference definition with no corresponding link. +It contributes nothing to the document.

+
[foo]: /url
+.
+
+

Here is another one:

+
[
+foo
+]: /url
+bar
+.
+<p>bar</p>
+
+

This is not a link reference definition, because there are +[non-whitespace characters] after the title:

+
[foo]: /url "title" ok
+.
+<p>[foo]: /url &quot;title&quot; ok</p>
+
+

This is a link reference definition, but it has no title:

+
[foo]: /url
+"title" ok
+.
+<p>&quot;title&quot; ok</p>
+
+

This is not a link reference definition, because it is indented +four spaces:

+
    [foo]: /url "title"
+
+[foo]
+.
+<pre><code>[foo]: /url &quot;title&quot;
+</code></pre>
+<p>[foo]</p>
+
+

This is not a link reference definition, because it occurs inside +a code block:

+
```
+[foo]: /url
+```
+
+[foo]
+.
+<pre><code>[foo]: /url
+</code></pre>
+<p>[foo]</p>
+
+

A [link reference definition] cannot interrupt a paragraph.

+
Foo
+[bar]: /baz
+
+[bar]
+.
+<p>Foo
+[bar]: /baz</p>
+<p>[bar]</p>
+
+

However, it can directly follow other block elements, such as headings +and thematic breaks, and it need not be followed by a blank line.

+
# [Foo]
+[foo]: /url
+> bar
+.
+<h1><a href="/url">Foo</a></h1>
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+
[foo]: /url
+bar
+===
+[foo]
+.
+<h1>bar</h1>
+<p><a href="/url">foo</a></p>
+
+
[foo]: /url
+===
+[foo]
+.
+<p>===
+<a href="/url">foo</a></p>
+
+

Several [link reference definitions] +can occur one after another, without intervening blank lines.

+
[foo]: /foo-url "foo"
+[bar]: /bar-url
+  "bar"
+[baz]: /baz-url
+
+[foo],
+[bar],
+[baz]
+.
+<p><a href="/foo-url" title="foo">foo</a>,
+<a href="/bar-url" title="bar">bar</a>,
+<a href="/baz-url">baz</a></p>
+
+

[Link reference definitions] can occur +inside block containers, like lists and block quotations. They +affect the entire document, not just the container in which they +are defined:

+
[foo]
+
+> [foo]: /url
+.
+<p><a href="/url">foo</a></p>
+<blockquote>
+</blockquote>
+
+

Whether something is a [link reference definition] is +independent of whether the link reference it defines is +used in the document. Thus, for example, the following +document contains just a link reference definition, and +no visible content:

+
[foo]: /url
+.
+
+

Paragraphs

+

A sequence of non-blank lines that cannot be interpreted as other +kinds of blocks forms a paragraph. +The contents of the paragraph are the result of parsing the +paragraph's raw content as inlines. The paragraph's raw content +is formed by concatenating the lines and removing initial and final +[whitespace].

+

A simple example with two paragraphs:

+
aaa
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+
+

Paragraphs can contain multiple lines, but no blank lines:

+
aaa
+bbb
+
+ccc
+ddd
+.
+<p>aaa
+bbb</p>
+<p>ccc
+ddd</p>
+
+

Multiple blank lines between paragraph have no effect:

+
aaa
+
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+
+

Leading spaces are skipped:

+
  aaa
+ bbb
+.
+<p>aaa
+bbb</p>
+
+

Lines after the first may be indented any amount, since indented +code blocks cannot interrupt paragraphs.

+
aaa
+             bbb
+                                       ccc
+.
+<p>aaa
+bbb
+ccc</p>
+
+

However, the first line may be indented at most three spaces, +or an indented code block will be triggered:

+
   aaa
+bbb
+.
+<p>aaa
+bbb</p>
+
+
    aaa
+bbb
+.
+<pre><code>aaa
+</code></pre>
+<p>bbb</p>
+
+

Final spaces are stripped before inline parsing, so a paragraph +that ends with two or more spaces will not end with a [hard line +break]:

+
aaa     
+bbb     
+.
+<p>aaa<br />
+bbb</p>
+
+

Blank lines

+

[Blank lines] between block-level elements are ignored, +except for the role they play in determining whether a [list] +is [tight] or [loose].

+

Blank lines at the beginning and end of the document are also ignored.

+
  
+
+aaa
+  
+
+# aaa
+
+  
+.
+<p>aaa</p>
+<h1>aaa</h1>
+
+

Container blocks

+

A container block is a block that has other +blocks as its contents. There are two basic kinds of container blocks: +[block quotes] and [list items]. +[Lists] are meta-containers for [list items].

+

We define the syntax for container blocks recursively. The general +form of the definition is:

+
+

If X is a sequence of blocks, then the result of +transforming X in such-and-such a way is a container of type Y +with these blocks as its content.

+
+

So, we explain what counts as a block quote or list item by explaining +how these can be generated from their contents. This should suffice +to define the syntax, although it does not give a recipe for parsing +these constructions. (A recipe is provided below in the section entitled +A parsing strategy.)

+

Block quotes

+

A block quote marker +consists of 0-3 spaces of initial indent, plus (a) the character > together +with a following space, or (b) a single character > not followed by a space.

+

The following rules define [block quotes]:

+
    +
  1. +

    Basic case. If a string of lines Ls constitute a sequence +of blocks Bs, then the result of prepending a [block quote +marker] to the beginning of each line in Ls +is a block quote containing Bs.

    +
  2. +
  3. +

    Laziness. If a string of lines Ls constitute a block +quote with contents Bs, then the result of deleting +the initial [block quote marker] from one or +more lines in which the next [non-whitespace character] after the [block +quote marker] is [paragraph continuation +text] is a block quote with Bs as its content. +Paragraph continuation text is text +that will be parsed as part of the content of a paragraph, but does +not occur at the beginning of the paragraph.

    +
  4. +
  5. +

    Consecutiveness. A document cannot contain two [block +quotes] in a row unless there is a [blank line] between them.

    +
  6. +
+

Nothing else counts as a block quote.

+

Here is a simple example:

+
> # Foo
+> bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+
+

The spaces after the > characters can be omitted:

+
># Foo
+>bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+
+

The > characters can be indented 1-3 spaces:

+
   > # Foo
+   > bar
+ > baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+
+

Four spaces gives us a code block:

+
    > # Foo
+    > bar
+    > baz
+.
+<pre><code>&gt; # Foo
+&gt; bar
+&gt; baz
+</code></pre>
+
+

The Laziness clause allows us to omit the > before +[paragraph continuation text]:

+
> # Foo
+> bar
+baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+
+

A block quote can contain some lazy and some non-lazy +continuation lines:

+
> bar
+baz
+> foo
+.
+<blockquote>
+<p>bar
+baz
+foo</p>
+</blockquote>
+
+

Laziness only applies to lines that would have been continuations of +paragraphs had they been prepended with [block quote markers]. +For example, the > cannot be omitted in the second line of

+
> foo
+> ---
+
+

without changing the meaning:

+
> foo
+---
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+
+

Similarly, if we omit the > in the second line of

+
> - foo
+> - bar
+
+

then the block quote ends after the first line:

+
> - foo
+- bar
+.
+<blockquote>
+<ul>
+<li>foo</li>
+</ul>
+</blockquote>
+<ul>
+<li>bar</li>
+</ul>
+
+

For the same reason, we can't omit the > in front of +subsequent lines of an indented or fenced code block:

+
>     foo
+    bar
+.
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+<pre><code>bar
+</code></pre>
+
+
> ```
+foo
+```
+.
+<blockquote>
+<pre><code></code></pre>
+</blockquote>
+<p>foo</p>
+<pre><code></code></pre>
+
+

Note that in the following case, we have a [lazy +continuation line]:

+
> foo
+    - bar
+.
+<blockquote>
+<p>foo
+- bar</p>
+</blockquote>
+
+

To see why, note that in

+
> foo
+>     - bar
+
+

the - bar is indented too far to start a list, and can't +be an indented code block because indented code blocks cannot +interrupt paragraphs, so it is [paragraph continuation text].

+

A block quote can be empty:

+
>
+.
+<blockquote>
+</blockquote>
+
+
>
+>  
+> 
+.
+<blockquote>
+</blockquote>
+
+

A block quote can have initial or final blank lines:

+
>
+> foo
+>  
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+
+

A blank line always separates block quotes:

+
> foo
+
+> bar
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+

(Most current Markdown implementations, including John Gruber's +original Markdown.pl, will parse this example as a single block quote +with two paragraphs. But it seems better to allow the author to decide +whether two block quotes or one are wanted.)

+

Consecutiveness means that if we put these block quotes together, +we get a single block quote:

+
> foo
+> bar
+.
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+
+

To get a block quote with two paragraphs, use:

+
> foo
+>
+> bar
+.
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+
+

Block quotes can interrupt paragraphs:

+
foo
+> bar
+.
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+

In general, blank lines are not needed before or after block +quotes:

+
> aaa
+***
+> bbb
+.
+<blockquote>
+<p>aaa</p>
+</blockquote>
+<hr />
+<blockquote>
+<p>bbb</p>
+</blockquote>
+
+

However, because of laziness, a blank line is needed between +a block quote and a following paragraph:

+
> bar
+baz
+.
+<blockquote>
+<p>bar
+baz</p>
+</blockquote>
+
+
> bar
+
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+
+
> bar
+>
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+
+

It is a consequence of the Laziness rule that any number +of initial >s may be omitted on a continuation line of a +nested block quote:

+
> > > foo
+bar
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+</blockquote>
+</blockquote>
+
+
>>> foo
+> bar
+>>baz
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar
+baz</p>
+</blockquote>
+</blockquote>
+</blockquote>
+
+

When including an indented code block in a block quote, +remember that the [block quote marker] includes +both the > and a following space. So five spaces are needed after +the >:

+
>     code
+
+>    not code
+.
+<blockquote>
+<pre><code>code
+</code></pre>
+</blockquote>
+<blockquote>
+<p>not code</p>
+</blockquote>
+
+

List items

+

A list marker is a +[bullet list marker] or an [ordered list marker].

+

A bullet list marker +is a -, +, or * character.

+

An ordered list marker +is a sequence of 1--9 arabic digits (0-9), followed by either a +. character or a ) character. (The reason for the length +limit is that with 10 digits we start seeing integer overflows +in some browsers.)

+

The following rules define [list items]:

+
    +
  1. +

    Basic case. If a sequence of lines Ls constitute a sequence of +blocks Bs starting with a [non-whitespace character], and M is a +list marker of width W followed by 1 ≤ N ≤ 4 spaces, then the result +of prepending M and the following spaces to the first line of +Ls, and indenting subsequent lines of Ls by W + N spaces, is a +list item with Bs as its contents. The type of the list item +(bullet or ordered) is determined by the type of its list marker. +If the list item is ordered, then it is also assigned a start +number, based on the ordered list marker.

    +

    Exceptions:

    +
      +
    1. When the first list item in a [list] interrupts +a paragraph---that is, when it starts on a line that would +otherwise count as [paragraph continuation text]---then (a) +the lines Ls must not begin with a blank line, and (b) if +the list item is ordered, the start number must be 1.
    2. +
    3. If any line is a [thematic break][thematic breaks] then +that line is not a list item.
    4. +
    +
  2. +
+

For example, let Ls be the lines

+
A paragraph
+with two lines.
+
+    indented code
+
+> A block quote.
+.
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+
+

And let M be the marker 1., and N = 2. Then rule #1 says +that the following is an ordered list item with start number 1, +and the same contents as Ls:

+
1.  A paragraph
+    with two lines.
+
+        indented code
+
+    > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+
+

The most important thing to notice is that the position of +the text after the list marker determines how much indentation +is needed in subsequent blocks in the list item. If the list +marker takes up two spaces, and there are three spaces between +the list marker and the next [non-whitespace character], then blocks +must be indented five spaces in order to fall under the list +item.

+

Here are some examples showing how far content must be indented to be +put under the list item:

+
- one
+
+ two
+.
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+
+
- one
+
+  two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+
+
 -    one
+
+     two
+.
+<ul>
+<li>one</li>
+</ul>
+<pre><code> two
+</code></pre>
+
+
 -    one
+
+      two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+
+

It is tempting to think of this in terms of columns: the continuation +blocks must be indented at least to the column of the first +[non-whitespace character] after the list marker. However, that is not quite right. +The spaces after the list marker determine how much relative indentation +is needed. Which column this indentation reaches will depend on +how the list item is embedded in other constructions, as shown by +this example:

+
   > > 1.  one
+>>
+>>     two
+.
+<blockquote>
+<blockquote>
+<ol>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ol>
+</blockquote>
+</blockquote>
+
+

Here two occurs in the same column as the list marker 1., +but is actually contained in the list item, because there is +sufficient indentation after the last containing blockquote marker.

+

The converse is also possible. In the following example, the word two +occurs far to the right of the initial text of the list item, one, but +it is not considered part of the list item, because it is not indented +far enough past the blockquote marker:

+
>>- one
+>>
+  >  > two
+.
+<blockquote>
+<blockquote>
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+</blockquote>
+</blockquote>
+
+

Note that at least one space is needed between the list marker and +any following content, so these are not list items:

+
-one
+
+2.two
+.
+<p>-one</p>
+<p>2.two</p>
+
+

A list item may contain blocks that are separated by more than +one blank line.

+
- foo
+
+
+  bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+
+

A list item may contain any kind of block:

+
1.  foo
+
+    ```
+    bar
+    ```
+
+    baz
+
+    > bam
+.
+<ol>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+<blockquote>
+<p>bam</p>
+</blockquote>
+</li>
+</ol>
+
+

A list item that contains an indented code block will preserve +empty lines within the code block verbatim.

+
- Foo
+
+      bar
+
+
+      baz
+.
+<ul>
+<li>
+<p>Foo</p>
+<pre><code>bar
+
+
+baz
+</code></pre>
+</li>
+</ul>
+
+

Note that ordered list start numbers must be nine digits or less:

+
123456789. ok
+.
+<ol start="123456789">
+<li>ok</li>
+</ol>
+
+
1234567890. not ok
+.
+<p>1234567890. not ok</p>
+
+

A start number may begin with 0s:

+
0. ok
+.
+<ol start="0">
+<li>ok</li>
+</ol>
+
+
003. ok
+.
+<ol start="3">
+<li>ok</li>
+</ol>
+
+

A start number may not be negative:

+
-1. not ok
+.
+<p>-1. not ok</p>
+
+
    +
  1. Item starting with indented code. If a sequence of lines Ls +constitute a sequence of blocks Bs starting with an indented code +block, and M is a list marker of width W followed by +one space, then the result of prepending M and the following +space to the first line of Ls, and indenting subsequent lines of +Ls by W + 1 spaces, is a list item with Bs as its contents. +If a line is empty, then it need not be indented. The type of the +list item (bullet or ordered) is determined by the type of its list +marker. If the list item is ordered, then it is also assigned a +start number, based on the ordered list marker.
  2. +
+

An indented code block will have to be indented four spaces beyond +the edge of the region where text will be included in the list item. +In the following case that is 6 spaces:

+
- foo
+
+      bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ul>
+
+

And in this case it is 11 spaces:

+
  10.  foo
+
+           bar
+.
+<ol start="10">
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ol>
+
+

If the first block in the list item is an indented code block, +then by rule #2, the contents must be indented one space after the +list marker:

+
    indented code
+
+paragraph
+
+    more code
+.
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+
+
1.     indented code
+
+   paragraph
+
+       more code
+.
+<ol>
+<li>
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+
+

Note that an additional space indent is interpreted as space +inside the code block:

+
1.      indented code
+
+   paragraph
+
+       more code
+.
+<ol>
+<li>
+<pre><code> indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+
+

Note that rules #1 and #2 only apply to two cases: (a) cases +in which the lines to be included in a list item begin with a +[non-whitespace character], and (b) cases in which +they begin with an indented code +block. In a case like the following, where the first block begins with +a three-space indent, the rules do not allow us to form a list item by +indenting the whole thing and prepending a list marker:

+
   foo
+
+bar
+.
+<p>foo</p>
+<p>bar</p>
+
+
-    foo
+
+  bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+
+

This is not a significant restriction, because when a block begins +with 1-3 spaces indent, the indentation can always be removed without +a change in interpretation, allowing rule #1 to be applied. So, in +the above case:

+
-  foo
+
+   bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+
+
    +
  1. Item starting with a blank line. If a sequence of lines Ls +starting with a single [blank line] constitute a (possibly empty) +sequence of blocks Bs, not separated from each other by more than +one blank line, and M is a list marker of width W, +then the result of prepending M to the first line of Ls, and +indenting subsequent lines of Ls by W + 1 spaces, is a list +item with Bs as its contents. +If a line is empty, then it need not be indented. The type of the +list item (bullet or ordered) is determined by the type of its list +marker. If the list item is ordered, then it is also assigned a +start number, based on the ordered list marker.
  2. +
+

Here are some list items that start with a blank line but are not empty:

+
-
+  foo
+-
+  ```
+  bar
+  ```
+-
+      baz
+.
+<ul>
+<li>foo</li>
+<li>
+<pre><code>bar
+</code></pre>
+</li>
+<li>
+<pre><code>baz
+</code></pre>
+</li>
+</ul>
+
+

When the list item starts with a blank line, the number of spaces +following the list marker doesn't change the required indentation:

+
-   
+  foo
+.
+<ul>
+<li>foo</li>
+</ul>
+
+

A list item can begin with at most one blank line. +In the following example, foo is not part of the list +item:

+
-
+
+  foo
+.
+<ul>
+<li></li>
+</ul>
+<p>foo</p>
+
+

Here is an empty bullet list item:

+
- foo
+-
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+
+

It does not matter whether there are spaces following the [list marker]:

+
- foo
+-   
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+
+

Here is an empty ordered list item:

+
1. foo
+2.
+3. bar
+.
+<ol>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ol>
+
+

A list may start or end with an empty list item:

+
*
+.
+<ul>
+<li></li>
+</ul>
+
+

However, an empty list item cannot interrupt a paragraph:

+
foo
+*
+
+foo
+1.
+.
+<p>foo
+*</p>
+<p>foo
+1.</p>
+
+
    +
  1. Indentation. If a sequence of lines Ls constitutes a list item +according to rule #1, #2, or #3, then the result of indenting each line +of Ls by 1-3 spaces (the same for each line) also constitutes a +list item with the same contents and attributes. If a line is +empty, then it need not be indented.
  2. +
+

Indented one space:

+
 1.  A paragraph
+     with two lines.
+
+         indented code
+
+     > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+
+

Indented two spaces:

+
  1.  A paragraph
+      with two lines.
+
+          indented code
+
+      > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+
+

Indented three spaces:

+
   1.  A paragraph
+       with two lines.
+
+           indented code
+
+       > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+
+

Four spaces indent gives a code block:

+
    1.  A paragraph
+        with two lines.
+
+            indented code
+
+        > A block quote.
+.
+<pre><code>1.  A paragraph
+    with two lines.
+
+        indented code
+
+    &gt; A block quote.
+</code></pre>
+
+
    +
  1. Laziness. If a string of lines Ls constitute a list +item with contents Bs, then the result of deleting +some or all of the indentation from one or more lines in which the +next [non-whitespace character] after the indentation is +[paragraph continuation text] is a +list item with the same contents and attributes. The unindented +lines are called +lazy continuation lines.
  2. +
+

Here is an example with [lazy continuation lines]:

+
  1.  A paragraph
+with two lines.
+
+          indented code
+
+      > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+
+

Indentation can be partially deleted:

+
  1.  A paragraph
+    with two lines.
+.
+<ol>
+<li>A paragraph
+with two lines.</li>
+</ol>
+
+

These examples show how laziness can work in nested structures:

+
> 1. > Blockquote
+continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+
+
> 1. > Blockquote
+> continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+
+
    +
  1. That's all. Nothing that is not counted as a list item by rules +#1--5 counts as a list item.
  2. +
+

The rules for sublists follow from the general rules +[above][List items]. A sublist must be indented the same number +of spaces a paragraph would need to be in order to be included +in the list item.

+

So, in this case we need two spaces indent:

+
- foo
+  - bar
+    - baz
+      - boo
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz
+<ul>
+<li>boo</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+

One is not enough:

+
- foo
+ - bar
+  - baz
+   - boo
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+<li>baz</li>
+<li>boo</li>
+</ul>
+
+

Here we need four, because the list marker is wider:

+
10) foo
+    - bar
+.
+<ol start="10">
+<li>foo
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+
+

Three is not enough:

+
10) foo
+   - bar
+.
+<ol start="10">
+<li>foo</li>
+</ol>
+<ul>
+<li>bar</li>
+</ul>
+
+

A list may be the first block in a list item:

+
- - foo
+.
+<ul>
+<li>
+<ul>
+<li>foo</li>
+</ul>
+</li>
+</ul>
+
+
1. - 2. foo
+.
+<ol>
+<li>
+<ul>
+<li>
+<ol start="2">
+<li>foo</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+
+

A list item can contain a heading:

+
- # Foo
+- Bar
+  ---
+  baz
+.
+<ul>
+<li>
+<h1>Foo</h1>
+</li>
+<li>
+<h2>Bar</h2>
+baz</li>
+</ul>
+
+

Motivation

+

John Gruber's Markdown spec says the following about list items:

+
    +
  1. +

    "List markers typically start at the left margin, but may be indented +by up to three spaces. List markers must be followed by one or more +spaces or a tab."

    +
  2. +
  3. +

    "To make lists look nice, you can wrap items with hanging indents.... +But if you don't want to, you don't have to."

    +
  4. +
  5. +

    "List items may consist of multiple paragraphs. Each subsequent +paragraph in a list item must be indented by either 4 spaces or one +tab."

    +
  6. +
  7. +

    "It looks nice if you indent every line of the subsequent paragraphs, +but here again, Markdown will allow you to be lazy."

    +
  8. +
  9. +

    "To put a blockquote within a list item, the blockquote's > +delimiters need to be indented."

    +
  10. +
  11. +

    "To put a code block within a list item, the code block needs to be +indented twice — 8 spaces or two tabs."

    +
  12. +
+

These rules specify that a paragraph under a list item must be indented +four spaces (presumably, from the left margin, rather than the start of +the list marker, but this is not said), and that code under a list item +must be indented eight spaces instead of the usual four. They also say +that a block quote must be indented, but not by how much; however, the +example given has four spaces indentation. Although nothing is said +about other kinds of block-level content, it is certainly reasonable to +infer that all block elements under a list item, including other +lists, must be indented four spaces. This principle has been called the +four-space rule.

+

The four-space rule is clear and principled, and if the reference +implementation Markdown.pl had followed it, it probably would have +become the standard. However, Markdown.pl allowed paragraphs and +sublists to start with only two spaces indentation, at least on the +outer level. Worse, its behavior was inconsistent: a sublist of an +outer-level list needed two spaces indentation, but a sublist of this +sublist needed three spaces. It is not surprising, then, that different +implementations of Markdown have developed very different rules for +determining what comes under a list item. (Pandoc and python-Markdown, +for example, stuck with Gruber's syntax description and the four-space +rule, while discount, redcarpet, marked, PHP Markdown, and others +followed Markdown.pl's behavior more closely.)

+

Unfortunately, given the divergences between implementations, there +is no way to give a spec for list items that will be guaranteed not +to break any existing documents. However, the spec given here should +correctly handle lists formatted with either the four-space rule or +the more forgiving Markdown.pl behavior, provided they are laid out +in a way that is natural for a human to read.

+

The strategy here is to let the width and indentation of the list marker +determine the indentation necessary for blocks to fall under the list +item, rather than having a fixed and arbitrary number. The writer can +think of the body of the list item as a unit which gets indented to the +right enough to fit the list marker (and any indentation on the list +marker). (The laziness rule, #5, then allows continuation lines to be +unindented if needed.)

+

This rule is superior, we claim, to any rule requiring a fixed level of +indentation from the margin. The four-space rule is clear but +unnatural. It is quite unintuitive that

+
- foo
+
+  bar
+
+  - baz
+
+

should be parsed as two lists with an intervening paragraph,

+
<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+
+

as the four-space rule demands, rather than a single list,

+
<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+
+

The choice of four spaces is arbitrary. It can be learned, but it is +not likely to be guessed, and it trips up beginners regularly.

+

Would it help to adopt a two-space rule? The problem is that such +a rule, together with the rule allowing 1--3 spaces indentation of the +initial list marker, allows text that is indented less than the +original list marker to be included in the list item. For example, +Markdown.pl parses

+
   - one
+
+  two
+
+

as a single list item, with two a continuation paragraph:

+
<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+
+

and similarly

+
>   - one
+>
+>  two
+
+

as

+
<blockquote>
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+</blockquote>
+
+

This is extremely unintuitive.

+

Rather than requiring a fixed indent from the margin, we could require +a fixed indent (say, two spaces, or even one space) from the list marker (which +may itself be indented). This proposal would remove the last anomaly +discussed. Unlike the spec presented above, it would count the following +as a list item with a subparagraph, even though the paragraph bar +is not indented as far as the first paragraph foo:

+
 10. foo
+
+   bar  
+
+

Arguably this text does read like a list item with bar as a subparagraph, +which may count in favor of the proposal. However, on this proposal indented +code would have to be indented six spaces after the list marker. And this +would break a lot of existing Markdown, which has the pattern:

+
1.  foo
+
+        indented code
+
+

where the code is indented eight spaces. The spec above, by contrast, will +parse this text as expected, since the code block's indentation is measured +from the beginning of foo.

+

The one case that needs special treatment is a list item that starts +with indented code. How much indentation is required in that case, since +we don't have a "first paragraph" to measure from? Rule #2 simply stipulates +that in such cases, we require one space indentation from the list marker +(and then the normal four spaces for the indented code). This will match the +four-space rule in cases where the list marker plus its initial indentation +takes four spaces (a common case), but diverge in other cases.

+

Lists

+

A list is a sequence of one or more +list items [of the same type]. The list items +may be separated by any number of blank lines.

+

Two list items are of the same type +if they begin with a [list marker] of the same type. +Two list markers are of the +same type if (a) they are bullet list markers using the same character +(-, +, or *) or (b) they are ordered list numbers with the same +delimiter (either . or )).

+

A list is an ordered list +if its constituent list items begin with +[ordered list markers], and a +bullet list if its constituent list +items begin with [bullet list markers].

+

The start number +of an [ordered list] is determined by the list number of +its initial list item. The numbers of subsequent list items are +disregarded.

+

A list is loose if any of its constituent +list items are separated by blank lines, or if any of its constituent +list items directly contain two block-level elements with a blank line +between them. Otherwise a list is tight. +(The difference in HTML output is that paragraphs in a loose list are +wrapped in <p> tags, while paragraphs in a tight list are not.)

+

Changing the bullet or ordered list delimiter starts a new list:

+
- foo
+- bar
++ baz
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<ul>
+<li>baz</li>
+</ul>
+
+
1. foo
+2. bar
+3) baz
+.
+<ol>
+<li>foo</li>
+<li>bar</li>
+</ol>
+<ol start="3">
+<li>baz</li>
+</ol>
+
+

In CommonMark, a list can interrupt a paragraph. That is, +no blank line is needed to separate a paragraph from a following +list:

+
Foo
+- bar
+- baz
+.
+<p>Foo</p>
+<ul>
+<li>bar</li>
+<li>baz</li>
+</ul>
+
+

Markdown.pl does not allow this, through fear of triggering a list +via a numeral in a hard-wrapped line:

+
The number of windows in my house is
+14.  The number of doors is 6.
+
+

Oddly, though, Markdown.pl does allow a blockquote to +interrupt a paragraph, even though the same considerations might +apply.

+

In CommonMark, we do allow lists to interrupt paragraphs, for +two reasons. First, it is natural and not uncommon for people +to start lists without blank lines:

+
I need to buy
+- new shoes
+- a coat
+- a plane ticket
+
+

Second, we are attracted to a

+
+

principle of uniformity: +if a chunk of text has a certain +meaning, it will continue to have the same meaning when put into a +container block (such as a list item or blockquote).

+
+

(Indeed, the spec for [list items] and [block quotes] presupposes +this principle.) This principle implies that if

+
  * I need to buy
+    - new shoes
+    - a coat
+    - a plane ticket
+
+

is a list item containing a paragraph followed by a nested sublist, +as all Markdown implementations agree it is (though the paragraph +may be rendered without <p> tags, since the list is "tight"), +then

+
I need to buy
+- new shoes
+- a coat
+- a plane ticket
+
+

by itself should be a paragraph followed by a nested sublist.

+

Since it is well established Markdown practice to allow lists to +interrupt paragraphs inside list items, the [principle of +uniformity] requires us to allow this outside list items as +well. (reStructuredText +takes a different approach, requiring blank lines before lists +even inside other list items.)

+

In order to solve of unwanted lists in paragraphs with +hard-wrapped numerals, we allow only lists starting with 1 to +interrupt paragraphs. Thus,

+
The number of windows in my house is
+14.  The number of doors is 6.
+.
+<p>The number of windows in my house is
+14.  The number of doors is 6.</p>
+
+

We may still get an unintended result in cases like

+
The number of windows in my house is
+1.  The number of doors is 6.
+.
+<p>The number of windows in my house is</p>
+<ol>
+<li>The number of doors is 6.</li>
+</ol>
+
+

but this rule should prevent most spurious list captures.

+

There can be any number of blank lines between items:

+
- foo
+
+- bar
+
+
+- baz
+.
+<ul>
+<li>
+<p>foo</p>
+</li>
+<li>
+<p>bar</p>
+</li>
+<li>
+<p>baz</p>
+</li>
+</ul>
+
+
- foo
+  - bar
+    - baz
+
+
+      bim
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>
+<p>baz</p>
+<p>bim</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+

To separate consecutive lists of the same type, or to separate a +list from an indented code block that would otherwise be parsed +as a subparagraph of the final list item, you can insert a blank HTML +comment:

+
- foo
+- bar
+
+<!-- -->
+
+- baz
+- bim
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<!-- -->
+<ul>
+<li>baz</li>
+<li>bim</li>
+</ul>
+
+
-   foo
+
+    notcode
+
+-   foo
+
+<!-- -->
+
+    code
+.
+<ul>
+<li>
+<p>foo</p>
+<p>notcode</p>
+</li>
+<li>
+<p>foo</p>
+</li>
+</ul>
+<!-- -->
+<pre><code>code
+</code></pre>
+
+

List items need not be indented to the same level. The following +list items will be treated as items at the same list level, +since none is indented enough to belong to the previous list +item:

+
- a
+ - b
+  - c
+   - d
+  - e
+ - f
+- g
+.
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d</li>
+<li>e</li>
+<li>f</li>
+<li>g</li>
+</ul>
+
+
1. a
+
+  2. b
+
+   3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ol>
+
+

Note, however, that list items may not be indented more than +three spaces. Here - e is treated as a paragraph continuation +line, because it is indented more than three spaces:

+
- a
+ - b
+  - c
+   - d
+    - e
+.
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d
+- e</li>
+</ul>
+
+

And here, 3. c is treated as in indented code block, +because it is indented four spaces and preceded by a +blank line.

+
1. a
+
+  2. b
+
+    3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+</ol>
+<pre><code>3. c
+</code></pre>
+
+

This is a loose list, because there is a blank line between +two of the list items:

+
- a
+- b
+
+- c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ul>
+
+

So is this, with a empty second item:

+
* a
+*
+
+* c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li></li>
+<li>
+<p>c</p>
+</li>
+</ul>
+
+

These are loose lists, even though there is no space between the items, +because one of the items directly contains two block-level elements +with a blank line between them:

+
- a
+- b
+
+  c
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+
+
- a
+- b
+
+  [ref]: /url
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+
+

This is a tight list, because the blank lines are in a code block:

+
- a
+- ```
+  b
+
+
+  ```
+- c
+.
+<ul>
+<li>a</li>
+<li>
+<pre><code>b
+
+
+</code></pre>
+</li>
+<li>c</li>
+</ul>
+
+

This is a tight list, because the blank line is between two +paragraphs of a sublist. So the sublist is loose while +the outer list is tight:

+
- a
+  - b
+
+    c
+- d
+.
+<ul>
+<li>a
+<ul>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+</ul>
+</li>
+<li>d</li>
+</ul>
+
+

This is a tight list, because the blank line is inside the +block quote:

+
* a
+  > b
+  >
+* c
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+</li>
+<li>c</li>
+</ul>
+
+

This list is tight, because the consecutive block elements +are not separated by blank lines:

+
- a
+  > b
+  ```
+  c
+  ```
+- d
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+<pre><code>c
+</code></pre>
+</li>
+<li>d</li>
+</ul>
+
+

A single-paragraph list is tight:

+
- a
+.
+<ul>
+<li>a</li>
+</ul>
+
+
- a
+  - b
+.
+<ul>
+<li>a
+<ul>
+<li>b</li>
+</ul>
+</li>
+</ul>
+
+

This list is loose, because of the blank line between the +two block elements in the list item:

+
1. ```
+   foo
+   ```
+
+   bar
+.
+<ol>
+<li>
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+</li>
+</ol>
+
+

Here the outer list is loose, the inner list tight:

+
* foo
+  * bar
+
+  baz
+.
+<ul>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+<p>baz</p>
+</li>
+</ul>
+
+
- a
+  - b
+  - c
+
+- d
+  - e
+  - f
+.
+<ul>
+<li>
+<p>a</p>
+<ul>
+<li>b</li>
+<li>c</li>
+</ul>
+</li>
+<li>
+<p>d</p>
+<ul>
+<li>e</li>
+<li>f</li>
+</ul>
+</li>
+</ul>
+
+

Inlines

+

Inlines are parsed sequentially from the beginning of the character +stream to the end (left to right, in left-to-right languages). +Thus, for example, in

+
`hi`lo`
+.
+<p><code>hi</code>lo`</p>
+
+

hi is parsed as code, leaving the backtick at the end as a literal +backtick.

+

Code spans

+

A backtick string +is a string of one or more backtick characters (`) that is neither +preceded nor followed by a backtick.

+

A code span begins with a backtick string and ends with +a backtick string of equal length. The contents of the code span are +the characters between these two backtick strings, normalized in the +following ways:

+
    +
  • First, [line endings] are converted to [spaces].
  • +
  • If the resulting string both begins and ends with a [space] +character, but does not consist entirely of [space] +characters, a single [space] character is removed from the +front and back. This allows you to include code that begins +or ends with backtick characters, which must be separated by +whitespace from the opening or closing backtick strings.
  • +
+

This is a simple code span:

+
`foo`
+.
+<p><code>foo</code></p>
+
+

Here two backticks are used, because the code contains a backtick. +This example also illustrates stripping of a single leading and +trailing space:

+
`` foo ` bar ``
+.
+<p><code>foo ` bar</code></p>
+
+

This example shows the motivation for stripping leading and trailing +spaces:

+
` `` `
+.
+<p><code>``</code></p>
+
+

Note that only one space is stripped:

+
`  ``  `
+.
+<p><code> `` </code></p>
+
+

The stripping only happens if the space is on both +sides of the string:

+
` a`
+.
+<p><code> a</code></p>
+
+

Only [spaces], and not [unicode whitespace] in general, are +stripped in this way:

+
` b `
+.
+<p><code> b </code></p>
+
+

No stripping occurs if the code span contains only spaces:

+
` `
+`  `
+.
+<p><code> </code>
+<code>  </code></p>
+
+

[Line endings] are treated like spaces:

+
``
+foo
+bar  
+baz
+``
+.
+<p><code>foo bar   baz</code></p>
+
+
``
+foo 
+``
+.
+<p><code>foo </code></p>
+
+

Interior spaces are not collapsed:

+
`foo   bar 
+baz`
+.
+<p><code>foo   bar  baz</code></p>
+
+

Note that browsers will typically collapse consecutive spaces +when rendering <code> elements, so it is recommended that +the following CSS be used:

+
code{white-space: pre-wrap;}
+
+

Note that backslash escapes do not work in code spans. All backslashes +are treated literally:

+
`foo\`bar`
+.
+<p><code>foo\</code>bar`</p>
+
+

Backslash escapes are never needed, because one can always choose a +string of n backtick characters as delimiters, where the code does +not contain any strings of exactly n backtick characters.

+
``foo`bar``
+.
+<p><code>foo`bar</code></p>
+
+
` foo `` bar `
+.
+<p><code>foo `` bar</code></p>
+
+

Code span backticks have higher precedence than any other inline +constructs except HTML tags and autolinks. Thus, for example, this is +not parsed as emphasized text, since the second * is part of a code +span:

+
*foo`*`
+.
+<p>*foo<code>*</code></p>
+
+

And this is not parsed as a link:

+
[not a `link](/foo`)
+.
+<p>[not a <code>link](/foo</code>)</p>
+
+

Code spans, HTML tags, and autolinks have the same precedence. +Thus, this is code:

+
`<a href="`">`
+.
+<p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
+
+

But this is an HTML tag:

+
<a href="`">`
+.
+<p><a href="`">`</p>
+
+

And this is code:

+
`<http://foo.bar.`baz>`
+.
+<p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
+
+

But this is an autolink:

+
<http://foo.bar.`baz>`
+.
+<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
+
+

When a backtick string is not closed by a matching backtick string, +we just have literal backticks:

+
```foo``
+.
+<p>```foo``</p>
+
+
`foo
+.
+<p>`foo</p>
+
+

The following case also illustrates the need for opening and +closing backtick strings to be equal in length:

+
`foo``bar``
+.
+<p>`foo<code>bar</code></p>
+
+

Emphasis and strong emphasis

+

John Gruber's original Markdown syntax +description says:

+
+

Markdown treats asterisks (*) and underscores (_) as indicators of +emphasis. Text wrapped with one * or _ will be wrapped with an HTML +<em> tag; double *'s or _'s will be wrapped with an HTML <strong> +tag.

+
+

This is enough for most users, but these rules leave much undecided, +especially when it comes to nested emphasis. The original +Markdown.pl test suite makes it clear that triple *** and +___ delimiters can be used for strong emphasis, and most +implementations have also allowed the following patterns:

+
***strong emph***
+***strong** in emph*
+***emph* in strong**
+**in strong *emph***
+*in emph **strong***
+
+

The following patterns are less widely supported, but the intent +is clear and they are useful (especially in contexts like bibliography +entries):

+
*emph *with emph* in it*
+**strong **with strong** in it**
+
+

Many implementations have also restricted intraword emphasis to +the * forms, to avoid unwanted emphasis in words containing +internal underscores. (It is best practice to put these in code +spans, but users often do not.)

+
internal emphasis: foo*bar*baz
+no emphasis: foo_bar_baz
+
+

The rules given below capture all of these patterns, while allowing +for efficient parsing strategies that do not backtrack.

+

First, some definitions. A delimiter run is either +a sequence of one or more * characters that is not preceded or +followed by a non-backslash-escaped * character, or a sequence +of one or more _ characters that is not preceded or followed by +a non-backslash-escaped _ character.

+

A left-flanking delimiter run is +a [delimiter run] that is (1) not followed by [Unicode whitespace], +and either (2a) not followed by a [punctuation character], or +(2b) followed by a [punctuation character] and +preceded by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace.

+

A right-flanking delimiter run is +a [delimiter run] that is (1) not preceded by [Unicode whitespace], +and either (2a) not preceded by a [punctuation character], or +(2b) preceded by a [punctuation character] and +followed by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace.

+

Here are some examples of delimiter runs.

+
    +
  • +

    left-flanking but not right-flanking:

    +
    ***abc
    +  _abc
    +**"abc"
    + _"abc"
    +
    +
  • +
  • +

    right-flanking but not left-flanking:

    +
     abc***
    + abc_
    +"abc"**
    +"abc"_
    +
    +
  • +
  • +

    Both left and right-flanking:

    +
     abc***def
    +"abc"_"def"
    +
    +
  • +
  • +

    Neither left nor right-flanking:

    +
    abc *** def
    +a _ b
    +
    +
  • +
+

(The idea of distinguishing left-flanking and right-flanking +delimiter runs based on the character before and the character +after comes from Roopesh Chander's +vfmd. +vfmd uses the terminology "emphasis indicator string" instead of "delimiter +run," and its rules for distinguishing left- and right-flanking runs +are a bit more complex than the ones given here.)

+

The following rules define emphasis and strong emphasis:

+
    +
  1. +

    A single * character can open emphasis +iff (if and only if) it is part of a [left-flanking delimiter run].

    +
  2. +
  3. +

    A single _ character [can open emphasis] iff +it is part of a [left-flanking delimiter run] +and either (a) not part of a [right-flanking delimiter run] +or (b) part of a [right-flanking delimiter run] +preceded by punctuation.

    +
  4. +
  5. +

    A single * character can close emphasis +iff it is part of a [right-flanking delimiter run].

    +
  6. +
  7. +

    A single _ character [can close emphasis] iff +it is part of a [right-flanking delimiter run] +and either (a) not part of a [left-flanking delimiter run] +or (b) part of a [left-flanking delimiter run] +followed by punctuation.

    +
  8. +
  9. +

    A double ** can open strong emphasis +iff it is part of a [left-flanking delimiter run].

    +
  10. +
  11. +

    A double __ [can open strong emphasis] iff +it is part of a [left-flanking delimiter run] +and either (a) not part of a [right-flanking delimiter run] +or (b) part of a [right-flanking delimiter run] +preceded by punctuation.

    +
  12. +
  13. +

    A double ** can close strong emphasis +iff it is part of a [right-flanking delimiter run].

    +
  14. +
  15. +

    A double __ [can close strong emphasis] iff +it is part of a [right-flanking delimiter run] +and either (a) not part of a [left-flanking delimiter run] +or (b) part of a [left-flanking delimiter run] +followed by punctuation.

    +
  16. +
  17. +

    Emphasis begins with a delimiter that [can open emphasis] and ends +with a delimiter that [can close emphasis], and that uses the same +character (_ or *) as the opening delimiter. The +opening and closing delimiters must belong to separate +[delimiter runs]. If one of the delimiters can both +open and close emphasis, then the sum of the lengths of the +delimiter runs containing the opening and closing delimiters +must not be a multiple of 3 unless both lengths are +multiples of 3.

    +
  18. +
  19. +

    Strong emphasis begins with a delimiter that +[can open strong emphasis] and ends with a delimiter that +[can close strong emphasis], and that uses the same character +(_ or *) as the opening delimiter. The +opening and closing delimiters must belong to separate +[delimiter runs]. If one of the delimiters can both open +and close strong emphasis, then the sum of the lengths of +the delimiter runs containing the opening and closing +delimiters must not be a multiple of 3 unless both lengths +are multiples of 3.

    +
  20. +
  21. +

    A literal * character cannot occur at the beginning or end of +*-delimited emphasis or **-delimited strong emphasis, unless it +is backslash-escaped.

    +
  22. +
  23. +

    A literal _ character cannot occur at the beginning or end of +_-delimited emphasis or __-delimited strong emphasis, unless it +is backslash-escaped.

    +
  24. +
+

Where rules 1--12 above are compatible with multiple parsings, +the following principles resolve ambiguity:

+
    +
  1. +

    The number of nestings should be minimized. Thus, for example, +an interpretation <strong>...</strong> is always preferred to +<em><em>...</em></em>.

    +
  2. +
  3. +

    An interpretation <em><strong>...</strong></em> is always +preferred to <strong><em>...</em></strong>.

    +
  4. +
  5. +

    When two potential emphasis or strong emphasis spans overlap, +so that the second begins before the first ends and ends after +the first ends, the first takes precedence. Thus, for example, +*foo _bar* baz_ is parsed as <em>foo _bar</em> baz_ rather +than *foo <em>bar* baz</em>.

    +
  6. +
  7. +

    When there are two potential emphasis or strong emphasis spans +with the same closing delimiter, the shorter one (the one that +opens later) takes precedence. Thus, for example, +**foo **bar baz** is parsed as **foo <strong>bar baz</strong> +rather than <strong>foo **bar baz</strong>.

    +
  8. +
  9. +

    Inline code spans, links, images, and HTML tags group more tightly +than emphasis. So, when there is a choice between an interpretation +that contains one of these elements and one that does not, the +former always wins. Thus, for example, *[foo*](bar) is +parsed as *<a href="bar">foo*</a> rather than as +<em>[foo</em>](bar).

    +
  10. +
+

These rules can be illustrated through a series of examples.

+

Rule 1:

+
*foo bar*
+.
+<p><em>foo bar</em></p>
+
+

This is not emphasis, because the opening * is followed by +whitespace, and hence not part of a [left-flanking delimiter run]:

+
a * foo bar*
+.
+<p>a * foo bar*</p>
+
+

This is not emphasis, because the opening * is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]:

+
a*"foo"*
+.
+<p>a*&quot;foo&quot;*</p>
+
+

Unicode nonbreaking spaces count as whitespace, too:

+
* a *
+.
+<p>* a *</p>
+
+

Intraword emphasis with * is permitted:

+
foo*bar*
+.
+<p>foo<em>bar</em></p>
+
+
5*6*78
+.
+<p>5<em>6</em>78</p>
+
+

Rule 2:

+
_foo bar_
+.
+<p><em>foo bar</em></p>
+
+

This is not emphasis, because the opening _ is followed by +whitespace:

+
_ foo bar_
+.
+<p>_ foo bar_</p>
+
+

This is not emphasis, because the opening _ is preceded +by an alphanumeric and followed by punctuation:

+
a_"foo"_
+.
+<p>a_&quot;foo&quot;_</p>
+
+

Emphasis with _ is not allowed inside words:

+
foo_bar_
+.
+<p>foo_bar_</p>
+
+
5_6_78
+.
+<p>5_6_78</p>
+
+
пристаням_стремятся_
+.
+<p>пристаням_стремятся_</p>
+
+

Here _ does not generate emphasis, because the first delimiter run +is right-flanking and the second left-flanking:

+
aa_"bb"_cc
+.
+<p>aa_&quot;bb&quot;_cc</p>
+
+

This is emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation:

+
foo-_(bar)_
+.
+<p>foo-<em>(bar)</em></p>
+
+

Rule 3:

+

This is not emphasis, because the closing delimiter does +not match the opening delimiter:

+
_foo*
+.
+<p>_foo*</p>
+
+

This is not emphasis, because the closing * is preceded by +whitespace:

+
*foo bar *
+.
+<p>*foo bar *</p>
+
+

A newline also counts as whitespace:

+
*foo bar
+*
+.
+<p>*foo bar
+*</p>
+
+

This is not emphasis, because the second * is +preceded by punctuation and followed by an alphanumeric +(hence it is not part of a [right-flanking delimiter run]:

+
*(*foo)
+.
+<p>*(*foo)</p>
+
+

The point of this restriction is more easily appreciated +with this example:

+
*(*foo*)*
+.
+<p><em>(<em>foo</em>)</em></p>
+
+

Intraword emphasis with * is allowed:

+
*foo*bar
+.
+<p><em>foo</em>bar</p>
+
+

Rule 4:

+

This is not emphasis, because the closing _ is preceded by +whitespace:

+
_foo bar _
+.
+<p>_foo bar _</p>
+
+

This is not emphasis, because the second _ is +preceded by punctuation and followed by an alphanumeric:

+
_(_foo)
+.
+<p>_(_foo)</p>
+
+

This is emphasis within emphasis:

+
_(_foo_)_
+.
+<p><em>(<em>foo</em>)</em></p>
+
+

Intraword emphasis is disallowed for _:

+
_foo_bar
+.
+<p>_foo_bar</p>
+
+
_пристаням_стремятся
+.
+<p>_пристаням_стремятся</p>
+
+
_foo_bar_baz_
+.
+<p><em>foo_bar_baz</em></p>
+
+

This is emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation:

+
_(bar)_.
+.
+<p><em>(bar)</em>.</p>
+
+

Rule 5:

+
**foo bar**
+.
+<p><strong>foo bar</strong></p>
+
+

This is not strong emphasis, because the opening delimiter is +followed by whitespace:

+
** foo bar**
+.
+<p>** foo bar**</p>
+
+

This is not strong emphasis, because the opening ** is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]:

+
a**"foo"**
+.
+<p>a**&quot;foo&quot;**</p>
+
+

Intraword strong emphasis with ** is permitted:

+
foo**bar**
+.
+<p>foo<strong>bar</strong></p>
+
+

Rule 6:

+
__foo bar__
+.
+<p><strong>foo bar</strong></p>
+
+

This is not strong emphasis, because the opening delimiter is +followed by whitespace:

+
__ foo bar__
+.
+<p>__ foo bar__</p>
+
+

A newline counts as whitespace:

+
__
+foo bar__
+.
+<p>__
+foo bar__</p>
+
+

This is not strong emphasis, because the opening __ is preceded +by an alphanumeric and followed by punctuation:

+
a__"foo"__
+.
+<p>a__&quot;foo&quot;__</p>
+
+

Intraword strong emphasis is forbidden with __:

+
foo__bar__
+.
+<p>foo__bar__</p>
+
+
5__6__78
+.
+<p>5__6__78</p>
+
+
пристаням__стремятся__
+.
+<p>пристаням__стремятся__</p>
+
+
__foo, __bar__, baz__
+.
+<p><strong>foo, <strong>bar</strong>, baz</strong></p>
+
+

This is strong emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation:

+
foo-__(bar)__
+.
+<p>foo-<strong>(bar)</strong></p>
+
+

Rule 7:

+

This is not strong emphasis, because the closing delimiter is preceded +by whitespace:

+
**foo bar **
+.
+<p>**foo bar **</p>
+
+

(Nor can it be interpreted as an emphasized *foo bar *, because of +Rule 11.)

+

This is not strong emphasis, because the second ** is +preceded by punctuation and followed by an alphanumeric:

+
**(**foo)
+.
+<p>**(**foo)</p>
+
+

The point of this restriction is more easily appreciated +with these examples:

+
*(**foo**)*
+.
+<p><em>(<strong>foo</strong>)</em></p>
+
+
**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
+*Asclepias physocarpa*)**
+.
+<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+<em>Asclepias physocarpa</em>)</strong></p>
+
+
**foo "*bar*" foo**
+.
+<p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
+
+

Intraword emphasis:

+
**foo**bar
+.
+<p><strong>foo</strong>bar</p>
+
+

Rule 8:

+

This is not strong emphasis, because the closing delimiter is +preceded by whitespace:

+
__foo bar __
+.
+<p>__foo bar __</p>
+
+

This is not strong emphasis, because the second __ is +preceded by punctuation and followed by an alphanumeric:

+
__(__foo)
+.
+<p>__(__foo)</p>
+
+

The point of this restriction is more easily appreciated +with this example:

+
_(__foo__)_
+.
+<p><em>(<strong>foo</strong>)</em></p>
+
+

Intraword strong emphasis is forbidden with __:

+
__foo__bar
+.
+<p>__foo__bar</p>
+
+
__пристаням__стремятся
+.
+<p>__пристаням__стремятся</p>
+
+
__foo__bar__baz__
+.
+<p><strong>foo__bar__baz</strong></p>
+
+

This is strong emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation:

+
__(bar)__.
+.
+<p><strong>(bar)</strong>.</p>
+
+

Rule 9:

+

Any nonempty sequence of inline elements can be the contents of an +emphasized span.

+
*foo [bar](/url)*
+.
+<p><em>foo <a href="/url">bar</a></em></p>
+
+
*foo
+bar*
+.
+<p><em>foo
+bar</em></p>
+
+

In particular, emphasis and strong emphasis can be nested +inside emphasis:

+
_foo __bar__ baz_
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+
+
_foo _bar_ baz_
+.
+<p><em>foo <em>bar</em> baz</em></p>
+
+
__foo_ bar_
+.
+<p><em><em>foo</em> bar</em></p>
+
+
*foo *bar**
+.
+<p><em>foo <em>bar</em></em></p>
+
+
*foo **bar** baz*
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+
+
*foo**bar**baz*
+.
+<p><em>foo<strong>bar</strong>baz</em></p>
+
+

Note that in the preceding case, the interpretation

+
<p><em>foo</em><em>bar<em></em>baz</em></p>
+
+

is precluded by the condition that a delimiter that +can both open and close (like the * after foo) +cannot form emphasis if the sum of the lengths of +the delimiter runs containing the opening and +closing delimiters is a multiple of 3 unless +both lengths are multiples of 3.

+

For the same reason, we don't get two consecutive +emphasis sections in this example:

+
*foo**bar*
+.
+<p><em>foo**bar</em></p>
+
+

The same condition ensures that the following +cases are all strong emphasis nested inside +emphasis, even when the interior spaces are +omitted:

+
***foo** bar*
+.
+<p><em><strong>foo</strong> bar</em></p>
+
+
*foo **bar***
+.
+<p><em>foo <strong>bar</strong></em></p>
+
+
*foo**bar***
+.
+<p><em>foo<strong>bar</strong></em></p>
+
+

When the lengths of the interior closing and opening +delimiter runs are both multiples of 3, though, +they can match to create emphasis:

+
foo***bar***baz
+.
+<p>foo<em><strong>bar</strong></em>baz</p>
+
+
foo******bar*********baz
+.
+<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+
+

Indefinite levels of nesting are possible:

+
*foo **bar *baz* bim** bop*
+.
+<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+
+
*foo [*bar*](/url)*
+.
+<p><em>foo <a href="/url"><em>bar</em></a></em></p>
+
+

There can be no empty emphasis or strong emphasis:

+
** is not an empty emphasis
+.
+<p>** is not an empty emphasis</p>
+
+
**** is not an empty strong emphasis
+.
+<p>**** is not an empty strong emphasis</p>
+
+

Rule 10:

+

Any nonempty sequence of inline elements can be the contents of an +strongly emphasized span.

+
**foo [bar](/url)**
+.
+<p><strong>foo <a href="/url">bar</a></strong></p>
+
+
**foo
+bar**
+.
+<p><strong>foo
+bar</strong></p>
+
+

In particular, emphasis and strong emphasis can be nested +inside strong emphasis:

+
__foo _bar_ baz__
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+
+
__foo __bar__ baz__
+.
+<p><strong>foo <strong>bar</strong> baz</strong></p>
+
+
____foo__ bar__
+.
+<p><strong><strong>foo</strong> bar</strong></p>
+
+
**foo **bar****
+.
+<p><strong>foo <strong>bar</strong></strong></p>
+
+
**foo *bar* baz**
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+
+
**foo*bar*baz**
+.
+<p><strong>foo<em>bar</em>baz</strong></p>
+
+
***foo* bar**
+.
+<p><strong><em>foo</em> bar</strong></p>
+
+
**foo *bar***
+.
+<p><strong>foo <em>bar</em></strong></p>
+
+

Indefinite levels of nesting are possible:

+
**foo *bar **baz**
+bim* bop**
+.
+<p><strong>foo <em>bar <strong>baz</strong>
+bim</em> bop</strong></p>
+
+
**foo [*bar*](/url)**
+.
+<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+
+

There can be no empty emphasis or strong emphasis:

+
__ is not an empty emphasis
+.
+<p>__ is not an empty emphasis</p>
+
+
____ is not an empty strong emphasis
+.
+<p>____ is not an empty strong emphasis</p>
+
+

Rule 11:

+
foo ***
+.
+<p>foo ***</p>
+
+
foo *\**
+.
+<p>foo <em>*</em></p>
+
+
foo *_*
+.
+<p>foo <em>_</em></p>
+
+
foo *****
+.
+<p>foo *****</p>
+
+
foo **\***
+.
+<p>foo <strong>*</strong></p>
+
+
foo **_**
+.
+<p>foo <strong>_</strong></p>
+
+

Note that when delimiters do not match evenly, Rule 11 determines +that the excess literal * characters will appear outside of the +emphasis, rather than inside it:

+
**foo*
+.
+<p>*<em>foo</em></p>
+
+
*foo**
+.
+<p><em>foo</em>*</p>
+
+
***foo**
+.
+<p>*<strong>foo</strong></p>
+
+
****foo*
+.
+<p>***<em>foo</em></p>
+
+
**foo***
+.
+<p><strong>foo</strong>*</p>
+
+
*foo****
+.
+<p><em>foo</em>***</p>
+
+

Rule 12:

+
foo ___
+.
+<p>foo ___</p>
+
+
foo _\__
+.
+<p>foo <em>_</em></p>
+
+
foo _*_
+.
+<p>foo <em>*</em></p>
+
+
foo _____
+.
+<p>foo _____</p>
+
+
foo __\___
+.
+<p>foo <strong>_</strong></p>
+
+
foo __*__
+.
+<p>foo <strong>*</strong></p>
+
+
__foo_
+.
+<p>_<em>foo</em></p>
+
+

Note that when delimiters do not match evenly, Rule 12 determines +that the excess literal _ characters will appear outside of the +emphasis, rather than inside it:

+
_foo__
+.
+<p><em>foo</em>_</p>
+
+
___foo__
+.
+<p>_<strong>foo</strong></p>
+
+
____foo_
+.
+<p>___<em>foo</em></p>
+
+
__foo___
+.
+<p><strong>foo</strong>_</p>
+
+
_foo____
+.
+<p><em>foo</em>___</p>
+
+

Rule 13 implies that if you want emphasis nested directly inside +emphasis, you must use different delimiters:

+
**foo**
+.
+<p><strong>foo</strong></p>
+
+
*_foo_*
+.
+<p><em><em>foo</em></em></p>
+
+
__foo__
+.
+<p><strong>foo</strong></p>
+
+
_*foo*_
+.
+<p><em><em>foo</em></em></p>
+
+

However, strong emphasis within strong emphasis is possible without +switching delimiters:

+
****foo****
+.
+<p><strong><strong>foo</strong></strong></p>
+
+
____foo____
+.
+<p><strong><strong>foo</strong></strong></p>
+
+

Rule 13 can be applied to arbitrarily long sequences of +delimiters:

+
******foo******
+.
+<p><strong><strong><strong>foo</strong></strong></strong></p>
+
+

Rule 14:

+
***foo***
+.
+<p><em><strong>foo</strong></em></p>
+
+
_____foo_____
+.
+<p><em><strong><strong>foo</strong></strong></em></p>
+
+

Rule 15:

+
*foo _bar* baz_
+.
+<p><em>foo _bar</em> baz_</p>
+
+
*foo __bar *baz bim__ bam*
+.
+<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+
+

Rule 16:

+
**foo **bar baz**
+.
+<p>**foo <strong>bar baz</strong></p>
+
+
*foo *bar baz*
+.
+<p>*foo <em>bar baz</em></p>
+
+

Rule 17:

+
*[bar*](/url)
+.
+<p>*<a href="/url">bar*</a></p>
+
+
_foo [bar_](/url)
+.
+<p>_foo <a href="/url">bar_</a></p>
+
+
*<img src="foo" title="*"/>
+.
+<p>*<img src="foo" title="*"/></p>
+
+
**<a href="**">
+.
+<p>**<a href="**"></p>
+
+
__<a href="__">
+.
+<p>__<a href="__"></p>
+
+
*a `*`*
+.
+<p><em>a <code>*</code></em></p>
+
+
_a `_`_
+.
+<p><em>a <code>_</code></em></p>
+
+
**a<http://foo.bar/?q=**>
+.
+<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
+
+
__a<http://foo.bar/?q=__>
+.
+<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
+
+

Links

+

A link contains [link text] (the visible text), a [link destination] +(the URI that is the link destination), and optionally a [link title]. +There are two basic kinds of links in Markdown. In [inline links] the +destination and title are given immediately after the link text. In +[reference links] the destination and title are defined elsewhere in +the document.

+

A link text consists of a sequence of zero or more +inline elements enclosed by square brackets ([ and ]). The +following rules apply:

+
    +
  • +

    Links may not contain other links, at any level of nesting. If +multiple otherwise valid link definitions appear nested inside each +other, the inner-most definition is used.

    +
  • +
  • +

    Brackets are allowed in the [link text] only if (a) they +are backslash-escaped or (b) they appear as a matched pair of brackets, +with an open bracket [, a sequence of zero or more inlines, and +a close bracket ].

    +
  • +
  • +

    Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly +than the brackets in link text. Thus, for example, +[foo`]` could not be a link text, since the second ] +is part of a code span.

    +
  • +
  • +

    The brackets in link text bind more tightly than markers for +[emphasis and strong emphasis]. Thus, for example, *[foo*](url) is a link.

    +
  • +
+

A link destination consists of either

+
    +
  • +

    a sequence of zero or more characters between an opening < and a +closing > that contains no line breaks or unescaped +< or > characters, or

    +
  • +
  • +

    a nonempty sequence of characters that does not start with <, +does not include [ASCII control characters][ASCII control character] +or [whitespace][], and includes parentheses only if (a) they are +backslash-escaped or (b) they are part of a balanced pair of +unescaped parentheses. +(Implementations may impose limits on parentheses nesting to +avoid performance issues, but at least three levels of nesting +should be supported.)

    +
  • +
+

A link title consists of either

+
    +
  • +

    a sequence of zero or more characters between straight double-quote +characters ("), including a " character only if it is +backslash-escaped, or

    +
  • +
  • +

    a sequence of zero or more characters between straight single-quote +characters ('), including a ' character only if it is +backslash-escaped, or

    +
  • +
  • +

    a sequence of zero or more characters between matching parentheses +((...)), including a ( or ) character only if it is +backslash-escaped.

    +
  • +
+

Although [link titles] may span multiple lines, they may not contain +a [blank line].

+

An inline link consists of a [link text] followed immediately +by a left parenthesis (, optional [whitespace], an optional +[link destination], an optional [link title] separated from the link +destination by [whitespace], optional [whitespace], and a right +parenthesis ). The link's text consists of the inlines contained +in the [link text] (excluding the enclosing square brackets). +The link's URI consists of the link destination, excluding enclosing +<...> if present, with backslash-escapes in effect as described +above. The link's title consists of the link title, excluding its +enclosing delimiters, with backslash-escapes in effect as described +above.

+

Here is a simple inline link:

+
[link](/uri "title")
+.
+<p><a href="/uri" title="title">link</a></p>
+
+

The title may be omitted:

+
[link](/uri)
+.
+<p><a href="/uri">link</a></p>
+
+

Both the title and the destination may be omitted:

+
[link]()
+.
+<p><a href="">link</a></p>
+
+
[link](<>)
+.
+<p><a href="">link</a></p>
+
+

The destination can only contain spaces if it is +enclosed in pointy brackets:

+
[link](/my uri)
+.
+<p>[link](/my uri)</p>
+
+
[link](</my uri>)
+.
+<p><a href="/my%20uri">link</a></p>
+
+

The destination cannot contain line breaks, +even if enclosed in pointy brackets:

+
[link](foo
+bar)
+.
+<p>[link](foo
+bar)</p>
+
+
[link](<foo
+bar>)
+.
+<p>[link](<foo
+bar>)</p>
+
+

The destination can contain ) if it is enclosed +in pointy brackets:

+
[a](<b)c>)
+.
+<p><a href="b)c">a</a></p>
+
+

Pointy brackets that enclose links must be unescaped:

+
[link](<foo\>)
+.
+<p>[link](&lt;foo&gt;)</p>
+
+

These are not links, because the opening pointy bracket +is not matched properly:

+
[a](<b)c
+[a](<b)c>
+[a](<b>c)
+.
+<p>[a](&lt;b)c
+[a](&lt;b)c&gt;
+[a](<b>c)</p>
+
+

Parentheses inside the link destination may be escaped:

+
[link](\(foo\))
+.
+<p><a href="(foo)">link</a></p>
+
+

Any number of parentheses are allowed without escaping, as long as they are +balanced:

+
[link](foo(and(bar)))
+.
+<p><a href="foo(and(bar))">link</a></p>
+
+

However, if you have unbalanced parentheses, you need to escape or use the +<...> form:

+
[link](foo(and(bar))
+.
+<p>[link](foo(and(bar))</p>
+
+
[link](foo\(and\(bar\))
+.
+<p><a href="foo(and(bar)">link</a></p>
+
+
[link](<foo(and(bar)>)
+.
+<p><a href="foo(and(bar)">link</a></p>
+
+

Parentheses and other symbols can also be escaped, as usual +in Markdown:

+
[link](foo\)\:)
+.
+<p><a href="foo):">link</a></p>
+
+

A link can contain fragment identifiers and queries:

+
[link](#fragment)
+
+[link](http://example.com#fragment)
+
+[link](http://example.com?foo=3#frag)
+.
+<p><a href="#fragment">link</a></p>
+<p><a href="http://example.com#fragment">link</a></p>
+<p><a href="http://example.com?foo=3#frag">link</a></p>
+
+

Note that a backslash before a non-escapable character is +just a backslash:

+
[link](foo\bar)
+.
+<p><a href="foo%5Cbar">link</a></p>
+
+

URL-escaping should be left alone inside the destination, as all +URL-escaped characters are also valid URL characters. Entity and +numerical character references in the destination will be parsed +into the corresponding Unicode code points, as usual. These may +be optionally URL-escaped when written as HTML, but this spec +does not enforce any particular policy for rendering URLs in +HTML or other formats. Renderers may make different decisions +about how to escape or normalize URLs in the output.

+
[link](foo%20b&auml;)
+.
+<p><a href="foo%20b%C3%A4">link</a></p>
+
+

Note that, because titles can often be parsed as destinations, +if you try to omit the destination and keep the title, you'll +get unexpected results:

+
[link]("title")
+.
+<p><a href="%22title%22">link</a></p>
+
+

Titles may be in single quotes, double quotes, or parentheses:

+
[link](/url "title")
+[link](/url 'title')
+[link](/url (title))
+.
+<p><a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a></p>
+
+

Backslash escapes and entity and numeric character references +may be used in titles:

+
[link](/url "title \"&quot;")
+.
+<p><a href="/url" title="title &quot;&quot;">link</a></p>
+
+

Titles must be separated from the link using a [whitespace]. +Other [Unicode whitespace] like non-breaking space doesn't work.

+
[link](/url "title")
+.
+<p><a href="/url%C2%A0%22title%22">link</a></p>
+
+

Nested balanced quotes are not allowed without escaping:

+
[link](/url "title "and" title")
+.
+<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
+
+

But it is easy to work around this by using a different quote type:

+
[link](/url 'title "and" title')
+.
+<p><a href="/url" title="title &quot;and&quot; title">link</a></p>
+
+

(Note: Markdown.pl did allow double quotes inside a double-quoted +title, and its test suite included a test demonstrating this. +But it is hard to see a good rationale for the extra complexity this +brings, since there are already many ways---backslash escaping, +entity and numeric character references, or using a different +quote type for the enclosing title---to write titles containing +double quotes. Markdown.pl's handling of titles has a number +of other strange features. For example, it allows single-quoted +titles in inline links, but not reference links. And, in +reference links but not inline links, it allows a title to begin +with " and end with ). Markdown.pl 1.0.1 even allows +titles with no closing quotation mark, though 1.0.2b8 does not. +It seems preferable to adopt a simple, rational rule that works +the same way in inline links and link reference definitions.)

+

[Whitespace] is allowed around the destination and title:

+
[link](   /uri
+  "title"  )
+.
+<p><a href="/uri" title="title">link</a></p>
+
+

But it is not allowed between the link text and the +following parenthesis:

+
[link] (/uri)
+.
+<p>[link] (/uri)</p>
+
+

The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped:

+
[link [foo [bar]]](/uri)
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+
+
[link] bar](/uri)
+.
+<p>[link] bar](/uri)</p>
+
+
[link [bar](/uri)
+.
+<p>[link <a href="/uri">bar</a></p>
+
+
[link \[bar](/uri)
+.
+<p><a href="/uri">link [bar</a></p>
+
+

The link text may contain inline content:

+
[link *foo **bar** `#`*](/uri)
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+
+
[![moon](moon.jpg)](/uri)
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+
+

However, links may not contain other links, at any level of nesting.

+
[foo [bar](/uri)](/uri)
+.
+<p>[foo <a href="/uri">bar</a>](/uri)</p>
+
+
[foo *[bar [baz](/uri)](/uri)*](/uri)
+.
+<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+
+
![[[foo](uri1)](uri2)](uri3)
+.
+<p><img src="uri3" alt="[foo](uri2)" /></p>
+
+

These cases illustrate the precedence of link text grouping over +emphasis grouping:

+
*[foo*](/uri)
+.
+<p>*<a href="/uri">foo*</a></p>
+
+
[foo *bar](baz*)
+.
+<p><a href="baz*">foo *bar</a></p>
+
+

Note that brackets that aren't part of links do not take +precedence:

+
*foo [bar* baz]
+.
+<p><em>foo [bar</em> baz]</p>
+
+

These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping:

+
[foo <bar attr="](baz)">
+.
+<p>[foo <bar attr="](baz)"></p>
+
+
[foo`](/uri)`
+.
+<p>[foo<code>](/uri)</code></p>
+
+
[foo<http://example.com/?search=](uri)>
+.
+<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
+
+

There are three kinds of reference links: +full, collapsed, +and shortcut.

+

A full reference link +consists of a [link text] immediately followed by a [link label] +that [matches] a [link reference definition] elsewhere in the document.

+

A link label begins with a left bracket ([) and ends +with the first right bracket (]) that is not backslash-escaped. +Between these brackets there must be at least one [non-whitespace character]. +Unescaped square bracket characters are not allowed inside the +opening and closing square brackets of [link labels]. A link +label can have at most 999 characters inside the square +brackets.

+

One label matches +another just in case their normalized forms are equal. To normalize a +label, strip off the opening and closing brackets, +perform the Unicode case fold, strip leading and trailing +[whitespace] and collapse consecutive internal +[whitespace] to a single space. If there are multiple +matching reference link definitions, the one that comes first in the +document is used. (It is desirable in such cases to emit a warning.)

+

The link's URI and title are provided by the matching [link +reference definition].

+

Here is a simple example:

+
[foo][bar]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+
+

The rules for the [link text] are the same as with +[inline links]. Thus:

+

The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped:

+
[link [foo [bar]]][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+
+
[link \[bar][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [bar</a></p>
+
+

The link text may contain inline content:

+
[link *foo **bar** `#`*][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+
+
[![moon](moon.jpg)][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+
+

However, links may not contain other links, at any level of nesting.

+
[foo [bar](/uri)][ref]
+
+[ref]: /uri
+.
+<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+
+
[foo *bar [baz][ref]*][ref]
+
+[ref]: /uri
+.
+<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+
+

(In the examples above, we have two [shortcut reference links] +instead of one [full reference link].)

+

The following cases illustrate the precedence of link text grouping over +emphasis grouping:

+
*[foo*][ref]
+
+[ref]: /uri
+.
+<p>*<a href="/uri">foo*</a></p>
+
+
[foo *bar][ref]*
+
+[ref]: /uri
+.
+<p><a href="/uri">foo *bar</a>*</p>
+
+

These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping:

+
[foo <bar attr="][ref]">
+
+[ref]: /uri
+.
+<p>[foo <bar attr="][ref]"></p>
+
+
[foo`][ref]`
+
+[ref]: /uri
+.
+<p>[foo<code>][ref]</code></p>
+
+
[foo<http://example.com/?search=][ref]>
+
+[ref]: /uri
+.
+<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
+
+

Matching is case-insensitive:

+
[foo][BaR]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+
+

Unicode case fold is used:

+
[ẞ]
+
+[SS]: /url
+.
+<p><a href="/url">ẞ</a></p>
+
+

Consecutive internal [whitespace] is treated as one space for +purposes of determining matching:

+
[Foo
+  bar]: /url
+
+[Baz][Foo bar]
+.
+<p><a href="/url">Baz</a></p>
+
+

No [whitespace] is allowed between the [link text] and the +[link label]:

+
[foo] [bar]
+
+[bar]: /url "title"
+.
+<p>[foo] <a href="/url" title="title">bar</a></p>
+
+
[foo]
+[bar]
+
+[bar]: /url "title"
+.
+<p>[foo]
+<a href="/url" title="title">bar</a></p>
+
+

This is a departure from John Gruber's original Markdown syntax +description, which explicitly allows whitespace between the link +text and the link label. It brings reference links in line with +[inline links], which (according to both original Markdown and +this spec) cannot have whitespace after the link text. More +importantly, it prevents inadvertent capture of consecutive +[shortcut reference links]. If whitespace is allowed between the +link text and the link label, then in the following we will have +a single reference link, not two shortcut reference links, as +intended:

+
[foo]
+[bar]
+
+[foo]: /url1
+[bar]: /url2
+
+

(Note that [shortcut reference links] were introduced by Gruber +himself in a beta version of Markdown.pl, but never included +in the official syntax description. Without shortcut reference +links, it is harmless to allow space between the link text and +link label; but once shortcut references are introduced, it is +too dangerous to allow this, as it frequently leads to +unintended results.)

+

When there are multiple matching [link reference definitions], +the first is used:

+
[foo]: /url1
+
+[foo]: /url2
+
+[bar][foo]
+.
+<p><a href="/url1">bar</a></p>
+
+

Note that matching is performed on normalized strings, not parsed +inline content. So the following does not match, even though the +labels define equivalent inline content:

+
[bar][foo\!]
+
+[foo!]: /url
+.
+<p>[bar][foo!]</p>
+
+

[Link labels] cannot contain brackets, unless they are +backslash-escaped:

+
[foo][ref[]
+
+[ref[]: /uri
+.
+<p>[foo][ref[]</p>
+<p>[ref[]: /uri</p>
+
+
[foo][ref[bar]]
+
+[ref[bar]]: /uri
+.
+<p>[foo][ref[bar]]</p>
+<p>[ref[bar]]: /uri</p>
+
+
[[[foo]]]
+
+[[[foo]]]: /url
+.
+<p>[[[foo]]]</p>
+<p>[[[foo]]]: /url</p>
+
+
[foo][ref\[]
+
+[ref\[]: /uri
+.
+<p><a href="/uri">foo</a></p>
+
+

Note that in this example ] is not backslash-escaped:

+
[bar\\]: /uri
+
+[bar\\]
+.
+<p><a href="/uri">bar\</a></p>
+
+

A [link label] must contain at least one [non-whitespace character]:

+
[]
+
+[]: /uri
+.
+<p>[]</p>
+<p>[]: /uri</p>
+
+
[
+ ]
+
+[
+ ]: /uri
+.
+<p>[
+]</p>
+<p>[
+]: /uri</p>
+
+

A collapsed reference link +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document, followed by the string []. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title are +provided by the matching reference link definition. Thus, +[foo][] is equivalent to [foo][foo].

+
[foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+
+
[*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+
+

The link labels are case-insensitive:

+
[Foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+
+

As with full reference links, [whitespace] is not +allowed between the two sets of brackets:

+
[foo] 
+[]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a>
+[]</p>
+
+

A shortcut reference link +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document and is not followed by [] or a link label. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title +are provided by the matching link reference definition. +Thus, [foo] is equivalent to [foo][].

+
[foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+
+
[*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+
+
[[*foo* bar]]
+
+[*foo* bar]: /url "title"
+.
+<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+
+
[[bar [foo]
+
+[foo]: /url
+.
+<p>[[bar <a href="/url">foo</a></p>
+
+

The link labels are case-insensitive:

+
[Foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+
+

A space after the link text should be preserved:

+
[foo] bar
+
+[foo]: /url
+.
+<p><a href="/url">foo</a> bar</p>
+
+

If you just want bracketed text, you can backslash-escape the +opening bracket to avoid links:

+
\[foo]
+
+[foo]: /url "title"
+.
+<p>[foo]</p>
+
+

Note that this is a link, because a link label ends with the first +following closing bracket:

+
[foo*]: /url
+
+*[foo*]
+.
+<p>*<a href="/url">foo*</a></p>
+
+

Full and compact references take precedence over shortcut +references:

+
[foo][bar]
+
+[foo]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a></p>
+
+
[foo][]
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a></p>
+
+

Inline links also take precedence:

+
[foo]()
+
+[foo]: /url1
+.
+<p><a href="">foo</a></p>
+
+
[foo](not a link)
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a>(not a link)</p>
+
+

In the following case [bar][baz] is parsed as a reference, +[foo] as normal text:

+
[foo][bar][baz]
+
+[baz]: /url
+.
+<p>[foo]<a href="/url">bar</a></p>
+
+

Here, though, [foo][bar] is parsed as a reference, since +[bar] is defined:

+
[foo][bar][baz]
+
+[baz]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+
+

Here [foo] is not parsed as a shortcut reference, because it +is followed by a link label (even though [bar] is not defined):

+
[foo][bar][baz]
+
+[baz]: /url1
+[foo]: /url2
+.
+<p>[foo]<a href="/url1">bar</a></p>
+
+

Images

+

Syntax for images is like the syntax for links, with one +difference. Instead of [link text], we have an +image description. The rules for this are the +same as for [link text], except that (a) an +image description starts with ![ rather than [, and +(b) an image description may contain links. +An image description has inline elements +as its contents. When an image is rendered to HTML, +this is standardly used as the image's alt attribute.

+
![foo](/url "title")
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+
+
![foo *bar*]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+
+
![foo ![bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+
+
![foo [bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+
+

Though this spec is concerned with parsing, not rendering, it is +recommended that in rendering to HTML, only the plain string content +of the [image description] be used. Note that in +the above example, the alt attribute's value is foo bar, not foo [bar](/url) or foo <a href="/url">bar</a>. Only the plain string +content is rendered, without formatting.

+
![foo *bar*][]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+
+
![foo *bar*][foobar]
+
+[FOOBAR]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+
+
![foo](train.jpg)
+.
+<p><img src="train.jpg" alt="foo" /></p>
+
+
My ![foo bar](/path/to/train.jpg  "title"   )
+.
+<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+
+
![foo](<url>)
+.
+<p><img src="url" alt="foo" /></p>
+
+
![](/url)
+.
+<p><img src="/url" alt="" /></p>
+
+

Reference-style:

+
![foo][bar]
+
+[bar]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+
+
![foo][bar]
+
+[BAR]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+
+

Collapsed:

+
![foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+
+
![*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+
+

The labels are case-insensitive:

+
![Foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+
+

As with reference links, [whitespace] is not allowed +between the two sets of brackets:

+
![foo] 
+[]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" />
+[]</p>
+
+

Shortcut:

+
![foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+
+
![*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+
+

Note that link labels cannot contain unescaped brackets:

+
![[foo]]
+
+[[foo]]: /url "title"
+.
+<p>![[foo]]</p>
+<p>[[foo]]: /url &quot;title&quot;</p>
+
+

The link labels are case-insensitive:

+
![Foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+
+

If you just want a literal ! followed by bracketed text, you can +backslash-escape the opening [:

+
!\[foo]
+
+[foo]: /url "title"
+.
+<p>![foo]</p>
+
+

If you want a link after a literal !, backslash-escape the +!:

+
\![foo]
+
+[foo]: /url "title"
+.
+<p>!<a href="/url" title="title">foo</a></p>
+
+

Autolinks

+

Autolinks are absolute URIs and email addresses inside +< and >. They are parsed as links, with the URL or email address +as the link label.

+

A URI autolink consists of <, followed by an +[absolute URI] followed by >. It is parsed as +a link to the URI, with the URI as the link's label.

+

An absolute URI, +for these purposes, consists of a [scheme] followed by a colon (:) +followed by zero or more characters other [ASCII control +characters][ASCII control character] or [whitespace][] , <, and >. +If the URI includes these characters, they must be percent-encoded +(e.g. %20 for a space).

+

For purposes of this spec, a scheme is any sequence +of 2--32 characters beginning with an ASCII letter and followed +by any combination of ASCII letters, digits, or the symbols plus +("+"), period ("."), or hyphen ("-").

+

Here are some valid autolinks:

+
<http://foo.bar.baz>
+.
+<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+
+
<http://foo.bar.baz/test?q=hello&id=22&boolean>
+.
+<p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+
+
<irc://foo.bar:2233/baz>
+.
+<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+
+

Uppercase is also fine:

+
<MAILTO:FOO@BAR.BAZ>
+.
+<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+
+

Note that many strings that count as [absolute URIs] for +purposes of this spec are not valid URIs, because their +schemes are not registered or because of other problems +with their syntax:

+
<a+b+c:d>
+.
+<p><a href="a+b+c:d">a+b+c:d</a></p>
+
+
<made-up-scheme://foo,bar>
+.
+<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+
+
<http://../>
+.
+<p><a href="http://../">http://../</a></p>
+
+
<localhost:5001/foo>
+.
+<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+
+

Spaces are not allowed in autolinks:

+
<http://foo.bar/baz bim>
+.
+<p>&lt;http://foo.bar/baz bim&gt;</p>
+
+

Backslash-escapes do not work inside autolinks:

+
<http://example.com/\[\>
+.
+<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
+
+

An email autolink +consists of <, followed by an [email address], +followed by >. The link's label is the email address, +and the URL is mailto: followed by the email address.

+

An email address, +for these purposes, is anything that matches +the non-normative regex from the HTML5 +spec:

+
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
+(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
+
+

Examples of email autolinks:

+
<foo@bar.example.com>
+.
+<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+
+
<foo+special@Bar.baz-bar0.com>
+.
+<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+
+

Backslash-escapes do not work inside email autolinks:

+
<foo\+@bar.example.com>
+.
+<p>&lt;foo+@bar.example.com&gt;</p>
+
+

These are not autolinks:

+
<>
+.
+<p>&lt;&gt;</p>
+
+
< http://foo.bar >
+.
+<p>&lt; http://foo.bar &gt;</p>
+
+
<m:abc>
+.
+<p>&lt;m:abc&gt;</p>
+
+
<foo.bar.baz>
+.
+<p>&lt;foo.bar.baz&gt;</p>
+
+
http://example.com
+.
+<p>http://example.com</p>
+
+
foo@bar.example.com
+.
+<p>foo@bar.example.com</p>
+
+

Raw HTML

+

Text between < and > that looks like an HTML tag is parsed as a +raw HTML tag and will be rendered in HTML without escaping. +Tag and attribute names are not limited to current HTML tags, +so custom tags (and even, say, DocBook tags) may be used.

+

Here is the grammar for tags:

+

A tag name consists of an ASCII letter +followed by zero or more ASCII letters, digits, or +hyphens (-).

+

An attribute consists of [whitespace], +an [attribute name], and an optional +[attribute value specification].

+

An attribute name +consists of an ASCII letter, _, or :, followed by zero or more ASCII +letters, digits, _, ., :, or -. (Note: This is the XML +specification restricted to ASCII. HTML5 is laxer.)

+

An attribute value specification +consists of optional [whitespace], +a = character, optional [whitespace], and an [attribute +value].

+

An attribute value +consists of an [unquoted attribute value], +a [single-quoted attribute value], or a [double-quoted attribute value].

+

An unquoted attribute value +is a nonempty string of characters not +including [whitespace], ", ', =, <, >, or `.

+

A single-quoted attribute value +consists of ', zero or more +characters not including ', and a final '.

+

A double-quoted attribute value +consists of ", zero or more +characters not including ", and a final ".

+

An open tag consists of a < character, a [tag name], +zero or more [attributes], optional [whitespace], an optional / +character, and a > character.

+

A closing tag consists of the string </, a +[tag name], optional [whitespace], and the character >.

+

An HTML comment consists of <!-- + text + -->, +where text does not start with > or ->, does not end with -, +and does not contain --. (See the +HTML5 spec.)

+

A processing instruction +consists of the string <?, a string +of characters not including the string ?>, and the string +?>.

+

A declaration consists of the string <!, an ASCII letter, zero or more +characters not including the character >, and the character >.

+

A CDATA section consists of +the string <![CDATA[, a string of characters not including the string +]]>, and the string ]]>.

+

An HTML tag consists of an [open tag], a [closing tag], +an [HTML comment], a [processing instruction], a [declaration], +or a [CDATA section].

+

Here are some simple open tags:

+
<a><bab><c2c>
+.
+<p><a><bab><c2c></p>
+
+

Empty elements:

+
<a/><b2/>
+.
+<p><a/><b2/></p>
+
+

[Whitespace] is allowed:

+
<a  /><b2
+data="foo" >
+.
+<p><a  /><b2
+data="foo" ></p>
+
+

With attributes:

+
<a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 />
+.
+<p><a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 /></p>
+
+

Custom tag names can be used:

+
Foo <responsive-image src="foo.jpg" />
+.
+<p>Foo <responsive-image src="foo.jpg" /></p>
+
+

Illegal tag names, not parsed as HTML:

+
<33> <__>
+.
+<p>&lt;33&gt; &lt;__&gt;</p>
+
+

Illegal attribute names:

+
<a h*#ref="hi">
+.
+<p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
+
+

Illegal attribute values:

+
<a href="hi'> <a href=hi'>
+.
+<p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
+
+

Illegal [whitespace]:

+
< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop />
+.
+<p>&lt; a&gt;&lt;
+foo&gt;&lt;bar/ &gt;
+&lt;foo bar=baz
+bim!bop /&gt;</p>
+
+

Missing [whitespace]:

+
<a href='bar'title=title>
+.
+<p>&lt;a href='bar'title=title&gt;</p>
+
+

Closing tags:

+
</a></foo >
+.
+<p></a></foo ></p>
+
+

Illegal attributes in closing tag:

+
</a href="foo">
+.
+<p>&lt;/a href=&quot;foo&quot;&gt;</p>
+
+

Comments:

+
foo <!-- this is a
+comment - with hyphen -->
+.
+<p>foo <!-- this is a
+comment - with hyphen --></p>
+
+
foo <!-- not a comment -- two hyphens -->
+.
+<p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
+
+

Not comments:

+
foo <!--> foo -->
+
+foo <!-- foo--->
+.
+<p>foo &lt;!--&gt; foo --&gt;</p>
+<p>foo &lt;!-- foo---&gt;</p>
+
+

Processing instructions:

+
foo <?php echo $a; ?>
+.
+<p>foo <?php echo $a; ?></p>
+
+

Declarations:

+
foo <!ELEMENT br EMPTY>
+.
+<p>foo <!ELEMENT br EMPTY></p>
+
+

CDATA sections:

+
foo <![CDATA[>&<]]>
+.
+<p>foo <![CDATA[>&<]]></p>
+
+

Entity and numeric character references are preserved in HTML +attributes:

+
foo <a href="&ouml;">
+.
+<p>foo <a href="&ouml;"></p>
+
+

Backslash escapes do not work in HTML attributes:

+
foo <a href="\*">
+.
+<p>foo <a href="\*"></p>
+
+
<a href="\"">
+.
+<p>&lt;a href=&quot;&quot;&quot;&gt;</p>
+
+

Hard line breaks

+

A line break (not in a code span or HTML tag) that is preceded +by two or more spaces and does not occur at the end of a block +is parsed as a hard line break (rendered +in HTML as a <br /> tag):

+
foo  
+baz
+.
+<p>foo<br />
+baz</p>
+
+

For a more visible alternative, a backslash before the +[line ending] may be used instead of two spaces:

+
foo\
+baz
+.
+<p>foo<br />
+baz</p>
+
+

More than two spaces can be used:

+
foo       
+baz
+.
+<p>foo<br />
+baz</p>
+
+

Leading spaces at the beginning of the next line are ignored:

+
foo  
+     bar
+.
+<p>foo<br />
+bar</p>
+
+
foo\
+     bar
+.
+<p>foo<br />
+bar</p>
+
+

Line breaks can occur inside emphasis, links, and other constructs +that allow inline content:

+
*foo  
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+
+
*foo\
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+
+

Line breaks do not occur inside code spans

+
`code 
+span`
+.
+<p><code>code  span</code></p>
+
+
`code\
+span`
+.
+<p><code>code\ span</code></p>
+
+

or HTML tags:

+
<a href="foo  
+bar">
+.
+<p><a href="foo  
+bar"></p>
+
+
<a href="foo\
+bar">
+.
+<p><a href="foo\
+bar"></p>
+
+

Hard line breaks are for separating inline content within a block. +Neither syntax for hard line breaks works at the end of a paragraph or +other block element:

+
foo\
+.
+<p>foo\</p>
+
+
foo  
+.
+<p>foo</p>
+
+
### foo\
+.
+<h3>foo\</h3>
+
+
### foo  
+.
+<h3>foo</h3>
+
+

Soft line breaks

+

A regular line break (not in a code span or HTML tag) that is not +preceded by two or more spaces or a backslash is parsed as a +softbreak. (A softbreak may be rendered in HTML either as a +[line ending] or as a space. The result will be the same in +browsers. In the examples here, a [line ending] will be used.)

+
foo
+baz
+.
+<p>foo
+baz</p>
+
+

Spaces at the end of the line and beginning of the next line are +removed:

+
foo 
+ baz
+.
+<p>foo
+baz</p>
+
+

A conforming parser may render a soft line break in HTML either as a +line break or as a space.

+

A renderer may also provide an option to render soft line breaks +as hard line breaks.

+

Textual content

+

Any characters not given an interpretation by the above rules will +be parsed as plain textual content.

+
hello $.;'there
+.
+<p>hello $.;'there</p>
+
+
Foo χρῆν
+.
+<p>Foo χρῆν</p>
+
+

Internal spaces are preserved verbatim:

+
Multiple     spaces
+.
+<p>Multiple     spaces</p>
+
+ +

Appendix: A parsing strategy

+

In this appendix we describe some features of the parsing strategy +used in the CommonMark reference implementations.

+

Overview

+

Parsing has two phases:

+
    +
  1. +

    In the first phase, lines of input are consumed and the block +structure of the document---its division into paragraphs, block quotes, +list items, and so on---is constructed. Text is assigned to these +blocks but not parsed. Link reference definitions are parsed and a +map of links is constructed.

    +
  2. +
  3. +

    In the second phase, the raw text contents of paragraphs and headings +are parsed into sequences of Markdown inline elements (strings, +code spans, links, emphasis, and so on), using the map of link +references constructed in phase 1.

    +
  4. +
+

At each point in processing, the document is represented as a tree of +blocks. The root of the tree is a document block. The document +may have any number of other blocks as children. These children +may, in turn, have other blocks as children. The last child of a block +is normally considered open, meaning that subsequent lines of input +can alter its contents. (Blocks that are not open are closed.) +Here, for example, is a possible document tree, with the open blocks +marked by arrows:

+
-> document
+  -> block_quote
+       paragraph
+         "Lorem ipsum dolor\nsit amet."
+    -> list (type=bullet tight=true bullet_char=-)
+         list_item
+           paragraph
+             "Qui *quodsi iracundia*"
+      -> list_item
+        -> paragraph
+             "aliquando id"
+
+

Phase 1: block structure

+

Each line that is processed has an effect on this tree. The line is +analyzed and, depending on its contents, the document may be altered +in one or more of the following ways:

+
    +
  1. One or more open blocks may be closed.
  2. +
  3. One or more new blocks may be created as children of the +last open block.
  4. +
  5. Text may be added to the last (deepest) open block remaining +on the tree.
  6. +
+

Once a line has been incorporated into the tree in this way, +it can be discarded, so input can be read in a stream.

+

For each line, we follow this procedure:

+
    +
  1. +

    First we iterate through the open blocks, starting with the +root document, and descending through last children down to the last +open block. Each block imposes a condition that the line must satisfy +if the block is to remain open. For example, a block quote requires a +> character. A paragraph requires a non-blank line. +In this phase we may match all or just some of the open +blocks. But we cannot close unmatched blocks yet, because we may have a +[lazy continuation line].

    +
  2. +
  3. +

    Next, after consuming the continuation markers for existing +blocks, we look for new block starts (e.g. > for a block quote). +If we encounter a new block start, we close any blocks unmatched +in step 1 before creating the new block as a child of the last +matched container block.

    +
  4. +
  5. +

    Finally, we look at the remainder of the line (after block +markers like >, list markers, and indentation have been consumed). +This is text that can be incorporated into the last open +block (a paragraph, code block, heading, or raw HTML).

    +
  6. +
+

Setext headings are formed when we see a line of a paragraph +that is a [setext heading underline].

+

Reference link definitions are detected when a paragraph is closed; +the accumulated text lines are parsed to see if they begin with +one or more reference link definitions. Any remainder becomes a +normal paragraph.

+

We can see how this works by considering how the tree above is +generated by four lines of Markdown:

+
> Lorem ipsum dolor
+sit amet.
+> - Qui *quodsi iracundia*
+> - aliquando id
+
+

At the outset, our document model is just

+
-> document
+
+

The first line of our text,

+
> Lorem ipsum dolor
+
+

causes a block_quote block to be created as a child of our +open document block, and a paragraph block as a child of +the block_quote. Then the text is added to the last open +block, the paragraph:

+
-> document
+  -> block_quote
+    -> paragraph
+         "Lorem ipsum dolor"
+
+

The next line,

+
sit amet.
+
+

is a "lazy continuation" of the open paragraph, so it gets added +to the paragraph's text:

+
-> document
+  -> block_quote
+    -> paragraph
+         "Lorem ipsum dolor\nsit amet."
+
+

The third line,

+
> - Qui *quodsi iracundia*
+
+

causes the paragraph block to be closed, and a new list block +opened as a child of the block_quote. A list_item is also +added as a child of the list, and a paragraph as a child of +the list_item. The text is then added to the new paragraph:

+
-> document
+  -> block_quote
+       paragraph
+         "Lorem ipsum dolor\nsit amet."
+    -> list (type=bullet tight=true bullet_char=-)
+      -> list_item
+        -> paragraph
+             "Qui *quodsi iracundia*"
+
+

The fourth line,

+
> - aliquando id
+
+

causes the list_item (and its child the paragraph) to be closed, +and a new list_item opened up as child of the list. A paragraph +is added as a child of the new list_item, to contain the text. +We thus obtain the final tree:

+
-> document
+  -> block_quote
+       paragraph
+         "Lorem ipsum dolor\nsit amet."
+    -> list (type=bullet tight=true bullet_char=-)
+         list_item
+           paragraph
+             "Qui *quodsi iracundia*"
+      -> list_item
+        -> paragraph
+             "aliquando id"
+
+

Phase 2: inline structure

+

Once all of the input has been parsed, all open blocks are closed.

+

We then "walk the tree," visiting every node, and parse raw +string contents of paragraphs and headings as inlines. At this +point we have seen all the link reference definitions, so we can +resolve reference links as we go.

+
document
+  block_quote
+    paragraph
+      str "Lorem ipsum dolor"
+      softbreak
+      str "sit amet."
+    list (type=bullet tight=true bullet_char=-)
+      list_item
+        paragraph
+          str "Qui "
+          emph
+            str "quodsi iracundia"
+      list_item
+        paragraph
+          str "aliquando id"
+
+

Notice how the [line ending] in the first paragraph has +been parsed as a softbreak, and the asterisks in the first list item +have become an emph.

+

An algorithm for parsing nested emphasis and links

+

By far the trickiest part of inline parsing is handling emphasis, +strong emphasis, links, and images. This is done using the following +algorithm.

+

When we're parsing inlines and we hit either

+
    +
  • a run of * or _ characters, or
  • +
  • a [ or ![
  • +
+

we insert a text node with these symbols as its literal content, and we +add a pointer to this text node to the delimiter stack.

+

The [delimiter stack] is a doubly linked list. Each +element contains a pointer to a text node, plus information about

+
    +
  • the type of delimiter ([, ![, *, _)
  • +
  • the number of delimiters,
  • +
  • whether the delimiter is "active" (all are active to start), and
  • +
  • whether the delimiter is a potential opener, a potential closer, +or both (which depends on what sort of characters precede +and follow the delimiters).
  • +
+

When we hit a ] character, we call the look for link or image +procedure (see below).

+

When we hit the end of the input, we call the process emphasis +procedure (see below), with stack_bottom = NULL.

+

look for link or image

+

Starting at the top of the delimiter stack, we look backwards +through the stack for an opening [ or ![ delimiter.

+
    +
  • +

    If we don't find one, we return a literal text node ].

    +
  • +
  • +

    If we do find one, but it's not active, we remove the inactive +delimiter from the stack, and return a literal text node ].

    +
  • +
  • +

    If we find one and it's active, then we parse ahead to see if +we have an inline link/image, reference link/image, compact reference +link/image, or shortcut reference link/image.

    +
      +
    • +

      If we don't, then we remove the opening delimiter from the +delimiter stack and return a literal text node ].

      +
    • +
    • +

      If we do, then

      +
        +
      • +

        We return a link or image node whose children are the inlines +after the text node pointed to by the opening delimiter.

        +
      • +
      • +

        We run process emphasis on these inlines, with the [ opener +as stack_bottom.

        +
      • +
      • +

        We remove the opening delimiter.

        +
      • +
      • +

        If we have a link (and not an image), we also set all +[ delimiters before the opening delimiter to inactive. (This +will prevent us from getting links within links.)

        +
      • +
      +
    • +
    +
  • +
+

process emphasis

+

Parameter stack_bottom sets a lower bound to how far we +descend in the [delimiter stack]. If it is NULL, we can +go all the way to the bottom. Otherwise, we stop before +visiting stack_bottom.

+

Let current_position point to the element on the [delimiter stack] +just above stack_bottom (or the first element if stack_bottom +is NULL).

+

We keep track of the openers_bottom for each delimiter +type (*, _) and each length of the closing delimiter run +(modulo 3). Initialize this to stack_bottom.

+

Then we repeat the following until we run out of potential +closers:

+
    +
  • +

    Move current_position forward in the delimiter stack (if needed) +until we find the first potential closer with delimiter * or _. +(This will be the potential closer closest +to the beginning of the input -- the first one in parse order.)

    +
  • +
  • +

    Now, look back in the stack (staying above stack_bottom and +the openers_bottom for this delimiter type) for the +first matching potential opener ("matching" means same delimiter).

    +
  • +
  • +

    If one is found:

    +
      +
    • +

      Figure out whether we have emphasis or strong emphasis: +if both closer and opener spans have length >= 2, we have +strong, otherwise regular.

      +
    • +
    • +

      Insert an emph or strong emph node accordingly, after +the text node corresponding to the opener.

      +
    • +
    • +

      Remove any delimiters between the opener and closer from +the delimiter stack.

      +
    • +
    • +

      Remove 1 (for regular emph) or 2 (for strong emph) delimiters +from the opening and closing text nodes. If they become empty +as a result, remove them and remove the corresponding element +of the delimiter stack. If the closing node is removed, reset +current_position to the next element in the stack.

      +
    • +
    +
  • +
  • +

    If none is found:

    +
      +
    • +

      Set openers_bottom to the element before current_position. +(We know that there are no openers for this kind of closer up to and +including this point, so this puts a lower bound on future searches.)

      +
    • +
    • +

      If the closer at current_position is not a potential opener, +remove it from the delimiter stack (since we know it can't +be a closer either).

      +
    • +
    • +

      Advance current_position to the next element in the stack.

      +
    • +
    +
  • +
+

After we're done, we remove all delimiters above stack_bottom from the +delimiter stack.

diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.md b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.md new file mode 100644 index 0000000..2aa39f1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/samples/cmark/spec.md @@ -0,0 +1,9720 @@ +--- +title: CommonMark Spec +author: John MacFarlane +version: 0.29 +date: '2019-04-06' +license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)' +... + +# Introduction + +## What is Markdown? + +Markdown is a plain text format for writing structured documents, +based on conventions for indicating formatting in email +and usenet posts. It was developed by John Gruber (with +help from Aaron Swartz) and released in 2004 in the form of a +[syntax description](http://daringfireball.net/projects/markdown/syntax) +and a Perl script (`Markdown.pl`) for converting Markdown to +HTML. In the next decade, dozens of implementations were +developed in many languages. Some extended the original +Markdown syntax with conventions for footnotes, tables, and +other document elements. Some allowed Markdown documents to be +rendered in formats other than HTML. Websites like Reddit, +StackOverflow, and GitHub had millions of people using Markdown. +And Markdown started to be used beyond the web, to author books, +articles, slide shows, letters, and lecture notes. + +What distinguishes Markdown from many other lightweight markup +syntaxes, which are often easier to write, is its readability. +As Gruber writes: + +> The overriding design goal for Markdown's formatting syntax is +> to make it as readable as possible. The idea is that a +> Markdown-formatted document should be publishable as-is, as +> plain text, without looking like it's been marked up with tags +> or formatting instructions. +> () + +The point can be illustrated by comparing a sample of +[AsciiDoc](http://www.methods.co.nz/asciidoc/) with +an equivalent sample of Markdown. Here is a sample of +AsciiDoc from the AsciiDoc manual: + +``` +1. List item one. ++ +List item one continued with a second paragraph followed by an +Indented block. ++ +................. +$ ls *.sh +$ mv *.sh ~/tmp +................. ++ +List item continued with a third paragraph. + +2. List item two continued with an open block. ++ +-- +This paragraph is part of the preceding list item. + +a. This list is nested and does not require explicit item +continuation. ++ +This paragraph is part of the preceding list item. + +b. List item b. + +This paragraph belongs to item two of the outer list. +-- +``` + +And here is the equivalent in Markdown: +``` +1. List item one. + + List item one continued with a second paragraph followed by an + Indented block. + + $ ls *.sh + $ mv *.sh ~/tmp + + List item continued with a third paragraph. + +2. List item two continued with an open block. + + This paragraph is part of the preceding list item. + + 1. This list is nested and does not require explicit item continuation. + + This paragraph is part of the preceding list item. + + 2. List item b. + + This paragraph belongs to item two of the outer list. +``` + +The AsciiDoc version is, arguably, easier to write. You don't need +to worry about indentation. But the Markdown version is much easier +to read. The nesting of list items is apparent to the eye in the +source, not just in the processed document. + +## Why is a spec needed? + +John Gruber's [canonical description of Markdown's +syntax](http://daringfireball.net/projects/markdown/syntax) +does not specify the syntax unambiguously. Here are some examples of +questions it does not answer: + +1. How much indentation is needed for a sublist? The spec says that + continuation paragraphs need to be indented four spaces, but is + not fully explicit about sublists. It is natural to think that + they, too, must be indented four spaces, but `Markdown.pl` does + not require that. This is hardly a "corner case," and divergences + between implementations on this issue often lead to surprises for + users in real documents. (See [this comment by John + Gruber](http://article.gmane.org/gmane.text.markdown.general/1997).) + +2. Is a blank line needed before a block quote or heading? + Most implementations do not require the blank line. However, + this can lead to unexpected results in hard-wrapped text, and + also to ambiguities in parsing (note that some implementations + put the heading inside the blockquote, while others do not). + (John Gruber has also spoken [in favor of requiring the blank + lines](http://article.gmane.org/gmane.text.markdown.general/2146).) + +3. Is a blank line needed before an indented code block? + (`Markdown.pl` requires it, but this is not mentioned in the + documentation, and some implementations do not require it.) + + ``` markdown + paragraph + code? + ``` + +4. What is the exact rule for determining when list items get + wrapped in `

` tags? Can a list be partially "loose" and partially + "tight"? What should we do with a list like this? + + ``` markdown + 1. one + + 2. two + 3. three + ``` + + Or this? + + ``` markdown + 1. one + - a + + - b + 2. two + ``` + + (There are some relevant comments by John Gruber + [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + +5. Can list markers be indented? Can ordered list markers be right-aligned? + + ``` markdown + 8. item 1 + 9. item 2 + 10. item 2a + ``` + +6. Is this one list with a thematic break in its second item, + or two lists separated by a thematic break? + + ``` markdown + * a + * * * * * + * b + ``` + +7. When list markers change from numbers to bullets, do we have + two lists or one? (The Markdown syntax description suggests two, + but the perl scripts and many other implementations produce one.) + + ``` markdown + 1. fee + 2. fie + - foe + - fum + ``` + +8. What are the precedence rules for the markers of inline structure? + For example, is the following a valid link, or does the code span + take precedence ? + + ``` markdown + [a backtick (`)](/url) and [another backtick (`)](/url). + ``` + +9. What are the precedence rules for markers of emphasis and strong + emphasis? For example, how should the following be parsed? + + ``` markdown + *foo *bar* baz* + ``` + +10. What are the precedence rules between block-level and inline-level + structure? For example, how should the following be parsed? + + ``` markdown + - `a long code span can contain a hyphen like this + - and it can screw things up` + ``` + +11. Can list items include section headings? (`Markdown.pl` does not + allow this, but does allow blockquotes to include headings.) + + ``` markdown + - # Heading + ``` + +12. Can list items be empty? + + ``` markdown + * a + * + * b + ``` + +13. Can link references be defined inside block quotes or list items? + + ``` markdown + > Blockquote [foo]. + > + > [foo]: /url + ``` + +14. If there are multiple definitions for the same reference, which takes + precedence? + + ``` markdown + [foo]: /url1 + [foo]: /url2 + + [foo][] + ``` + +In the absence of a spec, early implementers consulted `Markdown.pl` +to resolve these ambiguities. But `Markdown.pl` was quite buggy, and +gave manifestly bad results in many cases, so it was not a +satisfactory replacement for a spec. + +Because there is no unambiguous spec, implementations have diverged +considerably. As a result, users are often surprised to find that +a document that renders one way on one system (say, a GitHub wiki) +renders differently on another (say, converting to docbook using +pandoc). To make matters worse, because nothing in Markdown counts +as a "syntax error," the divergence often isn't discovered right away. + +## About this document + +This document attempts to specify Markdown syntax unambiguously. +It contains many examples with side-by-side Markdown and +HTML. These are intended to double as conformance tests. An +accompanying script `spec_tests.py` can be used to run the tests +against any Markdown program: + + python test/spec_tests.py --spec spec.txt --program PROGRAM + +Since this document describes how Markdown is to be parsed into +an abstract syntax tree, it would have made sense to use an abstract +representation of the syntax tree instead of HTML. But HTML is capable +of representing the structural distinctions we need to make, and the +choice of HTML for the tests makes it possible to run the tests against +an implementation without writing an abstract syntax tree renderer. + +This document is generated from a text file, `spec.txt`, written +in Markdown with a small extension for the side-by-side tests. +The script `tools/makespec.py` can be used to convert `spec.txt` into +HTML or CommonMark (which can then be converted into other formats). + +In the examples, the `→` character is used to represent tabs. + +# Preliminaries + +## Characters and lines + +Any sequence of [characters] is a valid CommonMark +document. + +A [character](@) is a Unicode code point. Although some +code points (for example, combining accents) do not correspond to +characters in an intuitive sense, all code points count as characters +for purposes of this spec. + +This spec does not specify an encoding; it thinks of lines as composed +of [characters] rather than bytes. A conforming parser may be limited +to a certain encoding. + +A [line](@) is a sequence of zero or more [characters] +other than newline (`U+000A`) or carriage return (`U+000D`), +followed by a [line ending] or by the end of file. + +A [line ending](@) is a newline (`U+000A`), a carriage return +(`U+000D`) not followed by a newline, or a carriage return and a +following newline. + +A line containing no characters, or a line containing only spaces +(`U+0020`) or tabs (`U+0009`), is called a [blank line](@). + +The following definitions of character classes will be used in this spec: + +A [whitespace character](@) is a space +(`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`), +form feed (`U+000C`), or carriage return (`U+000D`). + +[Whitespace](@) is a sequence of one or more [whitespace +characters]. + +A [Unicode whitespace character](@) is +any code point in the Unicode `Zs` general category, or a tab (`U+0009`), +carriage return (`U+000D`), newline (`U+000A`), or form feed +(`U+000C`). + +[Unicode whitespace](@) is a sequence of one +or more [Unicode whitespace characters]. + +A [space](@) is `U+0020`. + +A [non-whitespace character](@) is any character +that is not a [whitespace character]. + +An [ASCII control character](@) is a character between `U+0000–1F` (both +including) or `U+007F`. + +An [ASCII punctuation character](@) +is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, +`*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F), +`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040), +`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060), +`{`, `|`, `}`, or `~` (U+007B–007E). + +A [punctuation character](@) is an [ASCII +punctuation character] or anything in +the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`. + +## Tabs + +Tabs in lines are not expanded to [spaces]. However, +in contexts where whitespace helps to define block structure, +tabs behave as if they were replaced by spaces with a tab stop +of 4 characters. + +Thus, for example, a tab can be used instead of four spaces +in an indented code block. (Note, however, that internal +tabs are passed through as literal tabs, not expanded to +spaces.) + +```````````````````````````````` example +→foo→baz→→bim +. +

foo→baz→→bim
+
+```````````````````````````````` + +```````````````````````````````` example + →foo→baz→→bim +. +
foo→baz→→bim
+
+```````````````````````````````` + +```````````````````````````````` example + a→a + ὐ→a +. +
a→a
+ὐ→a
+
+```````````````````````````````` + +In the following example, a continuation paragraph of a list +item is indented with a tab; this has exactly the same effect +as indentation with four spaces would: + +```````````````````````````````` example + - foo + +→bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +- foo + +→→bar +. +
    +
  • +

    foo

    +
      bar
    +
    +
  • +
+```````````````````````````````` + +Normally the `>` that begins a block quote may be followed +optionally by a space, which is not considered part of the +content. In the following case `>` is followed by a tab, +which is treated as if it were expanded into three spaces. +Since one of these spaces is considered part of the +delimiter, `foo` is considered to be indented six spaces +inside the block quote context, so we get an indented +code block starting with two spaces. + +```````````````````````````````` example +>→→foo +. +
+
  foo
+
+
+```````````````````````````````` + +```````````````````````````````` example +-→→foo +. +
    +
  • +
      foo
    +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + foo +→bar +. +
foo
+bar
+
+```````````````````````````````` + +```````````````````````````````` example + - foo + - bar +→ - baz +. +
    +
  • foo +
      +
    • bar +
        +
      • baz
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +#→Foo +. +

Foo

+```````````````````````````````` + +```````````````````````````````` example +*→*→*→ +. +
+```````````````````````````````` + + +## Insecure characters + +For security reasons, the Unicode character `U+0000` must be replaced +with the REPLACEMENT CHARACTER (`U+FFFD`). + + +## Backslash escapes + +Any ASCII punctuation character may be backslash-escaped: + +```````````````````````````````` example +\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +. +

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

+```````````````````````````````` + + +Backslashes before other characters are treated as literal +backslashes: + +```````````````````````````````` example +\→\A\a\ \3\φ\« +. +

\→\A\a\ \3\φ\«

+```````````````````````````````` + + +Escaped characters are treated as regular characters and do +not have their usual Markdown meanings: + +```````````````````````````````` example +\*not emphasized* +\
not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +. +

*not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity

+```````````````````````````````` + + +If a backslash is itself escaped, the following character is not: + +```````````````````````````````` example +\\*emphasis* +. +

\emphasis

+```````````````````````````````` + + +A backslash at the end of the line is a [hard line break]: + +```````````````````````````````` example +foo\ +bar +. +

foo
+bar

+```````````````````````````````` + + +Backslash escapes do not work in code blocks, code spans, autolinks, or +raw HTML: + +```````````````````````````````` example +`` \[\` `` +. +

\[\`

+```````````````````````````````` + + +```````````````````````````````` example + \[\] +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +\[\] +~~~ +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://example.com?find=\*

+```````````````````````````````` + + +```````````````````````````````` example + +. + +```````````````````````````````` + + +But they work in all other contexts, including URLs and link titles, +link references, and [info strings] in [fenced code blocks]: + +```````````````````````````````` example +[foo](/bar\* "ti\*tle") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /bar\* "ti\*tle" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` foo\+bar +foo +``` +. +
foo
+
+```````````````````````````````` + + +## Entity and numeric character references + +Valid HTML entity references and numeric character references +can be used in place of the corresponding Unicode character, +with the following exceptions: + +- Entity and character references are not recognized in code + blocks and code spans. + +- Entity and character references cannot stand in place of + special characters that define structural elements in + CommonMark. For example, although `*` can be used + in place of a literal `*` character, `*` cannot replace + `*` in emphasis delimiters, bullet list markers, or thematic + breaks. + +Conforming CommonMark parsers need not store information about +whether a particular character was represented in the source +using a Unicode character or an entity reference. + +[Entity references](@) consist of `&` + any of the valid +HTML5 entity names + `;`. The +document +is used as an authoritative source for the valid entity +references and their corresponding code points. + +```````````````````````````````` example +  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +. +

& © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

+```````````````````````````````` + + +[Decimal numeric character +references](@) +consist of `&#` + a string of 1--7 arabic digits + `;`. A +numeric character reference is parsed as the corresponding +Unicode character. Invalid Unicode code points will be replaced by +the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons, +the code point `U+0000` will also be replaced by `U+FFFD`. + +```````````````````````````````` example +# Ӓ Ϡ � +. +

# Ӓ Ϡ �

+```````````````````````````````` + + +[Hexadecimal numeric character +references](@) consist of `&#` + +either `X` or `x` + a string of 1-6 hexadecimal digits + `;`. +They too are parsed as the corresponding Unicode character (this +time specified with a hexadecimal numeral instead of decimal). + +```````````````````````````````` example +" ആ ಫ +. +

" ആ ಫ

+```````````````````````````````` + + +Here are some nonentities: + +```````````````````````````````` example +  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +. +

&nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;

+```````````````````````````````` + + +Although HTML5 does accept some entity references +without a trailing semicolon (such as `©`), these are not +recognized here, because it makes the grammar too ambiguous: + +```````````````````````````````` example +© +. +

&copy

+```````````````````````````````` + + +Strings that are not on the list of HTML5 named entities are not +recognized as entity references either: + +```````````````````````````````` example +&MadeUpEntity; +. +

&MadeUpEntity;

+```````````````````````````````` + + +Entity and numeric character references are recognized in any +context besides code spans or code blocks, including +URLs, [link titles], and [fenced code block][] [info strings]: + +```````````````````````````````` example + +. + +```````````````````````````````` + + +```````````````````````````````` example +[foo](/föö "föö") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /föö "föö" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` föö +foo +``` +. +
foo
+
+```````````````````````````````` + + +Entity and numeric character references are treated as literal +text in code spans and code blocks: + +```````````````````````````````` example +`föö` +. +

f&ouml;&ouml;

+```````````````````````````````` + + +```````````````````````````````` example + föfö +. +
f&ouml;f&ouml;
+
+```````````````````````````````` + + +Entity and numeric character references cannot be used +in place of symbols indicating structure in CommonMark +documents. + +```````````````````````````````` example +*foo* +*foo* +. +

*foo* +foo

+```````````````````````````````` + +```````````````````````````````` example +* foo + +* foo +. +

* foo

+
    +
  • foo
  • +
+```````````````````````````````` + +```````````````````````````````` example +foo bar +. +

foo + +bar

+```````````````````````````````` + +```````````````````````````````` example + foo +. +

→foo

+```````````````````````````````` + + +```````````````````````````````` example +[a](url "tit") +. +

[a](url "tit")

+```````````````````````````````` + + + +# Blocks and inlines + +We can think of a document as a sequence of +[blocks](@)---structural elements like paragraphs, block +quotations, lists, headings, rules, and code blocks. Some blocks (like +block quotes and list items) contain other blocks; others (like +headings and paragraphs) contain [inline](@) content---text, +links, emphasized text, images, code spans, and so on. + +## Precedence + +Indicators of block structure always take precedence over indicators +of inline structure. So, for example, the following is a list with +two items, not a list with one item containing a code span: + +```````````````````````````````` example +- `one +- two` +. +
    +
  • `one
  • +
  • two`
  • +
+```````````````````````````````` + + +This means that parsing can proceed in two steps: first, the block +structure of the document can be discerned; second, text lines inside +paragraphs, headings, and other block constructs can be parsed for inline +structure. The second step requires information about link reference +definitions that will be available only at the end of the first +step. Note that the first step requires processing lines in sequence, +but the second can be parallelized, since the inline parsing of +one block element does not affect the inline parsing of any other. + +## Container blocks and leaf blocks + +We can divide blocks into two types: +[container blocks](@), +which can contain other blocks, and [leaf blocks](@), +which cannot. + +# Leaf blocks + +This section describes the different kinds of leaf block that make up a +Markdown document. + +## Thematic breaks + +A line consisting of 0-3 spaces of indentation, followed by a sequence +of three or more matching `-`, `_`, or `*` characters, each followed +optionally by any number of spaces or tabs, forms a +[thematic break](@). + +```````````````````````````````` example +*** +--- +___ +. +
+
+
+```````````````````````````````` + + +Wrong characters: + +```````````````````````````````` example ++++ +. +

+++

+```````````````````````````````` + + +```````````````````````````````` example +=== +. +

===

+```````````````````````````````` + + +Not enough characters: + +```````````````````````````````` example +-- +** +__ +. +

-- +** +__

+```````````````````````````````` + + +One to three spaces indent are allowed: + +```````````````````````````````` example + *** + *** + *** +. +
+
+
+```````````````````````````````` + + +Four spaces is too many: + +```````````````````````````````` example + *** +. +
***
+
+```````````````````````````````` + + +```````````````````````````````` example +Foo + *** +. +

Foo +***

+```````````````````````````````` + + +More than three characters may be used: + +```````````````````````````````` example +_____________________________________ +. +
+```````````````````````````````` + + +Spaces are allowed between the characters: + +```````````````````````````````` example + - - - +. +
+```````````````````````````````` + + +```````````````````````````````` example + ** * ** * ** * ** +. +
+```````````````````````````````` + + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +Spaces are allowed at the end: + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +However, no other characters may occur in the line: + +```````````````````````````````` example +_ _ _ _ a + +a------ + +---a--- +. +

_ _ _ _ a

+

a------

+

---a---

+```````````````````````````````` + + +It is required that all of the [non-whitespace characters] be the same. +So, this is not a thematic break: + +```````````````````````````````` example + *-* +. +

-

+```````````````````````````````` + + +Thematic breaks do not need blank lines before or after: + +```````````````````````````````` example +- foo +*** +- bar +. +
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +Thematic breaks can interrupt a paragraph: + +```````````````````````````````` example +Foo +*** +bar +. +

Foo

+
+

bar

+```````````````````````````````` + + +If a line of dashes that meets the above conditions for being a +thematic break could also be interpreted as the underline of a [setext +heading], the interpretation as a +[setext heading] takes precedence. Thus, for example, +this is a setext heading, not a paragraph followed by a thematic break: + +```````````````````````````````` example +Foo +--- +bar +. +

Foo

+

bar

+```````````````````````````````` + + +When both a thematic break and a list item are possible +interpretations of a line, the thematic break takes precedence: + +```````````````````````````````` example +* Foo +* * * +* Bar +. +
    +
  • Foo
  • +
+
+
    +
  • Bar
  • +
+```````````````````````````````` + + +If you want a thematic break in a list item, use a different bullet: + +```````````````````````````````` example +- Foo +- * * * +. +
    +
  • Foo
  • +
  • +
    +
  • +
+```````````````````````````````` + + +## ATX headings + +An [ATX heading](@) +consists of a string of characters, parsed as inline content, between an +opening sequence of 1--6 unescaped `#` characters and an optional +closing sequence of any number of unescaped `#` characters. +The opening sequence of `#` characters must be followed by a +[space] or by the end of line. The optional closing sequence of `#`s must be +preceded by a [space] and may be followed by spaces only. The opening +`#` character may be indented 0-3 spaces. The raw contents of the +heading are stripped of leading and trailing spaces before being parsed +as inline content. The heading level is equal to the number of `#` +characters in the opening sequence. + +Simple headings: + +```````````````````````````````` example +# foo +## foo +### foo +#### foo +##### foo +###### foo +. +

foo

+

foo

+

foo

+

foo

+
foo
+
foo
+```````````````````````````````` + + +More than six `#` characters is not a heading: + +```````````````````````````````` example +####### foo +. +

####### foo

+```````````````````````````````` + + +At least one space is required between the `#` characters and the +heading's contents, unless the heading is empty. Note that many +implementations currently do not require the space. However, the +space was required by the +[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py), +and it helps prevent things like the following from being parsed as +headings: + +```````````````````````````````` example +#5 bolt + +#hashtag +. +

#5 bolt

+

#hashtag

+```````````````````````````````` + + +This is not a heading, because the first `#` is escaped: + +```````````````````````````````` example +\## foo +. +

## foo

+```````````````````````````````` + + +Contents are parsed as inlines: + +```````````````````````````````` example +# foo *bar* \*baz\* +. +

foo bar *baz*

+```````````````````````````````` + + +Leading and trailing [whitespace] is ignored in parsing inline content: + +```````````````````````````````` example +# foo +. +

foo

+```````````````````````````````` + + +One to three spaces indentation are allowed: + +```````````````````````````````` example + ### foo + ## foo + # foo +. +

foo

+

foo

+

foo

+```````````````````````````````` + + +Four spaces are too much: + +```````````````````````````````` example + # foo +. +
# foo
+
+```````````````````````````````` + + +```````````````````````````````` example +foo + # bar +. +

foo +# bar

+```````````````````````````````` + + +A closing sequence of `#` characters is optional: + +```````````````````````````````` example +## foo ## + ### bar ### +. +

foo

+

bar

+```````````````````````````````` + + +It need not be the same length as the opening sequence: + +```````````````````````````````` example +# foo ################################## +##### foo ## +. +

foo

+
foo
+```````````````````````````````` + + +Spaces are allowed after the closing sequence: + +```````````````````````````````` example +### foo ### +. +

foo

+```````````````````````````````` + + +A sequence of `#` characters with anything but [spaces] following it +is not a closing sequence, but counts as part of the contents of the +heading: + +```````````````````````````````` example +### foo ### b +. +

foo ### b

+```````````````````````````````` + + +The closing sequence must be preceded by a space: + +```````````````````````````````` example +# foo# +. +

foo#

+```````````````````````````````` + + +Backslash-escaped `#` characters do not count as part +of the closing sequence: + +```````````````````````````````` example +### foo \### +## foo #\## +# foo \# +. +

foo ###

+

foo ###

+

foo #

+```````````````````````````````` + + +ATX headings need not be separated from surrounding content by blank +lines, and they can interrupt paragraphs: + +```````````````````````````````` example +**** +## foo +**** +. +
+

foo

+
+```````````````````````````````` + + +```````````````````````````````` example +Foo bar +# baz +Bar foo +. +

Foo bar

+

baz

+

Bar foo

+```````````````````````````````` + + +ATX headings can be empty: + +```````````````````````````````` example +## +# +### ### +. +

+

+

+```````````````````````````````` + + +## Setext headings + +A [setext heading](@) consists of one or more +lines of text, each containing at least one [non-whitespace +character], with no more than 3 spaces indentation, followed by +a [setext heading underline]. The lines of text must be such +that, were they not followed by the setext heading underline, +they would be interpreted as a paragraph: they cannot be +interpretable as a [code fence], [ATX heading][ATX headings], +[block quote][block quotes], [thematic break][thematic breaks], +[list item][list items], or [HTML block][HTML blocks]. + +A [setext heading underline](@) is a sequence of +`=` characters or a sequence of `-` characters, with no more than 3 +spaces indentation and any number of trailing spaces. If a line +containing a single `-` can be interpreted as an +empty [list items], it should be interpreted this way +and not as a [setext heading underline]. + +The heading is a level 1 heading if `=` characters are used in +the [setext heading underline], and a level 2 heading if `-` +characters are used. The contents of the heading are the result +of parsing the preceding lines of text as CommonMark inline +content. + +In general, a setext heading need not be preceded or followed by a +blank line. However, it cannot interrupt a paragraph, so when a +setext heading comes after a paragraph, a blank line is needed between +them. + +Simple examples: + +```````````````````````````````` example +Foo *bar* +========= + +Foo *bar* +--------- +. +

Foo bar

+

Foo bar

+```````````````````````````````` + + +The content of the header may span more than one line: + +```````````````````````````````` example +Foo *bar +baz* +==== +. +

Foo bar +baz

+```````````````````````````````` + +The contents are the result of parsing the headings's raw +content as inlines. The heading's raw content is formed by +concatenating the lines and removing initial and final +[whitespace]. + +```````````````````````````````` example + Foo *bar +baz*→ +==== +. +

Foo bar +baz

+```````````````````````````````` + + +The underlining can be any length: + +```````````````````````````````` example +Foo +------------------------- + +Foo += +. +

Foo

+

Foo

+```````````````````````````````` + + +The heading content can be indented up to three spaces, and need +not line up with the underlining: + +```````````````````````````````` example + Foo +--- + + Foo +----- + + Foo + === +. +

Foo

+

Foo

+

Foo

+```````````````````````````````` + + +Four spaces indent is too much: + +```````````````````````````````` example + Foo + --- + + Foo +--- +. +
Foo
+---
+
+Foo
+
+
+```````````````````````````````` + + +The setext heading underline can be indented up to three spaces, and +may have trailing spaces: + +```````````````````````````````` example +Foo + ---- +. +

Foo

+```````````````````````````````` + + +Four spaces is too much: + +```````````````````````````````` example +Foo + --- +. +

Foo +---

+```````````````````````````````` + + +The setext heading underline cannot contain internal spaces: + +```````````````````````````````` example +Foo += = + +Foo +--- - +. +

Foo += =

+

Foo

+
+```````````````````````````````` + + +Trailing spaces in the content line do not cause a line break: + +```````````````````````````````` example +Foo +----- +. +

Foo

+```````````````````````````````` + + +Nor does a backslash at the end: + +```````````````````````````````` example +Foo\ +---- +. +

Foo\

+```````````````````````````````` + + +Since indicators of block structure take precedence over +indicators of inline structure, the following are setext headings: + +```````````````````````````````` example +`Foo +---- +` + + +. +

`Foo

+

`

+

<a title="a lot

+

of dashes"/>

+```````````````````````````````` + + +The setext heading underline cannot be a [lazy continuation +line] in a list item or block quote: + +```````````````````````````````` example +> Foo +--- +. +
+

Foo

+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +bar +=== +. +
+

foo +bar +===

+
+```````````````````````````````` + + +```````````````````````````````` example +- Foo +--- +. +
    +
  • Foo
  • +
+
+```````````````````````````````` + + +A blank line is needed between a paragraph and a following +setext heading, since otherwise the paragraph becomes part +of the heading's content: + +```````````````````````````````` example +Foo +Bar +--- +. +

Foo +Bar

+```````````````````````````````` + + +But in general a blank line is not required before or after +setext headings: + +```````````````````````````````` example +--- +Foo +--- +Bar +--- +Baz +. +
+

Foo

+

Bar

+

Baz

+```````````````````````````````` + + +Setext headings cannot be empty: + +```````````````````````````````` example + +==== +. +

====

+```````````````````````````````` + + +Setext heading text lines must not be interpretable as block +constructs other than paragraphs. So, the line of dashes +in these examples gets interpreted as a thematic break: + +```````````````````````````````` example +--- +--- +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +- foo +----- +. +
    +
  • foo
  • +
+
+```````````````````````````````` + + +```````````````````````````````` example + foo +--- +. +
foo
+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +----- +. +
+

foo

+
+
+```````````````````````````````` + + +If you want a heading with `> foo` as its literal text, you can +use backslash escapes: + +```````````````````````````````` example +\> foo +------ +. +

> foo

+```````````````````````````````` + + +**Compatibility note:** Most existing Markdown implementations +do not allow the text of setext headings to span multiple lines. +But there is no consensus about how to interpret + +``` markdown +Foo +bar +--- +baz +``` + +One can find four different interpretations: + +1. paragraph "Foo", heading "bar", paragraph "baz" +2. paragraph "Foo bar", thematic break, paragraph "baz" +3. paragraph "Foo bar --- baz" +4. heading "Foo bar", paragraph "baz" + +We find interpretation 4 most natural, and interpretation 4 +increases the expressive power of CommonMark, by allowing +multiline headings. Authors who want interpretation 1 can +put a blank line after the first paragraph: + +```````````````````````````````` example +Foo + +bar +--- +baz +. +

Foo

+

bar

+

baz

+```````````````````````````````` + + +Authors who want interpretation 2 can put blank lines around +the thematic break, + +```````````````````````````````` example +Foo +bar + +--- + +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +or use a thematic break that cannot count as a [setext heading +underline], such as + +```````````````````````````````` example +Foo +bar +* * * +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +Authors who want interpretation 3 can use backslash escapes: + +```````````````````````````````` example +Foo +bar +\--- +baz +. +

Foo +bar +--- +baz

+```````````````````````````````` + + +## Indented code blocks + +An [indented code block](@) is composed of one or more +[indented chunks] separated by blank lines. +An [indented chunk](@) is a sequence of non-blank lines, +each indented four or more spaces. The contents of the code block are +the literal contents of the lines, including trailing +[line endings], minus four spaces of indentation. +An indented code block has no [info string]. + +An indented code block cannot interrupt a paragraph, so there must be +a blank line between a paragraph and a following indented code block. +(A blank line is not needed, however, between a code block and a following +paragraph.) + +```````````````````````````````` example + a simple + indented code block +. +
a simple
+  indented code block
+
+```````````````````````````````` + + +If there is any ambiguity between an interpretation of indentation +as a code block and as indicating that material belongs to a [list +item][list items], the list item interpretation takes precedence: + +```````````````````````````````` example + - foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo + + - bar +. +
    +
  1. +

    foo

    +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + + +The contents of a code block are literal text, and do not get parsed +as Markdown: + +```````````````````````````````` example +
+ *hi* + + - one +. +
<a/>
+*hi*
+
+- one
+
+```````````````````````````````` + + +Here we have three chunks separated by blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 + + + + chunk3 +. +
chunk1
+
+chunk2
+
+
+
+chunk3
+
+```````````````````````````````` + + +Any initial spaces beyond four will be included in the content, even +in interior blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 +. +
chunk1
+  
+  chunk2
+
+```````````````````````````````` + + +An indented code block cannot interrupt a paragraph. (This +allows hanging indents and the like.) + +```````````````````````````````` example +Foo + bar + +. +

Foo +bar

+```````````````````````````````` + + +However, any non-blank line with fewer than four leading spaces ends +the code block immediately. So a paragraph may occur immediately +after indented code: + +```````````````````````````````` example + foo +bar +. +
foo
+
+

bar

+```````````````````````````````` + + +And indented code can occur immediately before and after other kinds of +blocks: + +```````````````````````````````` example +# Heading + foo +Heading +------ + foo +---- +. +

Heading

+
foo
+
+

Heading

+
foo
+
+
+```````````````````````````````` + + +The first line can be indented more than four spaces: + +```````````````````````````````` example + foo + bar +. +
    foo
+bar
+
+```````````````````````````````` + + +Blank lines preceding or following an indented code block +are not included in it: + +```````````````````````````````` example + + + foo + + +. +
foo
+
+```````````````````````````````` + + +Trailing spaces are included in the code block's content: + +```````````````````````````````` example + foo +. +
foo  
+
+```````````````````````````````` + + + +## Fenced code blocks + +A [code fence](@) is a sequence +of at least three consecutive backtick characters (`` ` ``) or +tildes (`~`). (Tildes and backticks cannot be mixed.) +A [fenced code block](@) +begins with a code fence, indented no more than three spaces. + +The line with the opening code fence may optionally contain some text +following the code fence; this is trimmed of leading and trailing +whitespace and called the [info string](@). If the [info string] comes +after a backtick fence, it may not contain any backtick +characters. (The reason for this restriction is that otherwise +some inline code would be incorrectly interpreted as the +beginning of a fenced code block.) + +The content of the code block consists of all subsequent lines, until +a closing [code fence] of the same type as the code block +began with (backticks or tildes), and with at least as many backticks +or tildes as the opening code fence. If the leading code fence is +indented N spaces, then up to N spaces of indentation are removed from +each line of the content (if present). (If a content line is not +indented, it is preserved unchanged. If it is indented less than N +spaces, all of the indentation is removed.) + +The closing code fence may be indented up to three spaces, and may be +followed only by spaces, which are ignored. If the end of the +containing block (or document) is reached and no closing code fence +has been found, the code block contains all of the lines after the +opening code fence until the end of the containing block (or +document). (An alternative spec would require backtracking in the +event that a closing code fence is not found. But this makes parsing +much less efficient, and there seems to be no real down side to the +behavior described here.) + +A fenced code block may interrupt a paragraph, and does not require +a blank line either before or after. + +The content of a code fence is treated as literal text, not parsed +as inlines. The first word of the [info string] is typically used to +specify the language of the code sample, and rendered in the `class` +attribute of the `code` tag. However, this spec does not mandate any +particular treatment of the [info string]. + +Here is a simple example with backticks: + +```````````````````````````````` example +``` +< + > +``` +. +
<
+ >
+
+```````````````````````````````` + + +With tildes: + +```````````````````````````````` example +~~~ +< + > +~~~ +. +
<
+ >
+
+```````````````````````````````` + +Fewer than three backticks is not enough: + +```````````````````````````````` example +`` +foo +`` +. +

foo

+```````````````````````````````` + +The closing code fence must use the same character as the opening +fence: + +```````````````````````````````` example +``` +aaa +~~~ +``` +. +
aaa
+~~~
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +aaa +``` +~~~ +. +
aaa
+```
+
+```````````````````````````````` + + +The closing code fence must be at least as long as the opening fence: + +```````````````````````````````` example +```` +aaa +``` +`````` +. +
aaa
+```
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ +aaa +~~~ +~~~~ +. +
aaa
+~~~
+
+```````````````````````````````` + + +Unclosed code blocks are closed by the end of the document +(or the enclosing [block quote][block quotes] or [list item][list items]): + +```````````````````````````````` example +``` +. +
+```````````````````````````````` + + +```````````````````````````````` example +````` + +``` +aaa +. +

+```
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +> aaa + +bbb +. +
+
aaa
+
+
+

bbb

+```````````````````````````````` + + +A code block can have all empty lines as its content: + +```````````````````````````````` example +``` + + +``` +. +

+  
+
+```````````````````````````````` + + +A code block can be empty: + +```````````````````````````````` example +``` +``` +. +
+```````````````````````````````` + + +Fences can be indented. If the opening fence is indented, +content lines will have equivalent opening indentation removed, +if present: + +```````````````````````````````` example + ``` + aaa +aaa +``` +. +
aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + aaa +aaa + ``` +. +
aaa
+aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` + aaa + aaa + aaa + ``` +. +
aaa
+ aaa
+aaa
+
+```````````````````````````````` + + +Four spaces indentation produces an indented code block: + +```````````````````````````````` example + ``` + aaa + ``` +. +
```
+aaa
+```
+
+```````````````````````````````` + + +Closing fences may be indented by 0-3 spaces, and their indentation +need not match that of the opening fence: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +This is not a closing fence, because it is indented 4 spaces: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+    ```
+
+```````````````````````````````` + + + +Code fences (opening and closing) cannot contain internal spaces: + +```````````````````````````````` example +``` ``` +aaa +. +

+aaa

+```````````````````````````````` + + +```````````````````````````````` example +~~~~~~ +aaa +~~~ ~~ +. +
aaa
+~~~ ~~
+
+```````````````````````````````` + + +Fenced code blocks can interrupt paragraphs, and can be followed +directly by paragraphs, without a blank line between: + +```````````````````````````````` example +foo +``` +bar +``` +baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +Other blocks can also occur before and after fenced code blocks +without an intervening blank line: + +```````````````````````````````` example +foo +--- +~~~ +bar +~~~ +# baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +An [info string] can be provided after the opening code fence. +Although this spec doesn't mandate any particular treatment of +the info string, the first word is typically used to specify +the language of the code block. In HTML output, the language is +normally indicated by adding a class to the `code` element consisting +of `language-` followed by the language name. + +```````````````````````````````` example +```ruby +def foo(x) + return 3 +end +``` +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +````; +```` +. +
+```````````````````````````````` + + +[Info strings] for backtick code blocks cannot contain backticks: + +```````````````````````````````` example +``` aa ``` +foo +. +

aa +foo

+```````````````````````````````` + + +[Info strings] for tilde code blocks can contain backticks and tildes: + +```````````````````````````````` example +~~~ aa ``` ~~~ +foo +~~~ +. +
foo
+
+```````````````````````````````` + + +Closing code fences cannot have [info strings]: + +```````````````````````````````` example +``` +``` aaa +``` +. +
``` aaa
+
+```````````````````````````````` + + + +## HTML blocks + +An [HTML block](@) is a group of lines that is treated +as raw HTML (and will not be escaped in HTML output). + +There are seven kinds of [HTML block], which can be defined by their +start and end conditions. The block begins with a line that meets a +[start condition](@) (after up to three spaces optional indentation). +It ends with the first subsequent line that meets a matching [end +condition](@), or the last line of the document, or the last line of +the [container block](#container-blocks) containing the current HTML +block, if no line is encountered that meets the [end condition]. If +the first line meets both the [start condition] and the [end +condition], the block will contain just that line. + +1. **Start condition:** line begins with the string ``, or the end of the line.\ +**End condition:** line contains an end tag +``, ``, or `` (case-insensitive; it +need not match the start tag). + +2. **Start condition:** line begins with the string ``. + +3. **Start condition:** line begins with the string ``. + +4. **Start condition:** line begins with the string ``. + +5. **Start condition:** line begins with the string +``. + +6. **Start condition:** line begins the string `<` or ``, or +the string `/>`.\ +**End condition:** line is followed by a [blank line]. + +7. **Start condition:** line begins with a complete [open tag] +(with any [tag name] other than `script`, +`style`, or `pre`) or a complete [closing tag], +followed only by [whitespace] or the end of the line.\ +**End condition:** line is followed by a [blank line]. + +HTML blocks continue until they are closed by their appropriate +[end condition], or the last line of the document or other [container +block](#container-blocks). This means any HTML **within an HTML +block** that might otherwise be recognised as a start condition will +be ignored by the parser and passed through as-is, without changing +the parser's state. + +For instance, `
` within a HTML block started by `` will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:
+
+```````````````````````````````` example
+
+
+**Hello**,
+
+_world_.
+
+
+. +
+
+**Hello**,
+

world. +

+
+```````````````````````````````` + +In this case, the HTML block is terminated by the newline — the `**Hello**` +text remains verbatim — and regular parsing resumes, with a paragraph, +emphasised `world` and inline and block HTML following. + +All types of [HTML blocks] except type 7 may interrupt +a paragraph. Blocks of type 7 may not interrupt a paragraph. +(This restriction is intended to prevent unwanted interpretation +of long tags inside a wrapped paragraph as starting HTML blocks.) + +Some simple examples follow. Here are some basic HTML blocks +of type 6: + +```````````````````````````````` example + + + + +
+ hi +
+ +okay. +. + + + + +
+ hi +
+

okay.

+```````````````````````````````` + + +```````````````````````````````` example +
+*foo* +```````````````````````````````` + + +Here we have two HTML blocks with a Markdown paragraph between them: + +```````````````````````````````` example +
+ +*Markdown* + +
+. +
+

Markdown

+
+```````````````````````````````` + + +The tag on the first line can be partial, as long +as it is split where there would be whitespace: + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +An open tag need not be closed: +```````````````````````````````` example +
+*foo* + +*bar* +. +
+*foo* +

bar

+```````````````````````````````` + + + +A partial tag need not even be completed (garbage +in, garbage out): + +```````````````````````````````` example +
+. + +```````````````````````````````` + + +```````````````````````````````` example +
+foo +
+. +
+foo +
+```````````````````````````````` + + +Everything until the next blank line or end of document +gets included in the HTML block. So, in the following +example, what looks like a Markdown code block +is actually part of the HTML block, which continues until a blank +line or the end of the document is reached: + +```````````````````````````````` example +
+``` c +int x = 33; +``` +. +
+``` c +int x = 33; +``` +```````````````````````````````` + + +To start an [HTML block] with a tag that is *not* in the +list of block-level tags in (6), you must put the tag by +itself on the first line (and it must be complete): + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +In type 7 blocks, the [tag name] can be anything: + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* +. + +*bar* +```````````````````````````````` + + +These rules are designed to allow us to work with tags that +can function as either block-level or inline-level tags. +The `` tag is a nice example. We can surround content with +`` tags in three different ways. In this case, we get a raw +HTML block, because the `` tag is on a line by itself: + +```````````````````````````````` example + +*foo* + +. + +*foo* + +```````````````````````````````` + + +In this case, we get a raw HTML block that just includes +the `` tag (because it ends with the following blank +line). So the contents get interpreted as CommonMark: + +```````````````````````````````` example + + +*foo* + + +. + +

foo

+
+```````````````````````````````` + + +Finally, in this case, the `` tags are interpreted +as [raw HTML] *inside* the CommonMark paragraph. (Because +the tag is not on a line by itself, we get inline HTML +rather than an [HTML block].) + +```````````````````````````````` example +*foo* +. +

foo

+```````````````````````````````` + + +HTML tags designed to contain literal content +(`script`, `style`, `pre`), comments, processing instructions, +and declarations are treated somewhat differently. +Instead of ending at the first blank line, these blocks +end at the first line containing a corresponding end tag. +As a result, these blocks can contain blank lines: + +A pre tag (type 1): + +```````````````````````````````` example +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+okay +. +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+

okay

+```````````````````````````````` + + +A script tag (type 1): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +A style tag (type 1): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +If there is no matching end tag, the block will end at the +end of the document (or the enclosing [block quote][block quotes] +or [list item][list items]): + +```````````````````````````````` example + +*foo* +. + +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*bar* +*baz* +. +*bar* +

baz

+```````````````````````````````` + + +Note that anything on the last line after the +end tag will be included in the [HTML block]: + +```````````````````````````````` example +1. *bar* +. +1. *bar* +```````````````````````````````` + + +A comment (type 2): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + + +A processing instruction (type 3): + +```````````````````````````````` example +'; + +?> +okay +. +'; + +?> +

okay

+```````````````````````````````` + + +A declaration (type 4): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +CDATA (type 5): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +The opening tag can be indented 1-3 spaces, but not 4: + +```````````````````````````````` example + + + +. + +
<!-- foo -->
+
+```````````````````````````````` + + +```````````````````````````````` example +
+ +
+. +
+
<div>
+
+```````````````````````````````` + + +An HTML block of types 1--6 can interrupt a paragraph, and need not be +preceded by a blank line. + +```````````````````````````````` example +Foo +
+bar +
+. +

Foo

+
+bar +
+```````````````````````````````` + + +However, a following blank line is needed, except at the end of +a document, and except for blocks of types 1--5, [above][HTML +block]: + +```````````````````````````````` example +
+bar +
+*foo* +. +
+bar +
+*foo* +```````````````````````````````` + + +HTML blocks of type 7 cannot interrupt a paragraph: + +```````````````````````````````` example +Foo + +baz +. +

Foo + +baz

+```````````````````````````````` + + +This rule differs from John Gruber's original Markdown syntax +specification, which says: + +> The only restrictions are that block-level HTML elements — +> e.g. `
`, ``, `
`, `

`, etc. — must be separated from +> surrounding content by blank lines, and the start and end tags of the +> block should not be indented with tabs or spaces. + +In some ways Gruber's rule is more restrictive than the one given +here: + +- It requires that an HTML block be preceded by a blank line. +- It does not allow the start tag to be indented. +- It requires a matching end tag, which it also does not allow to + be indented. + +Most Markdown implementations (including some of Gruber's own) do not +respect all of these restrictions. + +There is one respect, however, in which Gruber's rule is more liberal +than the one given here, since it allows blank lines to occur inside +an HTML block. There are two reasons for disallowing them here. +First, it removes the need to parse balanced tags, which is +expensive and can require backtracking from the end of the document +if no matching end tag is found. Second, it provides a very simple +and flexible way of including Markdown content inside HTML tags: +simply separate the Markdown from the HTML using blank lines: + +Compare: + +```````````````````````````````` example +

+ +*Emphasized* text. + +
+. +
+

Emphasized text.

+
+```````````````````````````````` + + +```````````````````````````````` example +
+*Emphasized* text. +
+. +
+*Emphasized* text. +
+```````````````````````````````` + + +Some Markdown implementations have adopted a convention of +interpreting content inside tags as text if the open tag has +the attribute `markdown=1`. The rule given above seems a simpler and +more elegant way of achieving the same expressive power, which is also +much simpler to parse. + +The main potential drawback is that one can no longer paste HTML +blocks into Markdown documents with 100% reliability. However, +*in most cases* this will work fine, because the blank lines in +HTML are usually followed by HTML block tags. For example: + +```````````````````````````````` example +
+ + + + + + + +
+Hi +
+. + + + + +
+Hi +
+```````````````````````````````` + + +There are problems, however, if the inner tags are indented +*and* separated by spaces, as then they will be interpreted as +an indented code block: + +```````````````````````````````` example + + + + + + + + +
+ Hi +
+. + + +
<td>
+  Hi
+</td>
+
+ +
+```````````````````````````````` + + +Fortunately, blank lines are usually not necessary and can be +deleted. The exception is inside `
` tags, but as described
+[above][HTML blocks], raw HTML blocks starting with `
`
+*can* contain blank lines.
+
+## Link reference definitions
+
+A [link reference definition](@)
+consists of a [link label], indented up to three spaces, followed
+by a colon (`:`), optional [whitespace] (including up to one
+[line ending]), a [link destination],
+optional [whitespace] (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by [whitespace].
+No further [non-whitespace characters] may occur on the line.
+
+A [link reference definition]
+does not correspond to a structural element of a document.  Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document.  [Link
+reference definitions] can come either before or after the links that use
+them.
+
+```````````````````````````````` example
+[foo]: /url "title"
+
+[foo]
+.
+

foo

+```````````````````````````````` + + +```````````````````````````````` example + [foo]: + /url + 'the title' + +[foo] +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +. +

Foo*bar]

+```````````````````````````````` + + +```````````````````````````````` example +[Foo bar]: + +'title' + +[Foo bar] +. +

Foo bar

+```````````````````````````````` + + +The title may extend over multiple lines: + +```````````````````````````````` example +[foo]: /url ' +title +line1 +line2 +' + +[foo] +. +

foo

+```````````````````````````````` + + +However, it may not contain a [blank line]: + +```````````````````````````````` example +[foo]: /url 'title + +with blank line' + +[foo] +. +

[foo]: /url 'title

+

with blank line'

+

[foo]

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[foo]: +/url + +[foo] +. +

foo

+```````````````````````````````` + + +The link destination may not be omitted: + +```````````````````````````````` example +[foo]: + +[foo] +. +

[foo]:

+

[foo]

+```````````````````````````````` + + However, an empty link destination may be specified using + angle brackets: + +```````````````````````````````` example +[foo]: <> + +[foo] +. +

foo

+```````````````````````````````` + +The title must be separated from the link destination by +whitespace: + +```````````````````````````````` example +[foo]: (baz) + +[foo] +. +

[foo]: (baz)

+

[foo]

+```````````````````````````````` + + +Both title and destination can contain backslash escapes +and literal backslashes: + +```````````````````````````````` example +[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +. +

foo

+```````````````````````````````` + + +A link can come before its corresponding definition: + +```````````````````````````````` example +[foo] + +[foo]: url +. +

foo

+```````````````````````````````` + + +If there are several matching definitions, the first one takes +precedence: + +```````````````````````````````` example +[foo] + +[foo]: first +[foo]: second +. +

foo

+```````````````````````````````` + + +As noted in the section on [Links], matching of labels is +case-insensitive (see [matches]). + +```````````````````````````````` example +[FOO]: /url + +[Foo] +. +

Foo

+```````````````````````````````` + + +```````````````````````````````` example +[ΑΓΩ]: /φου + +[αγω] +. +

αγω

+```````````````````````````````` + + +Here is a link reference definition with no corresponding link. +It contributes nothing to the document. + +```````````````````````````````` example +[foo]: /url +. +```````````````````````````````` + + +Here is another one: + +```````````````````````````````` example +[ +foo +]: /url +bar +. +

bar

+```````````````````````````````` + + +This is not a link reference definition, because there are +[non-whitespace characters] after the title: + +```````````````````````````````` example +[foo]: /url "title" ok +. +

[foo]: /url "title" ok

+```````````````````````````````` + + +This is a link reference definition, but it has no title: + +```````````````````````````````` example +[foo]: /url +"title" ok +. +

"title" ok

+```````````````````````````````` + + +This is not a link reference definition, because it is indented +four spaces: + +```````````````````````````````` example + [foo]: /url "title" + +[foo] +. +
[foo]: /url "title"
+
+

[foo]

+```````````````````````````````` + + +This is not a link reference definition, because it occurs inside +a code block: + +```````````````````````````````` example +``` +[foo]: /url +``` + +[foo] +. +
[foo]: /url
+
+

[foo]

+```````````````````````````````` + + +A [link reference definition] cannot interrupt a paragraph. + +```````````````````````````````` example +Foo +[bar]: /baz + +[bar] +. +

Foo +[bar]: /baz

+

[bar]

+```````````````````````````````` + + +However, it can directly follow other block elements, such as headings +and thematic breaks, and it need not be followed by a blank line. + +```````````````````````````````` example +# [Foo] +[foo]: /url +> bar +. +

Foo

+
+

bar

+
+```````````````````````````````` + +```````````````````````````````` example +[foo]: /url +bar +=== +[foo] +. +

bar

+

foo

+```````````````````````````````` + +```````````````````````````````` example +[foo]: /url +=== +[foo] +. +

=== +foo

+```````````````````````````````` + + +Several [link reference definitions] +can occur one after another, without intervening blank lines. + +```````````````````````````````` example +[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +. +

foo, +bar, +baz

+```````````````````````````````` + + +[Link reference definitions] can occur +inside block containers, like lists and block quotations. They +affect the entire document, not just the container in which they +are defined: + +```````````````````````````````` example +[foo] + +> [foo]: /url +. +

foo

+
+
+```````````````````````````````` + + +Whether something is a [link reference definition] is +independent of whether the link reference it defines is +used in the document. Thus, for example, the following +document contains just a link reference definition, and +no visible content: + +```````````````````````````````` example +[foo]: /url +. +```````````````````````````````` + + +## Paragraphs + +A sequence of non-blank lines that cannot be interpreted as other +kinds of blocks forms a [paragraph](@). +The contents of the paragraph are the result of parsing the +paragraph's raw content as inlines. The paragraph's raw content +is formed by concatenating the lines and removing initial and final +[whitespace]. + +A simple example with two paragraphs: + +```````````````````````````````` example +aaa + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Paragraphs can contain multiple lines, but no blank lines: + +```````````````````````````````` example +aaa +bbb + +ccc +ddd +. +

aaa +bbb

+

ccc +ddd

+```````````````````````````````` + + +Multiple blank lines between paragraph have no effect: + +```````````````````````````````` example +aaa + + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Leading spaces are skipped: + +```````````````````````````````` example + aaa + bbb +. +

aaa +bbb

+```````````````````````````````` + + +Lines after the first may be indented any amount, since indented +code blocks cannot interrupt paragraphs. + +```````````````````````````````` example +aaa + bbb + ccc +. +

aaa +bbb +ccc

+```````````````````````````````` + + +However, the first line may be indented at most three spaces, +or an indented code block will be triggered: + +```````````````````````````````` example + aaa +bbb +. +

aaa +bbb

+```````````````````````````````` + + +```````````````````````````````` example + aaa +bbb +. +
aaa
+
+

bbb

+```````````````````````````````` + + +Final spaces are stripped before inline parsing, so a paragraph +that ends with two or more spaces will not end with a [hard line +break]: + +```````````````````````````````` example +aaa +bbb +. +

aaa
+bbb

+```````````````````````````````` + + +## Blank lines + +[Blank lines] between block-level elements are ignored, +except for the role they play in determining whether a [list] +is [tight] or [loose]. + +Blank lines at the beginning and end of the document are also ignored. + +```````````````````````````````` example + + +aaa + + +# aaa + + +. +

aaa

+

aaa

+```````````````````````````````` + + + +# Container blocks + +A [container block](#container-blocks) is a block that has other +blocks as its contents. There are two basic kinds of container blocks: +[block quotes] and [list items]. +[Lists] are meta-containers for [list items]. + +We define the syntax for container blocks recursively. The general +form of the definition is: + +> If X is a sequence of blocks, then the result of +> transforming X in such-and-such a way is a container of type Y +> with these blocks as its content. + +So, we explain what counts as a block quote or list item by explaining +how these can be *generated* from their contents. This should suffice +to define the syntax, although it does not give a recipe for *parsing* +these constructions. (A recipe is provided below in the section entitled +[A parsing strategy](#appendix-a-parsing-strategy).) + +## Block quotes + +A [block quote marker](@) +consists of 0-3 spaces of initial indent, plus (a) the character `>` together +with a following space, or (b) a single character `>` not followed by a space. + +The following rules define [block quotes]: + +1. **Basic case.** If a string of lines *Ls* constitute a sequence + of blocks *Bs*, then the result of prepending a [block quote + marker] to the beginning of each line in *Ls* + is a [block quote](#block-quotes) containing *Bs*. + +2. **Laziness.** If a string of lines *Ls* constitute a [block + quote](#block-quotes) with contents *Bs*, then the result of deleting + the initial [block quote marker] from one or + more lines in which the next [non-whitespace character] after the [block + quote marker] is [paragraph continuation + text] is a block quote with *Bs* as its content. + [Paragraph continuation text](@) is text + that will be parsed as part of the content of a paragraph, but does + not occur at the beginning of the paragraph. + +3. **Consecutiveness.** A document cannot contain two [block + quotes] in a row unless there is a [blank line] between them. + +Nothing else counts as a [block quote](#block-quotes). + +Here is a simple example: + +```````````````````````````````` example +> # Foo +> bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The spaces after the `>` characters can be omitted: + +```````````````````````````````` example +># Foo +>bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The `>` characters can be indented 1-3 spaces: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +Four spaces gives us a code block: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
> # Foo
+> bar
+> baz
+
+```````````````````````````````` + + +The Laziness clause allows us to omit the `>` before +[paragraph continuation text]: + +```````````````````````````````` example +> # Foo +> bar +baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +A block quote can contain some lazy and some non-lazy +continuation lines: + +```````````````````````````````` example +> bar +baz +> foo +. +
+

bar +baz +foo

+
+```````````````````````````````` + + +Laziness only applies to lines that would have been continuations of +paragraphs had they been prepended with [block quote markers]. +For example, the `> ` cannot be omitted in the second line of + +``` markdown +> foo +> --- +``` + +without changing the meaning: + +```````````````````````````````` example +> foo +--- +. +
+

foo

+
+
+```````````````````````````````` + + +Similarly, if we omit the `> ` in the second line of + +``` markdown +> - foo +> - bar +``` + +then the block quote ends after the first line: + +```````````````````````````````` example +> - foo +- bar +. +
+
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +For the same reason, we can't omit the `> ` in front of +subsequent lines of an indented or fenced code block: + +```````````````````````````````` example +> foo + bar +. +
+
foo
+
+
+
bar
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +foo +``` +. +
+
+
+

foo

+
+```````````````````````````````` + + +Note that in the following case, we have a [lazy +continuation line]: + +```````````````````````````````` example +> foo + - bar +. +
+

foo +- bar

+
+```````````````````````````````` + + +To see why, note that in + +```markdown +> foo +> - bar +``` + +the `- bar` is indented too far to start a list, and can't +be an indented code block because indented code blocks cannot +interrupt paragraphs, so it is [paragraph continuation text]. + +A block quote can be empty: + +```````````````````````````````` example +> +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> +> +> +. +
+
+```````````````````````````````` + + +A block quote can have initial or final blank lines: + +```````````````````````````````` example +> +> foo +> +. +
+

foo

+
+```````````````````````````````` + + +A blank line always separates block quotes: + +```````````````````````````````` example +> foo + +> bar +. +
+

foo

+
+
+

bar

+
+```````````````````````````````` + + +(Most current Markdown implementations, including John Gruber's +original `Markdown.pl`, will parse this example as a single block quote +with two paragraphs. But it seems better to allow the author to decide +whether two block quotes or one are wanted.) + +Consecutiveness means that if we put these block quotes together, +we get a single block quote: + +```````````````````````````````` example +> foo +> bar +. +
+

foo +bar

+
+```````````````````````````````` + + +To get a block quote with two paragraphs, use: + +```````````````````````````````` example +> foo +> +> bar +. +
+

foo

+

bar

+
+```````````````````````````````` + + +Block quotes can interrupt paragraphs: + +```````````````````````````````` example +foo +> bar +. +

foo

+
+

bar

+
+```````````````````````````````` + + +In general, blank lines are not needed before or after block +quotes: + +```````````````````````````````` example +> aaa +*** +> bbb +. +
+

aaa

+
+
+
+

bbb

+
+```````````````````````````````` + + +However, because of laziness, a blank line is needed between +a block quote and a following paragraph: + +```````````````````````````````` example +> bar +baz +. +
+

bar +baz

+
+```````````````````````````````` + + +```````````````````````````````` example +> bar + +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +```````````````````````````````` example +> bar +> +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +It is a consequence of the Laziness rule that any number +of initial `>`s may be omitted on a continuation line of a +nested block quote: + +```````````````````````````````` example +> > > foo +bar +. +
+
+
+

foo +bar

+
+
+
+```````````````````````````````` + + +```````````````````````````````` example +>>> foo +> bar +>>baz +. +
+
+
+

foo +bar +baz

+
+
+
+```````````````````````````````` + + +When including an indented code block in a block quote, +remember that the [block quote marker] includes +both the `>` and a following space. So *five spaces* are needed after +the `>`: + +```````````````````````````````` example +> code + +> not code +. +
+
code
+
+
+
+

not code

+
+```````````````````````````````` + + + +## List items + +A [list marker](@) is a +[bullet list marker] or an [ordered list marker]. + +A [bullet list marker](@) +is a `-`, `+`, or `*` character. + +An [ordered list marker](@) +is a sequence of 1--9 arabic digits (`0-9`), followed by either a +`.` character or a `)` character. (The reason for the length +limit is that with 10 digits we start seeing integer overflows +in some browsers.) + +The following rules define [list items]: + +1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of + blocks *Bs* starting with a [non-whitespace character], and *M* is a + list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result + of prepending *M* and the following spaces to the first line of + *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a + list item with *Bs* as its contents. The type of the list item + (bullet or ordered) is determined by the type of its list marker. + If the list item is ordered, then it is also assigned a start + number, based on the ordered list marker. + + Exceptions: + + 1. When the first list item in a [list] interrupts + a paragraph---that is, when it starts on a line that would + otherwise count as [paragraph continuation text]---then (a) + the lines *Ls* must not begin with a blank line, and (b) if + the list item is ordered, the start number must be 1. + 2. If any line is a [thematic break][thematic breaks] then + that line is not a list item. + +For example, let *Ls* be the lines + +```````````````````````````````` example +A paragraph +with two lines. + + indented code + +> A block quote. +. +

A paragraph +with two lines.

+
indented code
+
+
+

A block quote.

+
+```````````````````````````````` + + +And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says +that the following is an ordered list item with start number 1, +and the same contents as *Ls*: + +```````````````````````````````` example +1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +The most important thing to notice is that the position of +the text after the list marker determines how much indentation +is needed in subsequent blocks in the list item. If the list +marker takes up two spaces, and there are three spaces between +the list marker and the next [non-whitespace character], then blocks +must be indented five spaces in order to fall under the list +item. + +Here are some examples showing how far content must be indented to be +put under the list item: + +```````````````````````````````` example +- one + + two +. +
    +
  • one
  • +
+

two

+```````````````````````````````` + + +```````````````````````````````` example +- one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • one
  • +
+
 two
+
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +It is tempting to think of this in terms of columns: the continuation +blocks must be indented at least to the column of the first +[non-whitespace character] after the list marker. However, that is not quite right. +The spaces after the list marker determine how much relative indentation +is needed. Which column this indentation reaches will depend on +how the list item is embedded in other constructions, as shown by +this example: + +```````````````````````````````` example + > > 1. one +>> +>> two +. +
+
+
    +
  1. +

    one

    +

    two

    +
  2. +
+
+
+```````````````````````````````` + + +Here `two` occurs in the same column as the list marker `1.`, +but is actually contained in the list item, because there is +sufficient indentation after the last containing blockquote marker. + +The converse is also possible. In the following example, the word `two` +occurs far to the right of the initial text of the list item, `one`, but +it is not considered part of the list item, because it is not indented +far enough past the blockquote marker: + +```````````````````````````````` example +>>- one +>> + > > two +. +
+
+
    +
  • one
  • +
+

two

+
+
+```````````````````````````````` + + +Note that at least one space is needed between the list marker and +any following content, so these are not list items: + +```````````````````````````````` example +-one + +2.two +. +

-one

+

2.two

+```````````````````````````````` + + +A list item may contain blocks that are separated by more than +one blank line. + +```````````````````````````````` example +- foo + + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +A list item may contain any kind of block: + +```````````````````````````````` example +1. foo + + ``` + bar + ``` + + baz + + > bam +. +
    +
  1. +

    foo

    +
    bar
    +
    +

    baz

    +
    +

    bam

    +
    +
  2. +
+```````````````````````````````` + + +A list item that contains an indented code block will preserve +empty lines within the code block verbatim. + +```````````````````````````````` example +- Foo + + bar + + + baz +. +
    +
  • +

    Foo

    +
    bar
    +
    +
    +baz
    +
    +
  • +
+```````````````````````````````` + +Note that ordered list start numbers must be nine digits or less: + +```````````````````````````````` example +123456789. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +1234567890. not ok +. +

1234567890. not ok

+```````````````````````````````` + + +A start number may begin with 0s: + +```````````````````````````````` example +0. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +003. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +A start number may not be negative: + +```````````````````````````````` example +-1. not ok +. +

-1. not ok

+```````````````````````````````` + + + +2. **Item starting with indented code.** If a sequence of lines *Ls* + constitute a sequence of blocks *Bs* starting with an indented code + block, and *M* is a list marker of width *W* followed by + one space, then the result of prepending *M* and the following + space to the first line of *Ls*, and indenting subsequent lines of + *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +An indented code block will have to be indented four spaces beyond +the edge of the region where text will be included in the list item. +In the following case that is 6 spaces: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +
    bar
    +
    +
  • +
+```````````````````````````````` + + +And in this case it is 11 spaces: + +```````````````````````````````` example + 10. foo + + bar +. +
    +
  1. +

    foo

    +
    bar
    +
    +
  2. +
+```````````````````````````````` + + +If the *first* block in the list item is an indented code block, +then by rule #2, the contents must be indented *one* space after the +list marker: + +```````````````````````````````` example + indented code + +paragraph + + more code +. +
indented code
+
+

paragraph

+
more code
+
+```````````````````````````````` + + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that an additional space indent is interpreted as space +inside the code block: + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
     indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that rules #1 and #2 only apply to two cases: (a) cases +in which the lines to be included in a list item begin with a +[non-whitespace character], and (b) cases in which +they begin with an indented code +block. In a case like the following, where the first block begins with +a three-space indent, the rules do not allow us to form a list item by +indenting the whole thing and prepending a list marker: + +```````````````````````````````` example + foo + +bar +. +

foo

+

bar

+```````````````````````````````` + + +```````````````````````````````` example +- foo + + bar +. +
    +
  • foo
  • +
+

bar

+```````````````````````````````` + + +This is not a significant restriction, because when a block begins +with 1-3 spaces indent, the indentation can always be removed without +a change in interpretation, allowing rule #1 to be applied. So, in +the above case: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +3. **Item starting with a blank line.** If a sequence of lines *Ls* + starting with a single [blank line] constitute a (possibly empty) + sequence of blocks *Bs*, not separated from each other by more than + one blank line, and *M* is a list marker of width *W*, + then the result of prepending *M* to the first line of *Ls*, and + indenting subsequent lines of *Ls* by *W + 1* spaces, is a list + item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +Here are some list items that start with a blank line but are not empty: + +```````````````````````````````` example +- + foo +- + ``` + bar + ``` +- + baz +. +
    +
  • foo
  • +
  • +
    bar
    +
    +
  • +
  • +
    baz
    +
    +
  • +
+```````````````````````````````` + +When the list item starts with a blank line, the number of spaces +following the list marker doesn't change the required indentation: + +```````````````````````````````` example +- + foo +. +
    +
  • foo
  • +
+```````````````````````````````` + + +A list item can begin with at most one blank line. +In the following example, `foo` is not part of the list +item: + +```````````````````````````````` example +- + + foo +. +
    +
  • +
+

foo

+```````````````````````````````` + + +Here is an empty bullet list item: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +It does not matter whether there are spaces following the [list marker]: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +Here is an empty ordered list item: + +```````````````````````````````` example +1. foo +2. +3. bar +. +
    +
  1. foo
  2. +
  3. +
  4. bar
  5. +
+```````````````````````````````` + + +A list may start or end with an empty list item: + +```````````````````````````````` example +* +. +
    +
  • +
+```````````````````````````````` + +However, an empty list item cannot interrupt a paragraph: + +```````````````````````````````` example +foo +* + +foo +1. +. +

foo +*

+

foo +1.

+```````````````````````````````` + + +4. **Indentation.** If a sequence of lines *Ls* constitutes a list item + according to rule #1, #2, or #3, then the result of indenting each line + of *Ls* by 1-3 spaces (the same for each line) also constitutes a + list item with the same contents and attributes. If a line is + empty, then it need not be indented. + +Indented one space: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented two spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented three spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Four spaces indent gives a code block: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
1.  A paragraph
+    with two lines.
+
+        indented code
+
+    > A block quote.
+
+```````````````````````````````` + + + +5. **Laziness.** If a string of lines *Ls* constitute a [list + item](#list-items) with contents *Bs*, then the result of deleting + some or all of the indentation from one or more lines in which the + next [non-whitespace character] after the indentation is + [paragraph continuation text] is a + list item with the same contents and attributes. The unindented + lines are called + [lazy continuation line](@)s. + +Here is an example with [lazy continuation lines]: + +```````````````````````````````` example + 1. A paragraph +with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indentation can be partially deleted: + +```````````````````````````````` example + 1. A paragraph + with two lines. +. +
    +
  1. A paragraph +with two lines.
  2. +
+```````````````````````````````` + + +These examples show how laziness can work in nested structures: + +```````````````````````````````` example +> 1. > Blockquote +continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> 1. > Blockquote +> continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + + +6. **That's all.** Nothing that is not counted as a list item by rules + #1--5 counts as a [list item](#list-items). + +The rules for sublists follow from the general rules +[above][List items]. A sublist must be indented the same number +of spaces a paragraph would need to be in order to be included +in the list item. + +So, in this case we need two spaces indent: + +```````````````````````````````` example +- foo + - bar + - baz + - boo +. +
    +
  • foo +
      +
    • bar +
        +
      • baz +
          +
        • boo
        • +
        +
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + +One is not enough: + +```````````````````````````````` example +- foo + - bar + - baz + - boo +. +
    +
  • foo
  • +
  • bar
  • +
  • baz
  • +
  • boo
  • +
+```````````````````````````````` + + +Here we need four, because the list marker is wider: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + +Three is not enough: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo
  2. +
+
    +
  • bar
  • +
+```````````````````````````````` + + +A list may be the first block in a list item: + +```````````````````````````````` example +- - foo +. +
    +
  • +
      +
    • foo
    • +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. - 2. foo +. +
    +
  1. +
      +
    • +
        +
      1. foo
      2. +
      +
    • +
    +
  2. +
+```````````````````````````````` + + +A list item can contain a heading: + +```````````````````````````````` example +- # Foo +- Bar + --- + baz +. +
    +
  • +

    Foo

    +
  • +
  • +

    Bar

    +baz
  • +
+```````````````````````````````` + + +### Motivation + +John Gruber's Markdown spec says the following about list items: + +1. "List markers typically start at the left margin, but may be indented + by up to three spaces. List markers must be followed by one or more + spaces or a tab." + +2. "To make lists look nice, you can wrap items with hanging indents.... + But if you don't want to, you don't have to." + +3. "List items may consist of multiple paragraphs. Each subsequent + paragraph in a list item must be indented by either 4 spaces or one + tab." + +4. "It looks nice if you indent every line of the subsequent paragraphs, + but here again, Markdown will allow you to be lazy." + +5. "To put a blockquote within a list item, the blockquote's `>` + delimiters need to be indented." + +6. "To put a code block within a list item, the code block needs to be + indented twice — 8 spaces or two tabs." + +These rules specify that a paragraph under a list item must be indented +four spaces (presumably, from the left margin, rather than the start of +the list marker, but this is not said), and that code under a list item +must be indented eight spaces instead of the usual four. They also say +that a block quote must be indented, but not by how much; however, the +example given has four spaces indentation. Although nothing is said +about other kinds of block-level content, it is certainly reasonable to +infer that *all* block elements under a list item, including other +lists, must be indented four spaces. This principle has been called the +*four-space rule*. + +The four-space rule is clear and principled, and if the reference +implementation `Markdown.pl` had followed it, it probably would have +become the standard. However, `Markdown.pl` allowed paragraphs and +sublists to start with only two spaces indentation, at least on the +outer level. Worse, its behavior was inconsistent: a sublist of an +outer-level list needed two spaces indentation, but a sublist of this +sublist needed three spaces. It is not surprising, then, that different +implementations of Markdown have developed very different rules for +determining what comes under a list item. (Pandoc and python-Markdown, +for example, stuck with Gruber's syntax description and the four-space +rule, while discount, redcarpet, marked, PHP Markdown, and others +followed `Markdown.pl`'s behavior more closely.) + +Unfortunately, given the divergences between implementations, there +is no way to give a spec for list items that will be guaranteed not +to break any existing documents. However, the spec given here should +correctly handle lists formatted with either the four-space rule or +the more forgiving `Markdown.pl` behavior, provided they are laid out +in a way that is natural for a human to read. + +The strategy here is to let the width and indentation of the list marker +determine the indentation necessary for blocks to fall under the list +item, rather than having a fixed and arbitrary number. The writer can +think of the body of the list item as a unit which gets indented to the +right enough to fit the list marker (and any indentation on the list +marker). (The laziness rule, #5, then allows continuation lines to be +unindented if needed.) + +This rule is superior, we claim, to any rule requiring a fixed level of +indentation from the margin. The four-space rule is clear but +unnatural. It is quite unintuitive that + +``` markdown +- foo + + bar + + - baz +``` + +should be parsed as two lists with an intervening paragraph, + +``` html +
    +
  • foo
  • +
+

bar

+
    +
  • baz
  • +
+``` + +as the four-space rule demands, rather than a single list, + +``` html +
    +
  • +

    foo

    +

    bar

    +
      +
    • baz
    • +
    +
  • +
+``` + +The choice of four spaces is arbitrary. It can be learned, but it is +not likely to be guessed, and it trips up beginners regularly. + +Would it help to adopt a two-space rule? The problem is that such +a rule, together with the rule allowing 1--3 spaces indentation of the +initial list marker, allows text that is indented *less than* the +original list marker to be included in the list item. For example, +`Markdown.pl` parses + +``` markdown + - one + + two +``` + +as a single list item, with `two` a continuation paragraph: + +``` html +
    +
  • +

    one

    +

    two

    +
  • +
+``` + +and similarly + +``` markdown +> - one +> +> two +``` + +as + +``` html +
+
    +
  • +

    one

    +

    two

    +
  • +
+
+``` + +This is extremely unintuitive. + +Rather than requiring a fixed indent from the margin, we could require +a fixed indent (say, two spaces, or even one space) from the list marker (which +may itself be indented). This proposal would remove the last anomaly +discussed. Unlike the spec presented above, it would count the following +as a list item with a subparagraph, even though the paragraph `bar` +is not indented as far as the first paragraph `foo`: + +``` markdown + 10. foo + + bar +``` + +Arguably this text does read like a list item with `bar` as a subparagraph, +which may count in favor of the proposal. However, on this proposal indented +code would have to be indented six spaces after the list marker. And this +would break a lot of existing Markdown, which has the pattern: + +``` markdown +1. foo + + indented code +``` + +where the code is indented eight spaces. The spec above, by contrast, will +parse this text as expected, since the code block's indentation is measured +from the beginning of `foo`. + +The one case that needs special treatment is a list item that *starts* +with indented code. How much indentation is required in that case, since +we don't have a "first paragraph" to measure from? Rule #2 simply stipulates +that in such cases, we require one space indentation from the list marker +(and then the normal four spaces for the indented code). This will match the +four-space rule in cases where the list marker plus its initial indentation +takes four spaces (a common case), but diverge in other cases. + +## Lists + +A [list](@) is a sequence of one or more +list items [of the same type]. The list items +may be separated by any number of blank lines. + +Two list items are [of the same type](@) +if they begin with a [list marker] of the same type. +Two list markers are of the +same type if (a) they are bullet list markers using the same character +(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same +delimiter (either `.` or `)`). + +A list is an [ordered list](@) +if its constituent list items begin with +[ordered list markers], and a +[bullet list](@) if its constituent list +items begin with [bullet list markers]. + +The [start number](@) +of an [ordered list] is determined by the list number of +its initial list item. The numbers of subsequent list items are +disregarded. + +A list is [loose](@) if any of its constituent +list items are separated by blank lines, or if any of its constituent +list items directly contain two block-level elements with a blank line +between them. Otherwise a list is [tight](@). +(The difference in HTML output is that paragraphs in a loose list are +wrapped in `

` tags, while paragraphs in a tight list are not.) + +Changing the bullet or ordered list delimiter starts a new list: + +```````````````````````````````` example +- foo +- bar ++ baz +. +

    +
  • foo
  • +
  • bar
  • +
+
    +
  • baz
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo +2. bar +3) baz +. +
    +
  1. foo
  2. +
  3. bar
  4. +
+
    +
  1. baz
  2. +
+```````````````````````````````` + + +In CommonMark, a list can interrupt a paragraph. That is, +no blank line is needed to separate a paragraph from a following +list: + +```````````````````````````````` example +Foo +- bar +- baz +. +

Foo

+
    +
  • bar
  • +
  • baz
  • +
+```````````````````````````````` + +`Markdown.pl` does not allow this, through fear of triggering a list +via a numeral in a hard-wrapped line: + +``` markdown +The number of windows in my house is +14. The number of doors is 6. +``` + +Oddly, though, `Markdown.pl` *does* allow a blockquote to +interrupt a paragraph, even though the same considerations might +apply. + +In CommonMark, we do allow lists to interrupt paragraphs, for +two reasons. First, it is natural and not uncommon for people +to start lists without blank lines: + +``` markdown +I need to buy +- new shoes +- a coat +- a plane ticket +``` + +Second, we are attracted to a + +> [principle of uniformity](@): +> if a chunk of text has a certain +> meaning, it will continue to have the same meaning when put into a +> container block (such as a list item or blockquote). + +(Indeed, the spec for [list items] and [block quotes] presupposes +this principle.) This principle implies that if + +``` markdown + * I need to buy + - new shoes + - a coat + - a plane ticket +``` + +is a list item containing a paragraph followed by a nested sublist, +as all Markdown implementations agree it is (though the paragraph +may be rendered without `

` tags, since the list is "tight"), +then + +``` markdown +I need to buy +- new shoes +- a coat +- a plane ticket +``` + +by itself should be a paragraph followed by a nested sublist. + +Since it is well established Markdown practice to allow lists to +interrupt paragraphs inside list items, the [principle of +uniformity] requires us to allow this outside list items as +well. ([reStructuredText](http://docutils.sourceforge.net/rst.html) +takes a different approach, requiring blank lines before lists +even inside other list items.) + +In order to solve of unwanted lists in paragraphs with +hard-wrapped numerals, we allow only lists starting with `1` to +interrupt paragraphs. Thus, + +```````````````````````````````` example +The number of windows in my house is +14. The number of doors is 6. +. +

The number of windows in my house is +14. The number of doors is 6.

+```````````````````````````````` + +We may still get an unintended result in cases like + +```````````````````````````````` example +The number of windows in my house is +1. The number of doors is 6. +. +

The number of windows in my house is

+
    +
  1. The number of doors is 6.
  2. +
+```````````````````````````````` + +but this rule should prevent most spurious list captures. + +There can be any number of blank lines between items: + +```````````````````````````````` example +- foo + +- bar + + +- baz +. +
    +
  • +

    foo

    +
  • +
  • +

    bar

    +
  • +
  • +

    baz

    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +- foo + - bar + - baz + + + bim +. +
    +
  • foo +
      +
    • bar +
        +
      • +

        baz

        +

        bim

        +
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + +To separate consecutive lists of the same type, or to separate a +list from an indented code block that would otherwise be parsed +as a subparagraph of the final list item, you can insert a blank HTML +comment: + +```````````````````````````````` example +- foo +- bar + + + +- baz +- bim +. +
    +
  • foo
  • +
  • bar
  • +
+ +
    +
  • baz
  • +
  • bim
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- foo + + notcode + +- foo + + + + code +. +
    +
  • +

    foo

    +

    notcode

    +
  • +
  • +

    foo

    +
  • +
+ +
code
+
+```````````````````````````````` + + +List items need not be indented to the same level. The following +list items will be treated as items at the same list level, +since none is indented enough to belong to the previous list +item: + +```````````````````````````````` example +- a + - b + - c + - d + - e + - f +- g +. +
    +
  • a
  • +
  • b
  • +
  • c
  • +
  • d
  • +
  • e
  • +
  • f
  • +
  • g
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. a + + 2. b + + 3. c +. +
    +
  1. +

    a

    +
  2. +
  3. +

    b

    +
  4. +
  5. +

    c

    +
  6. +
+```````````````````````````````` + +Note, however, that list items may not be indented more than +three spaces. Here `- e` is treated as a paragraph continuation +line, because it is indented more than three spaces: + +```````````````````````````````` example +- a + - b + - c + - d + - e +. +
    +
  • a
  • +
  • b
  • +
  • c
  • +
  • d +- e
  • +
+```````````````````````````````` + +And here, `3. c` is treated as in indented code block, +because it is indented four spaces and preceded by a +blank line. + +```````````````````````````````` example +1. a + + 2. b + + 3. c +. +
    +
  1. +

    a

    +
  2. +
  3. +

    b

    +
  4. +
+
3. c
+
+```````````````````````````````` + + +This is a loose list, because there is a blank line between +two of the list items: + +```````````````````````````````` example +- a +- b + +- c +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +So is this, with a empty second item: + +```````````````````````````````` example +* a +* + +* c +. +
    +
  • +

    a

    +
  • +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +These are loose lists, even though there is no space between the items, +because one of the items directly contains two block-level elements +with a blank line between them: + +```````````````````````````````` example +- a +- b + + c +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +

    c

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a +- b + + [ref]: /url +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +This is a tight list, because the blank lines are in a code block: + +```````````````````````````````` example +- a +- ``` + b + + + ``` +- c +. +
    +
  • a
  • +
  • +
    b
    +
    +
    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is between two +paragraphs of a sublist. So the sublist is loose while +the outer list is tight: + +```````````````````````````````` example +- a + - b + + c +- d +. +
    +
  • a +
      +
    • +

      b

      +

      c

      +
    • +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is inside the +block quote: + +```````````````````````````````` example +* a + > b + > +* c +. +
    +
  • a +
    +

    b

    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This list is tight, because the consecutive block elements +are not separated by blank lines: + +```````````````````````````````` example +- a + > b + ``` + c + ``` +- d +. +
    +
  • a +
    +

    b

    +
    +
    c
    +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +A single-paragraph list is tight: + +```````````````````````````````` example +- a +. +
    +
  • a
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b +. +
    +
  • a +
      +
    • b
    • +
    +
  • +
+```````````````````````````````` + + +This list is loose, because of the blank line between the +two block elements in the list item: + +```````````````````````````````` example +1. ``` + foo + ``` + + bar +. +
    +
  1. +
    foo
    +
    +

    bar

    +
  2. +
+```````````````````````````````` + + +Here the outer list is loose, the inner list tight: + +```````````````````````````````` example +* foo + * bar + + baz +. +
    +
  • +

    foo

    +
      +
    • bar
    • +
    +

    baz

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b + - c + +- d + - e + - f +. +
    +
  • +

    a

    +
      +
    • b
    • +
    • c
    • +
    +
  • +
  • +

    d

    +
      +
    • e
    • +
    • f
    • +
    +
  • +
+```````````````````````````````` + + +# Inlines + +Inlines are parsed sequentially from the beginning of the character +stream to the end (left to right, in left-to-right languages). +Thus, for example, in + +```````````````````````````````` example +`hi`lo` +. +

hilo`

+```````````````````````````````` + +`hi` is parsed as code, leaving the backtick at the end as a literal +backtick. + + + +## Code spans + +A [backtick string](@) +is a string of one or more backtick characters (`` ` ``) that is neither +preceded nor followed by a backtick. + +A [code span](@) begins with a backtick string and ends with +a backtick string of equal length. The contents of the code span are +the characters between these two backtick strings, normalized in the +following ways: + +- First, [line endings] are converted to [spaces]. +- If the resulting string both begins *and* ends with a [space] + character, but does not consist entirely of [space] + characters, a single [space] character is removed from the + front and back. This allows you to include code that begins + or ends with backtick characters, which must be separated by + whitespace from the opening or closing backtick strings. + +This is a simple code span: + +```````````````````````````````` example +`foo` +. +

foo

+```````````````````````````````` + + +Here two backticks are used, because the code contains a backtick. +This example also illustrates stripping of a single leading and +trailing space: + +```````````````````````````````` example +`` foo ` bar `` +. +

foo ` bar

+```````````````````````````````` + + +This example shows the motivation for stripping leading and trailing +spaces: + +```````````````````````````````` example +` `` ` +. +

``

+```````````````````````````````` + +Note that only *one* space is stripped: + +```````````````````````````````` example +` `` ` +. +

``

+```````````````````````````````` + +The stripping only happens if the space is on both +sides of the string: + +```````````````````````````````` example +` a` +. +

a

+```````````````````````````````` + +Only [spaces], and not [unicode whitespace] in general, are +stripped in this way: + +```````````````````````````````` example +` b ` +. +

b

+```````````````````````````````` + +No stripping occurs if the code span contains only spaces: + +```````````````````````````````` example +` ` +` ` +. +

+

+```````````````````````````````` + + +[Line endings] are treated like spaces: + +```````````````````````````````` example +`` +foo +bar +baz +`` +. +

foo bar baz

+```````````````````````````````` + +```````````````````````````````` example +`` +foo +`` +. +

foo

+```````````````````````````````` + + +Interior spaces are not collapsed: + +```````````````````````````````` example +`foo bar +baz` +. +

foo bar baz

+```````````````````````````````` + +Note that browsers will typically collapse consecutive spaces +when rendering `` elements, so it is recommended that +the following CSS be used: + + code{white-space: pre-wrap;} + + +Note that backslash escapes do not work in code spans. All backslashes +are treated literally: + +```````````````````````````````` example +`foo\`bar` +. +

foo\bar`

+```````````````````````````````` + + +Backslash escapes are never needed, because one can always choose a +string of *n* backtick characters as delimiters, where the code does +not contain any strings of exactly *n* backtick characters. + +```````````````````````````````` example +``foo`bar`` +. +

foo`bar

+```````````````````````````````` + +```````````````````````````````` example +` foo `` bar ` +. +

foo `` bar

+```````````````````````````````` + + +Code span backticks have higher precedence than any other inline +constructs except HTML tags and autolinks. Thus, for example, this is +not parsed as emphasized text, since the second `*` is part of a code +span: + +```````````````````````````````` example +*foo`*` +. +

*foo*

+```````````````````````````````` + + +And this is not parsed as a link: + +```````````````````````````````` example +[not a `link](/foo`) +. +

[not a link](/foo)

+```````````````````````````````` + + +Code spans, HTML tags, and autolinks have the same precedence. +Thus, this is code: + +```````````````````````````````` example +`` +. +

<a href="">`

+```````````````````````````````` + + +But this is an HTML tag: + +```````````````````````````````` example +
` +. +

`

+```````````````````````````````` + + +And this is code: + +```````````````````````````````` example +`` +. +

<http://foo.bar.baz>`

+```````````````````````````````` + + +But this is an autolink: + +```````````````````````````````` example +` +. +

http://foo.bar.`baz`

+```````````````````````````````` + + +When a backtick string is not closed by a matching backtick string, +we just have literal backticks: + +```````````````````````````````` example +```foo`` +. +

```foo``

+```````````````````````````````` + + +```````````````````````````````` example +`foo +. +

`foo

+```````````````````````````````` + +The following case also illustrates the need for opening and +closing backtick strings to be equal in length: + +```````````````````````````````` example +`foo``bar`` +. +

`foobar

+```````````````````````````````` + + +## Emphasis and strong emphasis + +John Gruber's original [Markdown syntax +description](http://daringfireball.net/projects/markdown/syntax#em) says: + +> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of +> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML +> `` tag; double `*`'s or `_`'s will be wrapped with an HTML `` +> tag. + +This is enough for most users, but these rules leave much undecided, +especially when it comes to nested emphasis. The original +`Markdown.pl` test suite makes it clear that triple `***` and +`___` delimiters can be used for strong emphasis, and most +implementations have also allowed the following patterns: + +``` markdown +***strong emph*** +***strong** in emph* +***emph* in strong** +**in strong *emph*** +*in emph **strong*** +``` + +The following patterns are less widely supported, but the intent +is clear and they are useful (especially in contexts like bibliography +entries): + +``` markdown +*emph *with emph* in it* +**strong **with strong** in it** +``` + +Many implementations have also restricted intraword emphasis to +the `*` forms, to avoid unwanted emphasis in words containing +internal underscores. (It is best practice to put these in code +spans, but users often do not.) + +``` markdown +internal emphasis: foo*bar*baz +no emphasis: foo_bar_baz +``` + +The rules given below capture all of these patterns, while allowing +for efficient parsing strategies that do not backtrack. + +First, some definitions. A [delimiter run](@) is either +a sequence of one or more `*` characters that is not preceded or +followed by a non-backslash-escaped `*` character, or a sequence +of one or more `_` characters that is not preceded or followed by +a non-backslash-escaped `_` character. + +A [left-flanking delimiter run](@) is +a [delimiter run] that is (1) not followed by [Unicode whitespace], +and either (2a) not followed by a [punctuation character], or +(2b) followed by a [punctuation character] and +preceded by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +A [right-flanking delimiter run](@) is +a [delimiter run] that is (1) not preceded by [Unicode whitespace], +and either (2a) not preceded by a [punctuation character], or +(2b) preceded by a [punctuation character] and +followed by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +Here are some examples of delimiter runs. + + - left-flanking but not right-flanking: + + ``` + ***abc + _abc + **"abc" + _"abc" + ``` + + - right-flanking but not left-flanking: + + ``` + abc*** + abc_ + "abc"** + "abc"_ + ``` + + - Both left and right-flanking: + + ``` + abc***def + "abc"_"def" + ``` + + - Neither left nor right-flanking: + + ``` + abc *** def + a _ b + ``` + +(The idea of distinguishing left-flanking and right-flanking +delimiter runs based on the character before and the character +after comes from Roopesh Chander's +[vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags). +vfmd uses the terminology "emphasis indicator string" instead of "delimiter +run," and its rules for distinguishing left- and right-flanking runs +are a bit more complex than the ones given here.) + +The following rules define emphasis and strong emphasis: + +1. A single `*` character [can open emphasis](@) + iff (if and only if) it is part of a [left-flanking delimiter run]. + +2. A single `_` character [can open emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +3. A single `*` character [can close emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +4. A single `_` character [can close emphasis] iff + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +5. A double `**` [can open strong emphasis](@) + iff it is part of a [left-flanking delimiter run]. + +6. A double `__` [can open strong emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +7. A double `**` [can close strong emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +8. A double `__` [can close strong emphasis] iff + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +9. Emphasis begins with a delimiter that [can open emphasis] and ends + with a delimiter that [can close emphasis], and that uses the same + character (`_` or `*`) as the opening delimiter. The + opening and closing delimiters must belong to separate + [delimiter runs]. If one of the delimiters can both + open and close emphasis, then the sum of the lengths of the + delimiter runs containing the opening and closing delimiters + must not be a multiple of 3 unless both lengths are + multiples of 3. + +10. Strong emphasis begins with a delimiter that + [can open strong emphasis] and ends with a delimiter that + [can close strong emphasis], and that uses the same character + (`_` or `*`) as the opening delimiter. The + opening and closing delimiters must belong to separate + [delimiter runs]. If one of the delimiters can both open + and close strong emphasis, then the sum of the lengths of + the delimiter runs containing the opening and closing + delimiters must not be a multiple of 3 unless both lengths + are multiples of 3. + +11. A literal `*` character cannot occur at the beginning or end of + `*`-delimited emphasis or `**`-delimited strong emphasis, unless it + is backslash-escaped. + +12. A literal `_` character cannot occur at the beginning or end of + `_`-delimited emphasis or `__`-delimited strong emphasis, unless it + is backslash-escaped. + +Where rules 1--12 above are compatible with multiple parsings, +the following principles resolve ambiguity: + +13. The number of nestings should be minimized. Thus, for example, + an interpretation `...` is always preferred to + `...`. + +14. An interpretation `...` is always + preferred to `...`. + +15. When two potential emphasis or strong emphasis spans overlap, + so that the second begins before the first ends and ends after + the first ends, the first takes precedence. Thus, for example, + `*foo _bar* baz_` is parsed as `foo _bar baz_` rather + than `*foo bar* baz`. + +16. When there are two potential emphasis or strong emphasis spans + with the same closing delimiter, the shorter one (the one that + opens later) takes precedence. Thus, for example, + `**foo **bar baz**` is parsed as `**foo bar baz` + rather than `foo **bar baz`. + +17. Inline code spans, links, images, and HTML tags group more tightly + than emphasis. So, when there is a choice between an interpretation + that contains one of these elements and one that does not, the + former always wins. Thus, for example, `*[foo*](bar)` is + parsed as `*foo*` rather than as + `[foo](bar)`. + +These rules can be illustrated through a series of examples. + +Rule 1: + +```````````````````````````````` example +*foo bar* +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is followed by +whitespace, and hence not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a * foo bar* +. +

a * foo bar*

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a*"foo"* +. +

a*"foo"*

+```````````````````````````````` + + +Unicode nonbreaking spaces count as whitespace, too: + +```````````````````````````````` example +* a * +. +

* a *

+```````````````````````````````` + + +Intraword emphasis with `*` is permitted: + +```````````````````````````````` example +foo*bar* +. +

foobar

+```````````````````````````````` + + +```````````````````````````````` example +5*6*78 +. +

5678

+```````````````````````````````` + + +Rule 2: + +```````````````````````````````` example +_foo bar_ +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is followed by +whitespace: + +```````````````````````````````` example +_ foo bar_ +. +

_ foo bar_

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a_"foo"_ +. +

a_"foo"_

+```````````````````````````````` + + +Emphasis with `_` is not allowed inside words: + +```````````````````````````````` example +foo_bar_ +. +

foo_bar_

+```````````````````````````````` + + +```````````````````````````````` example +5_6_78 +. +

5_6_78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням_стремятся_ +. +

пристаням_стремятся_

+```````````````````````````````` + + +Here `_` does not generate emphasis, because the first delimiter run +is right-flanking and the second left-flanking: + +```````````````````````````````` example +aa_"bb"_cc +. +

aa_"bb"_cc

+```````````````````````````````` + + +This is emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-_(bar)_ +. +

foo-(bar)

+```````````````````````````````` + + +Rule 3: + +This is not emphasis, because the closing delimiter does +not match the opening delimiter: + +```````````````````````````````` example +_foo* +. +

_foo*

+```````````````````````````````` + + +This is not emphasis, because the closing `*` is preceded by +whitespace: + +```````````````````````````````` example +*foo bar * +. +

*foo bar *

+```````````````````````````````` + + +A newline also counts as whitespace: + +```````````````````````````````` example +*foo bar +* +. +

*foo bar +*

+```````````````````````````````` + + +This is not emphasis, because the second `*` is +preceded by punctuation and followed by an alphanumeric +(hence it is not part of a [right-flanking delimiter run]: + +```````````````````````````````` example +*(*foo) +. +

*(*foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +*(*foo*)* +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis with `*` is allowed: + +```````````````````````````````` example +*foo*bar +. +

foobar

+```````````````````````````````` + + + +Rule 4: + +This is not emphasis, because the closing `_` is preceded by +whitespace: + +```````````````````````````````` example +_foo bar _ +. +

_foo bar _

+```````````````````````````````` + + +This is not emphasis, because the second `_` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +_(_foo) +. +

_(_foo)

+```````````````````````````````` + + +This is emphasis within emphasis: + +```````````````````````````````` example +_(_foo_)_ +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis is disallowed for `_`: + +```````````````````````````````` example +_foo_bar +. +

_foo_bar

+```````````````````````````````` + + +```````````````````````````````` example +_пристаням_стремятся +. +

_пристаням_стремятся

+```````````````````````````````` + + +```````````````````````````````` example +_foo_bar_baz_ +. +

foo_bar_baz

+```````````````````````````````` + + +This is emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +_(bar)_. +. +

(bar).

+```````````````````````````````` + + +Rule 5: + +```````````````````````````````` example +**foo bar** +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +** foo bar** +. +

** foo bar**

+```````````````````````````````` + + +This is not strong emphasis, because the opening `**` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a**"foo"** +. +

a**"foo"**

+```````````````````````````````` + + +Intraword strong emphasis with `**` is permitted: + +```````````````````````````````` example +foo**bar** +. +

foobar

+```````````````````````````````` + + +Rule 6: + +```````````````````````````````` example +__foo bar__ +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +__ foo bar__ +. +

__ foo bar__

+```````````````````````````````` + + +A newline counts as whitespace: +```````````````````````````````` example +__ +foo bar__ +. +

__ +foo bar__

+```````````````````````````````` + + +This is not strong emphasis, because the opening `__` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a__"foo"__ +. +

a__"foo"__

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +foo__bar__ +. +

foo__bar__

+```````````````````````````````` + + +```````````````````````````````` example +5__6__78 +. +

5__6__78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням__стремятся__ +. +

пристаням__стремятся__

+```````````````````````````````` + + +```````````````````````````````` example +__foo, __bar__, baz__ +. +

foo, bar, baz

+```````````````````````````````` + + +This is strong emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-__(bar)__ +. +

foo-(bar)

+```````````````````````````````` + + + +Rule 7: + +This is not strong emphasis, because the closing delimiter is preceded +by whitespace: + +```````````````````````````````` example +**foo bar ** +. +

**foo bar **

+```````````````````````````````` + + +(Nor can it be interpreted as an emphasized `*foo bar *`, because of +Rule 11.) + +This is not strong emphasis, because the second `**` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +**(**foo) +. +

**(**foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with these examples: + +```````````````````````````````` example +*(**foo**)* +. +

(foo)

+```````````````````````````````` + + +```````````````````````````````` example +**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +. +

Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

+```````````````````````````````` + + +```````````````````````````````` example +**foo "*bar*" foo** +. +

foo "bar" foo

+```````````````````````````````` + + +Intraword emphasis: + +```````````````````````````````` example +**foo**bar +. +

foobar

+```````````````````````````````` + + +Rule 8: + +This is not strong emphasis, because the closing delimiter is +preceded by whitespace: + +```````````````````````````````` example +__foo bar __ +. +

__foo bar __

+```````````````````````````````` + + +This is not strong emphasis, because the second `__` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +__(__foo) +. +

__(__foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +_(__foo__)_ +. +

(foo)

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +__foo__bar +. +

__foo__bar

+```````````````````````````````` + + +```````````````````````````````` example +__пристаням__стремятся +. +

__пристаням__стремятся

+```````````````````````````````` + + +```````````````````````````````` example +__foo__bar__baz__ +. +

foo__bar__baz

+```````````````````````````````` + + +This is strong emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +__(bar)__. +. +

(bar).

+```````````````````````````````` + + +Rule 9: + +Any nonempty sequence of inline elements can be the contents of an +emphasized span. + +```````````````````````````````` example +*foo [bar](/url)* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo +bar* +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside emphasis: + +```````````````````````````````` example +_foo __bar__ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +_foo _bar_ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ bar_ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar** baz* +. +

foo bar baz

+```````````````````````````````` + +```````````````````````````````` example +*foo**bar**baz* +. +

foobarbaz

+```````````````````````````````` + +Note that in the preceding case, the interpretation + +``` markdown +

foobarbaz

+``` + + +is precluded by the condition that a delimiter that +can both open and close (like the `*` after `foo`) +cannot form emphasis if the sum of the lengths of +the delimiter runs containing the opening and +closing delimiters is a multiple of 3 unless +both lengths are multiples of 3. + + +For the same reason, we don't get two consecutive +emphasis sections in this example: + +```````````````````````````````` example +*foo**bar* +. +

foo**bar

+```````````````````````````````` + + +The same condition ensures that the following +cases are all strong emphasis nested inside +emphasis, even when the interior spaces are +omitted: + + +```````````````````````````````` example +***foo** bar* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar*** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo**bar*** +. +

foobar

+```````````````````````````````` + + +When the lengths of the interior closing and opening +delimiter runs are *both* multiples of 3, though, +they can match to create emphasis: + +```````````````````````````````` example +foo***bar***baz +. +

foobarbaz

+```````````````````````````````` + +```````````````````````````````` example +foo******bar*********baz +. +

foobar***baz

+```````````````````````````````` + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +*foo **bar *baz* bim** bop* +. +

foo bar baz bim bop

+```````````````````````````````` + + +```````````````````````````````` example +*foo [*bar*](/url)* +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +** is not an empty emphasis +. +

** is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +**** is not an empty strong emphasis +. +

**** is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 10: + +Any nonempty sequence of inline elements can be the contents of an +strongly emphasized span. + +```````````````````````````````` example +**foo [bar](/url)** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo +bar** +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside strong emphasis: + +```````````````````````````````` example +__foo _bar_ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo __bar__ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +____foo__ bar__ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo **bar**** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar* baz** +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +**foo*bar*baz** +. +

foobarbaz

+```````````````````````````````` + + +```````````````````````````````` example +***foo* bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar*** +. +

foo bar

+```````````````````````````````` + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +**foo *bar **baz** +bim* bop** +. +

foo bar baz +bim bop

+```````````````````````````````` + + +```````````````````````````````` example +**foo [*bar*](/url)** +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +__ is not an empty emphasis +. +

__ is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +____ is not an empty strong emphasis +. +

____ is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 11: + +```````````````````````````````` example +foo *** +. +

foo ***

+```````````````````````````````` + + +```````````````````````````````` example +foo *\** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo *_* +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo ***** +. +

foo *****

+```````````````````````````````` + + +```````````````````````````````` example +foo **\*** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo **_** +. +

foo _

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 11 determines +that the excess literal `*` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +**foo* +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +*foo** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +***foo** +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +****foo* +. +

***foo

+```````````````````````````````` + + +```````````````````````````````` example +**foo*** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +*foo**** +. +

foo***

+```````````````````````````````` + + + +Rule 12: + +```````````````````````````````` example +foo ___ +. +

foo ___

+```````````````````````````````` + + +```````````````````````````````` example +foo _\__ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo _*_ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo _____ +. +

foo _____

+```````````````````````````````` + + +```````````````````````````````` example +foo __\___ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo __*__ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ +. +

_foo

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 12 determines +that the excess literal `_` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +_foo__ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +___foo__ +. +

_foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo_ +. +

___foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo___ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +_foo____ +. +

foo___

+```````````````````````````````` + + +Rule 13 implies that if you want emphasis nested directly inside +emphasis, you must use different delimiters: + +```````````````````````````````` example +**foo** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*_foo_* +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo__ +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_*foo*_ +. +

foo

+```````````````````````````````` + + +However, strong emphasis within strong emphasis is possible without +switching delimiters: + +```````````````````````````````` example +****foo**** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo____ +. +

foo

+```````````````````````````````` + + + +Rule 13 can be applied to arbitrarily long sequences of +delimiters: + +```````````````````````````````` example +******foo****** +. +

foo

+```````````````````````````````` + + +Rule 14: + +```````````````````````````````` example +***foo*** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_____foo_____ +. +

foo

+```````````````````````````````` + + +Rule 15: + +```````````````````````````````` example +*foo _bar* baz_ +. +

foo _bar baz_

+```````````````````````````````` + + +```````````````````````````````` example +*foo __bar *baz bim__ bam* +. +

foo bar *baz bim bam

+```````````````````````````````` + + +Rule 16: + +```````````````````````````````` example +**foo **bar baz** +. +

**foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar baz* +. +

*foo bar baz

+```````````````````````````````` + + +Rule 17: + +```````````````````````````````` example +*[bar*](/url) +. +

*bar*

+```````````````````````````````` + + +```````````````````````````````` example +_foo [bar_](/url) +. +

_foo bar_

+```````````````````````````````` + + +```````````````````````````````` example +* +. +

*

+```````````````````````````````` + + +```````````````````````````````` example +** +. +

**

+```````````````````````````````` + + +```````````````````````````````` example +__ +. +

__

+```````````````````````````````` + + +```````````````````````````````` example +*a `*`* +. +

a *

+```````````````````````````````` + + +```````````````````````````````` example +_a `_`_ +. +

a _

+```````````````````````````````` + + +```````````````````````````````` example +**a +. +

**ahttp://foo.bar/?q=**

+```````````````````````````````` + + +```````````````````````````````` example +__a +. +

__ahttp://foo.bar/?q=__

+```````````````````````````````` + + + +## Links + +A link contains [link text] (the visible text), a [link destination] +(the URI that is the link destination), and optionally a [link title]. +There are two basic kinds of links in Markdown. In [inline links] the +destination and title are given immediately after the link text. In +[reference links] the destination and title are defined elsewhere in +the document. + +A [link text](@) consists of a sequence of zero or more +inline elements enclosed by square brackets (`[` and `]`). The +following rules apply: + +- Links may not contain other links, at any level of nesting. If + multiple otherwise valid link definitions appear nested inside each + other, the inner-most definition is used. + +- Brackets are allowed in the [link text] only if (a) they + are backslash-escaped or (b) they appear as a matched pair of brackets, + with an open bracket `[`, a sequence of zero or more inlines, and + a close bracket `]`. + +- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly + than the brackets in link text. Thus, for example, + `` [foo`]` `` could not be a link text, since the second `]` + is part of a code span. + +- The brackets in link text bind more tightly than markers for + [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link. + +A [link destination](@) consists of either + +- a sequence of zero or more characters between an opening `<` and a + closing `>` that contains no line breaks or unescaped + `<` or `>` characters, or + +- a nonempty sequence of characters that does not start with `<`, + does not include [ASCII control characters][ASCII control character] + or [whitespace][], and includes parentheses only if (a) they are + backslash-escaped or (b) they are part of a balanced pair of + unescaped parentheses. + (Implementations may impose limits on parentheses nesting to + avoid performance issues, but at least three levels of nesting + should be supported.) + +A [link title](@) consists of either + +- a sequence of zero or more characters between straight double-quote + characters (`"`), including a `"` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between straight single-quote + characters (`'`), including a `'` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between matching parentheses + (`(...)`), including a `(` or `)` character only if it is + backslash-escaped. + +Although [link titles] may span multiple lines, they may not contain +a [blank line]. + +An [inline link](@) consists of a [link text] followed immediately +by a left parenthesis `(`, optional [whitespace], an optional +[link destination], an optional [link title] separated from the link +destination by [whitespace], optional [whitespace], and a right +parenthesis `)`. The link's text consists of the inlines contained +in the [link text] (excluding the enclosing square brackets). +The link's URI consists of the link destination, excluding enclosing +`<...>` if present, with backslash-escapes in effect as described +above. The link's title consists of the link title, excluding its +enclosing delimiters, with backslash-escapes in effect as described +above. + +Here is a simple inline link: + +```````````````````````````````` example +[link](/uri "title") +. +

link

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[link](/uri) +. +

link

+```````````````````````````````` + + +Both the title and the destination may be omitted: + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link](<>) +. +

link

+```````````````````````````````` + +The destination can only contain spaces if it is +enclosed in pointy brackets: + +```````````````````````````````` example +[link](/my uri) +. +

[link](/my uri)

+```````````````````````````````` + +```````````````````````````````` example +[link](
) +. +

link

+```````````````````````````````` + +The destination cannot contain line breaks, +even if enclosed in pointy brackets: + +```````````````````````````````` example +[link](foo +bar) +. +

[link](foo +bar)

+```````````````````````````````` + +```````````````````````````````` example +[link]() +. +

[link]()

+```````````````````````````````` + +The destination can contain `)` if it is enclosed +in pointy brackets: + +```````````````````````````````` example +[a]() +. +

a

+```````````````````````````````` + +Pointy brackets that enclose links must be unescaped: + +```````````````````````````````` example +[link]() +. +

[link](<foo>)

+```````````````````````````````` + +These are not links, because the opening pointy bracket +is not matched properly: + +```````````````````````````````` example +[a]( +[a](c) +. +

[a](<b)c +[a](<b)c> +[a](c)

+```````````````````````````````` + +Parentheses inside the link destination may be escaped: + +```````````````````````````````` example +[link](\(foo\)) +. +

link

+```````````````````````````````` + +Any number of parentheses are allowed without escaping, as long as they are +balanced: + +```````````````````````````````` example +[link](foo(and(bar))) +. +

link

+```````````````````````````````` + +However, if you have unbalanced parentheses, you need to escape or use the +`<...>` form: + +```````````````````````````````` example +[link](foo(and(bar)) +. +

[link](foo(and(bar))

+```````````````````````````````` + + +```````````````````````````````` example +[link](foo\(and\(bar\)) +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +Parentheses and other symbols can also be escaped, as usual +in Markdown: + +```````````````````````````````` example +[link](foo\)\:) +. +

link

+```````````````````````````````` + + +A link can contain fragment identifiers and queries: + +```````````````````````````````` example +[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +. +

link

+

link

+

link

+```````````````````````````````` + + +Note that a backslash before a non-escapable character is +just a backslash: + +```````````````````````````````` example +[link](foo\bar) +. +

link

+```````````````````````````````` + + +URL-escaping should be left alone inside the destination, as all +URL-escaped characters are also valid URL characters. Entity and +numerical character references in the destination will be parsed +into the corresponding Unicode code points, as usual. These may +be optionally URL-escaped when written as HTML, but this spec +does not enforce any particular policy for rendering URLs in +HTML or other formats. Renderers may make different decisions +about how to escape or normalize URLs in the output. + +```````````````````````````````` example +[link](foo%20bä) +. +

link

+```````````````````````````````` + + +Note that, because titles can often be parsed as destinations, +if you try to omit the destination and keep the title, you'll +get unexpected results: + +```````````````````````````````` example +[link]("title") +. +

link

+```````````````````````````````` + + +Titles may be in single quotes, double quotes, or parentheses: + +```````````````````````````````` example +[link](/url "title") +[link](/url 'title') +[link](/url (title)) +. +

link +link +link

+```````````````````````````````` + + +Backslash escapes and entity and numeric character references +may be used in titles: + +```````````````````````````````` example +[link](/url "title \""") +. +

link

+```````````````````````````````` + + +Titles must be separated from the link using a [whitespace]. +Other [Unicode whitespace] like non-breaking space doesn't work. + +```````````````````````````````` example +[link](/url "title") +. +

link

+```````````````````````````````` + + +Nested balanced quotes are not allowed without escaping: + +```````````````````````````````` example +[link](/url "title "and" title") +. +

[link](/url "title "and" title")

+```````````````````````````````` + + +But it is easy to work around this by using a different quote type: + +```````````````````````````````` example +[link](/url 'title "and" title') +. +

link

+```````````````````````````````` + + +(Note: `Markdown.pl` did allow double quotes inside a double-quoted +title, and its test suite included a test demonstrating this. +But it is hard to see a good rationale for the extra complexity this +brings, since there are already many ways---backslash escaping, +entity and numeric character references, or using a different +quote type for the enclosing title---to write titles containing +double quotes. `Markdown.pl`'s handling of titles has a number +of other strange features. For example, it allows single-quoted +titles in inline links, but not reference links. And, in +reference links but not inline links, it allows a title to begin +with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows +titles with no closing quotation mark, though 1.0.2b8 does not. +It seems preferable to adopt a simple, rational rule that works +the same way in inline links and link reference definitions.) + +[Whitespace] is allowed around the destination and title: + +```````````````````````````````` example +[link]( /uri + "title" ) +. +

link

+```````````````````````````````` + + +But it is not allowed between the link text and the +following parenthesis: + +```````````````````````````````` example +[link] (/uri) +. +

[link] (/uri)

+```````````````````````````````` + + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]](/uri) +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link] bar](/uri) +. +

[link] bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[link [bar](/uri) +. +

[link bar

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar](/uri) +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*](/uri) +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)](/uri) +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)](/uri) +. +

[foo bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo *[bar [baz](/uri)](/uri)*](/uri) +. +

[foo [bar baz](/uri)](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +![[[foo](uri1)](uri2)](uri3) +. +

[foo](uri2)

+```````````````````````````````` + + +These cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*](/uri) +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar](baz*) +. +

foo *bar

+```````````````````````````````` + + +Note that brackets that *aren't* part of links do not take +precedence: + +```````````````````````````````` example +*foo [bar* baz] +. +

foo [bar baz]

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`](/uri)` +. +

[foo](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo +. +

[foohttp://example.com/?search=](uri)

+```````````````````````````````` + + +There are three kinds of [reference link](@)s: +[full](#full-reference-link), [collapsed](#collapsed-reference-link), +and [shortcut](#shortcut-reference-link). + +A [full reference link](@) +consists of a [link text] immediately followed by a [link label] +that [matches] a [link reference definition] elsewhere in the document. + +A [link label](@) begins with a left bracket (`[`) and ends +with the first right bracket (`]`) that is not backslash-escaped. +Between these brackets there must be at least one [non-whitespace character]. +Unescaped square bracket characters are not allowed inside the +opening and closing square brackets of [link labels]. A link +label can have at most 999 characters inside the square +brackets. + +One label [matches](@) +another just in case their normalized forms are equal. To normalize a +label, strip off the opening and closing brackets, +perform the *Unicode case fold*, strip leading and trailing +[whitespace] and collapse consecutive internal +[whitespace] to a single space. If there are multiple +matching reference link definitions, the one that comes first in the +document is used. (It is desirable in such cases to emit a warning.) + +The link's URI and title are provided by the matching [link +reference definition]. + +Here is a simple example: + +```````````````````````````````` example +[foo][bar] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +The rules for the [link text] are the same as with +[inline links]. Thus: + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]][ref] + +[ref]: /uri +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar][ref] + +[ref]: /uri +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*][ref] + +[ref]: /uri +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)][ref] + +[ref]: /uri +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)][ref] + +[ref]: /uri +. +

[foo bar]ref

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar [baz][ref]*][ref] + +[ref]: /uri +. +

[foo bar baz]ref

+```````````````````````````````` + + +(In the examples above, we have two [shortcut reference links] +instead of one [full reference link].) + +The following cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*][ref] + +[ref]: /uri +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar][ref]* + +[ref]: /uri +. +

foo *bar*

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`][ref]` + +[ref]: /uri +. +

[foo][ref]

+```````````````````````````````` + + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foohttp://example.com/?search=][ref]

+```````````````````````````````` + + +Matching is case-insensitive: + +```````````````````````````````` example +[foo][BaR] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +Unicode case fold is used: + +```````````````````````````````` example +[ẞ] + +[SS]: /url +. +

+```````````````````````````````` + + +Consecutive internal [whitespace] is treated as one space for +purposes of determining matching: + +```````````````````````````````` example +[Foo + bar]: /url + +[Baz][Foo bar] +. +

Baz

+```````````````````````````````` + + +No [whitespace] is allowed between the [link text] and the +[link label]: + +```````````````````````````````` example +[foo] [bar] + +[bar]: /url "title" +. +

[foo] bar

+```````````````````````````````` + + +```````````````````````````````` example +[foo] +[bar] + +[bar]: /url "title" +. +

[foo] +bar

+```````````````````````````````` + + +This is a departure from John Gruber's original Markdown syntax +description, which explicitly allows whitespace between the link +text and the link label. It brings reference links in line with +[inline links], which (according to both original Markdown and +this spec) cannot have whitespace after the link text. More +importantly, it prevents inadvertent capture of consecutive +[shortcut reference links]. If whitespace is allowed between the +link text and the link label, then in the following we will have +a single reference link, not two shortcut reference links, as +intended: + +``` markdown +[foo] +[bar] + +[foo]: /url1 +[bar]: /url2 +``` + +(Note that [shortcut reference links] were introduced by Gruber +himself in a beta version of `Markdown.pl`, but never included +in the official syntax description. Without shortcut reference +links, it is harmless to allow space between the link text and +link label; but once shortcut references are introduced, it is +too dangerous to allow this, as it frequently leads to +unintended results.) + +When there are multiple matching [link reference definitions], +the first is used: + +```````````````````````````````` example +[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +. +

bar

+```````````````````````````````` + + +Note that matching is performed on normalized strings, not parsed +inline content. So the following does not match, even though the +labels define equivalent inline content: + +```````````````````````````````` example +[bar][foo\!] + +[foo!]: /url +. +

[bar][foo!]

+```````````````````````````````` + + +[Link labels] cannot contain brackets, unless they are +backslash-escaped: + +```````````````````````````````` example +[foo][ref[] + +[ref[]: /uri +. +

[foo][ref[]

+

[ref[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref[bar]] + +[ref[bar]]: /uri +. +

[foo][ref[bar]]

+

[ref[bar]]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[[[foo]]] + +[[[foo]]]: /url +. +

[[[foo]]]

+

[[[foo]]]: /url

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref\[] + +[ref\[]: /uri +. +

foo

+```````````````````````````````` + + +Note that in this example `]` is not backslash-escaped: + +```````````````````````````````` example +[bar\\]: /uri + +[bar\\] +. +

bar\

+```````````````````````````````` + + +A [link label] must contain at least one [non-whitespace character]: + +```````````````````````````````` example +[] + +[]: /uri +. +

[]

+

[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[ + ] + +[ + ]: /uri +. +

[ +]

+

[ +]: /uri

+```````````````````````````````` + + +A [collapsed reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document, followed by the string `[]`. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title are +provided by the matching reference link definition. Thus, +`[foo][]` is equivalent to `[foo][foo]`. + +```````````````````````````````` example +[foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + + +As with full reference links, [whitespace] is not +allowed between the two sets of brackets: + +```````````````````````````````` example +[foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +A [shortcut reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document and is not followed by `[]` or a link label. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title +are provided by the matching link reference definition. +Thus, `[foo]` is equivalent to `[foo][]`. + +```````````````````````````````` example +[foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +[[*foo* bar]] + +[*foo* bar]: /url "title" +. +

[foo bar]

+```````````````````````````````` + + +```````````````````````````````` example +[[bar [foo] + +[foo]: /url +. +

[[bar foo

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +A space after the link text should be preserved: + +```````````````````````````````` example +[foo] bar + +[foo]: /url +. +

foo bar

+```````````````````````````````` + + +If you just want bracketed text, you can backslash-escape the +opening bracket to avoid links: + +```````````````````````````````` example +\[foo] + +[foo]: /url "title" +. +

[foo]

+```````````````````````````````` + + +Note that this is a link, because a link label ends with the first +following closing bracket: + +```````````````````````````````` example +[foo*]: /url + +*[foo*] +. +

*foo*

+```````````````````````````````` + + +Full and compact references take precedence over shortcut +references: + +```````````````````````````````` example +[foo][bar] + +[foo]: /url1 +[bar]: /url2 +. +

foo

+```````````````````````````````` + +```````````````````````````````` example +[foo][] + +[foo]: /url1 +. +

foo

+```````````````````````````````` + +Inline links also take precedence: + +```````````````````````````````` example +[foo]() + +[foo]: /url1 +. +

foo

+```````````````````````````````` + +```````````````````````````````` example +[foo](not a link) + +[foo]: /url1 +. +

foo(not a link)

+```````````````````````````````` + +In the following case `[bar][baz]` is parsed as a reference, +`[foo]` as normal text: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url +. +

[foo]bar

+```````````````````````````````` + + +Here, though, `[foo][bar]` is parsed as a reference, since +`[bar]` is defined: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +. +

foobaz

+```````````````````````````````` + + +Here `[foo]` is not parsed as a shortcut reference, because it +is followed by a link label (even though `[bar]` is not defined): + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +. +

[foo]bar

+```````````````````````````````` + + + +## Images + +Syntax for images is like the syntax for links, with one +difference. Instead of [link text], we have an +[image description](@). The rules for this are the +same as for [link text], except that (a) an +image description starts with `![` rather than `[`, and +(b) an image description may contain links. +An image description has inline elements +as its contents. When an image is rendered to HTML, +this is standardly used as the image's `alt` attribute. + +```````````````````````````````` example +![foo](/url "title") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo ![bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo [bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +Though this spec is concerned with parsing, not rendering, it is +recommended that in rendering to HTML, only the plain string content +of the [image description] be used. Note that in +the above example, the alt attribute's value is `foo bar`, not `foo +[bar](/url)` or `foo bar`. Only the plain string +content is rendered, without formatting. + +```````````````````````````````` example +![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo](train.jpg) +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +My ![foo bar](/path/to/train.jpg "title" ) +. +

My foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo]() +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![](/url) +. +

+```````````````````````````````` + + +Reference-style: + +```````````````````````````````` example +![foo][bar] + +[bar]: /url +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo][bar] + +[BAR]: /url +. +

foo

+```````````````````````````````` + + +Collapsed: + +```````````````````````````````` example +![foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The labels are case-insensitive: + +```````````````````````````````` example +![Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +As with reference links, [whitespace] is not allowed +between the two sets of brackets: + +```````````````````````````````` example +![foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +Shortcut: + +```````````````````````````````` example +![foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +Note that link labels cannot contain unescaped brackets: + +```````````````````````````````` example +![[foo]] + +[[foo]]: /url "title" +. +

![[foo]]

+

[[foo]]: /url "title"

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +![Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +If you just want a literal `!` followed by bracketed text, you can +backslash-escape the opening `[`: + +```````````````````````````````` example +!\[foo] + +[foo]: /url "title" +. +

![foo]

+```````````````````````````````` + + +If you want a link after a literal `!`, backslash-escape the +`!`: + +```````````````````````````````` example +\![foo] + +[foo]: /url "title" +. +

!foo

+```````````````````````````````` + + +## Autolinks + +[Autolink](@)s are absolute URIs and email addresses inside +`<` and `>`. They are parsed as links, with the URL or email address +as the link label. + +A [URI autolink](@) consists of `<`, followed by an +[absolute URI] followed by `>`. It is parsed as +a link to the URI, with the URI as the link's label. + +An [absolute URI](@), +for these purposes, consists of a [scheme] followed by a colon (`:`) +followed by zero or more characters other [ASCII control +characters][ASCII control character] or [whitespace][] , `<`, and `>`. +If the URI includes these characters, they must be percent-encoded +(e.g. `%20` for a space). + +For purposes of this spec, a [scheme](@) is any sequence +of 2--32 characters beginning with an ASCII letter and followed +by any combination of ASCII letters, digits, or the symbols plus +("+"), period ("."), or hyphen ("-"). + +Here are some valid autolinks: + +```````````````````````````````` example + +. +

http://foo.bar.baz

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://foo.bar.baz/test?q=hello&id=22&boolean

+```````````````````````````````` + + +```````````````````````````````` example + +. +

irc://foo.bar:2233/baz

+```````````````````````````````` + + +Uppercase is also fine: + +```````````````````````````````` example + +. +

MAILTO:FOO@BAR.BAZ

+```````````````````````````````` + + +Note that many strings that count as [absolute URIs] for +purposes of this spec are not valid URIs, because their +schemes are not registered or because of other problems +with their syntax: + +```````````````````````````````` example + +. +

a+b+c:d

+```````````````````````````````` + + +```````````````````````````````` example + +. +

made-up-scheme://foo,bar

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://../

+```````````````````````````````` + + +```````````````````````````````` example + +. +

localhost:5001/foo

+```````````````````````````````` + + +Spaces are not allowed in autolinks: + +```````````````````````````````` example + +. +

<http://foo.bar/baz bim>

+```````````````````````````````` + + +Backslash-escapes do not work inside autolinks: + +```````````````````````````````` example + +. +

http://example.com/\[\

+```````````````````````````````` + + +An [email autolink](@) +consists of `<`, followed by an [email address], +followed by `>`. The link's label is the email address, +and the URL is `mailto:` followed by the email address. + +An [email address](@), +for these purposes, is anything that matches +the [non-normative regex from the HTML5 +spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)): + + /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + +Examples of email autolinks: + +```````````````````````````````` example + +. +

foo@bar.example.com

+```````````````````````````````` + + +```````````````````````````````` example + +. +

foo+special@Bar.baz-bar0.com

+```````````````````````````````` + + +Backslash-escapes do not work inside email autolinks: + +```````````````````````````````` example + +. +

<foo+@bar.example.com>

+```````````````````````````````` + + +These are not autolinks: + +```````````````````````````````` example +<> +. +

<>

+```````````````````````````````` + + +```````````````````````````````` example +< http://foo.bar > +. +

< http://foo.bar >

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<m:abc>

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<foo.bar.baz>

+```````````````````````````````` + + +```````````````````````````````` example +http://example.com +. +

http://example.com

+```````````````````````````````` + + +```````````````````````````````` example +foo@bar.example.com +. +

foo@bar.example.com

+```````````````````````````````` + + +## Raw HTML + +Text between `<` and `>` that looks like an HTML tag is parsed as a +raw HTML tag and will be rendered in HTML without escaping. +Tag and attribute names are not limited to current HTML tags, +so custom tags (and even, say, DocBook tags) may be used. + +Here is the grammar for tags: + +A [tag name](@) consists of an ASCII letter +followed by zero or more ASCII letters, digits, or +hyphens (`-`). + +An [attribute](@) consists of [whitespace], +an [attribute name], and an optional +[attribute value specification]. + +An [attribute name](@) +consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII +letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML +specification restricted to ASCII. HTML5 is laxer.) + +An [attribute value specification](@) +consists of optional [whitespace], +a `=` character, optional [whitespace], and an [attribute +value]. + +An [attribute value](@) +consists of an [unquoted attribute value], +a [single-quoted attribute value], or a [double-quoted attribute value]. + +An [unquoted attribute value](@) +is a nonempty string of characters not +including [whitespace], `"`, `'`, `=`, `<`, `>`, or `` ` ``. + +A [single-quoted attribute value](@) +consists of `'`, zero or more +characters not including `'`, and a final `'`. + +A [double-quoted attribute value](@) +consists of `"`, zero or more +characters not including `"`, and a final `"`. + +An [open tag](@) consists of a `<` character, a [tag name], +zero or more [attributes], optional [whitespace], an optional `/` +character, and a `>` character. + +A [closing tag](@) consists of the string ``. + +An [HTML comment](@) consists of ``, +where *text* does not start with `>` or `->`, does not end with `-`, +and does not contain `--`. (See the +[HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).) + +A [processing instruction](@) +consists of the string ``, and the string +`?>`. + +A [declaration](@) consists of the string ``, and the character `>`. + +A [CDATA section](@) consists of +the string ``, and the string `]]>`. + +An [HTML tag](@) consists of an [open tag], a [closing tag], +an [HTML comment], a [processing instruction], a [declaration], +or a [CDATA section]. + +Here are some simple open tags: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Empty elements: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +[Whitespace] is allowed: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +With attributes: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Custom tag names can be used: + +```````````````````````````````` example +Foo +. +

Foo

+```````````````````````````````` + + +Illegal tag names, not parsed as HTML: + +```````````````````````````````` example +<33> <__> +. +

<33> <__>

+```````````````````````````````` + + +Illegal attribute names: + +```````````````````````````````` example +
+. +

<a h*#ref="hi">

+```````````````````````````````` + + +Illegal attribute values: + +```````````````````````````````` example +
+. +

</a href="foo">

+```````````````````````````````` + + +Comments: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo <!-- not a comment -- two hyphens -->

+```````````````````````````````` + + +Not comments: + +```````````````````````````````` example +foo foo --> + +foo +. +

foo <!--> foo -->

+

foo <!-- foo--->

+```````````````````````````````` + + +Processing instructions: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +Declarations: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +CDATA sections: + +```````````````````````````````` example +foo &<]]> +. +

foo &<]]>

+```````````````````````````````` + + +Entity and numeric character references are preserved in HTML +attributes: + +```````````````````````````````` example +foo
+. +

foo

+```````````````````````````````` + + +Backslash escapes do not work in HTML attributes: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<a href=""">

+```````````````````````````````` + + +## Hard line breaks + +A line break (not in a code span or HTML tag) that is preceded +by two or more spaces and does not occur at the end of a block +is parsed as a [hard line break](@) (rendered +in HTML as a `
` tag): + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +For a more visible alternative, a backslash before the +[line ending] may be used instead of two spaces: + +```````````````````````````````` example +foo\ +baz +. +

foo
+baz

+```````````````````````````````` + + +More than two spaces can be used: + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +Leading spaces at the beginning of the next line are ignored: + +```````````````````````````````` example +foo + bar +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +foo\ + bar +. +

foo
+bar

+```````````````````````````````` + + +Line breaks can occur inside emphasis, links, and other constructs +that allow inline content: + +```````````````````````````````` example +*foo +bar* +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo\ +bar* +. +

foo
+bar

+```````````````````````````````` + + +Line breaks do not occur inside code spans + +```````````````````````````````` example +`code +span` +. +

code span

+```````````````````````````````` + + +```````````````````````````````` example +`code\ +span` +. +

code\ span

+```````````````````````````````` + + +or HTML tags: + +```````````````````````````````` example +
+. +

+```````````````````````````````` + + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Hard line breaks are for separating inline content within a block. +Neither syntax for hard line breaks works at the end of a paragraph or +other block element: + +```````````````````````````````` example +foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +### foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +### foo +. +

foo

+```````````````````````````````` + + +## Soft line breaks + +A regular line break (not in a code span or HTML tag) that is not +preceded by two or more spaces or a backslash is parsed as a +[softbreak](@). (A softbreak may be rendered in HTML either as a +[line ending] or as a space. The result will be the same in +browsers. In the examples here, a [line ending] will be used.) + +```````````````````````````````` example +foo +baz +. +

foo +baz

+```````````````````````````````` + + +Spaces at the end of the line and beginning of the next line are +removed: + +```````````````````````````````` example +foo + baz +. +

foo +baz

+```````````````````````````````` + + +A conforming parser may render a soft line break in HTML either as a +line break or as a space. + +A renderer may also provide an option to render soft line breaks +as hard line breaks. + +## Textual content + +Any characters not given an interpretation by the above rules will +be parsed as plain textual content. + +```````````````````````````````` example +hello $.;'there +. +

hello $.;'there

+```````````````````````````````` + + +```````````````````````````````` example +Foo χρῆν +. +

Foo χρῆν

+```````````````````````````````` + + +Internal spaces are preserved verbatim: + +```````````````````````````````` example +Multiple spaces +. +

Multiple spaces

+```````````````````````````````` + + + + +# Appendix: A parsing strategy + +In this appendix we describe some features of the parsing strategy +used in the CommonMark reference implementations. + +## Overview + +Parsing has two phases: + +1. In the first phase, lines of input are consumed and the block +structure of the document---its division into paragraphs, block quotes, +list items, and so on---is constructed. Text is assigned to these +blocks but not parsed. Link reference definitions are parsed and a +map of links is constructed. + +2. In the second phase, the raw text contents of paragraphs and headings +are parsed into sequences of Markdown inline elements (strings, +code spans, links, emphasis, and so on), using the map of link +references constructed in phase 1. + +At each point in processing, the document is represented as a tree of +**blocks**. The root of the tree is a `document` block. The `document` +may have any number of other blocks as **children**. These children +may, in turn, have other blocks as children. The last child of a block +is normally considered **open**, meaning that subsequent lines of input +can alter its contents. (Blocks that are not open are **closed**.) +Here, for example, is a possible document tree, with the open blocks +marked by arrows: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 1: block structure + +Each line that is processed has an effect on this tree. The line is +analyzed and, depending on its contents, the document may be altered +in one or more of the following ways: + +1. One or more open blocks may be closed. +2. One or more new blocks may be created as children of the + last open block. +3. Text may be added to the last (deepest) open block remaining + on the tree. + +Once a line has been incorporated into the tree in this way, +it can be discarded, so input can be read in a stream. + +For each line, we follow this procedure: + +1. First we iterate through the open blocks, starting with the +root document, and descending through last children down to the last +open block. Each block imposes a condition that the line must satisfy +if the block is to remain open. For example, a block quote requires a +`>` character. A paragraph requires a non-blank line. +In this phase we may match all or just some of the open +blocks. But we cannot close unmatched blocks yet, because we may have a +[lazy continuation line]. + +2. Next, after consuming the continuation markers for existing +blocks, we look for new block starts (e.g. `>` for a block quote). +If we encounter a new block start, we close any blocks unmatched +in step 1 before creating the new block as a child of the last +matched container block. + +3. Finally, we look at the remainder of the line (after block +markers like `>`, list markers, and indentation have been consumed). +This is text that can be incorporated into the last open +block (a paragraph, code block, heading, or raw HTML). + +Setext headings are formed when we see a line of a paragraph +that is a [setext heading underline]. + +Reference link definitions are detected when a paragraph is closed; +the accumulated text lines are parsed to see if they begin with +one or more reference link definitions. Any remainder becomes a +normal paragraph. + +We can see how this works by considering how the tree above is +generated by four lines of Markdown: + +``` markdown +> Lorem ipsum dolor +sit amet. +> - Qui *quodsi iracundia* +> - aliquando id +``` + +At the outset, our document model is just + +``` tree +-> document +``` + +The first line of our text, + +``` markdown +> Lorem ipsum dolor +``` + +causes a `block_quote` block to be created as a child of our +open `document` block, and a `paragraph` block as a child of +the `block_quote`. Then the text is added to the last open +block, the `paragraph`: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor" +``` + +The next line, + +``` markdown +sit amet. +``` + +is a "lazy continuation" of the open `paragraph`, so it gets added +to the paragraph's text: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor\nsit amet." +``` + +The third line, + +``` markdown +> - Qui *quodsi iracundia* +``` + +causes the `paragraph` block to be closed, and a new `list` block +opened as a child of the `block_quote`. A `list_item` is also +added as a child of the `list`, and a `paragraph` as a child of +the `list_item`. The text is then added to the new `paragraph`: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + -> list_item + -> paragraph + "Qui *quodsi iracundia*" +``` + +The fourth line, + +``` markdown +> - aliquando id +``` + +causes the `list_item` (and its child the `paragraph`) to be closed, +and a new `list_item` opened up as child of the `list`. A `paragraph` +is added as a child of the new `list_item`, to contain the text. +We thus obtain the final tree: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 2: inline structure + +Once all of the input has been parsed, all open blocks are closed. + +We then "walk the tree," visiting every node, and parse raw +string contents of paragraphs and headings as inlines. At this +point we have seen all the link reference definitions, so we can +resolve reference links as we go. + +``` tree +document + block_quote + paragraph + str "Lorem ipsum dolor" + softbreak + str "sit amet." + list (type=bullet tight=true bullet_char=-) + list_item + paragraph + str "Qui " + emph + str "quodsi iracundia" + list_item + paragraph + str "aliquando id" +``` + +Notice how the [line ending] in the first paragraph has +been parsed as a `softbreak`, and the asterisks in the first list item +have become an `emph`. + +### An algorithm for parsing nested emphasis and links + +By far the trickiest part of inline parsing is handling emphasis, +strong emphasis, links, and images. This is done using the following +algorithm. + +When we're parsing inlines and we hit either + +- a run of `*` or `_` characters, or +- a `[` or `![` + +we insert a text node with these symbols as its literal content, and we +add a pointer to this text node to the [delimiter stack](@). + +The [delimiter stack] is a doubly linked list. Each +element contains a pointer to a text node, plus information about + +- the type of delimiter (`[`, `![`, `*`, `_`) +- the number of delimiters, +- whether the delimiter is "active" (all are active to start), and +- whether the delimiter is a potential opener, a potential closer, + or both (which depends on what sort of characters precede + and follow the delimiters). + +When we hit a `]` character, we call the *look for link or image* +procedure (see below). + +When we hit the end of the input, we call the *process emphasis* +procedure (see below), with `stack_bottom` = NULL. + +#### *look for link or image* + +Starting at the top of the delimiter stack, we look backwards +through the stack for an opening `[` or `![` delimiter. + +- If we don't find one, we return a literal text node `]`. + +- If we do find one, but it's not *active*, we remove the inactive + delimiter from the stack, and return a literal text node `]`. + +- If we find one and it's active, then we parse ahead to see if + we have an inline link/image, reference link/image, compact reference + link/image, or shortcut reference link/image. + + + If we don't, then we remove the opening delimiter from the + delimiter stack and return a literal text node `]`. + + + If we do, then + + * We return a link or image node whose children are the inlines + after the text node pointed to by the opening delimiter. + + * We run *process emphasis* on these inlines, with the `[` opener + as `stack_bottom`. + + * We remove the opening delimiter. + + * If we have a link (and not an image), we also set all + `[` delimiters before the opening delimiter to *inactive*. (This + will prevent us from getting links within links.) + +#### *process emphasis* + +Parameter `stack_bottom` sets a lower bound to how far we +descend in the [delimiter stack]. If it is NULL, we can +go all the way to the bottom. Otherwise, we stop before +visiting `stack_bottom`. + +Let `current_position` point to the element on the [delimiter stack] +just above `stack_bottom` (or the first element if `stack_bottom` +is NULL). + +We keep track of the `openers_bottom` for each delimiter +type (`*`, `_`) and each length of the closing delimiter run +(modulo 3). Initialize this to `stack_bottom`. + +Then we repeat the following until we run out of potential +closers: + +- Move `current_position` forward in the delimiter stack (if needed) + until we find the first potential closer with delimiter `*` or `_`. + (This will be the potential closer closest + to the beginning of the input -- the first one in parse order.) + +- Now, look back in the stack (staying above `stack_bottom` and + the `openers_bottom` for this delimiter type) for the + first matching potential opener ("matching" means same delimiter). + +- If one is found: + + + Figure out whether we have emphasis or strong emphasis: + if both closer and opener spans have length >= 2, we have + strong, otherwise regular. + + + Insert an emph or strong emph node accordingly, after + the text node corresponding to the opener. + + + Remove any delimiters between the opener and closer from + the delimiter stack. + + + Remove 1 (for regular emph) or 2 (for strong emph) delimiters + from the opening and closing text nodes. If they become empty + as a result, remove them and remove the corresponding element + of the delimiter stack. If the closing node is removed, reset + `current_position` to the next element in the stack. + +- If none is found: + + + Set `openers_bottom` to the element before `current_position`. + (We know that there are no openers for this kind of closer up to and + including this point, so this puts a lower bound on future searches.) + + + If the closer at `current_position` is not a potential opener, + remove it from the delimiter stack (since we know it can't + be a closer either). + + + Advance `current_position` to the next element in the stack. + +After we're done, we remove all delimiters above `stack_bottom` from the +delimiter stack. + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/sourcepos.jl b/.julia-depot/packages/CommonMark/lmLkP/test/sourcepos.jl new file mode 100644 index 0000000..1b5b05c --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/sourcepos.jl @@ -0,0 +1,41 @@ +@testset "Sourcepos" begin + macro_ast_multiline = @__LINE__() + 2, + cm""" + # Header + + > quote + """ + out = html(macro_ast_multiline[2]; sourcepos = true) + @test occursin("data-sourcepos=\"$(macro_ast_multiline[1])", out) + + macro_ast_singleline = @__LINE__(), cm"Some *text*" + out = html(macro_ast_singleline[2]; sourcepos = true) + @test occursin("data-sourcepos=\"$(macro_ast_singleline[1])", out) + + function sourcepos(file) + function (pos) + "data-custom-sourcepos" => string(file, ":", pos[1][1]) + end + end + + out = html(macro_ast_multiline[2]; sourcepos = sourcepos(@__FILE__)) + @test occursin( + "data-custom-sourcepos=\"$(@__FILE__()):$(macro_ast_multiline[1])\"", + out, + ) + + out = html(macro_ast_singleline[2]; sourcepos = sourcepos(@__FILE__)) + @test occursin( + "data-custom-sourcepos=\"$(@__FILE__()):$(macro_ast_singleline[1])\"", + out, + ) + + filepath = joinpath(@__DIR__, "integration.md") + file_ast = open(Parser(), filepath) + + out = html(file_ast; sourcepos = true) + @test occursin("data-sourcepos=\"1", out) + + out = html(file_ast; sourcepos = sourcepos(filepath)) + @test occursin("data-custom-sourcepos=\"$(filepath):1\"", out) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/spec.jl b/.julia-depot/packages/CommonMark/lmLkP/test/spec.jl new file mode 100644 index 0000000..b78f055 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/spec.jl @@ -0,0 +1,18 @@ +@testset "Extra Spec" begin + cases = [( + """ + """, + "\n", + )] + p = Parser() + for (m, h) in cases + @test html(p(m)) == h + @test markdown(p(m)) == m + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/spec.json b/.julia-depot/packages/CommonMark/lmLkP/test/spec.json new file mode 100644 index 0000000..222fee4 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/spec.json @@ -0,0 +1,5194 @@ +[ + { + "markdown": "\tfoo\tbaz\t\tbim\n", + "html": "
foo\tbaz\t\tbim\n
\n", + "example": 1, + "start_line": 352, + "end_line": 357, + "section": "Tabs" + }, + { + "markdown": " \tfoo\tbaz\t\tbim\n", + "html": "
foo\tbaz\t\tbim\n
\n", + "example": 2, + "start_line": 359, + "end_line": 364, + "section": "Tabs" + }, + { + "markdown": " a\ta\n ὐ\ta\n", + "html": "
a\ta\nὐ\ta\n
\n", + "example": 3, + "start_line": 366, + "end_line": 373, + "section": "Tabs" + }, + { + "markdown": " - foo\n\n\tbar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 4, + "start_line": 379, + "end_line": 390, + "section": "Tabs" + }, + { + "markdown": "- foo\n\n\t\tbar\n", + "html": "
    \n
  • \n

    foo

    \n
      bar\n
    \n
  • \n
\n", + "example": 5, + "start_line": 392, + "end_line": 404, + "section": "Tabs" + }, + { + "markdown": ">\t\tfoo\n", + "html": "
\n
  foo\n
\n
\n", + "example": 6, + "start_line": 415, + "end_line": 422, + "section": "Tabs" + }, + { + "markdown": "-\t\tfoo\n", + "html": "
    \n
  • \n
      foo\n
    \n
  • \n
\n", + "example": 7, + "start_line": 424, + "end_line": 433, + "section": "Tabs" + }, + { + "markdown": " foo\n\tbar\n", + "html": "
foo\nbar\n
\n", + "example": 8, + "start_line": 436, + "end_line": 443, + "section": "Tabs" + }, + { + "markdown": " - foo\n - bar\n\t - baz\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 9, + "start_line": 445, + "end_line": 461, + "section": "Tabs" + }, + { + "markdown": "#\tFoo\n", + "html": "

Foo

\n", + "example": 10, + "start_line": 463, + "end_line": 467, + "section": "Tabs" + }, + { + "markdown": "*\t*\t*\t\n", + "html": "
\n", + "example": 11, + "start_line": 469, + "end_line": 473, + "section": "Tabs" + }, + { + "markdown": "- `one\n- two`\n", + "html": "
    \n
  • `one
  • \n
  • two`
  • \n
\n", + "example": 12, + "start_line": 496, + "end_line": 504, + "section": "Precedence" + }, + { + "markdown": "***\n---\n___\n", + "html": "
\n
\n
\n", + "example": 13, + "start_line": 535, + "end_line": 543, + "section": "Thematic breaks" + }, + { + "markdown": "+++\n", + "html": "

+++

\n", + "example": 14, + "start_line": 548, + "end_line": 552, + "section": "Thematic breaks" + }, + { + "markdown": "===\n", + "html": "

===

\n", + "example": 15, + "start_line": 555, + "end_line": 559, + "section": "Thematic breaks" + }, + { + "markdown": "--\n**\n__\n", + "html": "

--\n**\n__

\n", + "example": 16, + "start_line": 564, + "end_line": 572, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n ***\n ***\n", + "html": "
\n
\n
\n", + "example": 17, + "start_line": 577, + "end_line": 585, + "section": "Thematic breaks" + }, + { + "markdown": " ***\n", + "html": "
***\n
\n", + "example": 18, + "start_line": 590, + "end_line": 595, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n ***\n", + "html": "

Foo\n***

\n", + "example": 19, + "start_line": 598, + "end_line": 604, + "section": "Thematic breaks" + }, + { + "markdown": "_____________________________________\n", + "html": "
\n", + "example": 20, + "start_line": 609, + "end_line": 613, + "section": "Thematic breaks" + }, + { + "markdown": " - - -\n", + "html": "
\n", + "example": 21, + "start_line": 618, + "end_line": 622, + "section": "Thematic breaks" + }, + { + "markdown": " ** * ** * ** * **\n", + "html": "
\n", + "example": 22, + "start_line": 625, + "end_line": 629, + "section": "Thematic breaks" + }, + { + "markdown": "- - - -\n", + "html": "
\n", + "example": 23, + "start_line": 632, + "end_line": 636, + "section": "Thematic breaks" + }, + { + "markdown": "- - - - \n", + "html": "
\n", + "example": 24, + "start_line": 641, + "end_line": 645, + "section": "Thematic breaks" + }, + { + "markdown": "_ _ _ _ a\n\na------\n\n---a---\n", + "html": "

_ _ _ _ a

\n

a------

\n

---a---

\n", + "example": 25, + "start_line": 650, + "end_line": 660, + "section": "Thematic breaks" + }, + { + "markdown": " *-*\n", + "html": "

-

\n", + "example": 26, + "start_line": 666, + "end_line": 670, + "section": "Thematic breaks" + }, + { + "markdown": "- foo\n***\n- bar\n", + "html": "
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
\n", + "example": 27, + "start_line": 675, + "end_line": 687, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n***\nbar\n", + "html": "

Foo

\n
\n

bar

\n", + "example": 28, + "start_line": 692, + "end_line": 700, + "section": "Thematic breaks" + }, + { + "markdown": "Foo\n---\nbar\n", + "html": "

Foo

\n

bar

\n", + "example": 29, + "start_line": 709, + "end_line": 716, + "section": "Thematic breaks" + }, + { + "markdown": "* Foo\n* * *\n* Bar\n", + "html": "
    \n
  • Foo
  • \n
\n
\n
    \n
  • Bar
  • \n
\n", + "example": 30, + "start_line": 722, + "end_line": 734, + "section": "Thematic breaks" + }, + { + "markdown": "- Foo\n- * * *\n", + "html": "
    \n
  • Foo
  • \n
  • \n
    \n
  • \n
\n", + "example": 31, + "start_line": 739, + "end_line": 749, + "section": "Thematic breaks" + }, + { + "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n", + "html": "

foo

\n

foo

\n

foo

\n

foo

\n
foo
\n
foo
\n", + "example": 32, + "start_line": 768, + "end_line": 782, + "section": "ATX headings" + }, + { + "markdown": "####### foo\n", + "html": "

####### foo

\n", + "example": 33, + "start_line": 787, + "end_line": 791, + "section": "ATX headings" + }, + { + "markdown": "#5 bolt\n\n#hashtag\n", + "html": "

#5 bolt

\n

#hashtag

\n", + "example": 34, + "start_line": 802, + "end_line": 809, + "section": "ATX headings" + }, + { + "markdown": "\\## foo\n", + "html": "

## foo

\n", + "example": 35, + "start_line": 814, + "end_line": 818, + "section": "ATX headings" + }, + { + "markdown": "# foo *bar* \\*baz\\*\n", + "html": "

foo bar *baz*

\n", + "example": 36, + "start_line": 823, + "end_line": 827, + "section": "ATX headings" + }, + { + "markdown": "# foo \n", + "html": "

foo

\n", + "example": 37, + "start_line": 832, + "end_line": 836, + "section": "ATX headings" + }, + { + "markdown": " ### foo\n ## foo\n # foo\n", + "html": "

foo

\n

foo

\n

foo

\n", + "example": 38, + "start_line": 841, + "end_line": 849, + "section": "ATX headings" + }, + { + "markdown": " # foo\n", + "html": "
# foo\n
\n", + "example": 39, + "start_line": 854, + "end_line": 859, + "section": "ATX headings" + }, + { + "markdown": "foo\n # bar\n", + "html": "

foo\n# bar

\n", + "example": 40, + "start_line": 862, + "end_line": 868, + "section": "ATX headings" + }, + { + "markdown": "## foo ##\n ### bar ###\n", + "html": "

foo

\n

bar

\n", + "example": 41, + "start_line": 873, + "end_line": 879, + "section": "ATX headings" + }, + { + "markdown": "# foo ##################################\n##### foo ##\n", + "html": "

foo

\n
foo
\n", + "example": 42, + "start_line": 884, + "end_line": 890, + "section": "ATX headings" + }, + { + "markdown": "### foo ### \n", + "html": "

foo

\n", + "example": 43, + "start_line": 895, + "end_line": 899, + "section": "ATX headings" + }, + { + "markdown": "### foo ### b\n", + "html": "

foo ### b

\n", + "example": 44, + "start_line": 906, + "end_line": 910, + "section": "ATX headings" + }, + { + "markdown": "# foo#\n", + "html": "

foo#

\n", + "example": 45, + "start_line": 915, + "end_line": 919, + "section": "ATX headings" + }, + { + "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n", + "html": "

foo ###

\n

foo ###

\n

foo #

\n", + "example": 46, + "start_line": 925, + "end_line": 933, + "section": "ATX headings" + }, + { + "markdown": "****\n## foo\n****\n", + "html": "
\n

foo

\n
\n", + "example": 47, + "start_line": 939, + "end_line": 947, + "section": "ATX headings" + }, + { + "markdown": "Foo bar\n# baz\nBar foo\n", + "html": "

Foo bar

\n

baz

\n

Bar foo

\n", + "example": 48, + "start_line": 950, + "end_line": 958, + "section": "ATX headings" + }, + { + "markdown": "## \n#\n### ###\n", + "html": "

\n

\n

\n", + "example": 49, + "start_line": 963, + "end_line": 971, + "section": "ATX headings" + }, + { + "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n", + "html": "

Foo bar

\n

Foo bar

\n", + "example": 50, + "start_line": 1006, + "end_line": 1015, + "section": "Setext headings" + }, + { + "markdown": "Foo *bar\nbaz*\n====\n", + "html": "

Foo bar\nbaz

\n", + "example": 51, + "start_line": 1020, + "end_line": 1027, + "section": "Setext headings" + }, + { + "markdown": " Foo *bar\nbaz*\t\n====\n", + "html": "

Foo bar\nbaz

\n", + "example": 52, + "start_line": 1034, + "end_line": 1041, + "section": "Setext headings" + }, + { + "markdown": "Foo\n-------------------------\n\nFoo\n=\n", + "html": "

Foo

\n

Foo

\n", + "example": 53, + "start_line": 1046, + "end_line": 1055, + "section": "Setext headings" + }, + { + "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n", + "html": "

Foo

\n

Foo

\n

Foo

\n", + "example": 54, + "start_line": 1061, + "end_line": 1074, + "section": "Setext headings" + }, + { + "markdown": " Foo\n ---\n\n Foo\n---\n", + "html": "
Foo\n---\n\nFoo\n
\n
\n", + "example": 55, + "start_line": 1079, + "end_line": 1092, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---- \n", + "html": "

Foo

\n", + "example": 56, + "start_line": 1098, + "end_line": 1103, + "section": "Setext headings" + }, + { + "markdown": "Foo\n ---\n", + "html": "

Foo\n---

\n", + "example": 57, + "start_line": 1108, + "end_line": 1114, + "section": "Setext headings" + }, + { + "markdown": "Foo\n= =\n\nFoo\n--- -\n", + "html": "

Foo\n= =

\n

Foo

\n
\n", + "example": 58, + "start_line": 1119, + "end_line": 1130, + "section": "Setext headings" + }, + { + "markdown": "Foo \n-----\n", + "html": "

Foo

\n", + "example": 59, + "start_line": 1135, + "end_line": 1140, + "section": "Setext headings" + }, + { + "markdown": "Foo\\\n----\n", + "html": "

Foo\\

\n", + "example": 60, + "start_line": 1145, + "end_line": 1150, + "section": "Setext headings" + }, + { + "markdown": "`Foo\n----\n`\n\n
\n", + "html": "

`Foo

\n

`

\n

<a title="a lot

\n

of dashes"/>

\n", + "example": 61, + "start_line": 1156, + "end_line": 1169, + "section": "Setext headings" + }, + { + "markdown": "> Foo\n---\n", + "html": "
\n

Foo

\n
\n
\n", + "example": 62, + "start_line": 1175, + "end_line": 1183, + "section": "Setext headings" + }, + { + "markdown": "> foo\nbar\n===\n", + "html": "
\n

foo\nbar\n===

\n
\n", + "example": 63, + "start_line": 1186, + "end_line": 1196, + "section": "Setext headings" + }, + { + "markdown": "- Foo\n---\n", + "html": "
    \n
  • Foo
  • \n
\n
\n", + "example": 64, + "start_line": 1199, + "end_line": 1207, + "section": "Setext headings" + }, + { + "markdown": "Foo\nBar\n---\n", + "html": "

Foo\nBar

\n", + "example": 65, + "start_line": 1214, + "end_line": 1221, + "section": "Setext headings" + }, + { + "markdown": "---\nFoo\n---\nBar\n---\nBaz\n", + "html": "
\n

Foo

\n

Bar

\n

Baz

\n", + "example": 66, + "start_line": 1227, + "end_line": 1239, + "section": "Setext headings" + }, + { + "markdown": "\n====\n", + "html": "

====

\n", + "example": 67, + "start_line": 1244, + "end_line": 1249, + "section": "Setext headings" + }, + { + "markdown": "---\n---\n", + "html": "
\n
\n", + "example": 68, + "start_line": 1256, + "end_line": 1262, + "section": "Setext headings" + }, + { + "markdown": "- foo\n-----\n", + "html": "
    \n
  • foo
  • \n
\n
\n", + "example": 69, + "start_line": 1265, + "end_line": 1273, + "section": "Setext headings" + }, + { + "markdown": " foo\n---\n", + "html": "
foo\n
\n
\n", + "example": 70, + "start_line": 1276, + "end_line": 1283, + "section": "Setext headings" + }, + { + "markdown": "> foo\n-----\n", + "html": "
\n

foo

\n
\n
\n", + "example": 71, + "start_line": 1286, + "end_line": 1294, + "section": "Setext headings" + }, + { + "markdown": "\\> foo\n------\n", + "html": "

> foo

\n", + "example": 72, + "start_line": 1300, + "end_line": 1305, + "section": "Setext headings" + }, + { + "markdown": "Foo\n\nbar\n---\nbaz\n", + "html": "

Foo

\n

bar

\n

baz

\n", + "example": 73, + "start_line": 1331, + "end_line": 1341, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\n---\n\nbaz\n", + "html": "

Foo\nbar

\n
\n

baz

\n", + "example": 74, + "start_line": 1347, + "end_line": 1359, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n* * *\nbaz\n", + "html": "

Foo\nbar

\n
\n

baz

\n", + "example": 75, + "start_line": 1365, + "end_line": 1375, + "section": "Setext headings" + }, + { + "markdown": "Foo\nbar\n\\---\nbaz\n", + "html": "

Foo\nbar\n---\nbaz

\n", + "example": 76, + "start_line": 1380, + "end_line": 1390, + "section": "Setext headings" + }, + { + "markdown": " a simple\n indented code block\n", + "html": "
a simple\n  indented code block\n
\n", + "example": 77, + "start_line": 1408, + "end_line": 1415, + "section": "Indented code blocks" + }, + { + "markdown": " - foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 78, + "start_line": 1422, + "end_line": 1433, + "section": "Indented code blocks" + }, + { + "markdown": "1. foo\n\n - bar\n", + "html": "
    \n
  1. \n

    foo

    \n
      \n
    • bar
    • \n
    \n
  2. \n
\n", + "example": 79, + "start_line": 1436, + "end_line": 1449, + "section": "Indented code blocks" + }, + { + "markdown": "
\n *hi*\n\n - one\n", + "html": "
<a/>\n*hi*\n\n- one\n
\n", + "example": 80, + "start_line": 1456, + "end_line": 1467, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n", + "html": "
chunk1\n\nchunk2\n\n\n\nchunk3\n
\n", + "example": 81, + "start_line": 1472, + "end_line": 1489, + "section": "Indented code blocks" + }, + { + "markdown": " chunk1\n \n chunk2\n", + "html": "
chunk1\n  \n  chunk2\n
\n", + "example": 82, + "start_line": 1495, + "end_line": 1504, + "section": "Indented code blocks" + }, + { + "markdown": "Foo\n bar\n\n", + "html": "

Foo\nbar

\n", + "example": 83, + "start_line": 1510, + "end_line": 1517, + "section": "Indented code blocks" + }, + { + "markdown": " foo\nbar\n", + "html": "
foo\n
\n

bar

\n", + "example": 84, + "start_line": 1524, + "end_line": 1531, + "section": "Indented code blocks" + }, + { + "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n", + "html": "

Heading

\n
foo\n
\n

Heading

\n
foo\n
\n
\n", + "example": 85, + "start_line": 1537, + "end_line": 1552, + "section": "Indented code blocks" + }, + { + "markdown": " foo\n bar\n", + "html": "
    foo\nbar\n
\n", + "example": 86, + "start_line": 1557, + "end_line": 1564, + "section": "Indented code blocks" + }, + { + "markdown": "\n \n foo\n \n\n", + "html": "
foo\n
\n", + "example": 87, + "start_line": 1570, + "end_line": 1579, + "section": "Indented code blocks" + }, + { + "markdown": " foo \n", + "html": "
foo  \n
\n", + "example": 88, + "start_line": 1584, + "end_line": 1589, + "section": "Indented code blocks" + }, + { + "markdown": "```\n<\n >\n```\n", + "html": "
<\n >\n
\n", + "example": 89, + "start_line": 1639, + "end_line": 1648, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\n<\n >\n~~~\n", + "html": "
<\n >\n
\n", + "example": 90, + "start_line": 1653, + "end_line": 1662, + "section": "Fenced code blocks" + }, + { + "markdown": "``\nfoo\n``\n", + "html": "

foo

\n", + "example": 91, + "start_line": 1666, + "end_line": 1672, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n~~~\n```\n", + "html": "
aaa\n~~~\n
\n", + "example": 92, + "start_line": 1677, + "end_line": 1686, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~\naaa\n```\n~~~\n", + "html": "
aaa\n```\n
\n", + "example": 93, + "start_line": 1689, + "end_line": 1698, + "section": "Fenced code blocks" + }, + { + "markdown": "````\naaa\n```\n``````\n", + "html": "
aaa\n```\n
\n", + "example": 94, + "start_line": 1703, + "end_line": 1712, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~\naaa\n~~~\n~~~~\n", + "html": "
aaa\n~~~\n
\n", + "example": 95, + "start_line": 1715, + "end_line": 1724, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n", + "html": "
\n", + "example": 96, + "start_line": 1730, + "end_line": 1734, + "section": "Fenced code blocks" + }, + { + "markdown": "`````\n\n```\naaa\n", + "html": "
\n```\naaa\n
\n", + "example": 97, + "start_line": 1737, + "end_line": 1747, + "section": "Fenced code blocks" + }, + { + "markdown": "> ```\n> aaa\n\nbbb\n", + "html": "
\n
aaa\n
\n
\n

bbb

\n", + "example": 98, + "start_line": 1750, + "end_line": 1761, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n\n \n```\n", + "html": "
\n  \n
\n", + "example": 99, + "start_line": 1766, + "end_line": 1775, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n```\n", + "html": "
\n", + "example": 100, + "start_line": 1780, + "end_line": 1785, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\naaa\n```\n", + "html": "
aaa\naaa\n
\n", + "example": 101, + "start_line": 1792, + "end_line": 1801, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n aaa\naaa\n ```\n", + "html": "
aaa\naaa\naaa\n
\n", + "example": 102, + "start_line": 1804, + "end_line": 1815, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n aaa\n aaa\n ```\n", + "html": "
aaa\n aaa\naaa\n
\n", + "example": 103, + "start_line": 1818, + "end_line": 1829, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\n aaa\n ```\n", + "html": "
```\naaa\n```\n
\n", + "example": 104, + "start_line": 1834, + "end_line": 1843, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "
aaa\n
\n", + "example": 105, + "start_line": 1849, + "end_line": 1856, + "section": "Fenced code blocks" + }, + { + "markdown": " ```\naaa\n ```\n", + "html": "
aaa\n
\n", + "example": 106, + "start_line": 1859, + "end_line": 1866, + "section": "Fenced code blocks" + }, + { + "markdown": "```\naaa\n ```\n", + "html": "
aaa\n    ```\n
\n", + "example": 107, + "start_line": 1871, + "end_line": 1879, + "section": "Fenced code blocks" + }, + { + "markdown": "``` ```\naaa\n", + "html": "

\naaa

\n", + "example": 108, + "start_line": 1885, + "end_line": 1891, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~~~\naaa\n~~~ ~~\n", + "html": "
aaa\n~~~ ~~\n
\n", + "example": 109, + "start_line": 1894, + "end_line": 1902, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n```\nbar\n```\nbaz\n", + "html": "

foo

\n
bar\n
\n

baz

\n", + "example": 110, + "start_line": 1908, + "end_line": 1919, + "section": "Fenced code blocks" + }, + { + "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n", + "html": "

foo

\n
bar\n
\n

baz

\n", + "example": 111, + "start_line": 1925, + "end_line": 1937, + "section": "Fenced code blocks" + }, + { + "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n", + "html": "
def foo(x)\n  return 3\nend\n
\n", + "example": 112, + "start_line": 1947, + "end_line": 1958, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n", + "html": "
def foo(x)\n  return 3\nend\n
\n", + "example": 113, + "start_line": 1961, + "end_line": 1972, + "section": "Fenced code blocks" + }, + { + "markdown": "````;\n````\n", + "html": "
\n", + "example": 114, + "start_line": 1975, + "end_line": 1980, + "section": "Fenced code blocks" + }, + { + "markdown": "``` aa ```\nfoo\n", + "html": "

aa\nfoo

\n", + "example": 115, + "start_line": 1985, + "end_line": 1991, + "section": "Fenced code blocks" + }, + { + "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n", + "html": "
foo\n
\n", + "example": 116, + "start_line": 1996, + "end_line": 2003, + "section": "Fenced code blocks" + }, + { + "markdown": "```\n``` aaa\n```\n", + "html": "
``` aaa\n
\n", + "example": 117, + "start_line": 2008, + "end_line": 2015, + "section": "Fenced code blocks" + }, + { + "markdown": "
\n
\n**Hello**,\n\n_world_.\n
\n
\n", + "html": "
\n
\n**Hello**,\n

world.\n

\n
\n", + "example": 118, + "start_line": 2087, + "end_line": 2102, + "section": "HTML blocks" + }, + { + "markdown": "\n \n \n \n
\n hi\n
\n\nokay.\n", + "html": "\n \n \n \n
\n hi\n
\n

okay.

\n", + "example": 119, + "start_line": 2116, + "end_line": 2135, + "section": "HTML blocks" + }, + { + "markdown": "
\n*foo*\n", + "example": 121, + "start_line": 2151, + "end_line": 2157, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n*Markdown*\n\n
\n", + "html": "
\n

Markdown

\n
\n", + "example": 122, + "start_line": 2162, + "end_line": 2172, + "section": "HTML blocks" + }, + { + "markdown": "
\n
\n", + "html": "
\n
\n", + "example": 123, + "start_line": 2178, + "end_line": 2186, + "section": "HTML blocks" + }, + { + "markdown": "
\n
\n", + "html": "
\n
\n", + "example": 124, + "start_line": 2189, + "end_line": 2197, + "section": "HTML blocks" + }, + { + "markdown": "
\n*foo*\n\n*bar*\n", + "html": "
\n*foo*\n

bar

\n", + "example": 125, + "start_line": 2201, + "end_line": 2210, + "section": "HTML blocks" + }, + { + "markdown": "
\n", + "html": "\n", + "example": 129, + "start_line": 2250, + "end_line": 2254, + "section": "HTML blocks" + }, + { + "markdown": "
\nfoo\n
\n", + "html": "
\nfoo\n
\n", + "example": 130, + "start_line": 2257, + "end_line": 2265, + "section": "HTML blocks" + }, + { + "markdown": "
\n``` c\nint x = 33;\n```\n", + "html": "
\n``` c\nint x = 33;\n```\n", + "example": 131, + "start_line": 2274, + "end_line": 2284, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 132, + "start_line": 2291, + "end_line": 2299, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 133, + "start_line": 2304, + "end_line": 2312, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n\n", + "html": "\n*bar*\n\n", + "example": 134, + "start_line": 2315, + "end_line": 2323, + "section": "HTML blocks" + }, + { + "markdown": "\n*bar*\n", + "html": "\n*bar*\n", + "example": 135, + "start_line": 2326, + "end_line": 2332, + "section": "HTML blocks" + }, + { + "markdown": "\n*foo*\n\n", + "html": "\n*foo*\n\n", + "example": 136, + "start_line": 2341, + "end_line": 2349, + "section": "HTML blocks" + }, + { + "markdown": "\n\n*foo*\n\n\n", + "html": "\n

foo

\n
\n", + "example": 137, + "start_line": 2356, + "end_line": 2366, + "section": "HTML blocks" + }, + { + "markdown": "*foo*\n", + "html": "

foo

\n", + "example": 138, + "start_line": 2374, + "end_line": 2378, + "section": "HTML blocks" + }, + { + "markdown": "
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\nokay\n", + "html": "
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\n

okay

\n", + "example": 139, + "start_line": 2390, + "end_line": 2406, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 140, + "start_line": 2411, + "end_line": 2425, + "section": "HTML blocks" + }, + { + "markdown": "\nh1 {color:red;}\n\np {color:blue;}\n\nokay\n", + "html": "\nh1 {color:red;}\n\np {color:blue;}\n\n

okay

\n", + "example": 141, + "start_line": 2430, + "end_line": 2446, + "section": "HTML blocks" + }, + { + "markdown": "\n\nfoo\n", + "html": "\n\nfoo\n", + "example": 142, + "start_line": 2453, + "end_line": 2463, + "section": "HTML blocks" + }, + { + "markdown": ">
\n> foo\n\nbar\n", + "html": "
\n
\nfoo\n
\n

bar

\n", + "example": 143, + "start_line": 2466, + "end_line": 2477, + "section": "HTML blocks" + }, + { + "markdown": "-
\n- foo\n", + "html": "
    \n
  • \n
    \n
  • \n
  • foo
  • \n
\n", + "example": 144, + "start_line": 2480, + "end_line": 2490, + "section": "HTML blocks" + }, + { + "markdown": "\n*foo*\n", + "html": "\n

foo

\n", + "example": 145, + "start_line": 2495, + "end_line": 2501, + "section": "HTML blocks" + }, + { + "markdown": "*bar*\n*baz*\n", + "html": "*bar*\n

baz

\n", + "example": 146, + "start_line": 2504, + "end_line": 2510, + "section": "HTML blocks" + }, + { + "markdown": "1. *bar*\n", + "html": "1. *bar*\n", + "example": 147, + "start_line": 2516, + "end_line": 2524, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 148, + "start_line": 2529, + "end_line": 2541, + "section": "HTML blocks" + }, + { + "markdown": "';\n\n?>\nokay\n", + "html": "';\n\n?>\n

okay

\n", + "example": 149, + "start_line": 2547, + "end_line": 2561, + "section": "HTML blocks" + }, + { + "markdown": "\n", + "html": "\n", + "example": 150, + "start_line": 2566, + "end_line": 2570, + "section": "HTML blocks" + }, + { + "markdown": "\nokay\n", + "html": "\n

okay

\n", + "example": 151, + "start_line": 2575, + "end_line": 2603, + "section": "HTML blocks" + }, + { + "markdown": " \n\n \n", + "html": " \n
<!-- foo -->\n
\n", + "example": 152, + "start_line": 2608, + "end_line": 2616, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n
\n", + "html": "
\n
<div>\n
\n", + "example": 153, + "start_line": 2619, + "end_line": 2627, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n
\nbar\n
\n", + "html": "

Foo

\n
\nbar\n
\n", + "example": 154, + "start_line": 2633, + "end_line": 2643, + "section": "HTML blocks" + }, + { + "markdown": "
\nbar\n
\n*foo*\n", + "html": "
\nbar\n
\n*foo*\n", + "example": 155, + "start_line": 2650, + "end_line": 2660, + "section": "HTML blocks" + }, + { + "markdown": "Foo\n\nbaz\n", + "html": "

Foo\n\nbaz

\n", + "example": 156, + "start_line": 2665, + "end_line": 2673, + "section": "HTML blocks" + }, + { + "markdown": "
\n\n*Emphasized* text.\n\n
\n", + "html": "
\n

Emphasized text.

\n
\n", + "example": 157, + "start_line": 2706, + "end_line": 2716, + "section": "HTML blocks" + }, + { + "markdown": "
\n*Emphasized* text.\n
\n", + "html": "
\n*Emphasized* text.\n
\n", + "example": 158, + "start_line": 2719, + "end_line": 2727, + "section": "HTML blocks" + }, + { + "markdown": "\n\n\n\n\n\n\n\n
\nHi\n
\n", + "html": "\n\n\n\n
\nHi\n
\n", + "example": 159, + "start_line": 2741, + "end_line": 2761, + "section": "HTML blocks" + }, + { + "markdown": "\n\n \n\n \n\n \n\n
\n Hi\n
\n", + "html": "\n \n
<td>\n  Hi\n</td>\n
\n \n
\n", + "example": 160, + "start_line": 2768, + "end_line": 2789, + "section": "HTML blocks" + }, + { + "markdown": "[foo]: /url \"title\"\n\n[foo]\n", + "html": "

foo

\n", + "example": 161, + "start_line": 2816, + "end_line": 2822, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n", + "html": "

foo

\n", + "example": 162, + "start_line": 2825, + "end_line": 2833, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n", + "html": "

Foo*bar]

\n", + "example": 163, + "start_line": 2836, + "end_line": 2842, + "section": "Link reference definitions" + }, + { + "markdown": "[Foo bar]:\n\n'title'\n\n[Foo bar]\n", + "html": "

Foo bar

\n", + "example": 164, + "start_line": 2845, + "end_line": 2853, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n", + "html": "

foo

\n", + "example": 165, + "start_line": 2858, + "end_line": 2872, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n", + "html": "

[foo]: /url 'title

\n

with blank line'

\n

[foo]

\n", + "example": 166, + "start_line": 2877, + "end_line": 2887, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n/url\n\n[foo]\n", + "html": "

foo

\n", + "example": 167, + "start_line": 2892, + "end_line": 2899, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]:\n\n[foo]\n", + "html": "

[foo]:

\n

[foo]

\n", + "example": 168, + "start_line": 2904, + "end_line": 2911, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: <>\n\n[foo]\n", + "html": "

foo

\n", + "example": 169, + "start_line": 2916, + "end_line": 2922, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: (baz)\n\n[foo]\n", + "html": "

[foo]: (baz)

\n

[foo]

\n", + "example": 170, + "start_line": 2927, + "end_line": 2934, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n", + "html": "

foo

\n", + "example": 171, + "start_line": 2940, + "end_line": 2946, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: url\n", + "html": "

foo

\n", + "example": 172, + "start_line": 2951, + "end_line": 2957, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n", + "html": "

foo

\n", + "example": 173, + "start_line": 2963, + "end_line": 2970, + "section": "Link reference definitions" + }, + { + "markdown": "[FOO]: /url\n\n[Foo]\n", + "html": "

Foo

\n", + "example": 174, + "start_line": 2976, + "end_line": 2982, + "section": "Link reference definitions" + }, + { + "markdown": "[ΑΓΩ]: /φου\n\n[αγω]\n", + "html": "

αγω

\n", + "example": 175, + "start_line": 2985, + "end_line": 2991, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 176, + "start_line": 2997, + "end_line": 3000, + "section": "Link reference definitions" + }, + { + "markdown": "[\nfoo\n]: /url\nbar\n", + "html": "

bar

\n", + "example": 177, + "start_line": 3005, + "end_line": 3012, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url \"title\" ok\n", + "html": "

[foo]: /url "title" ok

\n", + "example": 178, + "start_line": 3018, + "end_line": 3022, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n\"title\" ok\n", + "html": "

"title" ok

\n", + "example": 179, + "start_line": 3027, + "end_line": 3032, + "section": "Link reference definitions" + }, + { + "markdown": " [foo]: /url \"title\"\n\n[foo]\n", + "html": "
[foo]: /url "title"\n
\n

[foo]

\n", + "example": 180, + "start_line": 3038, + "end_line": 3046, + "section": "Link reference definitions" + }, + { + "markdown": "```\n[foo]: /url\n```\n\n[foo]\n", + "html": "
[foo]: /url\n
\n

[foo]

\n", + "example": 181, + "start_line": 3052, + "end_line": 3062, + "section": "Link reference definitions" + }, + { + "markdown": "Foo\n[bar]: /baz\n\n[bar]\n", + "html": "

Foo\n[bar]: /baz

\n

[bar]

\n", + "example": 182, + "start_line": 3067, + "end_line": 3076, + "section": "Link reference definitions" + }, + { + "markdown": "# [Foo]\n[foo]: /url\n> bar\n", + "html": "

Foo

\n
\n

bar

\n
\n", + "example": 183, + "start_line": 3082, + "end_line": 3091, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\nbar\n===\n[foo]\n", + "html": "

bar

\n

foo

\n", + "example": 184, + "start_line": 3093, + "end_line": 3101, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n===\n[foo]\n", + "html": "

===\nfoo

\n", + "example": 185, + "start_line": 3103, + "end_line": 3110, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n", + "html": "

foo,\nbar,\nbaz

\n", + "example": 186, + "start_line": 3116, + "end_line": 3129, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]\n\n> [foo]: /url\n", + "html": "

foo

\n
\n
\n", + "example": 187, + "start_line": 3137, + "end_line": 3145, + "section": "Link reference definitions" + }, + { + "markdown": "[foo]: /url\n", + "html": "", + "example": 188, + "start_line": 3154, + "end_line": 3157, + "section": "Link reference definitions" + }, + { + "markdown": "aaa\n\nbbb\n", + "html": "

aaa

\n

bbb

\n", + "example": 189, + "start_line": 3171, + "end_line": 3178, + "section": "Paragraphs" + }, + { + "markdown": "aaa\nbbb\n\nccc\nddd\n", + "html": "

aaa\nbbb

\n

ccc\nddd

\n", + "example": 190, + "start_line": 3183, + "end_line": 3194, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n\n\nbbb\n", + "html": "

aaa

\n

bbb

\n", + "example": 191, + "start_line": 3199, + "end_line": 3207, + "section": "Paragraphs" + }, + { + "markdown": " aaa\n bbb\n", + "html": "

aaa\nbbb

\n", + "example": 192, + "start_line": 3212, + "end_line": 3218, + "section": "Paragraphs" + }, + { + "markdown": "aaa\n bbb\n ccc\n", + "html": "

aaa\nbbb\nccc

\n", + "example": 193, + "start_line": 3224, + "end_line": 3232, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "

aaa\nbbb

\n", + "example": 194, + "start_line": 3238, + "end_line": 3244, + "section": "Paragraphs" + }, + { + "markdown": " aaa\nbbb\n", + "html": "
aaa\n
\n

bbb

\n", + "example": 195, + "start_line": 3247, + "end_line": 3254, + "section": "Paragraphs" + }, + { + "markdown": "aaa \nbbb \n", + "html": "

aaa
\nbbb

\n", + "example": 196, + "start_line": 3261, + "end_line": 3267, + "section": "Paragraphs" + }, + { + "markdown": " \n\naaa\n \n\n# aaa\n\n \n", + "html": "

aaa

\n

aaa

\n", + "example": 197, + "start_line": 3278, + "end_line": 3290, + "section": "Blank lines" + }, + { + "markdown": "> # Foo\n> bar\n> baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 198, + "start_line": 3344, + "end_line": 3354, + "section": "Block quotes" + }, + { + "markdown": "># Foo\n>bar\n> baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 199, + "start_line": 3359, + "end_line": 3369, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 200, + "start_line": 3374, + "end_line": 3384, + "section": "Block quotes" + }, + { + "markdown": " > # Foo\n > bar\n > baz\n", + "html": "
> # Foo\n> bar\n> baz\n
\n", + "example": 201, + "start_line": 3389, + "end_line": 3398, + "section": "Block quotes" + }, + { + "markdown": "> # Foo\n> bar\nbaz\n", + "html": "
\n

Foo

\n

bar\nbaz

\n
\n", + "example": 202, + "start_line": 3404, + "end_line": 3414, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n> foo\n", + "html": "
\n

bar\nbaz\nfoo

\n
\n", + "example": 203, + "start_line": 3420, + "end_line": 3430, + "section": "Block quotes" + }, + { + "markdown": "> foo\n---\n", + "html": "
\n

foo

\n
\n
\n", + "example": 204, + "start_line": 3444, + "end_line": 3452, + "section": "Block quotes" + }, + { + "markdown": "> - foo\n- bar\n", + "html": "
\n
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
\n", + "example": 205, + "start_line": 3464, + "end_line": 3476, + "section": "Block quotes" + }, + { + "markdown": "> foo\n bar\n", + "html": "
\n
foo\n
\n
\n
bar\n
\n", + "example": 206, + "start_line": 3482, + "end_line": 3492, + "section": "Block quotes" + }, + { + "markdown": "> ```\nfoo\n```\n", + "html": "
\n
\n
\n

foo

\n
\n", + "example": 207, + "start_line": 3495, + "end_line": 3505, + "section": "Block quotes" + }, + { + "markdown": "> foo\n - bar\n", + "html": "
\n

foo\n- bar

\n
\n", + "example": 208, + "start_line": 3511, + "end_line": 3519, + "section": "Block quotes" + }, + { + "markdown": ">\n", + "html": "
\n
\n", + "example": 209, + "start_line": 3535, + "end_line": 3540, + "section": "Block quotes" + }, + { + "markdown": ">\n> \n> \n", + "html": "
\n
\n", + "example": 210, + "start_line": 3543, + "end_line": 3550, + "section": "Block quotes" + }, + { + "markdown": ">\n> foo\n> \n", + "html": "
\n

foo

\n
\n", + "example": 211, + "start_line": 3555, + "end_line": 3563, + "section": "Block quotes" + }, + { + "markdown": "> foo\n\n> bar\n", + "html": "
\n

foo

\n
\n
\n

bar

\n
\n", + "example": 212, + "start_line": 3568, + "end_line": 3579, + "section": "Block quotes" + }, + { + "markdown": "> foo\n> bar\n", + "html": "
\n

foo\nbar

\n
\n", + "example": 213, + "start_line": 3590, + "end_line": 3598, + "section": "Block quotes" + }, + { + "markdown": "> foo\n>\n> bar\n", + "html": "
\n

foo

\n

bar

\n
\n", + "example": 214, + "start_line": 3603, + "end_line": 3612, + "section": "Block quotes" + }, + { + "markdown": "foo\n> bar\n", + "html": "

foo

\n
\n

bar

\n
\n", + "example": 215, + "start_line": 3617, + "end_line": 3625, + "section": "Block quotes" + }, + { + "markdown": "> aaa\n***\n> bbb\n", + "html": "
\n

aaa

\n
\n
\n
\n

bbb

\n
\n", + "example": 216, + "start_line": 3631, + "end_line": 3643, + "section": "Block quotes" + }, + { + "markdown": "> bar\nbaz\n", + "html": "
\n

bar\nbaz

\n
\n", + "example": 217, + "start_line": 3649, + "end_line": 3657, + "section": "Block quotes" + }, + { + "markdown": "> bar\n\nbaz\n", + "html": "
\n

bar

\n
\n

baz

\n", + "example": 218, + "start_line": 3660, + "end_line": 3669, + "section": "Block quotes" + }, + { + "markdown": "> bar\n>\nbaz\n", + "html": "
\n

bar

\n
\n

baz

\n", + "example": 219, + "start_line": 3672, + "end_line": 3681, + "section": "Block quotes" + }, + { + "markdown": "> > > foo\nbar\n", + "html": "
\n
\n
\n

foo\nbar

\n
\n
\n
\n", + "example": 220, + "start_line": 3688, + "end_line": 3700, + "section": "Block quotes" + }, + { + "markdown": ">>> foo\n> bar\n>>baz\n", + "html": "
\n
\n
\n

foo\nbar\nbaz

\n
\n
\n
\n", + "example": 221, + "start_line": 3703, + "end_line": 3717, + "section": "Block quotes" + }, + { + "markdown": "> code\n\n> not code\n", + "html": "
\n
code\n
\n
\n
\n

not code

\n
\n", + "example": 222, + "start_line": 3725, + "end_line": 3737, + "section": "Block quotes" + }, + { + "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n", + "html": "

A paragraph\nwith two lines.

\n
indented code\n
\n
\n

A block quote.

\n
\n", + "example": 223, + "start_line": 3779, + "end_line": 3794, + "section": "List items" + }, + { + "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 224, + "start_line": 3801, + "end_line": 3820, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "
    \n
  • one
  • \n
\n

two

\n", + "example": 225, + "start_line": 3834, + "end_line": 3843, + "section": "List items" + }, + { + "markdown": "- one\n\n two\n", + "html": "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
\n", + "example": 226, + "start_line": 3846, + "end_line": 3857, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "
    \n
  • one
  • \n
\n
 two\n
\n", + "example": 227, + "start_line": 3860, + "end_line": 3870, + "section": "List items" + }, + { + "markdown": " - one\n\n two\n", + "html": "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
\n", + "example": 228, + "start_line": 3873, + "end_line": 3884, + "section": "List items" + }, + { + "markdown": " > > 1. one\n>>\n>> two\n", + "html": "
\n
\n
    \n
  1. \n

    one

    \n

    two

    \n
  2. \n
\n
\n
\n", + "example": 229, + "start_line": 3895, + "end_line": 3910, + "section": "List items" + }, + { + "markdown": ">>- one\n>>\n > > two\n", + "html": "
\n
\n
    \n
  • one
  • \n
\n

two

\n
\n
\n", + "example": 230, + "start_line": 3922, + "end_line": 3935, + "section": "List items" + }, + { + "markdown": "-one\n\n2.two\n", + "html": "

-one

\n

2.two

\n", + "example": 231, + "start_line": 3941, + "end_line": 3948, + "section": "List items" + }, + { + "markdown": "- foo\n\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 232, + "start_line": 3954, + "end_line": 3966, + "section": "List items" + }, + { + "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n", + "html": "
    \n
  1. \n

    foo

    \n
    bar\n
    \n

    baz

    \n
    \n

    bam

    \n
    \n
  2. \n
\n", + "example": 233, + "start_line": 3971, + "end_line": 3993, + "section": "List items" + }, + { + "markdown": "- Foo\n\n bar\n\n\n baz\n", + "html": "
    \n
  • \n

    Foo

    \n
    bar\n\n\nbaz\n
    \n
  • \n
\n", + "example": 234, + "start_line": 3999, + "end_line": 4017, + "section": "List items" + }, + { + "markdown": "123456789. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 235, + "start_line": 4021, + "end_line": 4027, + "section": "List items" + }, + { + "markdown": "1234567890. not ok\n", + "html": "

1234567890. not ok

\n", + "example": 236, + "start_line": 4030, + "end_line": 4034, + "section": "List items" + }, + { + "markdown": "0. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 237, + "start_line": 4039, + "end_line": 4045, + "section": "List items" + }, + { + "markdown": "003. ok\n", + "html": "
    \n
  1. ok
  2. \n
\n", + "example": 238, + "start_line": 4048, + "end_line": 4054, + "section": "List items" + }, + { + "markdown": "-1. not ok\n", + "html": "

-1. not ok

\n", + "example": 239, + "start_line": 4059, + "end_line": 4063, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n
    bar\n
    \n
  • \n
\n", + "example": 240, + "start_line": 4082, + "end_line": 4094, + "section": "List items" + }, + { + "markdown": " 10. foo\n\n bar\n", + "html": "
    \n
  1. \n

    foo

    \n
    bar\n
    \n
  2. \n
\n", + "example": 241, + "start_line": 4099, + "end_line": 4111, + "section": "List items" + }, + { + "markdown": " indented code\n\nparagraph\n\n more code\n", + "html": "
indented code\n
\n

paragraph

\n
more code\n
\n", + "example": 242, + "start_line": 4118, + "end_line": 4130, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "
    \n
  1. \n
    indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
\n", + "example": 243, + "start_line": 4133, + "end_line": 4149, + "section": "List items" + }, + { + "markdown": "1. indented code\n\n paragraph\n\n more code\n", + "html": "
    \n
  1. \n
     indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
\n", + "example": 244, + "start_line": 4155, + "end_line": 4171, + "section": "List items" + }, + { + "markdown": " foo\n\nbar\n", + "html": "

foo

\n

bar

\n", + "example": 245, + "start_line": 4182, + "end_line": 4189, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • foo
  • \n
\n

bar

\n", + "example": 246, + "start_line": 4192, + "end_line": 4201, + "section": "List items" + }, + { + "markdown": "- foo\n\n bar\n", + "html": "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
\n", + "example": 247, + "start_line": 4209, + "end_line": 4220, + "section": "List items" + }, + { + "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n", + "html": "
    \n
  • foo
  • \n
  • \n
    bar\n
    \n
  • \n
  • \n
    baz\n
    \n
  • \n
\n", + "example": 248, + "start_line": 4237, + "end_line": 4258, + "section": "List items" + }, + { + "markdown": "- \n foo\n", + "html": "
    \n
  • foo
  • \n
\n", + "example": 249, + "start_line": 4263, + "end_line": 4270, + "section": "List items" + }, + { + "markdown": "-\n\n foo\n", + "html": "
    \n
  • \n
\n

foo

\n", + "example": 250, + "start_line": 4277, + "end_line": 4286, + "section": "List items" + }, + { + "markdown": "- foo\n-\n- bar\n", + "html": "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
\n", + "example": 251, + "start_line": 4291, + "end_line": 4301, + "section": "List items" + }, + { + "markdown": "- foo\n- \n- bar\n", + "html": "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
\n", + "example": 252, + "start_line": 4306, + "end_line": 4316, + "section": "List items" + }, + { + "markdown": "1. foo\n2.\n3. bar\n", + "html": "
    \n
  1. foo
  2. \n
  3. \n
  4. bar
  5. \n
\n", + "example": 253, + "start_line": 4321, + "end_line": 4331, + "section": "List items" + }, + { + "markdown": "*\n", + "html": "
    \n
  • \n
\n", + "example": 254, + "start_line": 4336, + "end_line": 4342, + "section": "List items" + }, + { + "markdown": "foo\n*\n\nfoo\n1.\n", + "html": "

foo\n*

\n

foo\n1.

\n", + "example": 255, + "start_line": 4346, + "end_line": 4357, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 256, + "start_line": 4368, + "end_line": 4387, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 257, + "start_line": 4392, + "end_line": 4411, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 258, + "start_line": 4416, + "end_line": 4435, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
1.  A paragraph\n    with two lines.\n\n        indented code\n\n    > A block quote.\n
\n", + "example": 259, + "start_line": 4440, + "end_line": 4455, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n", + "html": "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
\n", + "example": 260, + "start_line": 4470, + "end_line": 4489, + "section": "List items" + }, + { + "markdown": " 1. A paragraph\n with two lines.\n", + "html": "
    \n
  1. A paragraph\nwith two lines.
  2. \n
\n", + "example": 261, + "start_line": 4494, + "end_line": 4502, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\ncontinued here.\n", + "html": "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
\n", + "example": 262, + "start_line": 4507, + "end_line": 4521, + "section": "List items" + }, + { + "markdown": "> 1. > Blockquote\n> continued here.\n", + "html": "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
\n", + "example": 263, + "start_line": 4524, + "end_line": 4538, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz\n
          \n
        • boo
        • \n
        \n
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 264, + "start_line": 4552, + "end_line": 4573, + "section": "List items" + }, + { + "markdown": "- foo\n - bar\n - baz\n - boo\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
  • baz
  • \n
  • boo
  • \n
\n", + "example": 265, + "start_line": 4578, + "end_line": 4590, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "
    \n
  1. foo\n
      \n
    • bar
    • \n
    \n
  2. \n
\n", + "example": 266, + "start_line": 4595, + "end_line": 4606, + "section": "List items" + }, + { + "markdown": "10) foo\n - bar\n", + "html": "
    \n
  1. foo
  2. \n
\n
    \n
  • bar
  • \n
\n", + "example": 267, + "start_line": 4611, + "end_line": 4621, + "section": "List items" + }, + { + "markdown": "- - foo\n", + "html": "
    \n
  • \n
      \n
    • foo
    • \n
    \n
  • \n
\n", + "example": 268, + "start_line": 4626, + "end_line": 4636, + "section": "List items" + }, + { + "markdown": "1. - 2. foo\n", + "html": "
    \n
  1. \n
      \n
    • \n
        \n
      1. foo
      2. \n
      \n
    • \n
    \n
  2. \n
\n", + "example": 269, + "start_line": 4639, + "end_line": 4653, + "section": "List items" + }, + { + "markdown": "- # Foo\n- Bar\n ---\n baz\n", + "html": "
    \n
  • \n

    Foo

    \n
  • \n
  • \n

    Bar

    \nbaz
  • \n
\n", + "example": 270, + "start_line": 4658, + "end_line": 4672, + "section": "List items" + }, + { + "markdown": "- foo\n- bar\n+ baz\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
\n
    \n
  • baz
  • \n
\n", + "example": 271, + "start_line": 4894, + "end_line": 4906, + "section": "Lists" + }, + { + "markdown": "1. foo\n2. bar\n3) baz\n", + "html": "
    \n
  1. foo
  2. \n
  3. bar
  4. \n
\n
    \n
  1. baz
  2. \n
\n", + "example": 272, + "start_line": 4909, + "end_line": 4921, + "section": "Lists" + }, + { + "markdown": "Foo\n- bar\n- baz\n", + "html": "

Foo

\n
    \n
  • bar
  • \n
  • baz
  • \n
\n", + "example": 273, + "start_line": 4928, + "end_line": 4938, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n", + "html": "

The number of windows in my house is\n14. The number of doors is 6.

\n", + "example": 274, + "start_line": 5005, + "end_line": 5011, + "section": "Lists" + }, + { + "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n", + "html": "

The number of windows in my house is

\n
    \n
  1. The number of doors is 6.
  2. \n
\n", + "example": 275, + "start_line": 5015, + "end_line": 5023, + "section": "Lists" + }, + { + "markdown": "- foo\n\n- bar\n\n\n- baz\n", + "html": "
    \n
  • \n

    foo

    \n
  • \n
  • \n

    bar

    \n
  • \n
  • \n

    baz

    \n
  • \n
\n", + "example": 276, + "start_line": 5029, + "end_line": 5048, + "section": "Lists" + }, + { + "markdown": "- foo\n - bar\n - baz\n\n\n bim\n", + "html": "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • \n

        baz

        \n

        bim

        \n
      • \n
      \n
    • \n
    \n
  • \n
\n", + "example": 277, + "start_line": 5050, + "end_line": 5072, + "section": "Lists" + }, + { + "markdown": "- foo\n- bar\n\n\n\n- baz\n- bim\n", + "html": "
    \n
  • foo
  • \n
  • bar
  • \n
\n\n
    \n
  • baz
  • \n
  • bim
  • \n
\n", + "example": 278, + "start_line": 5080, + "end_line": 5098, + "section": "Lists" + }, + { + "markdown": "- foo\n\n notcode\n\n- foo\n\n\n\n code\n", + "html": "
    \n
  • \n

    foo

    \n

    notcode

    \n
  • \n
  • \n

    foo

    \n
  • \n
\n\n
code\n
\n", + "example": 279, + "start_line": 5101, + "end_line": 5124, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n", + "html": "
    \n
  • a
  • \n
  • b
  • \n
  • c
  • \n
  • d
  • \n
  • e
  • \n
  • f
  • \n
  • g
  • \n
\n", + "example": 280, + "start_line": 5132, + "end_line": 5150, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
  5. \n

    c

    \n
  6. \n
\n", + "example": 281, + "start_line": 5153, + "end_line": 5171, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n - d\n - e\n", + "html": "
    \n
  • a
  • \n
  • b
  • \n
  • c
  • \n
  • d\n- e
  • \n
\n", + "example": 282, + "start_line": 5177, + "end_line": 5191, + "section": "Lists" + }, + { + "markdown": "1. a\n\n 2. b\n\n 3. c\n", + "html": "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
\n
3. c\n
\n", + "example": 283, + "start_line": 5197, + "end_line": 5214, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n- c\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    c

    \n
  • \n
\n", + "example": 284, + "start_line": 5220, + "end_line": 5237, + "section": "Lists" + }, + { + "markdown": "* a\n*\n\n* c\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n
  • \n

    c

    \n
  • \n
\n", + "example": 285, + "start_line": 5242, + "end_line": 5257, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n c\n- d\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n

    c

    \n
  • \n
  • \n

    d

    \n
  • \n
\n", + "example": 286, + "start_line": 5264, + "end_line": 5283, + "section": "Lists" + }, + { + "markdown": "- a\n- b\n\n [ref]: /url\n- d\n", + "html": "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    d

    \n
  • \n
\n", + "example": 287, + "start_line": 5286, + "end_line": 5304, + "section": "Lists" + }, + { + "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n", + "html": "
    \n
  • a
  • \n
  • \n
    b\n\n\n
    \n
  • \n
  • c
  • \n
\n", + "example": 288, + "start_line": 5309, + "end_line": 5328, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n\n c\n- d\n", + "html": "
    \n
  • a\n
      \n
    • \n

      b

      \n

      c

      \n
    • \n
    \n
  • \n
  • d
  • \n
\n", + "example": 289, + "start_line": 5335, + "end_line": 5353, + "section": "Lists" + }, + { + "markdown": "* a\n > b\n >\n* c\n", + "html": "
    \n
  • a\n
    \n

    b

    \n
    \n
  • \n
  • c
  • \n
\n", + "example": 290, + "start_line": 5359, + "end_line": 5373, + "section": "Lists" + }, + { + "markdown": "- a\n > b\n ```\n c\n ```\n- d\n", + "html": "
    \n
  • a\n
    \n

    b

    \n
    \n
    c\n
    \n
  • \n
  • d
  • \n
\n", + "example": 291, + "start_line": 5379, + "end_line": 5397, + "section": "Lists" + }, + { + "markdown": "- a\n", + "html": "
    \n
  • a
  • \n
\n", + "example": 292, + "start_line": 5402, + "end_line": 5408, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n", + "html": "
    \n
  • a\n
      \n
    • b
    • \n
    \n
  • \n
\n", + "example": 293, + "start_line": 5411, + "end_line": 5422, + "section": "Lists" + }, + { + "markdown": "1. ```\n foo\n ```\n\n bar\n", + "html": "
    \n
  1. \n
    foo\n
    \n

    bar

    \n
  2. \n
\n", + "example": 294, + "start_line": 5428, + "end_line": 5442, + "section": "Lists" + }, + { + "markdown": "* foo\n * bar\n\n baz\n", + "html": "
    \n
  • \n

    foo

    \n
      \n
    • bar
    • \n
    \n

    baz

    \n
  • \n
\n", + "example": 295, + "start_line": 5447, + "end_line": 5462, + "section": "Lists" + }, + { + "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n", + "html": "
    \n
  • \n

    a

    \n
      \n
    • b
    • \n
    • c
    • \n
    \n
  • \n
  • \n

    d

    \n
      \n
    • e
    • \n
    • f
    • \n
    \n
  • \n
\n", + "example": 296, + "start_line": 5465, + "end_line": 5490, + "section": "Lists" + }, + { + "markdown": "`hi`lo`\n", + "html": "

hilo`

\n", + "example": 297, + "start_line": 5499, + "end_line": 5503, + "section": "Inlines" + }, + { + "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n", + "html": "

!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~

\n", + "example": 298, + "start_line": 5513, + "end_line": 5517, + "section": "Backslash escapes" + }, + { + "markdown": "\\\t\\A\\a\\ \\3\\φ\\«\n", + "html": "

\\\t\\A\\a\\ \\3\\φ\\«

\n", + "example": 299, + "start_line": 5523, + "end_line": 5527, + "section": "Backslash escapes" + }, + { + "markdown": "\\*not emphasized*\n\\
not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n", + "html": "

*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity

\n", + "example": 300, + "start_line": 5533, + "end_line": 5553, + "section": "Backslash escapes" + }, + { + "markdown": "\\\\*emphasis*\n", + "html": "

\\emphasis

\n", + "example": 301, + "start_line": 5558, + "end_line": 5562, + "section": "Backslash escapes" + }, + { + "markdown": "foo\\\nbar\n", + "html": "

foo
\nbar

\n", + "example": 302, + "start_line": 5567, + "end_line": 5573, + "section": "Backslash escapes" + }, + { + "markdown": "`` \\[\\` ``\n", + "html": "

\\[\\`

\n", + "example": 303, + "start_line": 5579, + "end_line": 5583, + "section": "Backslash escapes" + }, + { + "markdown": " \\[\\]\n", + "html": "
\\[\\]\n
\n", + "example": 304, + "start_line": 5586, + "end_line": 5591, + "section": "Backslash escapes" + }, + { + "markdown": "~~~\n\\[\\]\n~~~\n", + "html": "
\\[\\]\n
\n", + "example": 305, + "start_line": 5594, + "end_line": 5601, + "section": "Backslash escapes" + }, + { + "markdown": "\n", + "html": "

http://example.com?find=\\*

\n", + "example": 306, + "start_line": 5604, + "end_line": 5608, + "section": "Backslash escapes" + }, + { + "markdown": "\n", + "html": "\n", + "example": 307, + "start_line": 5611, + "end_line": 5615, + "section": "Backslash escapes" + }, + { + "markdown": "[foo](/bar\\* \"ti\\*tle\")\n", + "html": "

foo

\n", + "example": 308, + "start_line": 5621, + "end_line": 5625, + "section": "Backslash escapes" + }, + { + "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n", + "html": "

foo

\n", + "example": 309, + "start_line": 5628, + "end_line": 5634, + "section": "Backslash escapes" + }, + { + "markdown": "``` foo\\+bar\nfoo\n```\n", + "html": "
foo\n
\n", + "example": 310, + "start_line": 5637, + "end_line": 5644, + "section": "Backslash escapes" + }, + { + "markdown": "  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n", + "html": "

  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸

\n", + "example": 311, + "start_line": 5674, + "end_line": 5682, + "section": "Entity and numeric character references" + }, + { + "markdown": "# Ӓ Ϡ �\n", + "html": "

# Ӓ Ϡ �

\n", + "example": 312, + "start_line": 5693, + "end_line": 5697, + "section": "Entity and numeric character references" + }, + { + "markdown": "" ആ ಫ\n", + "html": "

" ആ ಫ

\n", + "example": 313, + "start_line": 5706, + "end_line": 5710, + "section": "Entity and numeric character references" + }, + { + "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n", + "html": "

&nbsp &x; &#; &#x;\n&#987654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;

\n", + "example": 314, + "start_line": 5715, + "end_line": 5725, + "section": "Entity and numeric character references" + }, + { + "markdown": "©\n", + "html": "

&copy

\n", + "example": 315, + "start_line": 5732, + "end_line": 5736, + "section": "Entity and numeric character references" + }, + { + "markdown": "&MadeUpEntity;\n", + "html": "

&MadeUpEntity;

\n", + "example": 316, + "start_line": 5742, + "end_line": 5746, + "section": "Entity and numeric character references" + }, + { + "markdown": "\n", + "html": "\n", + "example": 317, + "start_line": 5753, + "end_line": 5757, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo](/föö \"föö\")\n", + "html": "

foo

\n", + "example": 318, + "start_line": 5760, + "end_line": 5764, + "section": "Entity and numeric character references" + }, + { + "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n", + "html": "

foo

\n", + "example": 319, + "start_line": 5767, + "end_line": 5773, + "section": "Entity and numeric character references" + }, + { + "markdown": "``` föö\nfoo\n```\n", + "html": "
foo\n
\n", + "example": 320, + "start_line": 5776, + "end_line": 5783, + "section": "Entity and numeric character references" + }, + { + "markdown": "`föö`\n", + "html": "

f&ouml;&ouml;

\n", + "example": 321, + "start_line": 5789, + "end_line": 5793, + "section": "Entity and numeric character references" + }, + { + "markdown": " föfö\n", + "html": "
f&ouml;f&ouml;\n
\n", + "example": 322, + "start_line": 5796, + "end_line": 5801, + "section": "Entity and numeric character references" + }, + { + "markdown": "*foo*\n*foo*\n", + "html": "

*foo*\nfoo

\n", + "example": 323, + "start_line": 5808, + "end_line": 5814, + "section": "Entity and numeric character references" + }, + { + "markdown": "* foo\n\n* foo\n", + "html": "

* foo

\n
    \n
  • foo
  • \n
\n", + "example": 324, + "start_line": 5816, + "end_line": 5825, + "section": "Entity and numeric character references" + }, + { + "markdown": "foo bar\n", + "html": "

foo\n\nbar

\n", + "example": 325, + "start_line": 5827, + "end_line": 5833, + "section": "Entity and numeric character references" + }, + { + "markdown": " foo\n", + "html": "

\tfoo

\n", + "example": 326, + "start_line": 5835, + "end_line": 5839, + "section": "Entity and numeric character references" + }, + { + "markdown": "[a](url "tit")\n", + "html": "

[a](url "tit")

\n", + "example": 327, + "start_line": 5842, + "end_line": 5846, + "section": "Entity and numeric character references" + }, + { + "markdown": "`foo`\n", + "html": "

foo

\n", + "example": 328, + "start_line": 5870, + "end_line": 5874, + "section": "Code spans" + }, + { + "markdown": "`` foo ` bar ``\n", + "html": "

foo ` bar

\n", + "example": 329, + "start_line": 5881, + "end_line": 5885, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "

``

\n", + "example": 330, + "start_line": 5891, + "end_line": 5895, + "section": "Code spans" + }, + { + "markdown": "` `` `\n", + "html": "

``

\n", + "example": 331, + "start_line": 5899, + "end_line": 5903, + "section": "Code spans" + }, + { + "markdown": "` a`\n", + "html": "

a

\n", + "example": 332, + "start_line": 5908, + "end_line": 5912, + "section": "Code spans" + }, + { + "markdown": "` b `\n", + "html": "

 b 

\n", + "example": 333, + "start_line": 5917, + "end_line": 5921, + "section": "Code spans" + }, + { + "markdown": "` `\n` `\n", + "html": "

 \n

\n", + "example": 334, + "start_line": 5925, + "end_line": 5931, + "section": "Code spans" + }, + { + "markdown": "``\nfoo\nbar \nbaz\n``\n", + "html": "

foo bar baz

\n", + "example": 335, + "start_line": 5936, + "end_line": 5944, + "section": "Code spans" + }, + { + "markdown": "``\nfoo \n``\n", + "html": "

foo

\n", + "example": 336, + "start_line": 5946, + "end_line": 5952, + "section": "Code spans" + }, + { + "markdown": "`foo bar \nbaz`\n", + "html": "

foo bar baz

\n", + "example": 337, + "start_line": 5957, + "end_line": 5962, + "section": "Code spans" + }, + { + "markdown": "`foo\\`bar`\n", + "html": "

foo\\bar`

\n", + "example": 338, + "start_line": 5974, + "end_line": 5978, + "section": "Code spans" + }, + { + "markdown": "``foo`bar``\n", + "html": "

foo`bar

\n", + "example": 339, + "start_line": 5985, + "end_line": 5989, + "section": "Code spans" + }, + { + "markdown": "` foo `` bar `\n", + "html": "

foo `` bar

\n", + "example": 340, + "start_line": 5991, + "end_line": 5995, + "section": "Code spans" + }, + { + "markdown": "*foo`*`\n", + "html": "

*foo*

\n", + "example": 341, + "start_line": 6003, + "end_line": 6007, + "section": "Code spans" + }, + { + "markdown": "[not a `link](/foo`)\n", + "html": "

[not a link](/foo)

\n", + "example": 342, + "start_line": 6012, + "end_line": 6016, + "section": "Code spans" + }, + { + "markdown": "``\n", + "html": "

<a href="">`

\n", + "example": 343, + "start_line": 6022, + "end_line": 6026, + "section": "Code spans" + }, + { + "markdown": "
`\n", + "html": "

`

\n", + "example": 344, + "start_line": 6031, + "end_line": 6035, + "section": "Code spans" + }, + { + "markdown": "``\n", + "html": "

<http://foo.bar.baz>`

\n", + "example": 345, + "start_line": 6040, + "end_line": 6044, + "section": "Code spans" + }, + { + "markdown": "`\n", + "html": "

http://foo.bar.`baz`

\n", + "example": 346, + "start_line": 6049, + "end_line": 6053, + "section": "Code spans" + }, + { + "markdown": "```foo``\n", + "html": "

```foo``

\n", + "example": 347, + "start_line": 6059, + "end_line": 6063, + "section": "Code spans" + }, + { + "markdown": "`foo\n", + "html": "

`foo

\n", + "example": 348, + "start_line": 6066, + "end_line": 6070, + "section": "Code spans" + }, + { + "markdown": "`foo``bar``\n", + "html": "

`foobar

\n", + "example": 349, + "start_line": 6075, + "end_line": 6079, + "section": "Code spans" + }, + { + "markdown": "*foo bar*\n", + "html": "

foo bar

\n", + "example": 350, + "start_line": 6292, + "end_line": 6296, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a * foo bar*\n", + "html": "

a * foo bar*

\n", + "example": 351, + "start_line": 6302, + "end_line": 6306, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a*\"foo\"*\n", + "html": "

a*"foo"*

\n", + "example": 352, + "start_line": 6313, + "end_line": 6317, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "* a *\n", + "html": "

* a *

\n", + "example": 353, + "start_line": 6322, + "end_line": 6326, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo*bar*\n", + "html": "

foobar

\n", + "example": 354, + "start_line": 6331, + "end_line": 6335, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5*6*78\n", + "html": "

5678

\n", + "example": 355, + "start_line": 6338, + "end_line": 6342, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar_\n", + "html": "

foo bar

\n", + "example": 356, + "start_line": 6347, + "end_line": 6351, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_ foo bar_\n", + "html": "

_ foo bar_

\n", + "example": 357, + "start_line": 6357, + "end_line": 6361, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a_\"foo\"_\n", + "html": "

a_"foo"_

\n", + "example": 358, + "start_line": 6367, + "end_line": 6371, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo_bar_\n", + "html": "

foo_bar_

\n", + "example": 359, + "start_line": 6376, + "end_line": 6380, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5_6_78\n", + "html": "

5_6_78

\n", + "example": 360, + "start_line": 6383, + "end_line": 6387, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням_стремятся_\n", + "html": "

пристаням_стремятся_

\n", + "example": 361, + "start_line": 6390, + "end_line": 6394, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "aa_\"bb\"_cc\n", + "html": "

aa_"bb"_cc

\n", + "example": 362, + "start_line": 6400, + "end_line": 6404, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-_(bar)_\n", + "html": "

foo-(bar)

\n", + "example": 363, + "start_line": 6411, + "end_line": 6415, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo*\n", + "html": "

_foo*

\n", + "example": 364, + "start_line": 6423, + "end_line": 6427, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar *\n", + "html": "

*foo bar *

\n", + "example": 365, + "start_line": 6433, + "end_line": 6437, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo bar\n*\n", + "html": "

*foo bar\n*

\n", + "example": 366, + "start_line": 6442, + "end_line": 6448, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo)\n", + "html": "

*(*foo)

\n", + "example": 367, + "start_line": 6455, + "end_line": 6459, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(*foo*)*\n", + "html": "

(foo)

\n", + "example": 368, + "start_line": 6465, + "end_line": 6469, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo*bar\n", + "html": "

foobar

\n", + "example": 369, + "start_line": 6474, + "end_line": 6478, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo bar _\n", + "html": "

_foo bar _

\n", + "example": 370, + "start_line": 6487, + "end_line": 6491, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo)\n", + "html": "

_(_foo)

\n", + "example": 371, + "start_line": 6497, + "end_line": 6501, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(_foo_)_\n", + "html": "

(foo)

\n", + "example": 372, + "start_line": 6506, + "end_line": 6510, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar\n", + "html": "

_foo_bar

\n", + "example": 373, + "start_line": 6515, + "end_line": 6519, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_пристаням_стремятся\n", + "html": "

_пристаням_стремятся

\n", + "example": 374, + "start_line": 6522, + "end_line": 6526, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo_bar_baz_\n", + "html": "

foo_bar_baz

\n", + "example": 375, + "start_line": 6529, + "end_line": 6533, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(bar)_.\n", + "html": "

(bar).

\n", + "example": 376, + "start_line": 6540, + "end_line": 6544, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar**\n", + "html": "

foo bar

\n", + "example": 377, + "start_line": 6549, + "end_line": 6553, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** foo bar**\n", + "html": "

** foo bar**

\n", + "example": 378, + "start_line": 6559, + "end_line": 6563, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a**\"foo\"**\n", + "html": "

a**"foo"**

\n", + "example": 379, + "start_line": 6570, + "end_line": 6574, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo**bar**\n", + "html": "

foobar

\n", + "example": 380, + "start_line": 6579, + "end_line": 6583, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar__\n", + "html": "

foo bar

\n", + "example": 381, + "start_line": 6588, + "end_line": 6592, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ foo bar__\n", + "html": "

__ foo bar__

\n", + "example": 382, + "start_line": 6598, + "end_line": 6602, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__\nfoo bar__\n", + "html": "

__\nfoo bar__

\n", + "example": 383, + "start_line": 6606, + "end_line": 6612, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "a__\"foo\"__\n", + "html": "

a__"foo"__

\n", + "example": 384, + "start_line": 6618, + "end_line": 6622, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo__bar__\n", + "html": "

foo__bar__

\n", + "example": 385, + "start_line": 6627, + "end_line": 6631, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "5__6__78\n", + "html": "

5__6__78

\n", + "example": 386, + "start_line": 6634, + "end_line": 6638, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "пристаням__стремятся__\n", + "html": "

пристаням__стремятся__

\n", + "example": 387, + "start_line": 6641, + "end_line": 6645, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo, __bar__, baz__\n", + "html": "

foo, bar, baz

\n", + "example": 388, + "start_line": 6648, + "end_line": 6652, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo-__(bar)__\n", + "html": "

foo-(bar)

\n", + "example": 389, + "start_line": 6659, + "end_line": 6663, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo bar **\n", + "html": "

**foo bar **

\n", + "example": 390, + "start_line": 6672, + "end_line": 6676, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**(**foo)\n", + "html": "

**(**foo)

\n", + "example": 391, + "start_line": 6685, + "end_line": 6689, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*(**foo**)*\n", + "html": "

(foo)

\n", + "example": 392, + "start_line": 6695, + "end_line": 6699, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n", + "html": "

Gomphocarpus (Gomphocarpus physocarpus, syn.\nAsclepias physocarpa)

\n", + "example": 393, + "start_line": 6702, + "end_line": 6708, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo \"*bar*\" foo**\n", + "html": "

foo "bar" foo

\n", + "example": 394, + "start_line": 6711, + "end_line": 6715, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**bar\n", + "html": "

foobar

\n", + "example": 395, + "start_line": 6720, + "end_line": 6724, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo bar __\n", + "html": "

__foo bar __

\n", + "example": 396, + "start_line": 6732, + "end_line": 6736, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(__foo)\n", + "html": "

__(__foo)

\n", + "example": 397, + "start_line": 6742, + "end_line": 6746, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_(__foo__)_\n", + "html": "

(foo)

\n", + "example": 398, + "start_line": 6752, + "end_line": 6756, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar\n", + "html": "

__foo__bar

\n", + "example": 399, + "start_line": 6761, + "end_line": 6765, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__пристаням__стремятся\n", + "html": "

__пристаням__стремятся

\n", + "example": 400, + "start_line": 6768, + "end_line": 6772, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__bar__baz__\n", + "html": "

foo__bar__baz

\n", + "example": 401, + "start_line": 6775, + "end_line": 6779, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__(bar)__.\n", + "html": "

(bar).

\n", + "example": 402, + "start_line": 6786, + "end_line": 6790, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [bar](/url)*\n", + "html": "

foo bar

\n", + "example": 403, + "start_line": 6798, + "end_line": 6802, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo\nbar*\n", + "html": "

foo\nbar

\n", + "example": 404, + "start_line": 6805, + "end_line": 6811, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo __bar__ baz_\n", + "html": "

foo bar baz

\n", + "example": 405, + "start_line": 6817, + "end_line": 6821, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo _bar_ baz_\n", + "html": "

foo bar baz

\n", + "example": 406, + "start_line": 6824, + "end_line": 6828, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_ bar_\n", + "html": "

foo bar

\n", + "example": 407, + "start_line": 6831, + "end_line": 6835, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar**\n", + "html": "

foo bar

\n", + "example": 408, + "start_line": 6838, + "end_line": 6842, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar** baz*\n", + "html": "

foo bar baz

\n", + "example": 409, + "start_line": 6845, + "end_line": 6849, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar**baz*\n", + "html": "

foobarbaz

\n", + "example": 410, + "start_line": 6851, + "end_line": 6855, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar*\n", + "html": "

foo**bar

\n", + "example": 411, + "start_line": 6875, + "end_line": 6879, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo** bar*\n", + "html": "

foo bar

\n", + "example": 412, + "start_line": 6888, + "end_line": 6892, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar***\n", + "html": "

foo bar

\n", + "example": 413, + "start_line": 6895, + "end_line": 6899, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**bar***\n", + "html": "

foobar

\n", + "example": 414, + "start_line": 6902, + "end_line": 6906, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo***bar***baz\n", + "html": "

foobarbaz

\n", + "example": 415, + "start_line": 6913, + "end_line": 6917, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo******bar*********baz\n", + "html": "

foobar***baz

\n", + "example": 416, + "start_line": 6919, + "end_line": 6923, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo **bar *baz* bim** bop*\n", + "html": "

foo bar baz bim bop

\n", + "example": 417, + "start_line": 6928, + "end_line": 6932, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo [*bar*](/url)*\n", + "html": "

foo bar

\n", + "example": 418, + "start_line": 6935, + "end_line": 6939, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "** is not an empty emphasis\n", + "html": "

** is not an empty emphasis

\n", + "example": 419, + "start_line": 6944, + "end_line": 6948, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**** is not an empty strong emphasis\n", + "html": "

**** is not an empty strong emphasis

\n", + "example": 420, + "start_line": 6951, + "end_line": 6955, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [bar](/url)**\n", + "html": "

foo bar

\n", + "example": 421, + "start_line": 6964, + "end_line": 6968, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo\nbar**\n", + "html": "

foo\nbar

\n", + "example": 422, + "start_line": 6971, + "end_line": 6977, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo _bar_ baz__\n", + "html": "

foo bar baz

\n", + "example": 423, + "start_line": 6983, + "end_line": 6987, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo __bar__ baz__\n", + "html": "

foo bar baz

\n", + "example": 424, + "start_line": 6990, + "end_line": 6994, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo__ bar__\n", + "html": "

foo bar

\n", + "example": 425, + "start_line": 6997, + "end_line": 7001, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar****\n", + "html": "

foo bar

\n", + "example": 426, + "start_line": 7004, + "end_line": 7008, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar* baz**\n", + "html": "

foo bar baz

\n", + "example": 427, + "start_line": 7011, + "end_line": 7015, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*bar*baz**\n", + "html": "

foobarbaz

\n", + "example": 428, + "start_line": 7018, + "end_line": 7022, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo* bar**\n", + "html": "

foo bar

\n", + "example": 429, + "start_line": 7025, + "end_line": 7029, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar***\n", + "html": "

foo bar

\n", + "example": 430, + "start_line": 7032, + "end_line": 7036, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo *bar **baz**\nbim* bop**\n", + "html": "

foo bar baz\nbim bop

\n", + "example": 431, + "start_line": 7041, + "end_line": 7047, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo [*bar*](/url)**\n", + "html": "

foo bar

\n", + "example": 432, + "start_line": 7050, + "end_line": 7054, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__ is not an empty emphasis\n", + "html": "

__ is not an empty emphasis

\n", + "example": 433, + "start_line": 7059, + "end_line": 7063, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____ is not an empty strong emphasis\n", + "html": "

____ is not an empty strong emphasis

\n", + "example": 434, + "start_line": 7066, + "end_line": 7070, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ***\n", + "html": "

foo ***

\n", + "example": 435, + "start_line": 7076, + "end_line": 7080, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *\\**\n", + "html": "

foo *

\n", + "example": 436, + "start_line": 7083, + "end_line": 7087, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *_*\n", + "html": "

foo _

\n", + "example": 437, + "start_line": 7090, + "end_line": 7094, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo *****\n", + "html": "

foo *****

\n", + "example": 438, + "start_line": 7097, + "end_line": 7101, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **\\***\n", + "html": "

foo *

\n", + "example": 439, + "start_line": 7104, + "end_line": 7108, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo **_**\n", + "html": "

foo _

\n", + "example": 440, + "start_line": 7111, + "end_line": 7115, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo*\n", + "html": "

*foo

\n", + "example": 441, + "start_line": 7122, + "end_line": 7126, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo**\n", + "html": "

foo*

\n", + "example": 442, + "start_line": 7129, + "end_line": 7133, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo**\n", + "html": "

*foo

\n", + "example": 443, + "start_line": 7136, + "end_line": 7140, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo*\n", + "html": "

***foo

\n", + "example": 444, + "start_line": 7143, + "end_line": 7147, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo***\n", + "html": "

foo*

\n", + "example": 445, + "start_line": 7150, + "end_line": 7154, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo****\n", + "html": "

foo***

\n", + "example": 446, + "start_line": 7157, + "end_line": 7161, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo ___\n", + "html": "

foo ___

\n", + "example": 447, + "start_line": 7167, + "end_line": 7171, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _\\__\n", + "html": "

foo _

\n", + "example": 448, + "start_line": 7174, + "end_line": 7178, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _*_\n", + "html": "

foo *

\n", + "example": 449, + "start_line": 7181, + "end_line": 7185, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo _____\n", + "html": "

foo _____

\n", + "example": 450, + "start_line": 7188, + "end_line": 7192, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __\\___\n", + "html": "

foo _

\n", + "example": 451, + "start_line": 7195, + "end_line": 7199, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "foo __*__\n", + "html": "

foo *

\n", + "example": 452, + "start_line": 7202, + "end_line": 7206, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo_\n", + "html": "

_foo

\n", + "example": 453, + "start_line": 7209, + "end_line": 7213, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo__\n", + "html": "

foo_

\n", + "example": 454, + "start_line": 7220, + "end_line": 7224, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "___foo__\n", + "html": "

_foo

\n", + "example": 455, + "start_line": 7227, + "end_line": 7231, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo_\n", + "html": "

___foo

\n", + "example": 456, + "start_line": 7234, + "end_line": 7238, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo___\n", + "html": "

foo_

\n", + "example": 457, + "start_line": 7241, + "end_line": 7245, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo____\n", + "html": "

foo___

\n", + "example": 458, + "start_line": 7248, + "end_line": 7252, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo**\n", + "html": "

foo

\n", + "example": 459, + "start_line": 7258, + "end_line": 7262, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*_foo_*\n", + "html": "

foo

\n", + "example": 460, + "start_line": 7265, + "end_line": 7269, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__foo__\n", + "html": "

foo

\n", + "example": 461, + "start_line": 7272, + "end_line": 7276, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_*foo*_\n", + "html": "

foo

\n", + "example": 462, + "start_line": 7279, + "end_line": 7283, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "****foo****\n", + "html": "

foo

\n", + "example": 463, + "start_line": 7289, + "end_line": 7293, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "____foo____\n", + "html": "

foo

\n", + "example": 464, + "start_line": 7296, + "end_line": 7300, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "******foo******\n", + "html": "

foo

\n", + "example": 465, + "start_line": 7307, + "end_line": 7311, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "***foo***\n", + "html": "

foo

\n", + "example": 466, + "start_line": 7316, + "end_line": 7320, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_____foo_____\n", + "html": "

foo

\n", + "example": 467, + "start_line": 7323, + "end_line": 7327, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo _bar* baz_\n", + "html": "

foo _bar baz_

\n", + "example": 468, + "start_line": 7332, + "end_line": 7336, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo __bar *baz bim__ bam*\n", + "html": "

foo bar *baz bim bam

\n", + "example": 469, + "start_line": 7339, + "end_line": 7343, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**foo **bar baz**\n", + "html": "

**foo bar baz

\n", + "example": 470, + "start_line": 7348, + "end_line": 7352, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*foo *bar baz*\n", + "html": "

*foo bar baz

\n", + "example": 471, + "start_line": 7355, + "end_line": 7359, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*[bar*](/url)\n", + "html": "

*bar*

\n", + "example": 472, + "start_line": 7364, + "end_line": 7368, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_foo [bar_](/url)\n", + "html": "

_foo bar_

\n", + "example": 473, + "start_line": 7371, + "end_line": 7375, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*\n", + "html": "

*

\n", + "example": 474, + "start_line": 7378, + "end_line": 7382, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**\n", + "html": "

**

\n", + "example": 475, + "start_line": 7385, + "end_line": 7389, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__\n", + "html": "

__

\n", + "example": 476, + "start_line": 7392, + "end_line": 7396, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "*a `*`*\n", + "html": "

a *

\n", + "example": 477, + "start_line": 7399, + "end_line": 7403, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "_a `_`_\n", + "html": "

a _

\n", + "example": 478, + "start_line": 7406, + "end_line": 7410, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "**a\n", + "html": "

**ahttp://foo.bar/?q=**

\n", + "example": 479, + "start_line": 7413, + "end_line": 7417, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "__a\n", + "html": "

__ahttp://foo.bar/?q=__

\n", + "example": 480, + "start_line": 7420, + "end_line": 7424, + "section": "Emphasis and strong emphasis" + }, + { + "markdown": "[link](/uri \"title\")\n", + "html": "

link

\n", + "example": 481, + "start_line": 7503, + "end_line": 7507, + "section": "Links" + }, + { + "markdown": "[link](/uri)\n", + "html": "

link

\n", + "example": 482, + "start_line": 7512, + "end_line": 7516, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

link

\n", + "example": 483, + "start_line": 7521, + "end_line": 7525, + "section": "Links" + }, + { + "markdown": "[link](<>)\n", + "html": "

link

\n", + "example": 484, + "start_line": 7528, + "end_line": 7532, + "section": "Links" + }, + { + "markdown": "[link](/my uri)\n", + "html": "

[link](/my uri)

\n", + "example": 485, + "start_line": 7537, + "end_line": 7541, + "section": "Links" + }, + { + "markdown": "[link](
)\n", + "html": "

link

\n", + "example": 486, + "start_line": 7543, + "end_line": 7547, + "section": "Links" + }, + { + "markdown": "[link](foo\nbar)\n", + "html": "

[link](foo\nbar)

\n", + "example": 487, + "start_line": 7552, + "end_line": 7558, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

[link]()

\n", + "example": 488, + "start_line": 7560, + "end_line": 7566, + "section": "Links" + }, + { + "markdown": "[a]()\n", + "html": "

a

\n", + "example": 489, + "start_line": 7571, + "end_line": 7575, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

[link](<foo>)

\n", + "example": 490, + "start_line": 7579, + "end_line": 7583, + "section": "Links" + }, + { + "markdown": "[a](\n[a](c)\n", + "html": "

[a](<b)c\n[a](<b)c>\n[a](c)

\n", + "example": 491, + "start_line": 7588, + "end_line": 7596, + "section": "Links" + }, + { + "markdown": "[link](\\(foo\\))\n", + "html": "

link

\n", + "example": 492, + "start_line": 7600, + "end_line": 7604, + "section": "Links" + }, + { + "markdown": "[link](foo(and(bar)))\n", + "html": "

link

\n", + "example": 493, + "start_line": 7609, + "end_line": 7613, + "section": "Links" + }, + { + "markdown": "[link](foo\\(and\\(bar\\))\n", + "html": "

link

\n", + "example": 494, + "start_line": 7618, + "end_line": 7622, + "section": "Links" + }, + { + "markdown": "[link]()\n", + "html": "

link

\n", + "example": 495, + "start_line": 7625, + "end_line": 7629, + "section": "Links" + }, + { + "markdown": "[link](foo\\)\\:)\n", + "html": "

link

\n", + "example": 496, + "start_line": 7635, + "end_line": 7639, + "section": "Links" + }, + { + "markdown": "[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)\n", + "html": "

link

\n

link

\n

link

\n", + "example": 497, + "start_line": 7644, + "end_line": 7654, + "section": "Links" + }, + { + "markdown": "[link](foo\\bar)\n", + "html": "

link

\n", + "example": 498, + "start_line": 7660, + "end_line": 7664, + "section": "Links" + }, + { + "markdown": "[link](foo%20bä)\n", + "html": "

link

\n", + "example": 499, + "start_line": 7676, + "end_line": 7680, + "section": "Links" + }, + { + "markdown": "[link](\"title\")\n", + "html": "

link

\n", + "example": 500, + "start_line": 7687, + "end_line": 7691, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n", + "html": "

link\nlink\nlink

\n", + "example": 501, + "start_line": 7696, + "end_line": 7704, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \\\""\")\n", + "html": "

link

\n", + "example": 502, + "start_line": 7710, + "end_line": 7714, + "section": "Links" + }, + { + "markdown": "[link](/url \"title\")\n", + "html": "

link

\n", + "example": 503, + "start_line": 7720, + "end_line": 7724, + "section": "Links" + }, + { + "markdown": "[link](/url \"title \"and\" title\")\n", + "html": "

[link](/url "title "and" title")

\n", + "example": 504, + "start_line": 7729, + "end_line": 7733, + "section": "Links" + }, + { + "markdown": "[link](/url 'title \"and\" title')\n", + "html": "

link

\n", + "example": 505, + "start_line": 7738, + "end_line": 7742, + "section": "Links" + }, + { + "markdown": "[link]( /uri\n \"title\" )\n", + "html": "

link

\n", + "example": 506, + "start_line": 7762, + "end_line": 7767, + "section": "Links" + }, + { + "markdown": "[link] (/uri)\n", + "html": "

[link] (/uri)

\n", + "example": 507, + "start_line": 7773, + "end_line": 7777, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]](/uri)\n", + "html": "

link [foo [bar]]

\n", + "example": 508, + "start_line": 7783, + "end_line": 7787, + "section": "Links" + }, + { + "markdown": "[link] bar](/uri)\n", + "html": "

[link] bar](/uri)

\n", + "example": 509, + "start_line": 7790, + "end_line": 7794, + "section": "Links" + }, + { + "markdown": "[link [bar](/uri)\n", + "html": "

[link bar

\n", + "example": 510, + "start_line": 7797, + "end_line": 7801, + "section": "Links" + }, + { + "markdown": "[link \\[bar](/uri)\n", + "html": "

link [bar

\n", + "example": 511, + "start_line": 7804, + "end_line": 7808, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*](/uri)\n", + "html": "

link foo bar #

\n", + "example": 512, + "start_line": 7813, + "end_line": 7817, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)](/uri)\n", + "html": "

\"moon\"

\n", + "example": 513, + "start_line": 7820, + "end_line": 7824, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)](/uri)\n", + "html": "

[foo bar](/uri)

\n", + "example": 514, + "start_line": 7829, + "end_line": 7833, + "section": "Links" + }, + { + "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n", + "html": "

[foo [bar baz](/uri)](/uri)

\n", + "example": 515, + "start_line": 7836, + "end_line": 7840, + "section": "Links" + }, + { + "markdown": "![[[foo](uri1)](uri2)](uri3)\n", + "html": "

\"[foo](uri2)\"

\n", + "example": 516, + "start_line": 7843, + "end_line": 7847, + "section": "Links" + }, + { + "markdown": "*[foo*](/uri)\n", + "html": "

*foo*

\n", + "example": 517, + "start_line": 7853, + "end_line": 7857, + "section": "Links" + }, + { + "markdown": "[foo *bar](baz*)\n", + "html": "

foo *bar

\n", + "example": 518, + "start_line": 7860, + "end_line": 7864, + "section": "Links" + }, + { + "markdown": "*foo [bar* baz]\n", + "html": "

foo [bar baz]

\n", + "example": 519, + "start_line": 7870, + "end_line": 7874, + "section": "Links" + }, + { + "markdown": "[foo \n", + "html": "

[foo

\n", + "example": 520, + "start_line": 7880, + "end_line": 7884, + "section": "Links" + }, + { + "markdown": "[foo`](/uri)`\n", + "html": "

[foo](/uri)

\n", + "example": 521, + "start_line": 7887, + "end_line": 7891, + "section": "Links" + }, + { + "markdown": "[foo\n", + "html": "

[foohttp://example.com/?search=](uri)

\n", + "example": 522, + "start_line": 7894, + "end_line": 7898, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n", + "html": "

foo

\n", + "example": 523, + "start_line": 7932, + "end_line": 7938, + "section": "Links" + }, + { + "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n", + "html": "

link [foo [bar]]

\n", + "example": 524, + "start_line": 7947, + "end_line": 7953, + "section": "Links" + }, + { + "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n", + "html": "

link [bar

\n", + "example": 525, + "start_line": 7956, + "end_line": 7962, + "section": "Links" + }, + { + "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n", + "html": "

link foo bar #

\n", + "example": 526, + "start_line": 7967, + "end_line": 7973, + "section": "Links" + }, + { + "markdown": "[![moon](moon.jpg)][ref]\n\n[ref]: /uri\n", + "html": "

\"moon\"

\n", + "example": 527, + "start_line": 7976, + "end_line": 7982, + "section": "Links" + }, + { + "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n", + "html": "

[foo bar]ref

\n", + "example": 528, + "start_line": 7987, + "end_line": 7993, + "section": "Links" + }, + { + "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n", + "html": "

[foo bar baz]ref

\n", + "example": 529, + "start_line": 7996, + "end_line": 8002, + "section": "Links" + }, + { + "markdown": "*[foo*][ref]\n\n[ref]: /uri\n", + "html": "

*foo*

\n", + "example": 530, + "start_line": 8011, + "end_line": 8017, + "section": "Links" + }, + { + "markdown": "[foo *bar][ref]\n\n[ref]: /uri\n", + "html": "

foo *bar

\n", + "example": 531, + "start_line": 8020, + "end_line": 8026, + "section": "Links" + }, + { + "markdown": "[foo \n\n[ref]: /uri\n", + "html": "

[foo

\n", + "example": 532, + "start_line": 8032, + "end_line": 8038, + "section": "Links" + }, + { + "markdown": "[foo`][ref]`\n\n[ref]: /uri\n", + "html": "

[foo][ref]

\n", + "example": 533, + "start_line": 8041, + "end_line": 8047, + "section": "Links" + }, + { + "markdown": "[foo\n\n[ref]: /uri\n", + "html": "

[foohttp://example.com/?search=][ref]

\n", + "example": 534, + "start_line": 8050, + "end_line": 8056, + "section": "Links" + }, + { + "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n", + "html": "

foo

\n", + "example": 535, + "start_line": 8061, + "end_line": 8067, + "section": "Links" + }, + { + "markdown": "[Толпой][Толпой] is a Russian word.\n\n[ТОЛПОЙ]: /url\n", + "html": "

Толпой is a Russian word.

\n", + "example": 536, + "start_line": 8072, + "end_line": 8078, + "section": "Links" + }, + { + "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n", + "html": "

Baz

\n", + "example": 537, + "start_line": 8084, + "end_line": 8091, + "section": "Links" + }, + { + "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n", + "html": "

[foo] bar

\n", + "example": 538, + "start_line": 8097, + "end_line": 8103, + "section": "Links" + }, + { + "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n", + "html": "

[foo]\nbar

\n", + "example": 539, + "start_line": 8106, + "end_line": 8114, + "section": "Links" + }, + { + "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n", + "html": "

bar

\n", + "example": 540, + "start_line": 8147, + "end_line": 8155, + "section": "Links" + }, + { + "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n", + "html": "

[bar][foo!]

\n", + "example": 541, + "start_line": 8162, + "end_line": 8168, + "section": "Links" + }, + { + "markdown": "[foo][ref[]\n\n[ref[]: /uri\n", + "html": "

[foo][ref[]

\n

[ref[]: /uri

\n", + "example": 542, + "start_line": 8174, + "end_line": 8181, + "section": "Links" + }, + { + "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n", + "html": "

[foo][ref[bar]]

\n

[ref[bar]]: /uri

\n", + "example": 543, + "start_line": 8184, + "end_line": 8191, + "section": "Links" + }, + { + "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n", + "html": "

[[[foo]]]

\n

[[[foo]]]: /url

\n", + "example": 544, + "start_line": 8194, + "end_line": 8201, + "section": "Links" + }, + { + "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n", + "html": "

foo

\n", + "example": 545, + "start_line": 8204, + "end_line": 8210, + "section": "Links" + }, + { + "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n", + "html": "

bar\\

\n", + "example": 546, + "start_line": 8215, + "end_line": 8221, + "section": "Links" + }, + { + "markdown": "[]\n\n[]: /uri\n", + "html": "

[]

\n

[]: /uri

\n", + "example": 547, + "start_line": 8226, + "end_line": 8233, + "section": "Links" + }, + { + "markdown": "[\n ]\n\n[\n ]: /uri\n", + "html": "

[\n]

\n

[\n]: /uri

\n", + "example": 548, + "start_line": 8236, + "end_line": 8247, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url \"title\"\n", + "html": "

foo

\n", + "example": 549, + "start_line": 8259, + "end_line": 8265, + "section": "Links" + }, + { + "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

foo bar

\n", + "example": 550, + "start_line": 8268, + "end_line": 8274, + "section": "Links" + }, + { + "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n", + "html": "

Foo

\n", + "example": 551, + "start_line": 8279, + "end_line": 8285, + "section": "Links" + }, + { + "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "

foo\n[]

\n", + "example": 552, + "start_line": 8292, + "end_line": 8300, + "section": "Links" + }, + { + "markdown": "[foo]\n\n[foo]: /url \"title\"\n", + "html": "

foo

\n", + "example": 553, + "start_line": 8312, + "end_line": 8318, + "section": "Links" + }, + { + "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

foo bar

\n", + "example": 554, + "start_line": 8321, + "end_line": 8327, + "section": "Links" + }, + { + "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

[foo bar]

\n", + "example": 555, + "start_line": 8330, + "end_line": 8336, + "section": "Links" + }, + { + "markdown": "[[bar [foo]\n\n[foo]: /url\n", + "html": "

[[bar foo

\n", + "example": 556, + "start_line": 8339, + "end_line": 8345, + "section": "Links" + }, + { + "markdown": "[Foo]\n\n[foo]: /url \"title\"\n", + "html": "

Foo

\n", + "example": 557, + "start_line": 8350, + "end_line": 8356, + "section": "Links" + }, + { + "markdown": "[foo] bar\n\n[foo]: /url\n", + "html": "

foo bar

\n", + "example": 558, + "start_line": 8361, + "end_line": 8367, + "section": "Links" + }, + { + "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "

[foo]

\n", + "example": 559, + "start_line": 8373, + "end_line": 8379, + "section": "Links" + }, + { + "markdown": "[foo*]: /url\n\n*[foo*]\n", + "html": "

*foo*

\n", + "example": 560, + "start_line": 8385, + "end_line": 8391, + "section": "Links" + }, + { + "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n", + "html": "

foo

\n", + "example": 561, + "start_line": 8397, + "end_line": 8404, + "section": "Links" + }, + { + "markdown": "[foo][]\n\n[foo]: /url1\n", + "html": "

foo

\n", + "example": 562, + "start_line": 8406, + "end_line": 8412, + "section": "Links" + }, + { + "markdown": "[foo]()\n\n[foo]: /url1\n", + "html": "

foo

\n", + "example": 563, + "start_line": 8416, + "end_line": 8422, + "section": "Links" + }, + { + "markdown": "[foo](not a link)\n\n[foo]: /url1\n", + "html": "

foo(not a link)

\n", + "example": 564, + "start_line": 8424, + "end_line": 8430, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url\n", + "html": "

[foo]bar

\n", + "example": 565, + "start_line": 8435, + "end_line": 8441, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n", + "html": "

foobaz

\n", + "example": 566, + "start_line": 8447, + "end_line": 8454, + "section": "Links" + }, + { + "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n", + "html": "

[foo]bar

\n", + "example": 567, + "start_line": 8460, + "end_line": 8467, + "section": "Links" + }, + { + "markdown": "![foo](/url \"title\")\n", + "html": "

\"foo\"

\n", + "example": 568, + "start_line": 8483, + "end_line": 8487, + "section": "Images" + }, + { + "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 569, + "start_line": 8490, + "end_line": 8496, + "section": "Images" + }, + { + "markdown": "![foo ![bar](/url)](/url2)\n", + "html": "

\"foo

\n", + "example": 570, + "start_line": 8499, + "end_line": 8503, + "section": "Images" + }, + { + "markdown": "![foo [bar](/url)](/url2)\n", + "html": "

\"foo

\n", + "example": 571, + "start_line": 8506, + "end_line": 8510, + "section": "Images" + }, + { + "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 572, + "start_line": 8520, + "end_line": 8526, + "section": "Images" + }, + { + "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n", + "html": "

\"foo

\n", + "example": 573, + "start_line": 8529, + "end_line": 8535, + "section": "Images" + }, + { + "markdown": "![foo](train.jpg)\n", + "html": "

\"foo\"

\n", + "example": 574, + "start_line": 8538, + "end_line": 8542, + "section": "Images" + }, + { + "markdown": "My ![foo bar](/path/to/train.jpg \"title\" )\n", + "html": "

My \"foo

\n", + "example": 575, + "start_line": 8545, + "end_line": 8549, + "section": "Images" + }, + { + "markdown": "![foo]()\n", + "html": "

\"foo\"

\n", + "example": 576, + "start_line": 8552, + "end_line": 8556, + "section": "Images" + }, + { + "markdown": "![](/url)\n", + "html": "

\"\"

\n", + "example": 577, + "start_line": 8559, + "end_line": 8563, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[bar]: /url\n", + "html": "

\"foo\"

\n", + "example": 578, + "start_line": 8568, + "end_line": 8574, + "section": "Images" + }, + { + "markdown": "![foo][bar]\n\n[BAR]: /url\n", + "html": "

\"foo\"

\n", + "example": 579, + "start_line": 8577, + "end_line": 8583, + "section": "Images" + }, + { + "markdown": "![foo][]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"

\n", + "example": 580, + "start_line": 8588, + "end_line": 8594, + "section": "Images" + }, + { + "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

\"foo

\n", + "example": 581, + "start_line": 8597, + "end_line": 8603, + "section": "Images" + }, + { + "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n", + "html": "

\"Foo\"

\n", + "example": 582, + "start_line": 8608, + "end_line": 8614, + "section": "Images" + }, + { + "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"\n[]

\n", + "example": 583, + "start_line": 8620, + "end_line": 8628, + "section": "Images" + }, + { + "markdown": "![foo]\n\n[foo]: /url \"title\"\n", + "html": "

\"foo\"

\n", + "example": 584, + "start_line": 8633, + "end_line": 8639, + "section": "Images" + }, + { + "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n", + "html": "

\"foo

\n", + "example": 585, + "start_line": 8642, + "end_line": 8648, + "section": "Images" + }, + { + "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n", + "html": "

![[foo]]

\n

[[foo]]: /url "title"

\n", + "example": 586, + "start_line": 8653, + "end_line": 8660, + "section": "Images" + }, + { + "markdown": "![Foo]\n\n[foo]: /url \"title\"\n", + "html": "

\"Foo\"

\n", + "example": 587, + "start_line": 8665, + "end_line": 8671, + "section": "Images" + }, + { + "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n", + "html": "

![foo]

\n", + "example": 588, + "start_line": 8677, + "end_line": 8683, + "section": "Images" + }, + { + "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n", + "html": "

!foo

\n", + "example": 589, + "start_line": 8689, + "end_line": 8695, + "section": "Images" + }, + { + "markdown": "\n", + "html": "

http://foo.bar.baz

\n", + "example": 590, + "start_line": 8722, + "end_line": 8726, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

http://foo.bar.baz/test?q=hello&id=22&boolean

\n", + "example": 591, + "start_line": 8729, + "end_line": 8733, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

irc://foo.bar:2233/baz

\n", + "example": 592, + "start_line": 8736, + "end_line": 8740, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

MAILTO:FOO@BAR.BAZ

\n", + "example": 593, + "start_line": 8745, + "end_line": 8749, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

a+b+c:d

\n", + "example": 594, + "start_line": 8757, + "end_line": 8761, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

made-up-scheme://foo,bar

\n", + "example": 595, + "start_line": 8764, + "end_line": 8768, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

http://../

\n", + "example": 596, + "start_line": 8771, + "end_line": 8775, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

localhost:5001/foo

\n", + "example": 597, + "start_line": 8778, + "end_line": 8782, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<http://foo.bar/baz bim>

\n", + "example": 598, + "start_line": 8787, + "end_line": 8791, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

http://example.com/\\[\\

\n", + "example": 599, + "start_line": 8796, + "end_line": 8800, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

foo@bar.example.com

\n", + "example": 600, + "start_line": 8818, + "end_line": 8822, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

foo+special@Bar.baz-bar0.com

\n", + "example": 601, + "start_line": 8825, + "end_line": 8829, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<foo+@bar.example.com>

\n", + "example": 602, + "start_line": 8834, + "end_line": 8838, + "section": "Autolinks" + }, + { + "markdown": "<>\n", + "html": "

<>

\n", + "example": 603, + "start_line": 8843, + "end_line": 8847, + "section": "Autolinks" + }, + { + "markdown": "< http://foo.bar >\n", + "html": "

< http://foo.bar >

\n", + "example": 604, + "start_line": 8850, + "end_line": 8854, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<m:abc>

\n", + "example": 605, + "start_line": 8857, + "end_line": 8861, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

<foo.bar.baz>

\n", + "example": 606, + "start_line": 8864, + "end_line": 8868, + "section": "Autolinks" + }, + { + "markdown": "http://example.com\n", + "html": "

http://example.com

\n", + "example": 607, + "start_line": 8871, + "end_line": 8875, + "section": "Autolinks" + }, + { + "markdown": "foo@bar.example.com\n", + "html": "

foo@bar.example.com

\n", + "example": 608, + "start_line": 8878, + "end_line": 8882, + "section": "Autolinks" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 609, + "start_line": 8960, + "end_line": 8964, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 610, + "start_line": 8969, + "end_line": 8973, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 611, + "start_line": 8978, + "end_line": 8984, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 612, + "start_line": 8989, + "end_line": 8995, + "section": "Raw HTML" + }, + { + "markdown": "Foo \n", + "html": "

Foo

\n", + "example": 613, + "start_line": 9000, + "end_line": 9004, + "section": "Raw HTML" + }, + { + "markdown": "<33> <__>\n", + "html": "

<33> <__>

\n", + "example": 614, + "start_line": 9009, + "end_line": 9013, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a h*#ref="hi">

\n", + "example": 615, + "start_line": 9018, + "end_line": 9022, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a href="hi'> <a href=hi'>

\n", + "example": 616, + "start_line": 9027, + "end_line": 9031, + "section": "Raw HTML" + }, + { + "markdown": "< a><\nfoo>\n\n", + "html": "

< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />

\n", + "example": 617, + "start_line": 9036, + "end_line": 9046, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

<a href='bar'title=title>

\n", + "example": 618, + "start_line": 9051, + "end_line": 9055, + "section": "Raw HTML" + }, + { + "markdown": "
\n", + "html": "

\n", + "example": 619, + "start_line": 9060, + "end_line": 9064, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

</a href="foo">

\n", + "example": 620, + "start_line": 9069, + "end_line": 9073, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 621, + "start_line": 9078, + "end_line": 9084, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo <!-- not a comment -- two hyphens -->

\n", + "example": 622, + "start_line": 9087, + "end_line": 9091, + "section": "Raw HTML" + }, + { + "markdown": "foo foo -->\n\nfoo \n", + "html": "

foo <!--> foo -->

\n

foo <!-- foo--->

\n", + "example": 623, + "start_line": 9096, + "end_line": 9103, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 624, + "start_line": 9108, + "end_line": 9112, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 625, + "start_line": 9117, + "end_line": 9121, + "section": "Raw HTML" + }, + { + "markdown": "foo &<]]>\n", + "html": "

foo &<]]>

\n", + "example": 626, + "start_line": 9126, + "end_line": 9130, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 627, + "start_line": 9136, + "end_line": 9140, + "section": "Raw HTML" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 628, + "start_line": 9145, + "end_line": 9149, + "section": "Raw HTML" + }, + { + "markdown": "\n", + "html": "

<a href=""">

\n", + "example": 629, + "start_line": 9152, + "end_line": 9156, + "section": "Raw HTML" + }, + { + "markdown": "foo \nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 630, + "start_line": 9166, + "end_line": 9172, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 631, + "start_line": 9178, + "end_line": 9184, + "section": "Hard line breaks" + }, + { + "markdown": "foo \nbaz\n", + "html": "

foo
\nbaz

\n", + "example": 632, + "start_line": 9189, + "end_line": 9195, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n bar\n", + "html": "

foo
\nbar

\n", + "example": 633, + "start_line": 9200, + "end_line": 9206, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n bar\n", + "html": "

foo
\nbar

\n", + "example": 634, + "start_line": 9209, + "end_line": 9215, + "section": "Hard line breaks" + }, + { + "markdown": "*foo \nbar*\n", + "html": "

foo
\nbar

\n", + "example": 635, + "start_line": 9221, + "end_line": 9227, + "section": "Hard line breaks" + }, + { + "markdown": "*foo\\\nbar*\n", + "html": "

foo
\nbar

\n", + "example": 636, + "start_line": 9230, + "end_line": 9236, + "section": "Hard line breaks" + }, + { + "markdown": "`code \nspan`\n", + "html": "

code span

\n", + "example": 637, + "start_line": 9241, + "end_line": 9246, + "section": "Hard line breaks" + }, + { + "markdown": "`code\\\nspan`\n", + "html": "

code\\ span

\n", + "example": 638, + "start_line": 9249, + "end_line": 9254, + "section": "Hard line breaks" + }, + { + "markdown": "
\n", + "html": "

\n", + "example": 639, + "start_line": 9259, + "end_line": 9265, + "section": "Hard line breaks" + }, + { + "markdown": "\n", + "html": "

\n", + "example": 640, + "start_line": 9268, + "end_line": 9274, + "section": "Hard line breaks" + }, + { + "markdown": "foo\\\n", + "html": "

foo\\

\n", + "example": 641, + "start_line": 9281, + "end_line": 9285, + "section": "Hard line breaks" + }, + { + "markdown": "foo \n", + "html": "

foo

\n", + "example": 642, + "start_line": 9288, + "end_line": 9292, + "section": "Hard line breaks" + }, + { + "markdown": "### foo\\\n", + "html": "

foo\\

\n", + "example": 643, + "start_line": 9295, + "end_line": 9299, + "section": "Hard line breaks" + }, + { + "markdown": "### foo \n", + "html": "

foo

\n", + "example": 644, + "start_line": 9302, + "end_line": 9306, + "section": "Hard line breaks" + }, + { + "markdown": "foo\nbaz\n", + "html": "

foo\nbaz

\n", + "example": 645, + "start_line": 9317, + "end_line": 9323, + "section": "Soft line breaks" + }, + { + "markdown": "foo \n baz\n", + "html": "

foo\nbaz

\n", + "example": 646, + "start_line": 9329, + "end_line": 9335, + "section": "Soft line breaks" + }, + { + "markdown": "hello $.;'there\n", + "html": "

hello $.;'there

\n", + "example": 647, + "start_line": 9349, + "end_line": 9353, + "section": "Textual content" + }, + { + "markdown": "Foo χρῆν\n", + "html": "

Foo χρῆν

\n", + "example": 648, + "start_line": 9356, + "end_line": 9360, + "section": "Textual content" + }, + { + "markdown": "Multiple spaces\n", + "html": "

Multiple spaces

\n", + "example": 649, + "start_line": 9365, + "end_line": 9369, + "section": "Textual content" + } +] \ No newline at end of file diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates.jl b/.julia-depot/packages/CommonMark/lmLkP/test/templates.jl new file mode 100644 index 0000000..cb5e1c1 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates.jl @@ -0,0 +1,120 @@ +test_template_str(filename) = read(joinpath(@__DIR__, "templates", filename), String) + +@testset "Templates" begin + p = Parser() + + ast = p("*word*") + dict = Dict("template-engine" => render) + + test = function (a, b) + norm = s -> replace(s, "\r\n" => "\n") + @test norm(a) == norm(b) + end + + # Basic. + + test(html(ast, dict), test_template_str("basic.html")) + test(latex(ast, dict), test_template_str("basic.tex")) + + # Ignore templates. + test(markdown(ast, dict), "*word*\n") + test(term(ast, dict), " \e[3mword\e[23m\n") + test(join(JSON.parse(notebook(ast, dict))["cells"][1]["source"]), "*word*\n") + + # Global Configuration. + + env = merge( + dict, + Dict( + "date" => "DATE", + "authors" => ["ONE", "TWO"], + "title" => "TITLE", + "subtitle" => "SUBTITLE", + "abstract" => "ABSTRACT", + "keywords" => ["1", "2"], + "lang" => "fr", + "html" => Dict( + "css" => ["one.css", "two.css"], + "js" => ["one.js", "two.js"], + "header" => "", + "footer" => "
", + ), + "latex" => + Dict("documentclass" => "book", "preamble" => "\\usepackage{custom}"), + ), + ) + + test(html(ast, env), test_template_str("env.html")) + test(latex(ast, env), test_template_str("env.tex")) + + # Ignore templates. + test(markdown(ast, env), "*word*\n") + test(term(ast, env), " \e[3mword\e[23m\n") + test(join(JSON.parse(notebook(ast, env))["cells"][1]["source"]), "*word*\n") + + # Front Matter Configuration. + + p = enable!(Parser(), FrontMatterRule(toml = TOML.parse)) + text = """ + +++ + authors = ["THREE", "FOUR"] + title = "NEW TITLE" + abstract = "NEW ABSTRACT" + keywords = ["3", "4"] + +++ + + *word* + """ + ast = p(text) + + test(html(ast, dict), test_template_str("frontmatter.html")) + test(latex(ast, dict), test_template_str("frontmatter.tex")) + + # Ignore templates. + test(markdown(ast, dict), text) + test(term(ast, dict), " \e[3mword\e[23m\n") + test(join(JSON.parse(notebook(ast, dict))["cells"][1]["source"]), text) + + # Front Matter and Global Configuration. + + test(html(ast, env), test_template_str("frontmatter-env.html")) + test(latex(ast, env), test_template_str("frontmatter-env.tex")) + + # Ignore templates. + test(markdown(ast, env), text) + test(term(ast, env), " \e[3mword\e[23m\n") + test(join(JSON.parse(notebook(ast, env))["cells"][1]["source"]), text) + + # File and string templates. + + text = """ + +++ + [html.template] + file = "templates/custom-template.html.mustache" + [latex.template] + file = "templates/custom-template.latex.mustache" + +++ + + *word* + """ + ast = p(text) + cd(@__DIR__) do + test(html(ast, env), "
\n

word

\n\n
\n") + test( + latex(ast, env), + "\\documentclass{memoir}\n\\begin{document}\n\\textit{word}\\par\n\n\\end{document}\n", + ) + end + + config = """ + [html.template] + string = "\\n\${{body}}" + [latex.template] + string = "\\\\begin{document}\\n\${{body}}\\\\end{document}" + """ + env = merge(dict, TOML.parse(config)) + cd(@__DIR__) do + test(html(ast, env), "\n

word

\n") + test(latex(ast, env), "\\begin{document}\n\\textit{word}\\par\n\\end{document}") + end +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.html b/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.html new file mode 100644 index 0000000..9fde1d6 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.html @@ -0,0 +1,16 @@ + + + + + + + + + + + +

word

+ + + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.tex b/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.tex new file mode 100644 index 0000000..14ae928 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/basic.tex @@ -0,0 +1,22 @@ +\documentclass{article} + +\usepackage{fontspec} +\usepackage{amssymb,amsmath} +\defaultfontfeatures{Scale=MatchLowercase} +\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\usepackage{hyperref} + +\author{} + + + +\begin{document} + + + +\tableofcontents + +\textit{word}\par + + +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.html.mustache b/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.html.mustache new file mode 100644 index 0000000..c853930 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.html.mustache @@ -0,0 +1,3 @@ +
+${{body}} +
diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.latex.mustache b/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.latex.mustache new file mode 100644 index 0000000..e5b1c57 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/custom-template.latex.mustache @@ -0,0 +1,4 @@ +\documentclass{memoir} +\begin{document} +${{body}} +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.html b/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.html new file mode 100644 index 0000000..160cec5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.html @@ -0,0 +1,22 @@ + + + + + + + + + + TITLE + + + + + + + +

word

+ +
+ + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.tex b/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.tex new file mode 100644 index 0000000..aa7b9ec --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/env.tex @@ -0,0 +1,29 @@ +\documentclass{book} + +\usepackage{fontspec} +\usepackage{amssymb,amsmath} +\defaultfontfeatures{Scale=MatchLowercase} +\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\usepackage{hyperref} + +\title{TITLE} +\subtitle{SUBTITLE} +\author{ONE \and TWO} +\date{DATE} + +\usepackage{custom} + +\begin{document} + +\maketitle + +\begin{abstract} +ABSTRACT +\end{abstract} + +\tableofcontents + +\textit{word}\par + + +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.html b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.html new file mode 100644 index 0000000..23e7f41 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.html @@ -0,0 +1,22 @@ + + + + + + + + + + NEW TITLE + + + + + + + +

word

+ +
+ + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.tex b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.tex new file mode 100644 index 0000000..0b12d09 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter-env.tex @@ -0,0 +1,29 @@ +\documentclass{book} + +\usepackage{fontspec} +\usepackage{amssymb,amsmath} +\defaultfontfeatures{Scale=MatchLowercase} +\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\usepackage{hyperref} + +\title{NEW TITLE} +\subtitle{SUBTITLE} +\author{THREE \and FOUR} +\date{DATE} + +\usepackage{custom} + +\begin{document} + +\maketitle + +\begin{abstract} +NEW ABSTRACT +\end{abstract} + +\tableofcontents + +\textit{word}\par + + +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.html b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.html new file mode 100644 index 0000000..2f12bc4 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.html @@ -0,0 +1,18 @@ + + + + + + + + + + NEW TITLE + + + +

word

+ + + + diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.tex b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.tex new file mode 100644 index 0000000..635bd55 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/templates/frontmatter.tex @@ -0,0 +1,27 @@ +\documentclass{article} + +\usepackage{fontspec} +\usepackage{amssymb,amsmath} +\defaultfontfeatures{Scale=MatchLowercase} +\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\usepackage{hyperref} + +\title{NEW TITLE} +\author{THREE \and FOUR} + + + +\begin{document} + +\maketitle + +\begin{abstract} +NEW ABSTRACT +\end{abstract} + +\tableofcontents + +\textit{word}\par + + +\end{document} diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/unicodes.jl b/.julia-depot/packages/CommonMark/lmLkP/test/unicodes.jl new file mode 100644 index 0000000..c080acb --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/unicodes.jl @@ -0,0 +1,7 @@ +@testset "Unicodes" begin + p = Parser() + enable!(p, AdmonitionRule()) + text = "!!! note \"Ju 的文字\"\n Ju\n" + @test html(p(text)) == + "

Ju 的文字

\n

Ju

\n
" +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers.jl new file mode 100644 index 0000000..7c9076b --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers.jl @@ -0,0 +1,5 @@ +include("writers/latex.jl") +include("writers/term.jl") +include("writers/markdown.jl") +include("writers/notebook.jl") +include("writers/typst.jl") diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers/latex.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers/latex.jl new file mode 100644 index 0000000..7935745 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers/latex.jl @@ -0,0 +1,78 @@ +@testset "LaTeX" begin + p = Parser() + + test = function (text, expected) + ast = p(text) + @test latex(ast) == expected + end + + # Code blocks. + test("`code`", "\\texttt{code}\\par\n") + # Inline HTML. + test("text", "text\\par\n") + # Links. + test("[link](url)", "\\href{url}{link}\\par\n") + # Images. + test( + "![link](url)", + "\\begin{figure}\n\\centering\n\\includegraphics[max width=\\linewidth]{url}\n\\caption{link}\n\\end{figure}\n\\par\n", + ) + # Emphasis. + test("*text*", "\\textit{text}\\par\n") + # Strong. + test("**text**", "\\textbf{text}\\par\n") + # Headings. + test("# h1", "\\section{h1}\n") + test("## h2", "\\subsection{h2}\n") + test("### h3", "\\subsubsection{h3}\n") + test("#### h4", "\\paragraph{h4}\n") + test("##### h5", "\\subparagraph{h5}\n") + test("###### h6", "\\subsubparagraph{h6}\n") + # Block quotes. + test("> quote", "\\begin{quote}\nquote\\par\n\\end{quote}\n") + # Lists. + test( + "- item", + "\\begin{itemize}\n\\setlength{\\itemsep}{0pt}\n\\setlength{\\parskip}{0pt}\n\\item\nitem\\par\n\\end{itemize}\n", + ) + test( + "1. item", + "\\begin{enumerate}\n\\def\\labelenumi{\\arabic{enumi}.}\n\\setcounter{enumi}{0}\n\\setlength{\\itemsep}{0pt}\n\\setlength{\\parskip}{0pt}\n\\item\nitem\\par\n\\end{enumerate}\n", + ) + test( + "3. item", + "\\begin{enumerate}\n\\def\\labelenumi{\\arabic{enumi}.}\n\\setcounter{enumi}{2}\n\\setlength{\\itemsep}{0pt}\n\\setlength{\\parskip}{0pt}\n\\item\nitem\\par\n\\end{enumerate}\n", + ) + test( + "- item\n- item", + "\\begin{itemize}\n\\setlength{\\itemsep}{0pt}\n\\setlength{\\parskip}{0pt}\n\\item\nitem\\par\n\\item\nitem\\par\n\\end{itemize}\n", + ) + test( + "1. item\n2. item", + "\\begin{enumerate}\n\\def\\labelenumi{\\arabic{enumi}.}\n\\setcounter{enumi}{0}\n\\setlength{\\itemsep}{0pt}\n\\setlength{\\parskip}{0pt}\n\\item\nitem\\par\n\\item\nitem\\par\n\\end{enumerate}\n", + ) + test( + "- item\n\n- item", + "\\begin{itemize}\n\\item\nitem\\par\n\\item\nitem\\par\n\\end{itemize}\n", + ) + + # Thematic Breaks. + test("***", "\\par\\bigskip\\noindent\\hrulefill\\par\\bigskip\n") + # Code blocks. + test( + """ + code + """, + "\\begin{verbatim}\ncode\n\\end{verbatim}\n", + ) + test( + """ + ``` + code + ``` + """, + "\\begin{lstlisting}\ncode\n\\end{lstlisting}\n", + ) + # Escapes. + test("^~\\&%\$#_{}", "\\^{}{\\textasciitilde}\\&\\%\\\$\\#\\_\\{\\}\\par\n") +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers/markdown.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers/markdown.jl new file mode 100644 index 0000000..3fe247e --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers/markdown.jl @@ -0,0 +1,92 @@ +@testset "Markdown" begin + p = Parser() + + test = function (text, expected) + ast = p(text) + @test markdown(ast) == expected + @test markdown(p(markdown(ast))) == expected # Is markdown output round-trip-able? + end + + # Code blocks. + test("`code`", "`code`\n") + # Inline HTML. + test("text", "text\n") + # Links. + test("[link](url)", "[link](url)\n") + # Images. + test("![link](url)", "![link](url)\n") + # Emphasis. + test("*text*", "*text*\n") + # Strong. + test("**text**", "**text**\n") + # Emphasis. + test("_text_", "_text_\n") + # Strong. + test("__text__", "__text__\n") + # Emphasis. + test("_**text**_", "_**text**_\n") + # Strong. + test("*__text__*", "*__text__*\n") + # Headings. + test("# h1", "# h1\n") + test("## h2", "## h2\n") + test("### h3", "### h3\n") + test("#### h4", "#### h4\n") + test("##### h5", "##### h5\n") + test("###### h6", "###### h6\n") + # Block quotes. + test("> quote", "> quote\n") + test(">", ">\n") + # Lists. + test( + "1. one\n2. 5. five\n 6. six\n3. three\n4. four\n", + " 1. one\n 2. 5. five\n 6. six\n 3. three\n 4. four\n", + ) + test("- - - - - - - item", " - + * - + * * item\n") + test(" - ", " - ") + test("1. ", " 1. ") + test(" - one\n - \n - three\n", " - one\n - \n - three\n") + test("1. one\n2.\n3. three", " 1. one\n 2. \n 3. three\n") + # Thematic Breaks. + test("***", "* * *\n") + # Code blocks. + test( + """ + ```julia + code + ``` + """, + "```julia\ncode\n```\n", + ) + test( + """ + code + """, + " code\n", + ) + test( + """ + ```jldoctest + julia> a = 1 + 1 + + julia> b = 2 + 2 + ``` + """, + "```jldoctest\njulia> a = 1\n1\n\njulia> b = 2\n2\n```\n", + ) + test( + """ + julia> a = 1 + 1 + + julia> b = 2 + 2 + """, + " julia> a = 1\n 1\n\n julia> b = 2\n 2\n", + ) + # Escapes. + test("\\\\", "\\\\\n") + test("\\`x\\`", "\\`x\\`\n") +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers/notebook.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers/notebook.jl new file mode 100644 index 0000000..4bdfaf9 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers/notebook.jl @@ -0,0 +1,54 @@ +@testset "Notebook" begin + p = Parser() + + test = function (text, expected) + ast = p(text) + json = JSON.Parser.parse(notebook(ast)) + @test join(json["cells"][1]["source"]) == expected + end + + # Code blocks. + test("`code`", "`code`\n") + # Inline HTML. + test("text", "text\n") + # Links. + test("[link](url)", "[link](url)\n") + # Images. + test("![link](url)", "![link](url)\n") + # Emphasis. + test("*text*", "*text*\n") + # Strong. + test("**text**", "**text**\n") + # Headings. + test("# h1", "# h1\n") + test("## h2", "## h2\n") + test("### h3", "### h3\n") + test("#### h4", "#### h4\n") + test("##### h5", "##### h5\n") + test("###### h6", "###### h6\n") + # Block quotes. + test("> quote", "> quote\n") + # Lists. + test( + "1. one\n2. 5. five\n 6. six\n3. three\n4. four\n", + " 1. one\n 2. 5. five\n 6. six\n 3. three\n 4. four\n", + ) + test("- - - - - - - item", " - + * - + * * item\n") + # Thematic Breaks. + test("***", "* * *\n") + # Code blocks. + test( + """ + ```julia + code + ``` + """, + "code", + ) + test( + """ + code + """, + " code\n", + ) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers/term.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers/term.jl new file mode 100644 index 0000000..9826eaf --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers/term.jl @@ -0,0 +1,56 @@ +@testset "Terminal" begin + p = Parser() + + test = function (text, expected) + ast = p(text) + @test term(ast) == expected + end + + # Code blocks. + test("`code`", " \e[36mcode\e[39m\n") + # Inline HTML. + test("text", " \e[90m\e[39mtext\e[90m\e[39m\n") + # Links. + test("[link](url)", " \e[34;4mlink\e[39;24m\n") + # Images. + test("![link](url)", " \e[32mlink\e[39m\n") + # Emphasis. + test("*text*", " \e[3mtext\e[23m\n") + # Strong. + test("**text**", " \e[1mtext\e[22m\n") + # Headings. + test("# h1", " \e[34;1m#\e[39;22m h1\n") + test("## h2", " \e[34;1m##\e[39;22m h2\n") + test("### h3", " \e[34;1m###\e[39;22m h3\n") + test("#### h4", " \e[34;1m####\e[39;22m h4\n") + test("##### h5", " \e[34;1m#####\e[39;22m h5\n") + test("###### h6", " \e[34;1m######\e[39;22m h6\n") + # Block quotes. + test("> quote", " \e[1m│\e[22m quote\n") + test(">", " \e[1m│\e[22m\n") + # Lists. + test( + "1. one\n2. 5. five\n 6. six\n3. three\n4. four\n", + " 1. one\n \n 2. 5. five\n \n 6. six\n \n 3. three\n \n 4. four\n", + ) + test("- - - - - - - item", " ● ○ ▶ ▷ ■ □ □ item\n") + test(" - ", " ● \n") + test("1. ", " 1. \n") + test(" - one\n *\n + three\n", " ● one\n \n ● \n \n ● three\n") + test("1. one\n2.\n3. three", " 1. one\n \n 2. \n \n 3. three\n") + + # Thematic Breaks. + test( + "***", + " \e[90m═════════════════════════════════════ § ═════════════════════════════════════\e[39m\n", + ) + # Code blocks. + test( + """ + ``` + code + ``` + """, + " \e[36m│\e[39m \e[90mcode\e[39m\n", + ) +end diff --git a/.julia-depot/packages/CommonMark/lmLkP/test/writers/typst.jl b/.julia-depot/packages/CommonMark/lmLkP/test/writers/typst.jl new file mode 100644 index 0000000..08ea2b5 --- /dev/null +++ b/.julia-depot/packages/CommonMark/lmLkP/test/writers/typst.jl @@ -0,0 +1,57 @@ +@testset "Typst" begin + p = Parser() + + test = function (text, expected) + ast = p(text) + @test typst(ast) == expected + end + + # Code blocks. + test("`code`", "`code`\n") + # Inline HTML. + test("text", "text\n") + # Links. + test("[link](url)", "#link(\"url\")[link]\n") + # Images. + test("![link](url)", "#figure(image(\"url\"), caption: [link])\n") + # Emphasis. + test("*text*", "#emph[text]\n") + # Strong. + test("**text**", "#strong[text]\n") + # Headings. + test("# h1", "= h1\n") + test("## h2", "== h2\n") + test("### h3", "=== h3\n") + test("#### h4", "==== h4\n") + test("##### h5", "===== h5\n") + test("###### h6", "====== h6\n") + # Block quotes. + test("> quote", "#quote(block: true)[\nquote\n]\n") + # Lists. + test("- item", " - item\n") + test("1. item", " 1. item\n") + test("3. item", " 3. item\n") + test("- item\n- item", " - item\n - item\n") + test("1. item\n2. item", " 1. item\n 2. item\n") + test("- item\n\n- item", " - item\n\n - item\n") + + # Thematic Breaks. + test("***", "#line(start: (25%, 0%), end: (75%, 0%))\n") + # Code blocks. + test( + """ + code + """, + "```\ncode\n```\n", + ) + test( + """ + ``` + code + ``` + """, + "```\ncode\n```\n", + ) + # Escapes. + test("^~\\&%\$#_{}", "^\\~\\&%\\\$\\#\\_{}\n") +end diff --git a/.julia-depot/packages/Glob/Dcl2i/.github/dependabot.yml b/.julia-depot/packages/Glob/Dcl2i/.github/dependabot.yml new file mode 100644 index 0000000..d60f070 --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.julia-depot/packages/Glob/Dcl2i/.github/workflows/CI.yml b/.julia-depot/packages/Glob/Dcl2i/.github/workflows/CI.yml new file mode 100644 index 0000000..30fcd9a --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/.github/workflows/CI.yml @@ -0,0 +1,64 @@ +name: CI +on: + pull_request: + branches: + - master + push: + branches: + - master + +jobs: + test: + name: Julia ${{ join(matrix.*, ' - ') }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.0' # Minimum compatible version + - '1.10' # LTS + - '1' # Current stable + - 'nightly' + os: + - ubuntu-latest + arch: + - x64 + include: + - version: '1' + os: ubuntu-latest + arch: x86 + - version: '1' + os: windows-latest + arch: x64 + - version: '1' + os: macos-latest + arch: default + steps: + - uses: actions/checkout@v6 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v5 + with: + files: lcov.info + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - uses: coverallsapp/github-action@v2 + with: + file: lcov.info + flag-name: Julia ${{ join(matrix.*, ' - ') }} + parallel: true + finish: + needs: test + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + parallel-finished: true diff --git a/.julia-depot/packages/Glob/Dcl2i/.github/workflows/TagBot.yml b/.julia-depot/packages/Glob/Dcl2i/.github/workflows/TagBot.yml new file mode 100644 index 0000000..3320a96 --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/.github/workflows/TagBot.yml @@ -0,0 +1,31 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: + inputs: + lookback: + default: 3 +permissions: + actions: read + checks: read + contents: write + deployments: read + issues: read + discussions: read + packages: read + pages: read + pull-requests: read + repository-projects: read + security-events: read + statuses: read +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + #ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.julia-depot/packages/Glob/Dcl2i/LICENSE.md b/.julia-depot/packages/Glob/Dcl2i/LICENSE.md new file mode 100644 index 0000000..ef5bc2b --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/LICENSE.md @@ -0,0 +1,22 @@ +The Glob.jl package is licensed under the MIT "Expat" License: + +> Copyright (c) 2014: Jameson Nash. +> +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +> CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +> TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.julia-depot/packages/Glob/Dcl2i/Project.toml b/.julia-depot/packages/Glob/Dcl2i/Project.toml new file mode 100644 index 0000000..7d165ba --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/Project.toml @@ -0,0 +1,12 @@ +name = "Glob" +uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" +version = "1.4.0" + +[compat] +julia = "1" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/.julia-depot/packages/Glob/Dcl2i/README.md b/.julia-depot/packages/Glob/Dcl2i/README.md new file mode 100644 index 0000000..868a67a --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/README.md @@ -0,0 +1,78 @@ +# Glob + +[![Build Status](https://github.com/vtjnash/Glob.jl/workflows/CI/badge.svg)](https://github.com/vtjnash/Glob.jl/actions/workflows/CI.yml?query=branch%3Amaster) +[![coveralls](https://coveralls.io/repos/github/vtjnash/Glob.jl/badge.svg?label=coveralls)](https://coveralls.io/github/vtjnash/Glob.jl) +[![codecov](https://codecov.io/gh/vtjnash/Glob.jl/branch/master/graph/badge.svg?label=codecov&token=QDfy4Cs9FB)](https://codecov.io/gh/vtjnash/Glob.jl) + + + +This implementation of Glob is based on the IEEE Std 1003.1, 2004 Edition (Open Group Base Specifications Issue 6) for fnmatch and glob. The specification of which can be found online: [fnmatch](http://pubs.opengroup.org/onlinepubs/009696899/functions/fnmatch.html) and [glob](http://pubs.opengroup.org/onlinepubs/009696899/functions/glob.html). + +> Note, because this is based on the POSIX specification, the path separator in a glob pattern is always `/` and the escape character is always `\`. However, the returned path string will always contain the system path separator character `Base.path_separator`. Therefore, it may be true that a path returned by `glob` will fail to match a `Glob.FilenameMatch` constructed from the same pattern. + +## Usage + +Glob is implemented to have both a functional form and an object-oriented form. There is no "correct" choice; you are encouraged to pick whichever is better suited to your application. + +* `glob(pattern, [directory::AbstractString])` :: + * Returns a list of all files matching `pattern` in `directory`. + * If directory is not specified, it defaults to the current working directory. + * Pattern can be any of: + 1. A `Glob.GlobMatch` object: + + glob"a/?/c" + + 2. A string, which will be converted into a GlobMatch expression: + + "a/?/c" # equivalent to 1, above + + 3. A vector of strings and/or objects which implement `occursin`, including `Regex` and `Glob.FilenameMatch` objects + + ["a", r".", fn"c"] # again, equivalent to 1, above + + * Each element of the vector will be used to match another level in the file hierarchy + * no conversion of strings to `Glob.FilenameMatch` objects or directory splitting on `/` will occur. + + 4. A trailing `/` (or equivalently, a trailing empty string in the vector) will cause glob to only match directories + + 5. Attempting to creat a GlobMatch object from a string with a leading `/` or the empty string is an error + +* `readdir(pattern::GlobMatch, [directory::AbstractString])` :: + * alias for `glob()` + +* `glob"pattern"` :: + * Returns a `Glob.GlobMatch` object, which can be used with `glob()` or `readdir()`. See above descriptions. + +* `fn"pattern"ipedx` :: + * Returns a `Glob.FilenameMatch` object, which can be used with `ismatch()` or `occursin()`. Available flags are: + * `i` = `CASELESS` : Performs case-insensitive matching + * `p` = `PERIOD` : A leading period (`.`) character must be exactly matched by a period (`.`) character (not a `?`, `*`, or `[]`). A leading period is a period at the beginning of a string, or a period after a slash if PATHNAME is true. + * `e` = `NOESCAPE` : Do not treat backslash (`\`) as a special character (in extended mode, this only outside of `[]`) + * `d` = `PATHNAME` : A slash (`/`) character must be exactly matched by a slash (`/`) character (not a `?`, `*`, or `[]`). When this flag is set, `**/` is treated as a globstar pattern that matches zero or more directories (see below). + * `x` = `EXTENDED` : Additional features borrowed from newer shells, such as `bash` and `tcsh` + * Backslash (`\`) characters in `[]` groups escape the next character + +## Globstar (`**`) + +When the `PATHNAME` flag (`d`) is enabled, `**/` is treated as a **globstar** pattern that matches zero or more directory components. This follows [zsh-style recursive globbing](https://zsh.sourceforge.io/Doc/Release/Expansion.html#Recursive-Globbing) semantics, not [bash's globstar](https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html). + +Notes: +- `**/` matches zero or more directories, including none (e.g., `a/**/b` matches both `a/b` and `a/x/y/b`) +- `**` at the end of a pattern matches everything remaining +- `**` not followed by `/` is treated as a regular `*` wildcard +- `**` not preceded by `/` or at the start of a string is treated as a regular `*` wildcard + +Examples: +```julia +occursin(fn"**/*.png"d, "a/b/c.png") # true - matches files in any subdirectory +occursin(fn"**/*.png"d, "c.png") # true - **/ can match zero directories +occursin(fn"a/**/b"d, "a/b") # true - zero directories between a and b +occursin(fn"a/**/b"d, "a/x/y/z/b") # true - multiple directories +occursin(fn"**/c/**/*.png"d, "a/b/c/d/e/test.png") # true - multiple globstars +``` + +## Unimplemented features + + * `[.` collating symbols only accept single characters (the Unicode locale has no collating symbols defined) + * `[=` equivalence classes only match the exact character specified (the Unicode locale has no equivalence classes defined) + * Advanced extended features (beyond the POSIX spec) such as `{}` groups, have not yet been implemented diff --git a/.julia-depot/packages/Glob/Dcl2i/src/Glob.jl b/.julia-depot/packages/Glob/Dcl2i/src/Glob.jl new file mode 100644 index 0000000..1a1079f --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/src/Glob.jl @@ -0,0 +1,537 @@ +__precompile__() + +module Glob + +import Base: readdir, show, occursin + +export glob, @fn_str, @fn_mstr, @glob_str, @glob_mstr + +@static if VERSION < v"1.7" +macro something(args...) + noth = GlobalRef(Base, :nothing) + something = GlobalRef(Base, :something) + expr = :($something($noth)) + for arg in reverse(args) + val = gensym() + expr = quote + $val = $(esc(arg)) + if $val === $noth + $expr + else + $something($val) + end + end + end + return expr +end +end + +const CASELESS = 1 << 0 # i -- Do case-insensitive matching +const PERIOD = 1 << 1 # p -- A leading period (.) character must be exactly matched by a period (.) character +const NOESCAPE = 1 << 2 # e -- Do not treat backslash (\) as a special character +const PATHNAME = 1 << 3 # d -- Slash (/) character must be exactly matched by a slash (/) character +const EXTENDED = 1 << 4 # x -- Support extended (bash-like) features + +struct FilenameMatch{S<:AbstractString} + pattern::S + options::UInt32 + FilenameMatch{S}(pattern, options) where {S} = new{S}(pattern, options) +end +function FilenameMatch(pattern::S, options::Integer=0) where {S<:AbstractString} + return FilenameMatch{S}(pattern, options) +end +function FilenameMatch(pattern::AbstractString, flags::AbstractString) + options = 0 + for f in flags + options |= (f == 'i') ? CASELESS : + (f == 'p') ? PERIOD : + (f == 'e') ? NOESCAPE : + (f == 'd') ? PATHNAME : + (f == 'x') ? EXTENDED : + error("unknown Filename Matcher flag: $f") + end + return FilenameMatch(pattern, options) +end + +""" + fn"pattern"ipedx + +Returns a `Glob.FilenameMatch` object, which can be used with `ismatch()` or `occursin()`. Available flags are: + +* `i` = `CASELESS` : Performs case-insensitive matching +* `p` = `PERIOD` : A leading period (`.`) character must be exactly matched by a period (`.`) character (not a `?`, `*`, or `[]`). A leading period is a period at the beginning of a string, or a period after a slash if PATHNAME is true. +* `e` = `NOESCAPE` : Do not treat backslash (`\`) as a special character (in extended mode, this only outside of `[]`) +* `d` = `PATHNAME` : A slash (`/`) character must be exactly matched by a slash (`/`) character (not a `?`, `*`, or `[]`), "**/" matches zero or more directories (globstar) +* `x` = `EXTENDED` : Additional features borrowed from newer shells, such as `bash` and `tcsh` + * Backslash (`\``) characters in `[]` groups escape the next character +""" +macro fn_str(pattern, flags...) FilenameMatch(pattern, flags...) end +macro fn_mstr(pattern, flags...) FilenameMatch(pattern, flags...) end + +function show(io::IO, fn::FilenameMatch) + print(io, "fn\"", fn.pattern, '"') + (fn.options & CASELESS) != 0 && print(io, 'i') + (fn.options & PERIOD ) != 0 && print(io, 'p') + (fn.options & NOESCAPE) != 0 && print(io, 'e') + (fn.options & PATHNAME) != 0 && print(io, 'd') + (fn.options & EXTENDED) != 0 && print(io, 'x') + nothing +end + +function occursin(fn::FilenameMatch, s::AbstractString) + pattern = fn.pattern + caseless = (fn.options & CASELESS) != 0 + periodfl = (fn.options & PERIOD ) != 0 + noescape = (fn.options & NOESCAPE) != 0 + pathname = (fn.options & PATHNAME) != 0 + extended = (fn.options & EXTENDED) != 0 + + mi = firstindex(pattern) # current index into pattern + i = firstindex(s) # current index into s + starmatch = i + star = 0 + globstarmatch = 0 # Track globstar match position for directory-level backtracking + globstar_mi = 0 # Pattern index after globstar + globstar_period = false # Track if period was encountered during globstar + globstar_star = 0 # Saved star state when entering globstar + globstar_starmatch = i # Saved starmatch state when entering globstar + period = periodfl + after_slash = true # Track if previous pattern char was '/' (or at start) + while true + matchnext = iterate(s, i) + matchnext === nothing && break + patnext = iterate(pattern, mi) + if patnext === nothing + # String characters left to match, but no pattern left + match = false + else + mc, mi = patnext + if mc == '*' + # Check if this is a **/ globstar pattern + # Conditions: after '/' (or at start), followed by '*/' + # Use iterate to peek ahead without string allocation + if pathname && after_slash + peek1_c, peek1_s = @something iterate(pattern, mi) @goto no_globstar + if peek1_c == '*' + peek2_c, peek2_s = @something iterate(pattern, peek1_s) return true # this is trailing_globstar + if peek2_c == '/' + # This is **/ globstar pattern - use directory-level backtracking + mi = peek2_s # Skip past **/ + globstarmatch = i + globstar_mi = mi + # Save current star state for restoration on globstar backtrack + globstar_star = star + globstar_starmatch = starmatch + after_slash = true # After **/, we're effectively after a / + c = '/' # Fake previous character as / + match = true + continue + end + end + end + @label no_globstar + # Not a globstar pattern - treat as regular * + # Even if it's **, each * will be processed separately + starmatch = i # backup the current search index + star = mi + c, _ = matchnext # peek-ahead + if period & (c == '.') + return false # * does not match leading . + end + after_slash = false + match = true + else + c, i = matchnext + if mc == '[' + mi, valid, match = _match(pattern, mi, c, caseless, extended) + if pathname & valid & match & (c == '/') + match = false + end + if period & valid & match & (c == '.') + match = false + end + elseif mc == '?' + if pathname & (c == '/') + return false # ? does not match / + end + if period & (c == '.') + return false # ? does not match leading . + end + match = true + else + if (!noescape) & (mc == '\\') # escape the next character after backslash, unless it is the last character + patnext = iterate(pattern, mi) + if patnext !== nothing + mc, mi = patnext + end + end + match = ((c == mc) || (caseless && uppercase(c)==uppercase(mc))) + end + # Track if we're matching a . during globstar + if globstarmatch > 0 && period && (c == '.') + globstar_period = true + end + # Update after_slash for next iteration (track if pattern char was '/') + after_slash = (mc == '/') + if match && after_slash && pathname + # in pathname mode, once matching a / explicitly, backtracking to starmatch will not be necessary + star = 0 + end + end + end + if !match # try to backtrack + # Try * backtracking first + if star != 0 + c, i = something(iterate(s, starmatch)) + if !(pathname & (c == '/')) + mi = star + starmatch = i + continue + end + end + # Then try **/ backtracking + if globstarmatch > 0 + nextslash = findnext(==('/'), s, globstarmatch) + if nextslash !== nothing && !globstar_period + i = nextind(s, nextslash) + globstarmatch = i + mi = globstar_mi + star = globstar_star + starmatch = globstar_starmatch + period = periodfl + continue + end + globstarmatch = 0 + end + return false + end + period = (periodfl & pathname & (c == '/')) + end + while true # allow trailing *'s and **'s + patnext = iterate(pattern, mi) + patnext === nothing && break + mc, mi = patnext + mc == '*' || return false # pattern characters left to match, but no string left + end + return true +end + +@deprecate ismatch(fn::FilenameMatch, s::AbstractString) occursin(fn, s) + +filter!(fn::FilenameMatch, v) = filter!(x -> occursin(fn, x), v) +filter(fn::FilenameMatch, v) = filter(x -> occursin(fn, x), v) +filter!(fn::FilenameMatch, d::Dict) = filter!(((k, _),) -> occursin(fn, k), d) +filter(fn::FilenameMatch, d::Dict) = filter!(fn, copy(d)) + +function _match_bracket(pat::AbstractString, mc::Char, i, cl::Char, cu::Char) # returns (mc, i, valid, match) + next = iterate(pat, i) + if next === nothing + return (mc, i, false, false) + end + mc2, j = next + if (mc2 != ':') & (mc2 != '.') & (mc2 != '=') + return (mc, i, false, true) + end + mc3 = mc4 = '\0' + k0 = k1 = k2 = k3 = j + next = iterate(pat, k3) + while mc3 != mc2 && mc4 != ']' + if next === nothing + return (mc, i, false, false) + end + mc3 = mc4 + k0 = k1 + k1 = k2 + k2 = k3 + next = iterate(pat, k3) + if next === nothing + return (mc, i, false, false) + end + mc4, k3 = next + end + if mc2 == ':' + phrase = SubString(pat, j, k0) + match = ( + if phrase == "alnum" + isletter(cl) || isnumeric(cl) + elseif phrase == "alpha" + isletter(cl) + elseif phrase == "blank" + (cl == ' ' || cl == '\t') + elseif phrase == "cntrl" + iscntrl(cl) + elseif phrase == "digit" + isdigit(cl) + elseif phrase == "graph" + isprint(cl) && !isspace(cl) + elseif phrase == "lower" + islowercase(cl) | islowercase(cu) + elseif phrase == "print" + isprint(cl) + elseif phrase == "punct" + ispunct(cl) + elseif phrase == "space" + isspace(cl) + elseif phrase == "upper" + isuppercase(cl) | isuppercase(cu) + elseif phrase == "xdigit" + isxdigit(cl) + else + error(string("invalid character expression [:",phrase,":]")) + end) + return (mc, k3, true, match) + elseif mc2 == '.' + if j != k0 + error(string("only single characters are currently supported as collating symbols, got [.", SubString(pat, j, k0), ".]")) + #match = (pat[j:k0] == s[ci:ci+(k0-j)]) + #return (mc, k3, true, match) + end + mc, j = something(iterate(pat, j)) + return (mc, k3, false, true) + else #if mc2 == '=' + if j != k0 + error(string("only single characters are currently supported as character equivalents, got [=", SubString(pat, j, k0), "=]")) + end + mc, j = something(iterate(pat, j)) + match = (cl==mc) | (cu==mc) + return (mc, k3, true, match) + end +end + +function _match(pat::AbstractString, i0, c::Char, caseless::Bool, extended::Bool) # returns (i, valid, match) + if caseless + cl = lowercase(c) + cu = uppercase(c) + else + cl = cu = c + end + i = i0 + next = iterate(pat, i) + if next === nothing + return (i0, false, c=='[') + end + mc, j = next + negate = false + if mc == '!' + negate = true + i = j + end + match = false + notfirst = false + while true + next = iterate(pat, i) + next === nothing && break + mc, i = next + if (mc == ']') & notfirst + return (i, true, match ⊻ negate) + end + notfirst = true + if (mc == '[') + mc, i, valid, match2 = _match_bracket(pat, mc, i, cl, cu) + if valid + match |= match2 + continue + elseif !match2 + return (i0, false, c=='[') + end + elseif extended & (mc == '\\') + next = iterate(pat, i) + if next === nothing + return (i0, false, c=='[') + end + mc, i = next + end + next = iterate(pat, i) + if next === nothing + return (i0, false, c=='[') + end + mc2, j = next + if mc2 == '-' + next = iterate(pat, j) + if next === nothing + return (i0, false, c=='[') + end + mc2, j = next + if mc2 == ']' + match |= ((cl == mc) | (cu == mc) | (c == '-')) + return (j, true, match ⊻ negate) + end + if mc2 == '[' + mc2, j, valid, match2 = _match_bracket(pat, mc2, j, cl, cu) + if valid + error("[: and [= are not valid range endpoints") + elseif !match2 + return (i0, false, c=='[') + end + elseif extended & (mc2 == '\\') + next = iterate(pat, j) + if next === nothing + return (i0, false, c=='[') + end + mc2, j = next + end + match |= (mc <= cl <= mc2) + match |= (mc <= cu <= mc2) + i = j + else + match |= ((cl == mc) | (cu == mc)) + end + end + return (i0, false, c=='[') +end + +""" + glob"pattern" + +Returns a `Glob.GlobMatch` object, which can be used with `glob()` or `readdir()`. +""" +macro glob_str(pattern) GlobMatch(pattern) end +macro glob_mstr(pattern) GlobMatch(pattern) end + +struct GlobMatch + pattern::Vector + GlobMatch(pattern) = isempty(pattern) ? error("GlobMatch pattern cannot be an empty vector") : new(pattern) +end +GlobMatch(gm::GlobMatch) = gm +function GlobMatch(pattern::AbstractString) + if isempty(pattern) || first(pattern) == '/' + error("Glob pattern cannot be empty or start with a / character") + end + pat = split(pattern, '/') + S = eltype(pat) + if !isconcretetype(S) + S = Any + else + S = Union{S, FilenameMatch{S}} + end + glob = Array{S}(undef, length(pat)) + extended = false + for i = 1:length(pat) + p = pat[i] + next = iterate(p) + ispattern = false + while next !== nothing + c, j = next + next = iterate(p, j) + if extended & (c == '\\') + if next === nothing + break + end + next = iterate(p, j) + elseif (c == '*') | (c == '?') | + (c == '[' && _match(p, j, '\0', false, extended)[2]) + ispattern = true + break + end + end + if ispattern + glob[i] = FilenameMatch(p, PERIOD|PATHNAME) + else + glob[i] = p + end + end + return GlobMatch(glob) +end + +function show(io::IO, gm::GlobMatch) + for pat in gm.pattern + if !isa(pat, AbstractString) && !isa(pat, FilenameMatch) + print(io, "Glob.GlobMatch(") + show(io, gm.pattern) + print(io, ')') + return + end + end + print(io, "glob\"") + notfirst = false + for pat in gm.pattern + notfirst && print(io, '/') + notfirst = true + if isa(pat, FilenameMatch) + print(io, pat.pattern) + else + print(io, pat) + end + end + print(io, '"') +end + +""" + readdir(pattern::GlobMatch, [directory::AbstractString]) + +Alias for [`glob()`](@ref). +""" +readdir(pattern::GlobMatch, prefix::AbstractString="") = glob(pattern, prefix) + +""" + glob(pattern, [directory::AbstractString]) + +Returns a list of all files matching `pattern` in `directory`. + +* If directory is not specified, it defaults to the current working directory. +* Pattern can be any of: + 1. A `Glob.GlobMatch` object: + + glob"a/?/c" + + 2. A string, which will be converted into a GlobMatch expression: + + "a/?/c" # equivalent to 1, above + + 3. A vector of strings and/or objects which implement `occursin`, including `Regex` and `Glob.FilenameMatch` objects + + ["a", r".", fn"c"] # again, equivalent to 1, above + + * Each element of the vector will be used to match another level in the file hierarchy + * no conversion of strings to `Glob.FilenameMatch` objects or directory splitting on `/` will occur. + +A trailing `/` (or equivalently, a trailing empty string in the vector) will cause glob to only match directories. + +Attempting to use a pattern with a leading `/` or the empty string is an error; use the `directory` argument to specify the absolute path to the directory in such a case. +""" +function glob(pattern, prefix::AbstractString="") + matches = String[prefix] + for pat in GlobMatch(pattern).pattern + matches = _glob!(matches, pat) + end + return matches +end + +function _glob!(matches, pat::AbstractString) + i = 1 + last = length(matches) + while i <= last + path = joinpath(matches[i], pat) + if ispath(path) + matches[i] = path + i += 1 + else + matches[i] = matches[last] + last -= 1 + end + end + resize!(matches, last) + return matches +end + +function _glob!(matches, pat) + m2 = String[] + for m in matches + if isempty(m) + for d in readdir() + if occursin(pat, d) + push!(m2, d) + end + end + elseif isdir(m) + for d in readdir(m) + if occursin(pat, d) + push!(m2, joinpath(m, d)) + end + end + end + end + return m2 +end + +end # module diff --git a/.julia-depot/packages/Glob/Dcl2i/test/runtests.jl b/.julia-depot/packages/Glob/Dcl2i/test/runtests.jl new file mode 100644 index 0000000..6c8fe50 --- /dev/null +++ b/.julia-depot/packages/Glob/Dcl2i/test/runtests.jl @@ -0,0 +1,287 @@ +using Glob +using Test + +macro test_types(arr, types) + return quote + @test length($arr) == length($types) + for i in 1:length($arr) + @test isa($arr[i], $types[i]) + end + end +end + +# various unit tests, in no particular order + +@test !occursin(fn"abc*", "ABXABXAB") +@test occursin(fn"AB*AB*AB", "ABXABXAB") +@test occursin(fn"AB*AB*AB", "ABXABAB") +@test !occursin(fn"AB*AB*AB", "AABAB") +@test occursin(fn"AB*AB*AB", "ABABAB") +@test occursin(fn"AB*AB*B", "ABABAB") +@test occursin(fn"AB*AB*", "ABABAB") +@test occursin(fn"AB*AB*??", "ABABAB") +@test !occursin(fn"AB*AB*???", "ABABAB") +@test occursin(fn"AB*AB*??***", "ABABAB") +@test occursin(fn"AB*AB*??***", "ABABABC") +@test occursin(fn"AB*AB*??***", "ABABABCDEFG") +@test occursin(fn"?AB*AB*??***", ".ABABABCDEFG") +@test !occursin(fn"?AB*AB*??***"p, ".ABABABCDEFG") +@test_throws ErrorException Glob.FilenameMatch("?AB*AB*??***","z") +@test occursin(fn"[abc]", "a") +@test !occursin(fn"[abc]", "A") +@test occursin(fn"[abc]"i, "A") +@test occursin(fn"[abc]", "b") +@test occursin(fn"[abc]", "c") +@test !occursin(fn"[abc]", "x") +@test !occursin(fn"[a-d]", "x") +@test occursin(fn"[a-d]", "a") +@test occursin(fn"[a-d]", "d") +@test !occursin(fn"[a--]", "e") +@test occursin(fn"[--e]", "e") +@test !occursin(fn"[f-e]", "e") +@test !occursin(fn"[g-e]", "e") +@test !occursin(fn"[g-f]", "e") +@test occursin(fn"[a-f]", "e") +@test occursin(fn"[a-e]", "e") +@test occursin(fn"[f-ee]", "e") +@test !occursin(fn"[A-Z]", "e") +@test occursin(fn"[A-z]", "e") +@test occursin(fn"[\]", "\\") +@test_throws ErrorException occursin(fn"[[:a:]]", "e") +@test_throws ErrorException !occursin(fn"[\[:a:]]", "e") +@test !occursin(fn"[\[:a:]]"x, "e") +@test_throws ErrorException occursin(fn"[\\[:a:]]", "e") +@test occursin(fn"[\[:a-e:]]"x, "e]") +@test occursin(fn"[\[:a-e:]"x, "e") +@test !occursin(fn"[\[:a-e:xxxx"x, "e") +@test occursin(fn"[\[:a-e:xxxx-]"x, "e") +@test occursin(fn"[a-]", "a") +@test occursin(fn"[a-]", "-") +@test !occursin(fn"[a-]", "b") +@test occursin(fn"[!a-]", "b") +@test !occursin(fn"[!a-]", "a") +@test occursin(fn"[!a]", "!") +@test !occursin(fn"[!!]", "!") +@test !occursin(fn"[!a]", "a") +@test occursin(fn"[!a]", "b") +@test !occursin(fn"[][]", "") +@test occursin(fn"[]", "[]") +@test occursin(fn"[][]", "[") +@test occursin(fn"[][]", "]") +@test !occursin(fn"[][]", "x") +@test !occursin(fn"[]-[]", "x") +@test !occursin(fn"[]-[]", "-") +@test !occursin(fn"[]-[]", "\\") +@test occursin(fn"[\[-\]]*"x, "][") +@test occursin(fn"[\]]*"x, "][") +@test occursin(fn"[\[-\]]*"x, "][") +@test occursin(fn"[[-\]]*"x, "][") +@test occursin(fn"base/[\[-\]]*"dpx,"base/][x") +@test occursin(fn"[\[-\]]"x, "\\") +@test occursin(fn"[[-\]]"x, "\\") +@test occursin(fn"[---]", "-") +@test !occursin(fn"[!---]", "-") +@test occursin(fn"[!---]", "0") +@test !occursin(fn"[---a-zA-Z]", "0") +@test !occursin(fn"[---a-zA-Z:]", "0") +@test !occursin(fn"[---!]", "0") +@test occursin(fn"[---!]", "!") +@test !occursin(fn"[---!]", "a") +@test !occursin(fn"[---!]", "\0") +@test occursin(fn"ab/c/d"dp, "ab/c/d") +@test !occursin(fn"ab/c/d"dp, "ab/c?d") +@test !occursin(fn"ab/./d"dp, "ab/?/d") +@test !occursin(fn"ab*d"dp, "aba/d") +@test !occursin(fn"ab*d"dp, "ab/d") +@test occursin(fn"ab*d", "ab/d") +@test occursin(fn"ab*d", "aba/d") +@test occursin(fn"[a-z]"i, "B") +@test !occursin(fn"[a-z]"i, "_") +@test occursin(fn"[A-z]"i, "_") +@test !occursin(fn"[a-Z]"i, "_") +@test !occursin(fn"#[a-Z]%"i, "#a%") +@test occursin(fn"#[α-ω]%"i, "#Γ%") +@test !occursin(fn"#[α-ω]%", "#Γ%") +@test occursin(fn"#[α-ω]%", "#γ%") +@test !occursin(fn"a?b"d, "a/b") +@test occursin(fn"a?b", "a/b") +@test !occursin(fn"?b"p, ".b") +@test occursin(fn"?b", ".b") +@test occursin(fn"?/?b", "./.b") +@test !occursin(fn"?/?b"p, "./.b") +@test occursin(fn"./?b"p, "./.b") +@test !occursin(fn"./?b"pd, "./.b") +@test occursin(fn"./.b"pd, "./.b") +@test !occursin(fn"?/.b"pd, "./.b") +@test occursin(fn"""./.b"""pd, "./.b") +@test !occursin(fn"""?/.b"""pd, "./.b") +@test occursin(fn"_[[:blank:][.a.]-c]_", "_b_") +@test !occursin(fn"_[[:blank:][.a.]-c]_", "_-_") +@test occursin(fn"_[[:blank:][.a.]-c]_", "_ _") +@test occursin(fn"_[[:alnum:]]_", "_a_") +@test !occursin(fn"_[[:alnum:]]_", "_[_") +@test !occursin(fn"_[[:alnum:]]_", "_]_") +@test !occursin(fn"_[[:alnum:]]_", "_:_") +@test occursin(fn"_[[:alpha:]]_", "_z_") +@test !occursin(fn"_[[:alpha:]]_", "_[_") +@test occursin(fn"_[[:cntrl:]]_", "_\0_") +@test occursin(fn"_[[:cntrl:]]_", "_\b_") +@test !occursin(fn"_[[:cntrl:]]_", "_:_") +@test !occursin(fn"_[[:cntrl:]]_", "_ _") +@test occursin(fn"_[[:digit:]]_", "_0_") +@test !occursin(fn"_[[:digit:]]_", "_:_") +@test occursin(fn"_[[:graph:]]_", "_._") +@test !occursin(fn"_[[:graph:]]_", "_ _") +@test occursin(fn"_[[:lower:]]_", "_a_") +@test occursin(fn"_[[:lower:]]_"i, "_A_") +@test !occursin(fn"_[[:lower:]]_", "_A_") +@test !occursin(fn"_[[:lower:]]_", "_:_") +@test occursin(fn"_[[:print:]]_", "_a_") +@test !occursin(fn"_[[:print:]]_", "_\7_") +@test occursin(fn"_[[:punct:]]_", "_:_") +@test !occursin(fn"_[[:punct:]]_", "_p_") +@test occursin(fn"_[[:space:]]_", "_\f_") +@test !occursin(fn"_[[:space:]]_", "_:_") +@test !occursin(fn"_[[:space:]]_", "_\r\n_") +@test occursin(fn"_[[:upper:]]_", "_A_") +@test occursin(fn"_[[:upper:]]_"i, "_a_") +@test !occursin(fn"_[[:upper:]]_", "_a_") +@test !occursin(fn"_[[:upper:]]_", "_:_") +@test occursin(fn"_[[:xdigit:]]_", "_a_") +@test !occursin(fn"_[[:xdigit:]]_", "_:_") +@test occursin(fn"_[[.a.]-[.z.]]_", "_c_") +@test !occursin(fn"_[[.a.]-[.z.]]_", "_-_") +@test !occursin(fn"_[[.a.]-[.z.]]_", "_]_") +@test !occursin(fn"_[[.a.]-[.z.]]_", "_[_") +@test occursin(fn"_[[=a=]]_", "_a_") +@test !occursin(fn"_[[=a=]]_", "_=_") +@test !occursin(fn"_[[=a=]]_", "_á_") +@test occursin(fn"[[=a=]-z]", "-") +@test_throws ErrorException occursin(fn"[a-[=z=]]", "e") + +@test !occursin(fn"\?", "\\?") +@test occursin(fn"\?", "?") +@test occursin(fn"\?"e, "\\!") +@test !occursin(fn"\?"e, "?") + +@testset "FilenameMatch with ** globstar" begin + # Basic **/ patterns + @test occursin(fn"**/*.png"d, "c.png") + @test occursin(fn"**/*.png"d, "a/c.png") + @test occursin(fn"**/*.png"d, "a/b/c.png") + + # Absolute paths with **/ + @test occursin(fn"/**/*.png"d, "/c.png") + @test occursin(fn"/**/*.png"d, "/a/c.png") + @test occursin(fn"/**/*.png"d, "/a/b/c.png") + + @test occursin(fn"**/*.png"d, "/c.png") + @test occursin(fn"**/*.png"d, "/a/c.png") + @test occursin(fn"**/*.png"d, "/a/b/c.png") + + @test !occursin(fn"/**/*.png"d, "c.png") + @test !occursin(fn"/**/*.png"d, "a/c.png") + @test !occursin(fn"/**/*.png"d, "a/b/c.png") + + # ** without trailing / + @test occursin(fn"**.png"d, "c.png") + @test !occursin(fn"**.png"d, "a/b/c.png") + + # ** alone + @test occursin(fn"**"d, "c.png") + @test occursin(fn"**"d, "a/c.png") + @test occursin(fn"**"d, "/a/c.png") + @test occursin(fn"/**"d, "/a/c.png") + @test occursin(fn"/a/**"d, "/a/c.png") + @test !occursin(fn"/b/**"d, "/a/c.png") + @test !occursin(fn"/**"d, "a/c.png") + + # Complex patterns with multiple **/ + @test occursin(fn"**/c/**/*"d, "a/b/c/d/e/test.png") + @test !occursin(fn"**/c/*/*"d, "a/b/c/d/e/test.png") + @test occursin(fn"**/c/**/*.png"d, "a/b/c/d/e/test.png") + @test !occursin(fn"**/c/**/*.png"d, "a/b/c/d/e/test.gif") + + # PERIOD flag tests + @test occursin(fn"**/c/**/*.png"d, "a/b/c/d/e/.png") + @test occursin(fn"**/c/**/*png"d, "a/b/c/d/e/.png") + @test occursin(fn"**/c/**/?png"d, "a/b/c/d/e/.png") + + @test !occursin(fn"**/c/**/?png"dp, "a/b/c/d/e/.png") + @test !occursin(fn"**/c/**/*png"dp, "a/b/c/d/e/.png") + + @test !occursin(fn"**/c/**/?png"dp, "a/.b/c/d/e/apng") + @test !occursin(fn"**/c/**/?png"dp, ".a/b/c/d/e/apng") + @test !occursin(fn"**/c/**/?png"dp, "a/b/c/d/e/.png") + @test !occursin(fn"*/**/*.png"d, "c.png") + @test !occursin(fn"**/*/*.png"d, "c.png") + + @test occursin(fn"**/c/**/*png"dp, "a/b/c/d/e/*png") + @test occursin(fn"**/c/**/*png"d, "a/b/c/d/e/.png") + @test !occursin(fn"**/c/**/*png"dp, "a/b/c/d/e/.png") + + # Wildcards combined with **/ + @test occursin(fn"a*/**/c/test.gif"d, "ab/b/c/test.gif") + @test occursin(fn"a*/**/test.gif"d, "ab/b/c/test.gif") + @test !occursin(fn"a**/test.gif"d, "ab/b/h/test.gif") + + # Test wildcards appearing both before and after **/ + @test occursin(fn"a*/**/*b"d, "ax/y/z/wb") + @test occursin(fn"a*/**/*b"d, "ax/y/wb") + @test occursin(fn"a*/**/*b"d, "ax/wb") + @test occursin(fn"a*/**/*b"d, "a/wb") + @test !occursin(fn"a*/**/*b"d, "ax/y/z/w") + @test !occursin(fn"a*/**/*b"d, "x/y/z/wb") + @test occursin(fn"*a/**/*b"d, "xa/y/zb") + @test occursin(fn"*a/**/*b"d, "xa/zb") + @test occursin(fn"*a*/**/*b"d, "xaay/m/nb") + @test occursin(fn"a*x/**/*b"d, "ayx/z/wb") + @test occursin(fn"a*x/**/*b"d, "ayxx/z/wb") + @test occursin(fn"a*/**/b"d, "ax/y/b") + @test occursin(fn"a*/**/b"d, "ax/b") + @test !occursin(fn"a*/**/b"d, "ax/y/c") + + # Test ** without / (in non-pathname mode, matches any character including /) + @test occursin(fn"a/**test.jl", "a/test.jl") + @test occursin(fn"a/**test.jl", "a/b/test.jl") + + # Test **/ matching zero or more directories + @test occursin(fn"a/**/b"d, "a/b") + @test occursin(fn"a/**/b"d, "a/x/b") + @test occursin(fn"a/**/b"d, "a/x/y/b") + @test occursin(fn"a/**/b"d, "a/x/y/z/b") + @test !occursin(fn"a/**/b"d, "a/b/c") + @test !occursin(fn"a/**/b"d, "x/a/b") +end + +@test_types glob"ab/?/d".pattern (AbstractString, Glob.FilenameMatch, AbstractString) +@test_types glob"""ab/*/d""".pattern (AbstractString, Glob.FilenameMatch, AbstractString) +@test length(glob"ab/[/d".pattern) == 3 +@test length(glob"ab/[/]d".pattern) == 3 +@test_types glob"ab/[/]d".pattern (AbstractString, AbstractString, AbstractString) +@test_types glob"ab/[/d".pattern (AbstractString, AbstractString, AbstractString) +@test_types glob"ab/[]/d".pattern (AbstractString, AbstractString, AbstractString) +@test_types glob"ab/[]]/d".pattern (AbstractString, Glob.FilenameMatch, AbstractString) + +@test glob("*") == filter(x->!startswith(x,'.'), readdir()) == readdir(glob"*") +@test glob(".*") == filter(x->startswith(x,'.'), readdir()) == readdir(glob".*") +@test isempty(Glob.glob("[.]*")) +@test glob([r".*"]) == readdir() +@test glob([".", r".*"]) == map(x->joinpath(".",x), readdir()) +@test all([!startswith(x,'.') for x in Glob.glob("*.*")]) + +function test_string(x1) + x2 = string(eval(Meta.parse(x1))) + x1 == x2 ? nothing : error(string( + "string test failed:", + "\noriginal: ", x1, + "\n\nstringify: ", x2)) +end + +test_string("""Glob.GlobMatch(Any["base", r"h\\.+"])""") +test_string("""glob"base/*/a/[b]\"""") +test_string("""fn"base/*/a/[b]\"ipedx""") +test_string("""fn"base/*/a/[b]\"""") + +@test_throws ErrorException Glob.GlobMatch("") +@test_throws ErrorException Glob.GlobMatch("/a/b/c") diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.JuliaFormatter.toml b/.julia-depot/packages/JuliaFormatter/zLsPw/.JuliaFormatter.toml new file mode 100644 index 0000000..cc69bba --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.JuliaFormatter.toml @@ -0,0 +1,5 @@ +remove_extra_newlines = true +always_for_in = true +conditional_to_if = true +separate_kwargs_with_semicolon = true +short_to_long_function_def = true diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.github/dependabot.yml b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/dependabot.yml new file mode 100644 index 0000000..700707c --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/CompatHelper.yml b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/CompatHelper.yml new file mode 100644 index 0000000..cba9134 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/CompatHelper.yml @@ -0,0 +1,16 @@ +name: CompatHelper +on: + schedule: + - cron: 0 0 * * * + workflow_dispatch: +jobs: + CompatHelper: + runs-on: ubuntu-latest + steps: + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/TagBot.yml b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/TagBot.yml new file mode 100644 index 0000000..f49313b --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/TagBot.yml @@ -0,0 +1,15 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/ci.yml b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/ci.yml new file mode 100644 index 0000000..d13d7a8 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.github/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI +on: + push: + tags: + - '*' + branches: + - 'master' + pull_request: + branches: + - 'master' +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + version: + - '1.10' + - '1.11' + # - 'nightly' + arch: [x64, x86] + os: [ubuntu-latest, windows-latest, macos-13] + exclude: + - os: macos-13 + arch: x86 + - os: macos-13 + version: '1.4' + include: + - os: macos-latest + version: '1' + arch: aarch64 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: julia-actions/setup-julia@v2 + with: + show-versioninfo: true + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/julia-buildpkg@v1 + with: + ignore-no-cache: true + - uses: julia-actions/julia-runtest@latest + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: julia-actions/setup-julia@v2 + with: + show-versioninfo: true + version: '1' + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.gitignore b/.julia-depot/packages/JuliaFormatter/zLsPw/.gitignore new file mode 100644 index 0000000..ba39cc5 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.gitignore @@ -0,0 +1 @@ +Manifest.toml diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-config.yaml b/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-config.yaml new file mode 100644 index 0000000..61f1d09 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +# NOTE: Do NOT use this config in your own repositories. Instead, see +# docs/integrations.md +repos: +- repo: local + hooks: + - id: "julia-formatter" \ No newline at end of file diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-hooks.yaml b/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-hooks.yaml new file mode 100644 index 0000000..0cde306 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/.pre-commit-hooks.yaml @@ -0,0 +1,9 @@ +- id: julia-formatter + name: "Julia Formatter" + entry: "julia -e 'import JuliaFormatter: format; format(ARGS)'" + pass_filenames: true + always_run: false + types: [file] + files: \.(jl|[jq]?md)$ + language: "system" + description: "An opinionated code formatter for Julia. Plot twist - the opinion is your own." diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/LICENSE b/.julia-depot/packages/JuliaFormatter/zLsPw/LICENSE new file mode 100644 index 0000000..9c3d6db --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Dominique Luna + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/Project.toml b/.julia-depot/packages/JuliaFormatter/zLsPw/Project.toml new file mode 100644 index 0000000..4019e1a --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/Project.toml @@ -0,0 +1,28 @@ +name = "JuliaFormatter" +uuid = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +version = "2.2.0" +authors = ["Dominique Luna "] + +[deps] +CommonMark = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +Glob = "c27321d9-0574-5035-807b-f59d2c89b15c" +JuliaSyntax = "70703baa-626e-46a2-a12c-08ffd08c73b4" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" + +[compat] +CommonMark = "0.5, 0.6, 0.7, 0.8, 0.9" +Glob = "1.3" +JuliaSyntax = "^0.4.10" +PrecompileTools = "1" +TOML = "1" +Test = "1" +julia = "1.10" + +[apps.jlfmt] + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/README.md b/.julia-depot/packages/JuliaFormatter/zLsPw/README.md new file mode 100644 index 0000000..b1a3cc3 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/README.md @@ -0,0 +1,83 @@ +# JuliaFormatter.jl + +[![Documenter: stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://domluna.github.io/JuliaFormatter.jl/stable/) +[![Documenter: dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://domluna.github.io/JuliaFormatter.jl/dev/) +![Build Status](https://github.com/domluna/JuliaFormatter.jl/actions/workflows/ci.yml/badge.svg) + +> **If you're having issues with v2 outputs use the latest v1. `add JuliaFormatter@v1` should install 1.0.62** + + +> I don't have the time to commit large changes regarding v2. JuliaSyntax v1 broke a bunch of things again and it is a large undertaking fix everything needed to upgrade and then also fix previous issues. If you would like to contribute via PRs they would be welcomed. + +Width-sensitive formatter for Julia code. Inspired by gofmt, refmt, and black. + +![Screencast](https://user-images.githubusercontent.com/1813121/72941091-0b146300-3d68-11ea-9c95-75ec979caf6e.gif) + +## Installation + +```julia +pkg> add JuliaFormatter +``` + +## Quick Start + +```julia +julia> using JuliaFormatter + +# Recursively formats all Julia files in the current directory +julia> format(".") + +# Formats an individual file +julia> format_file("foo.jl") + +# Formats a string (contents of a Julia file) +julia> format_text(str) +``` + +Check out [the docs](https://domluna.github.io/JuliaFormatter.jl/stable/) for further description of the formatter and its options. + +## Command Line Tool + +Starting from version 2.2.0, JuliaFormatter provides a command-line executable `jlfmt`. + +To install: + +```julia +pkg> app add JuliaFormatter +``` + +Usage: + +```bash +# Format a file and write to stdout +jlfmt src/file.jl + +# Format a file in place +jlfmt --inplace src/file.jl + +# Check if all files in a directory are already formatted with verbose mode +jlfmt --check -v src/ + +# Format all files in a directory with multiple threads +jlfmt --threads=6 -- --inplace -v src/ + +# Show diff without modifying files +jlfmt --diff src/file.jl +``` + +Run `jlfmt --help` for more options. + +Check out [the CLI docs](https://domluna.github.io/JuliaFormatter.jl/dev/cli) for further description of the formatter and its options. + +## Github Actions + +[Use With GitHub Actions](https://github.com/julia-actions/julia-format) + +## Editor Plugins + +For integration with other editors: + + - [VSCode](https://github.com/singularitti/vscode-julia-formatter/) + - [Emacs](https://codeberg.org/FelipeLema/julia-formatter.el) + - [Vim](https://github.com/kdheepak/JuliaFormatter.vim) + - [Atom (deprecated)](https://github.com/JunoLab/Atom.jl) diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/bin/hook.jl b/.julia-depot/packages/JuliaFormatter/zLsPw/bin/hook.jl new file mode 100755 index 0000000..23c0a5d --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/bin/hook.jl @@ -0,0 +1,6 @@ +#!/usr/bin/env -S julia --startup-file=no -O1 +using JuliaFormatter + +@debug ARGS +filename = ARGS[1] +exit(format_file(filename) ? 0 : 1) diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/.gitignore b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/.gitignore @@ -0,0 +1 @@ +build diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/Project.toml b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/Project.toml new file mode 100644 index 0000000..5eec8f4 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/Project.toml @@ -0,0 +1,3 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/make.jl b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/make.jl new file mode 100644 index 0000000..d49b410 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/make.jl @@ -0,0 +1,24 @@ +using Documenter, JuliaFormatter + +makedocs(; + sitename = "JuliaFormatter", + format = Documenter.HTML(; prettyurls = get(ENV, "CI", nothing) == "true"), + modules = [JuliaFormatter], + pages = [ + "Introduction" => "index.md", + "How It Works" => "how_it_works.md", + "Code Style" => "style.md", + "Skipping Formatting" => "skipping_formatting.md", + "Syntax Transforms" => "transforms.md", + "Custom Alignment" => "custom_alignment.md", + "YAS Style" => "yas_style.md", + "Blue Style" => "blue_style.md", + "SciML Style" => "sciml_style.md", + "Configuration File" => "config.md", + "Command Line Interface" => "cli.md", + "API Reference" => "api.md", + ], + warnonly = true, +) + +deploydocs(; repo = "github.com/domluna/JuliaFormatter.jl.git", push_preview = true) diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/api.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/api.md new file mode 100644 index 0000000..c1bd17c --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/api.md @@ -0,0 +1,6 @@ +# API Documentation + +```@autodocs +Modules = [JuliaFormatter] +Filter = t -> (t != YASStyle && t != BlueStyle && t != SciMLStyle) # on their own pages +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/blue_style.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/blue_style.md new file mode 100644 index 0000000..5de6b79 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/blue_style.md @@ -0,0 +1,32 @@ +# Blue Style + +```@docs +BlueStyle +``` + +## Configuration File Example + +The `.JuliaFormatter.toml` which represents these settings is + +```toml +style = "blue" +``` + +Or to use `BlueStyle` except change one of the settings: + +```toml +style = "blue" +remove_extra_newlines = false +``` + +## Direct Usage + +```julia +format("file.jl", BlueStyle()) +``` + +Or to use `BlueStyle` except change one of the settings: + +```julia +format("file.jl", BlueStyle(), remove_extra_newlines=false) +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/cli.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/cli.md new file mode 100644 index 0000000..50de316 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/cli.md @@ -0,0 +1,90 @@ +# Command Line Interface + +JuliaFormatter provides a command-line executable `jlfmt` for formatting Julia source code. + +## Installation + +Install using Julia's app manager: + +```julia +pkg> app add JuliaFormatter +``` + +This makes the `jlfmt` command available in your `PATH`. + +Alternatively, invoke directly without installation: + +```bash +julia -m JuliaFormatter [] ... +``` + +!!! note "Runic Compatibility" + The CLI interface is designed to be compatible with [Runic.jl](https://github.com/fredrikekre/Runic.jl)'s CLI where possible, making it easier to switch between formatters. + + !!! warning "Missing features" + Note that the `--lines` option is not yet implemented. + +## Quick Start + +```bash +# Preview formatted output +jlfmt src/file.jl + +# Check if files are already formatted with verbose mode +jlfmt --check -v src/ + +# Format files in-place with multiple threads +jlfmt --threads=6 -- --inplace -v src/ + +# Show diff without modifying +jlfmt --diff src/file.jl +``` + +## Options + +Run `jlfmt --help` for a complete list: + +```@repl +using JuliaFormatter # hide +JuliaFormatter.main(["--help"]); # hide +``` + +## Configuration Files + +`jlfmt` searches for [`.JuliaFormatter.toml` configuration](@ref config) files starting from each input file's directory and walking up the directory tree. + +By default, command-line options override configuration file settings: + +```bash +# Use indent=2 even if config file specifies indent=4 +jlfmt --indent=2 src/file.jl +``` + +Use `--prioritize-config-file` to make configuration file settings take precedence (might be useful for language server integration): + +```bash +jlfmt --prioritize-config-file --indent=2 src/file.jl +``` + +### Configuration with stdin + +When formatting from stdin, no configuration file is used by default. +Use `--config-dir` to specify a directory for configuration file lookup: + +```bash +# Format stdin using config from ./src directory +echo 'f(x,y)=x+y' | jlfmt --config-dir=./src + +# Useful in editor integrations to respect project config +cat file.jl | jlfmt --config-dir=$(dirname file.jl) +``` + +The formatter will search for `.JuliaFormatter.toml` in the specified directory and its parent directories, just like it does for regular file inputs. + +## Conventions + +`jlfmt` follows standard CLI conventions: +- Exit code 0 on success +- Exit code 1 on formatting errors or when `--check` detects unformatted files +- Formatted output to stdout (default) or in-place with `--inplace` +- Error messages to stderr diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/config.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/config.md new file mode 100644 index 0000000..58732c4 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/config.md @@ -0,0 +1,87 @@ +```@meta +CurrentModule = JuliaFormatter +``` + +# [Configuration File](@id config) + +From v0.4.3, JuliaFormatter offers [`.prettierrc` style](https://prettier.io/docs/en/configuration.html) +configuration file support. +This means you can specify formatting options shown in [`format_text`](@ref) in `.JuliaFormatter.toml` file and share that with others. + +When [`format`](@ref) is called, it will look for `.JuliaFormatter.toml` in the location of the file being formatted, +and searching _up_ the file tree until a config file is (or isn't) found. +When found, the configurations in the file will overwrite the given options. + +## Basic Configuration + +In `.JuliaFormatter.toml`, you can specify any of the formatting options shown in [`format_text`](@ref) in TOML, e.g. if you have + +> somedir/.JuliaFormatter.toml + +```toml +indent = 2 +margin = 100 +``` + +then files under `somedir` will be formatted with 2 spaces indentation and the maximum line length 100. + +## Non Default Style + +If you would use another style, such as `YASStyle` you can write this in your configuration like so: + +```toml +style = "yas" +``` + +Styles choices are: + +- "default" (default choice if nothing is specified) +- "yas" +- "blue" +- "sciml" +- "minimal" + + + +## Search Rule + +`.JuliaFormatter.toml` will be searched _up_ from the directory of the file being formatted. +So if you have: + +``` +dir +├─ .JuliaFormatter.toml +├─ code.jl +└─ subdir + └─ sub_code.jl +``` + +then `format("subdir/sub_code.jl")` will be automatically configured by the `dir/.JuliaFormatter.toml`, as well as +`format("dir")` will format both `dir/code.jl` and `dir/subdir/sub_code.jl` according to the same configuration. + +What will happen when we have multiple `.JuliaFormatter.toml` files ? In that case, the _deepest_ configuration has the +precedence. For example, if you have + +``` +dir +├─ .JuliaFormatter.toml +├─ code.jl +├─ subdir1 +│ ├─ .JuliaFormatter.toml +│ └─ sub_code1.jl +└─ subdir2 + └─ sub_code2.jl +``` + +and call `format("dir")`, `code.jl` and `sub_code2.jl` will be formatted according to the rules defined in +`dir/.JuliaFormatter.toml`, while formatting `sub_code1.jl` will be configured by `dir/subdir1/.JuliaFormatter.toml`. + +## [Ignoring specific files and directories](@id ignore) + +If there is an entry in `.JuliaFormatter.toml` with +``` +ignore = ["file.jl", "directory", "file_*.jl"] +``` +then all of these files will be reported as already formatted: `./file.jl`, +`./directory/something.jl` `./other_directory/file.jl`, `file_1.jl`, +`.other_directory/file_name.jl`. diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/custom_alignment.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/custom_alignment.md new file mode 100644 index 0000000..0898ac8 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/custom_alignment.md @@ -0,0 +1,249 @@ +# Custom Alignment + +> Solution for [issue 179](https://github.com/domluna/JuliaFormatter.jl/issues/179) + +Custom alignment is determined by a whitespace heuristic: + +A token (typically an operator, i.e. `=, ?, ::, etc`) is custom aligned if there are +`> 1` whitespaces from the previous expression since the formatter only outputs +0 or 1 whitespaces for separation. If custom alignment is determined then all +expressions in the code block will be aligned to the furthest aligned token. + +> NOTE: alignment overrides nesting behavior, meaning it ignores the allowed maximum margin + +### Example + +Suppose the source text is as follows + +```julia +const variable1 = 1 +const var2 = 2 +const var3 = 3 +const var4 = 4 +const var5 = 5 +``` + +If the `align_assignment` option is enabled the formatter will detect that `var2` +is aligned to `variable1` AND `var2` has several whitespaces (>1) prior to +`=`. Since `var3`,`var4`, and `var5` are part of the same code block (no comments +or newlines separating code) they will also be aligned. + +So the output would be + +```julia +const variable1 = 1 +const var2 = 2 +const var3 = 3 +const var4 = 4 +const var5 = 5 +``` + +Notice how the `=` operator for `var5` is correctly positioned +despite it being located further to the right than other `=` operators. + +However, if the source code is + +```julia +const variable1 = 1 +const variable2 = 2 +const var3 = 3 +const var4 = 4 +const var5 = 5 +``` + +It's now ambiguous whether this is meant to be aligned and so the formatter will +proceed with normal behavior. + +## Alignment Options + + +In order for alignment to occur the option must be set to `true`. Available options: + +- `align_assignment` +- `align_struct_field` +- `align_conditional` +- `align_pair_arrow` +- `align_matrix` + +> **Caveat: Since nesting is disabled when alignment occurs be careful when adding comments to the RHS expression. This will be fixed in a future release** + +For example: + +```julia +const variable1 = 1 +const var2 = foo(10, + # comment, + 20) +``` + +This will be formatted to + +```julia +const variable1 = 1 +const var2 = foo(10, # comment, 20) +``` + +which causes a parsing error. + +### `align_assignment` + +Align to `=`-like operators. This covers variable assignments and short definition functions. + + +```julia +const UTF8PROC_STABLE = (1 << 1) +const UTF8PROC_COMPAT = (1 << 2) +const UTF8PROC_COMPOSE = (1 << 3) +const UTF8PROC_DECOMPOSE = (1 << 4) +const UTF8PROC_IGNORE = (1 << 5) +const UTF8PROC_REJECTNA = (1 << 6) +const UTF8PROC_NLF2LS = (1 << 7) +const UTF8PROC_NLF2PS = (1 << 8) +const UTF8PROC_NLF2LF = (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS) +const UTF8PROC_STRIPCC = (1 << 9) +const UTF8PROC_CASEFOLD = (1 << 10) +const UTF8PROC_CHARBOUND = (1 << 11) +const UTF8PROC_LUMP = (1 << 12) +const UTF8PROC_STRIP = (1 << 13) + + +vcat(X::T...) where {T} = T[X[i] for i = 1:length(X)] +vcat(X::T...) where {T<:Number} = T[X[i] for i = 1:length(X)] +hcat(X::T...) where {T} = T[X[j] for i = 1:1, j = 1:length(X)] +hcat(X::T...) where {T<:Number} = T[X[j] for i = 1:1, j = 1:length(X)] + +a = 1 +bc = 2 + +long_variable = 1 +other_var = 2 +``` + +### `align_struct_field` + +Align struct field definitions to `::` or `=` - whichever has higher precedence. + +```julia +Base.@kwdef struct Options + indent::Int = 4 + margin::Int = 92 + always_for_in::Bool = false + whitespace_typedefs::Bool = false + whitespace_ops_in_indices::Bool = false + remove_extra_newlines::Bool = false + import_to_using::Bool = false + pipe_to_function_call::Bool = false + short_to_long_function_def::Bool = false + always_use_return::Bool = false + whitespace_in_kwargs::Bool = true + annotate_untyped_fields_with_any::Bool = true + format_docstrings::Bool = false + align_struct_fields::Bool = false + + # no custom whitespace so this block is not aligned + another_field1::BlahBlahBlah = 10 + field2::Foo = 10 + + # no custom whitespace but single line blocks are not aligned + # either way + Options() = new() +end + + +mutable struct Foo + a :: T + longfieldname :: T +end +``` + +### `align_conditional` + +Align conditional expressions to either `?`, `:`, or both. + +```julia +# This will remain like this if using YASStyle +index = zeros(n <= typemax(Int8) ? Int8 : + n <= typemax(Int16) ? Int16 : + n <= typemax(Int32) ? Int32 : Int64, n) + +# Using DefaultStyle +index = zeros( + n <= typemax(Int8) ? Int8 : + n <= typemax(Int16) ? Int16 : + n <= typemax(Int32) ? Int32 : Int64, + n, +) + +# Note even if the maximum margin is set to 1, the alignment remains intact +index = + zeros( + n <= typemax(Int8) ? Int8 : + n <= typemax(Int16) ? Int16 : + n <= typemax(Int32) ? Int32 : Int64, + n, + ) + +``` + +### `align_pair_arrow` + +Align pair arrows (`=>`). + +```julia +pages = [ + "Introduction" => "index.md", + "How It Works" => "how_it_works.md", + "Code Style" => "style.md", + "Skipping Formatting" => "skipping_formatting.md", + "Syntax Transforms" => "transforms.md", + "Custom Alignment" => "custom_alignment.md", + "Custom Styles" => "custom_styles.md", + "YAS Style" => "yas_style.md", + "Configuration File" => "config.md", + "API Reference" => "api.md", +] +``` + + +### `align_matrix` + + > TLDR: If you want to align matrix elements yourself set this to `true` + +Whitespace surrounding matrix elements in the original source file is maintained. Differs from other alignment options since it does not try to "detect" alignment and then adjust other elements. + +```julia +# Elements left-aligned in original source +julia> s = """ + a = [ + 100 300 400 + 1 eee 40000 + 2 α b + ]""" +"a = [\n100 300 400\n1 eee 40000\n2 α b\n]" + +julia> format_text(s, align_matrix=true) |> print +a = [ + 100 300 400 + 1 eee 40000 + 2 α b +] + +# Elements right-aligned in original source +julia> s = """ + a = [ + 100 300 400 + 1 ee 40000 + 2 a b + ]""" +"a = [\n100 300 400\n 1 ee 40000\n 2 a b\n]" + +julia> + +julia> format_text(s, align_matrix=true) |> print +a = [ + 100 300 400 + 1 ee 40000 + 2 a b +] +``` + diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/how_it_works.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/how_it_works.md new file mode 100644 index 0000000..fded593 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/how_it_works.md @@ -0,0 +1,114 @@ +# How It Works + +The formatter takes a `.jl` file as input and produce a _idealized_, formatted `.jl` +as output. Some formatters mutate the state of the current file, `JuliaFormatter` takes a different +approach - first generating a canonical output, and then mutating that canonical output; adhering +to the indent and margin constraints. + +## Generating an `FST` + +The source code is parsed with `CSTParser.jl` which returns a CST (Concrete Syntax Tree). A CST +is a one-to-one mapping of the language to a tree form. In most cases a more compact AST (Abstract Syntax Tree) +representation is desired. However, since formatting manipulate the source text itself, the richer representation +of a CST is incredibly useful. + +Once the CST is created it's then used to generate a `FST` (Formatted Syntax Tree). + +> Note: this is not an actual term, just something I made up. Essentially it's a CST with additional formatting specific metadata. + +The important part of an FST is any `.jl` file that is syntactically the same (whitespace is irrelevant) produce an identical +`FST`. + +For example: + +```julia +# p1.jl +a = + foo(a, b, + c,d) +``` + +and + +```julia +# p2.jl +a = foo(a, +b, +c,d) +``` + +will produce the **same FST**, which printed would look like: + +```julia +# fst output +a = foo(a, b, c, d) +``` + +So what does a typical `FST` look like? + +Code and comments are indented to match surrounding code blocks. +Unnecessary whitespace is removed. Newlines in between code blocks are untouched. + +If the expression can be put on a single line it will be. It doesn't matter +it's a function call which 120 arguments, making it 1000 characters long. +During this initial stage it will be put on a single line. + +If the expression has a structure to it, such as a `try`, `if`, or 'struct' +definition. It will be spread across multiple lines appropriately: + +```julia + +# original source +try a1;a2 catch e b1;b2 finally c1;c2 end + +-> + +# printed FST +try + a1 + a2 +catch e + b1 + b2 +finally + c1 + c2 +end +``` + +With this `FST` representation it's much easier to determine when and how +lines should be broken. + +## Nesting - breaking lines + +During the nesting stage and original `FST` is mutated to adhere to the margin specification. + +Throughout the previous stage, while the `FST` was being generated, `PLACEHOLDER` nodes were +being inserted at various points. These can be converted to `NEWLINE` nodes during nesting, which +is how lines are broken. + +Assume we had a function call which went over the margin. + +```julia +begin + foo = funccall(argument1, argument2, ..., argument120) # way over margin limit !!! +end +``` + +It would be nested to + +```julia +begin + foo = funccall( + argument1, + argument2, + ..., + argument120 + ) # way over margin limit !!! +end +``` + +> You can read how code is nested in the style section. + +Once the `FST` has been nested it's then printed out to a file and voila! You have a formatted +version of your code! diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/index.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/index.md new file mode 100644 index 0000000..b2836ce --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/index.md @@ -0,0 +1,685 @@ +```@meta +CurrentModule = JuliaFormatter +``` + +# JuliaFormatter.jl + +Width-sensitive formatter for Julia code. Inspired by gofmt, refmt, black, and prettier. Built with [`CSTParser.jl`](https://github.com/julia-vscode/CSTParser.jl). + +- Sane defaults out of the box with options to customize. +- Supports [YAS](https://github.com/jrevels/YASGuide), [Blue](https://github.com/invenia/BlueStyle) and [SciML](https://github.com/SciML/SciMLStyle) style guides. +- `.JuliaFormatter.toml` configuration file to store options. + +![](https://user-images.githubusercontent.com/1813121/72941091-0b146300-3d68-11ea-9c95-75ec979caf6e.gif) + +## Installation + +```julia +]add JuliaFormatter +``` + +## Quick Start + +```julia +julia> using JuliaFormatter + +# Recursively formats all Julia files in the current directory +julia> format(".") + +# Formats an individual file +julia> format_file("foo.jl") + +# Formats a string (contents of a Julia file) +julia> format_text(str) +``` + +Check out the docs for further description of the formatter and its options. + +[Use With GitHub Actions](https://github.com/julia-actions/julia-format) + +## Formatting Options + +### `indent` + +> default: `4` + +The number of spaces used for an indentation. + +### `margin` + +> default: `92` + +The maximum length of a line. Code exceeding this margin will +be formatted across multiple lines. + +### `always_for_in` + +> default: `false` + +If true, `=` is always replaced with `in` if part of a `for` loop condition. +For example, `for i = 1:10` will be transformed to `for i in 1:10`. Set +this to `nothing` to leave the choice to the user. + +### `whitespace_typedefs` + +> default: `false` + +If true, whitespace is added for type definitions. Make this `true` +if you prefer `Union{A <: B, C}` to `Union{A<:B,C}`. + +### `whitespace_ops_in_indices` + +> default: `false` + +If true, whitespace is added for binary operations in indices. Make this +`true` if you prefer `arr[a + b]` to `arr[a+b]`. Additionally, if there's +a colon `:` involved, parenthesis will be added to the LHS and RHS. + +Example: `arr[(i1 + i2):(i3 + i4)]` instead of `arr[i1+i2:i3+i4]`. + +### `remove_extra_newlines` + +> default: `false` + +If true, superfluous newlines will be removed. For example: + +```julia +module M + + + +a = 1 + +function foo() + + + return nothing + +end + + +b = 2 + + +end +``` + +is rewritten as + +```julia +module M + +a = 1 + +function foo() + return nothing +end + +b = 2 + +end +``` + +Modules are the only type of code block allowed to keep a single newline +prior to the initial or after the final piece of code. + +### `import_to_using` + +> default: `false` + +If true, `import` expressions are rewritten to `using` expressions +in the following cases: + +```julia +import A + +import A, B, C +``` + +is rewritten to: + +```julia +using A: A + +using A: A +using B: B +using C: C +``` + +Exceptions: + +If `as` is found in the import expression. `using` CANNOT be used in this context. The following example will NOT BE rewritten. + +```julia +import Base.Threads as th +``` + +If `import` is used in the following context it is NOT rewritten. This may change in a future patch. + +```julia +@everywhere import A, B +``` + +### `pipe_to_function_call` + +> default: `false` + +If true, `x |> f` is rewritten to `f(x)`. + +### `short_to_long_function_def` + +> default: `false` + +Transforms a *short* function definition + +```julia +f(arg1, arg2) = body +``` + +to a *long* function definition if the short function definition exceeds the maximum margin. Or +if `force_long_function_def` is set to `true`. + +```julia +function f(arg2, arg2) + body +end +``` + +### `force_long_function_def` +> default: `false` + +If `true` tweaks the behavior of `short_to_long_function_def` to force the transformation no matter +how short the function definition is. + +### `long_to_short_function_def` + +> default: `false` + +Transforms a *long* function definition + +```julia +function f(arg2, arg2) + body +end +``` + +to a *short* function definition if the short function definition does not exceed the maximum margin. + +```julia +f(arg1, arg2) = body +``` + +### `always_use_return` + +> default: `false` + +If true, `return` will be prepended to the last expression where +applicable in function definitions, macro definitions, and do blocks. + +Example: + +```julia +function foo() + expr1 + expr2 +end +``` + +to + +```julia +function foo() + expr1 + return expr2 +end +``` + +### `whitespace_in_kwargs` + +> default: `true` + +If true, `=` in keyword arguments will be surrounded by whitespace. + +```julia +f(; a=4) +``` + +to + +```julia +f(; a = 4) +``` + +An exception to this is if the LHS ends with "!" then even if `whitespace_in_kwargs` is +false, `=` will still be surrounded by whitespace. The logic behind this intervention being +on the following parse the `!` will be treated as part of `=`, as in a "not equal" binary +operation. This would change the semantics of the code and is therefore disallowed. + +### `annotate_untyped_fields_with_any` + +> default: `true` + +Annotates fields in a type definitions with `::Any` if no type annotation is provided: + +```julia +struct A + arg1 +end +``` + +to + +```julia +struct A + arg1::Any +end +``` + +### `format_docstrings` + +> default: `false` + +Format code docstrings with the same options used for the code source. + +Markdown is formatted with [`CommonMark`](https://github.com/MichaelHatherly/CommonMark.jl) alongside Julia code. + +### `align_*` + +> default: `false` + +See `Custom Alignment` documentation. + +### `conditional_to_if` + +> default: `false` + +If the conditional `E ? A : B` exceeds the maximum margin converts it into the equivalent `if` block: + +```julia +if E + A +else + B +end +``` + +### `normalize_line_endings` + +> default: `"auto"` + +One of `"unix"` (normalize all `\r\n` to `\n`), `"windows"` (normalize all `\n` to `\r\n`), `"auto"` (automatically +choose based on which line ending is more common in the file). + +### `trailing_comma` + +> default: `true` + +One of `true`, `false`, or `nothing`. + +Trailing commas are added after the final argument when nesting occurs and the closing punctuation appears on the next line. + +For example when the following is nested (assuming `DefaultStyle`): + +```julia +funccall(arg1, arg2, arg3) +``` + +it turns into: + +```julia +funccall( + arg1, + arg2, + arg3, # trailing comma added after `arg3` (final argument) !!! +) +``` + +* When set to `true`, the trailing comma is always added during nesting. +* When set to `false`, the trailing comma is always removed during nesting. +* When set to `nothing`, the trailing comma appears as it does in the original source. + +### `trailing_zero` + +> default: `true` + +Add a trailing zero, if needed. + +### `join_lines_based_on_source` + +> default: `false` + +When `true` lines are joined as they appear in the original source file. + +```julia +function foo(arg1, + arg2, arg3 + ) + body +end +``` + +When `false` and the maximum margin is > than the length of `"function foo(arg1, arg2, arg3)"` +this is formatted to + +```julia +function foo(arg1, arg2, arg3) + body +end +``` + +When `true`, `arg1` and `arg2, arg3` will remain on separate lines even if they can fit on the +same line since it's within maximum margin. The indentation is dependent on the style. + +```julia +function foo(arg1, + arg2, arg3, +) +end +``` + +There are exceptions to this: + +```julia +if a body1 elseif b body2 else body3 end +``` + +will be formatted to the following, even if this option is set to `true`: + +```julia +if a + body1 +elseif b + body2 +else + body3 +end +``` + +!!! warning + + The maximum margin still applies even when this option is set to `true`. + +### `indent_submodule` + +> default: `false` + +When set to `true`, submodule(s) appearing in the same file will be indented. + +```julia +module A +a = 1 + +module B +b = 2 +module C +c = 3 +end +end + +d = 4 + +end +``` + +will be formatted to: + +```julia +module A +a = 1 + +module B + b = 2 + module C + c = 3 + end +end + +d = 4 + +end +``` + +### `separate_kwargs_with_semicolon` + +> default: `false` + +When set to `true`, keyword arguments in a function call will be separated with a semicolon. + +```julia +f(a, b=1) + +-> + +f(a; b=1) +``` + +### `surround_whereop_typeparameters` + +> default: `true` + +Surrounds type parameters with curly brackets when set to `true` if the brackets are not +already present. + +```julia +function func(...) where TPARAM +end + +-> + +function func(...) where {TPARAM} +end +``` + +### `for_in_replacement` + +Can be used when `always_for_in` is `true` to replace the default `in` with `∈` (`\\in`), +or `=` instead. The replacement options are `("in", "=", "∈")`. + +```julia +for a = 1:10 +end + +# formatted with always_for_in = true, for_in_replacement = "∈" +for a ∈ 1:10 +end +``` + +### `variable_call_indent` && `yas_style_nesting` + +The `SciMLStyle` supports the additional options `variable_call_indent` and `yas_style_nesting`. + +The option `variable_call_indent` is set to `[]` by default. +It allows calls without aligning to the opening parenthesis: + +```julia +# Allowed with and without `Dict in variable_call_indent` +Dict{Int, Int}(1 => 2, + 3 => 4) + +# Allowed when `Dict in variable_call_indent`, but +# will be changed to the first example when `Dict ∉ variable_call_indent`. +Dict{Int, Int}( + 1 => 2, + 3 => 4) +``` + +The option `yas_style_nesting` is set to `false` by default. +Setting it to `true` makes the `SciMLStyle` use the `YASStyle` nesting rules: + +```julia +# With `yas_style_nesting = false` +function my_large_function(argument1, argument2, + argument3, argument4, + argument5, x, y, z) + foo(x) + goo(y) +end + +# With `yas_style_nesting = true` +function my_large_function(argument1, argument2, + argument3, argument4, + argument5, x, y, z) + foo(x) + goo(y) +end +``` + +### `short_circuit_to_if` + +You can convert short circuit expressions to the equivalent if expression. + +```julia +function foo(a, b) + a || return "bar" + + "hello" + + b && return "ooo" +end + +BECOMES + +function foo(a, b) + if !(a) + return "bar" + end + + "hello" + + if b + return "ooo" + else + false + end +end +``` + +### `disallow_single_arg_nesting` + +Prevents the nesting of a single argument `arg` in parenthesis, brackets, and curly braces. + +```julia +# Without `disallow_single_arg_nesting`: +function_call( + "String argument" +) +[array_item( + 10 +)] +{key => value( + "String value" +)} + +# With `disallow_single_arg_nesting` enabled: +function_call("String argument") +[array_item(10)] +{key => value("String value")} +``` + +## File Options + +### `overwrite` + +> default: `true` + +If `true` the file will be reformatted in place, overwriting the existing file; +if it is `false`, the formatted version of foo.jl will not be written anywhere. + +### `verbose` + +> default: `false` + +If `true` details related to formatting the file will be printed to `stdout`. + +### `format_markdown` + +> default: `false` + +If `true`, Markdown files are also formatted. Julia code blocks will be formatted in +addition to the Markdown being normalized. + +### `ignore` + +An array of paths to files and directories (with possible Glob wildcards) +which will not be formatted. + +## Special Format Comments + +### Turn off/on formatting + +You can skip sections of code by using the `#! format: off` and `#! format: on` comments. + +```julia + +# this should be formatted +a = f(aaa, bbb, ccc) + +# this should not be formatted +#! format: off +a = f(aaa, + bbb,ccc) + +c = 102000 + +d = @foo 10 20 + +e = "what the foocho" +#! format: on + +# this should be formatted +a = f(aaa, bbb, ccc) + +# ok +``` + +If you wish to not format an entire file just add `#! format: off` to the top of the file. + +### Stopping a block of code from indenting + +Sometimes you may wish for a block of code to not be indented. You can achieve this with `#! format: noindent`. + +```julia +begin +@muladd begin + #! format: noindent + a = 10 + b = 20 + begin + # another indent + z = 33 + end + + a * b +end + end +``` + +is formatted to + + +```julia +begin + @muladd begin + #! format: noindent + a = 10 + b = 20 + begin + # another indent + z = 33 + end + + a * b + end +end +``` + +Notice the contents of `@muladd begin` is not indented. + +`#! format: noindent` can also be nested. + +## Editor Plugins + +For integration with other editors: + + - [VSCode](https://github.com/singularitti/vscode-julia-formatter/) + - [Emacs](https://codeberg.org/FelipeLema/julia-formatter.el) + - [Vim](https://github.com/kdheepak/JuliaFormatter.vim) + - [Atom (deprecated)](https://github.com/JunoLab/Atom.jl) diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/integrations.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/integrations.md new file mode 100644 index 0000000..b5cdfb8 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/integrations.md @@ -0,0 +1,23 @@ +# Integrations + +## `pre-commit` + +To learn more about `pre-commit`, [check out their docs](https://pre-commit.com). + +With [Pull 674](https://github.com/domluna/JuliaFormatter.jl/pull/674), support for +`pre-commit` was added. To add `JuliaFormatter.jl` to your own `pre-commit` workflow, +add the following to your `.pre-commit-config.yaml`. + +```yaml +repos: +# ... other repos you may have +- repo: "https://github.com/domluna/JuliaFormatter.jl" + rev: "v1.0.18" # or whatever the desired release is + hooks: + - id: "julia-formatter" +# ... other repos you may have +``` + +You can find a list of releases [here](https://github.com/domluna/JuliaFormatter.jl/releases). +**Be sure to use the entire version string!** (You can double-check this by opening the +release and looking at the part of the URL that follows `.../releases/tag/VERSION`.) \ No newline at end of file diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/sciml_style.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/sciml_style.md new file mode 100644 index 0000000..ed47561 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/sciml_style.md @@ -0,0 +1,70 @@ +# SciML Style + +```@docs +SciMLStyle +``` + +## Configuration File Example + +The `.JuliaFormatter.toml` which represents these settings is + +```toml +style = "sciml" +``` + +Or to use `SciMLStyle` except change one of the settings: + +```toml +style = "sciml" +remove_extra_newlines = false +``` + +## Direct Usage + +```julia +format("file.jl", SciMLStyle()) +``` + +Or to use `SciMLStyle` except change one of the settings: + +```julia +format("file.jl", SciMLStyle(), remove_extra_newlines=false) +``` + +## Additional Options + +The `SciMLStyle` supports the additional options `variable_call_indent` and `yas_style_nesting`. + +The option `variable_call_indent` is set to `[]` by default. +It allows calls without aligning to the opening parenthesis: + +```julia +# Allowed with and without `Dict in variable_call_indent` +Dict{Int, Int}(1 => 2, + 3 => 4) + +# Allowed when `Dict in variable_call_indent`, but +# will be changed to the first example when `Dict ∉ variable_call_indent`. +Dict{Int, Int}( + 1 => 2, + 3 => 4) +``` + +The option `yas_style_nesting` is set to `false` by default. +Setting it to `true` makes the `SciMLStyle` use the `YASStyle` nesting rules: + +```julia +# With `yas_style_nesting = false` +function my_large_function(argument1, argument2, + argument3, argument4, + argument5, x, y, z) + foo(x) + goo(y) +end + +# With `yas_style_nesting = true` +function my_large_function(argument1, argument2, + argument3, argument4, + argument5, x, y, z) + foo(x) + goo(y) +end +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/skipping_formatting.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/skipping_formatting.md new file mode 100644 index 0000000..9a4109f --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/skipping_formatting.md @@ -0,0 +1,32 @@ +# Skipping Formatting + +By default formatting is always on but can be toggled with the following comments: + +```julia +#! format: off +# Turns off formatting from this point onwards +... + +#! format: on +# Turns formatting back on from this point onwards +``` + +These can be used throughout a file, or, for an entire file not be formatted add "format: off" at the top of the file: + +```julia +#! format: off +# +# It doesn't actually matter if it's on +# the first line of the line but anything +# onwards will NOT be formatted. + +module Foo +... +end +``` + +!!! note "Ignoring files" + You can also ignore entire files and directories by supplying + [the `ignore` option](@ref ignore) in `.JuliaFormatter.toml`. + +Note the formatter expects `#! format: on` and `#! format: off` to be on its own line and the whitespace to be an exact match. diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/style.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/style.md new file mode 100644 index 0000000..5114bfd --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/style.md @@ -0,0 +1,350 @@ +```@meta +CurrentModule = JuliaFormatter +``` + +# Style + +This is meant to give an impression of how the output of a formatted file looks like. +Additional examples can be found in the [test files](https://github.com/domluna/JuliaFormatter.jl/tree/master/test/files). + +## Initial `FST` + +> All examples assume indentation of **4 spaces** + +Functions, macros, structs with no arguments are placed on a single line: + +```julia +function foo +end + +-> + +function foo end +``` + +This also applies to abstract and primitive types: + +```julia +abstract type +AbstractFoo +end + +-> + +abstract type AbstractFoo end +``` + +Functions calls `foo(args...)`, tuples `(args...)`, arrays `[args...]`, braces `{args...}`, struct or where definitions `Foo{args...}` are placed on a single line. This applies to any code which has opening and closing punctuation: `(...)`, `{...}`, `[...]`. + +```julia +f( + +a,b + +,c ) + +-> + +f(a, b, c) +``` + +By default type definitions have no whitespace after commas: + +```julia +Foo{ +a,b +,c } + +-> + +Foo{a,b,c} +``` + +Blocks and their bodies are spread across multiple lines properly indented. + +Example 1: + +```julia +begin + a + b; c + end + +-> + +begin + a + b + c +end +``` + +Example 2: + +```julia +struct Foo{A, B} + a::A + b::B +end + +-> + +struct Foo{A,B} + a::A + b::B +end +``` + +Binary calls are placed on a single line and separated by whitespace. +The exception to this are colon operations and operations inside an indexing expression. +The latter being optional. + +Example 1: + +```julia +a+b + +-> + +a + b +``` + +Example 2: + +```julia +a : a : c + +-> + +a:b:c +``` + +Example 3: + +```julia +list[a + b] + +-> + +list[a+b] +``` + +Conditionals are placed on a single line and separated by whitespace. + +```julia +cond1 ? +expr1 : expr2 + +-> + +cond1 ? expr1 : expr2 +``` + +Comments are aligned to surrounding code blocks. + +```julia +# comment +if a +# comment +elseif b +# comment +elseif c +# comment +else +# comment +end +# comment + +-> + +# comment +if a + # comment +elseif b + # comment +elseif c + # comment +else + # comment +end +# comment +``` + +## Nesting `FST` + +Binary operations and conditionals are nested back-to-front. + +Example 1: + +```julia +arg1 + arg2 + +-> + +arg1 + +arg2 +``` + +Example 2: + +```julia +cond ? e1 : e2 + +-> + +cond ? e1 : +e2 + +-> + +cond ? +e1 : +e2 +``` + +If nesting is required for a `=` binary operation, the RHS is placed on the following line and indented. + +```julia +foo() = body + +-> + +foo() = + body +``` + +Lazy `&&` and `||` operations are nested according to [`is_standalone_shortcircuit`](@ref) rules. + +All arguments of a function call (applies to any opening/closing punctuation type) are nested +if the expression exceeds the margin. The arguments are indented one level. + +```julia +function longfunctionname_that_is_long(lots, of, args, even, more, args) + body +end + +-> + +function longfunctionname_that_is_long( + lots, + of, + args, + even, + more, + args, +) + body +end +``` + +With `where` operations (`A where B`), `A` is nested prior to `B`. + +```julia +function f(arg1::A, key1 = val1; key2 = val2) where {A,B,C} + body +end + +-> + +function f( + arg1::A, + key1 = val1; + key2 = val2, +) where {A,B,C} + body +end + +-> + +function f( + arg1::A, + key1 = val1; + key2 = val2, +) where { + A, + B, + C, +} + body +end +``` + +If a comment is detected inside of an expression, that expression is automatically nested: + +```julia +var = foo( + a, b, # comment + c, +) + +-> + +var = foo( + a, + b, # comment + c, +) +``` + +## Unnesting `FST` + +In certain cases it's desirable to unnest parts of a `FST`. + +Example 1: + +```julia +# short function def +function foo(arg1, arg2, arg3) = body + +-> + +function foo(arg1, arg2, arg3) = + body + +-> + +function foo( + arg1, + arg2, + arg3, +) = + body + +# If the margin allows it, `body` will be joined back +# with the previous line. + +function foo( + arg1, + arg2, + arg3, +) = body +``` + +Example 2: + +```julia +var = funccall(arg1, arg2, arg3) + +-> + +var = + funccall(arg1, arg2, arg3) + +-> + +var = + funccall( + arg1, + arg2, + arg3, + ) + +# If the margin allows it, the RHS will be joined back +# with the previous line. + +var = funccall( + arg1, + arg2, + arg3, +) +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/transforms.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/transforms.md new file mode 100644 index 0000000..88e0ded --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/transforms.md @@ -0,0 +1,115 @@ +# Syntax Tree Transformations + +## `for in` vs. `for =` + +By default if the RHS is a range, i.e. `1:10` then `for in` is converted to `for =`. Otherwise `for =` is converted to `for in`. See [this issue](https://github.com/domluna/JuliaFormatter.jl/issues/34) for the rationale and further explanation. + +Alternative to the above - setting `always_for_in` to `true`, i.e. `format_text(..., always_for_in = true)` will always convert `=` to `in` even if the RHS is a range. +`always_for_in=nothing` will leave the choice of `in` vs `=` up to the user. + +## Trailing Commas + +If the node is _iterable_, for example a function call or list and is nested, a trailing comma is added to the last argument. The trailing comma is removed if unnested: + +```julia +func(a, b, c) + +-> + +func( + a, + b, + c, +) +``` + +See [this issue](https://github.com/domluna/JuliaFormatter.jl/issues/44) for more details. + +## Trailing Semicolons + +If a matrix node is nested the semicolons are removed. + +```julia +A = [1 0; 0 1] + +-> + +A = [ + 1 0 + 0 1 +] +``` + +See [this issue](https://github.com/domluna/JuliaFormatter.jl/issues/77) for more details. + +## Leading and trailing 0s for float literals + +If a float literal is missing a *trailing* 0 it is added: + +```julia +a = 1. + +-> + +a = 1.0 +``` + +If a float literal is missing a *leading* 0 it is added: + +```julia +a = .1 + +-> + +a = 0.1 +``` + +For `Float32` if there is no decimal point, `.0` is added: + +```julia +a = 1f0 + +-> + +a = 1.0f0 +``` + +See [this issue](https://github.com/domluna/JuliaFormatter.jl/issues/66) for more details. + +## Surround `where` arguments with curly brackets + +If the arguments of a `where` call are not surrounded by curly brackets, they are added: + +```julia +foo(x::T) where T = ... + +-> + +foo(x::T) where {T} = ... +``` + +See [this issue](https://github.com/domluna/JuliaFormatter.jl/issues/53) for more details. + +## Annotate unannotated type fields with `Any` + +```julia +struct Foo + field +end + +-> + +struct Foo + field::Any +end +``` + +## Move `@` in macro calls to the final identifier + +```julia +@Module.macro + +-> + +Module.@macro +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/yas_style.md b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/yas_style.md new file mode 100644 index 0000000..161b7ce --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/docs/src/yas_style.md @@ -0,0 +1,99 @@ +# YAS Style + +```@docs +YASStyle +``` + +## Configuration File Example + +The `.JuliaFormatter.toml` which represents these settings is + +```toml +style = "yas" +``` + +Or to use `YASStyle` except change one of the settings: + +```toml +style = "yas" +remove_extra_newlines = false +``` + +## Direct Usage + +```julia +format("file.jl", YASStyle()) +``` + +Or to use `YASStyle` except change one of the settings: + +```julia +format("file.jl", YASStyle(), remove_extra_newlines=false) +``` + +## Differences from `DefaultStyle` + +There are three main differences between `YASStyle` and `DefaultStyle`. They are based +on alignment and line break behaviors. + + 1. Arguments are aligned to just after the start of the *opener* `[, {, (, etc`. + +```julia +function_call(arg1, + arg2) +``` + + 2. As you can see from the above the *closer* sticks to the final argument. + + 3. Nesting (line breaks) only occur when the margin of the next argument exceeds + the maximim limit. + +```julia +function_call(arg1, arg2, + arg3) +``` + +`arg3` exceeded the margin limit and so it was placed on the following line. + +### Nesting `=` + +Unlike `DefaultStyle`, assignment operations `=` are not nested. That +is, the following + +```julia +my_function(arg1, arg2) = arg1 * arg2 +``` + +Is not nested to + +```julia +my_function(arg1, arg2) = + arg1 * arg2 +``` + +It is highly recommended setting `short_to_long_function_def` to `true`. This option +transforms the above to a long function definition if it exceeds the maximum margin. + +```julia +function my_function(arg1, arg2) + arg1 * arg2 +end +``` + +## Additional Options + +The `YASStyle` supports the additional option `variable_call_indent`, +which is set to `[]` by default. +It allows calls without aligning to the opening parenthesis: + +```julia +# Allowed with and without `Dict in variable_call_indent` +Dict{Int,Int}(1 => 2, + 3 => 4) + +# Allowed when `Dict in variable_call_indent`, but +# will be changed to the first example when `Dict ∉ variable_call_indent`. +Dict{Int,Int}( + 1 => 2, + 3 => 4) +``` diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/src/JuliaFormatter.jl b/.julia-depot/packages/JuliaFormatter/zLsPw/src/JuliaFormatter.jl new file mode 100644 index 0000000..25dca11 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/src/JuliaFormatter.jl @@ -0,0 +1,589 @@ +module JuliaFormatter + +# reduces compilation time +if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@max_methods")) + @eval Base.Experimental.@max_methods 1 +end + +using PrecompileTools: @setup_workload, @compile_workload +using JuliaSyntax +using JuliaSyntax: haschildren, children, span, @K_str, kind, @KSet_str +using TOML: parsefile +using Glob +import CommonMark: block_modifier +import Base: get, pairs, show, push!, @kwdef +using CommonMark: + AdmonitionRule, + CodeBlock, + enable!, + FootnoteRule, + markdown, + MathRule, + Parser, + Rule, + TableRule, + FrontMatterRule + +export format, + format_text, + format_file, + format_md, + DefaultStyle, + YASStyle, + BlueStyle, + SciMLStyle, + MinimalStyle + +struct Configuration + args::Dict{String,Any} + file::Dict{String,Any} +end +Configuration() = Configuration(Dict{String,Any}(), Dict{String,Any}()) +Configuration(args) = Configuration(args, Dict{String,Any}()) +function get(config::Configuration, s::String, default) + if haskey(config.args, s) + return config.args[s] + end + if haskey(config.file, s) + return config.file[s] + end + return default +end +function pairs(conf::Configuration) + pairs(merge(conf.file, conf.args)) +end + +abstract type AbstractStyle end + +options(::AbstractStyle) = NamedTuple() + +struct NoopStyle <: AbstractStyle end + +""" + DefaultStyle + +The default formatting style. See the [Style](@ref) section of the documentation +for more details. + +See also: [`BlueStyle`](@ref), [`YASStyle`](@ref), [`SciMLStyle`](@ref), [`MinimalStyle`](@ref) +""" +struct DefaultStyle <: AbstractStyle + innerstyle::AbstractStyle +end +DefaultStyle() = DefaultStyle(NoopStyle()) + +getstyle(s::NoopStyle) = s +getstyle(s::DefaultStyle) = s.innerstyle isa NoopStyle ? s : s.innerstyle + +function options(::DefaultStyle) + return (; + indent = 4, + margin = 92, + always_for_in = false, + whitespace_typedefs = false, + whitespace_ops_in_indices = false, + remove_extra_newlines = false, + import_to_using = false, + pipe_to_function_call = false, + short_to_long_function_def = false, + long_to_short_function_def = false, + always_use_return = false, + whitespace_in_kwargs = true, + annotate_untyped_fields_with_any = true, + format_docstrings = false, + align_struct_field = false, + align_assignment = false, + align_conditional = false, + align_pair_arrow = false, + conditional_to_if = false, + normalize_line_endings = "auto", + align_matrix = false, + join_lines_based_on_source = false, + trailing_comma = true, + trailing_zero = true, + indent_submodule = false, + separate_kwargs_with_semicolon = false, + surround_whereop_typeparameters = true, + variable_call_indent = [], + short_circuit_to_if = false, + disallow_single_arg_nesting = false, + ) +end + +include("document.jl") +include("options.jl") +include("state.jl") +include("fst.jl") +include("passes.jl") +include("align.jl") + +function list_different_defaults(style) + options_style = pairs(options(style)) + options_default = pairs(options(DefaultStyle())) + options_changed = setdiff(options_style, options_default) + sort!(options_changed; by = first) + io = IOBuffer() + for (key, val) in options_changed + println(io, "- `$key` = $val") + end + String(take!(io)) +end + +include("styles/default/pretty.jl") +include("styles/default/nest.jl") +include("styles/yas/pretty.jl") +include("styles/yas/nest.jl") +include("styles/blue/pretty.jl") +include("styles/blue/nest.jl") +include("styles/sciml/pretty.jl") +include("styles/sciml/nest.jl") +include("styles/minimal/pretty.jl") + +include("format_docstring.jl") +include("nest_utils.jl") +include("print.jl") +include("markdown.jl") +include("copied_from_documenter.jl") + +const UNIX_TO_WINDOWS = r"\r?\n" => "\r\n" +const WINDOWS_TO_UNIX = "\r\n" => "\n" +function choose_line_ending_replacer(text) + rn = count("\r\n", text) + n = count(r"(?= rn ? WINDOWS_TO_UNIX : UNIX_TO_WINDOWS +end +normalize_line_ending(s::AbstractString, replacer = WINDOWS_TO_UNIX) = replace(s, replacer) + +""" + format_text( + text::AbstractString; + style::AbstractStyle = DefaultStyle(), + indent::Int = 4, + margin::Int = 92, + options..., + )::String + +Formats a Julia source passed in as a string, returning the formatted +code as another string. + +See https://domluna.github.io/JuliaFormatter.jl/dev/#Formatting-Options for details on available options. +""" +function format_text(text::AbstractString; style::AbstractStyle = DefaultStyle(), kwargs...) + return format_text(text, style; kwargs...) +end + +function format_text(text::AbstractString, style::AbstractStyle; kwargs...) + if isempty(text) + return text + end + opts = Options(; merge(options(style), kwargs)...) + return format_text(text, style, opts) +end + +function format_text(text::AbstractString, style::SciMLStyle; maxiters = 3, kwargs...) + if isempty(text) + return text + end + opts = Options(; merge(options(style), kwargs)...) + # We need to iterate to a fixpoint because the result of short to long + # form isn't properly formatted + formatted_text = format_text(text, style, opts) + if maxiters == 0 + return formatted_text + end + iter = 1 + while formatted_text != text + if iter > maxiters + error("formatted_text hasn't reached to a fixpoint in $iter iterations") + end + text = formatted_text + formatted_text = format_text(text, style, opts) + iter += 1 + end + return formatted_text +end + +function format_text(text::AbstractString, style::AbstractStyle, opts::Options) + if opts.always_for_in == true + @assert valid_for_in_op(opts.for_in_replacement) "`for_in_replacement` is set to an invalid operator \"$(opts.for_in_replacement)\", valid operators are $(VALID_FOR_IN_OPERATORS). Change it to one of the valid operators and then reformat." + end + t = JuliaSyntax.parseall(JuliaSyntax.GreenNode, text; ignore_warnings = true) + state = State(Document(text), opts) + text = format_text(t, style, state) + return text +end + +function format_text(node::JuliaSyntax.GreenNode, style::AbstractStyle, s::State) + fst::FST = try + pretty(style, node, s) + catch e + loc = cursor_loc(s, s.offset) + @warn "Error occurred during prettification" line = loc[1] offset = loc[2] goffset = + s.offset + rethrow(e) + end + if hascomment(s.doc, fst.endline) + add_node!(fst, InlineComment(fst.endline), s) + end + + if s.opts.pipe_to_function_call + pipe_to_function_call_pass!(fst) + end + + flatten_fst!(fst) + + if s.opts.short_circuit_to_if + short_circuit_to_if_pass!(fst, s) + end + + if needs_alignment(s.opts) + align_fst!(fst, s.opts) + end + + nest!(style, fst, s) + + # ignore maximum width can be extra whitespace at the end of lines + # remove it all before we print. + if s.opts.join_lines_based_on_source + remove_superfluous_whitespace!(fst) + end + + s.line_offset = 0 + io = IOBuffer() + + # Print comments and whitespace before code. + if fst.startline > 1 + format_check(io, Notcode(1, fst.startline - 1), s) + print_leaf(io, Newline(), s) + end + print_tree(io, fst, s) + nlines = numlines(s.doc) + if s.on && fst.endline < nlines + print_leaf(io, Newline(), s) + format_check(io, Notcode(fst.endline + 1, nlines), s) + end + if s.doc.ends_on_nl + print_leaf(io, Newline(), s) + end + text = String(take!(io)) + + replacer = if s.opts.normalize_line_endings == "unix" + WINDOWS_TO_UNIX + elseif s.opts.normalize_line_endings == "windows" + UNIX_TO_WINDOWS + else + choose_line_ending_replacer(s.doc.srcfile.code) + end + text = normalize_line_ending(text, replacer) + + try + _ = JuliaSyntax.parseall(JuliaSyntax.GreenNode, text; ignore_warnings = true) + catch err + @warn "Formatted text is not parsable ... no change made." + rethrow(err) + end + + return text +end + +function _format_file( + filename::AbstractString; + overwrite::Bool = true, + verbose::Bool = false, + format_markdown::Bool = false, + format_options..., +)::Bool + path, ext = splitext(filename) + shebang_pattern = r"^#!\s*/.*\bjulia[0-9.-]*\b" + formatted_str = if match(r"^\.[jq]*md$", ext) ≠ nothing + if !(format_markdown) + return true + end + if verbose + println("Formatting $filename") + end + str = String(read(filename)) + format_md(str; format_options...) + elseif ext == ".jl" || match(shebang_pattern, readline(filename)) !== nothing + if verbose + println("Formatting $filename") + end + str = String(read(filename)) + format_text(str; format_options...) + else + error("$filename must be a Julia (.jl) or Markdown (.md, .jmd or .qmd) source file") + end + formatted_str = replace(formatted_str, r"\n*$" => "\n") + already_formatted = (formatted_str == str) + if overwrite && !already_formatted + write(filename, formatted_str) + end + return already_formatted +end + +function _format_file(filename::AbstractString, style::AbstractStyle; kwargs...) + return _format_file(filename; style = style, kwargs...) +end + +const CONFIG_FILE_NAME = ".JuliaFormatter.toml" + +""" + format_file( + filename::AbstractString; + overwrite::Bool = true, + verbose::Bool = false, + format_markdown::Bool = false, + format_options..., + )::Bool + +Formats the contents of `filename` assuming it's a `.jl`, `.md`, `.jmd` or `.qmd` file. + +See https://domluna.github.io/JuliaFormatter.jl/dev/#File-Options for details on available options. + +## Output + +Returns a boolean indicating whether the file was already formatted (`true`) or not (`false`). +""" +function format_file( + filename::AbstractString; + overwrite::Bool = true, + verbose::Bool = false, + format_markdown::Bool = false, + format_options..., +) + format( + filename; + overwrite = overwrite, + verbose = verbose, + format_markdown = format_markdown, + format_options..., + ) +end + +function format_file(filename::AbstractString, style::AbstractStyle; kwargs...) + return format_file(filename; style = style, kwargs...) +end + +""" + format( + paths; # a path or collection of paths + options..., + )::Bool + +Recursively descend into files and directories, formatting any `.jl`, `.md`, `.jmd`, +or `.qmd` files. + +See [`format_file`](@ref) and [`format_text`](@ref) for a description of the options. + +This function will look for `.JuliaFormatter.toml` in the location of the file being +formatted, and searching *up* the file tree until a config file is (or isn't) found. +When found, the configurations in the file will overwrite the given `options`. +See [Configuration File](@ref) for more details. + +### Output + +Returns a boolean indicating whether the file was already formatted (`true`) +or not (`false`). +""" +function format(paths; options...) + format(paths, Configuration(Dict{String,Any}(String(k) => v for (k, v) in options))) +end +function format(paths, options::Configuration)::Bool + already_formatted = true + # Don't parallelize this, since there could be a race condition on a + # subdirectory that is included in both paths + for path in paths + already_formatted &= format(path, options) + end + return already_formatted +end + +function format(path::AbstractString; verbose::Bool = false, options...) + config = Dict{String,Any}(String(k) => v for (k, v) in options) + config["verbose"] = verbose + formatted = format(path, Configuration(config)) + if verbose && formatted + println("Well done! ✨ 🍰 ✨") + end + return formatted +end + +function format(path::AbstractString, options::Configuration) + path = realpath(path) + if !get(options, "config_applied", false) + # Run recursive search upward *once* + options = + Configuration(copy(options.args), Dict{String,Any}(find_config_file(path))) + options.args["config_applied"] = true + end + if isignored(path, options) + return true + end + if isdir(path) + configpath = joinpath(path, CONFIG_FILE_NAME) + if isfile(configpath) + options = Configuration(copy(options.args), parse_config(configpath)) + end + formatted = Threads.Atomic{Bool}(true) + Threads.@threads for subpath in readdir(path) + subpath = joinpath(path, subpath) + if !ispath(subpath) || islink(subpath) + continue + end + is_formatted = format(subpath, options) + Threads.atomic_and!(formatted, is_formatted) + end + return formatted.value + end + # `path` is not a directory but a file + _, ext = splitext(path) + if !in(ext, (".jl", ".md", ".jmd", ".qmd")) + return true + end + try + formatted = _format_file(path; [Symbol(k) => v for (k, v) in pairs(options)]...) + return formatted + catch err + if err isa JuliaSyntax.ParseError + @warn "Failed to format file $path due to a parsing error, skipping file" error = + err + return true + end + @info "Error in formatting file $path" + @debug "formatting failed due to" exception = (err, catch_backtrace()) + return _format_file(path; [Symbol(k) => v for (k, v) in pairs(options)]...) + end +end + +""" + format(path, style::AbstractStyle; options...)::Bool +""" +function format(path::AbstractString, style::AbstractStyle; options...) + formatted = format(path; style = style, options...) + formatted +end + +""" + format(mod::Module, args...; options...) +""" +format(mod::Module; options...) = _format_module(mod; options...) +function format(mod::Module, style::AbstractStyle; options...) + _format_module(mod, style; options...) +end +function format(mod::Module, config::Configuration; options...) + _format_module(mod, config; options...) +end + +# This separate is needed to remove ambiguity in `format` without code duplication +function _format_module(mod::Module, args...; options...) + path = pkgdir(mod) + if path === nothing + throw(ArgumentError("couldn't find a directory of module `$mod`")) + end + format(path, args...; options...) +end + +function kwargs(dict) + ns = (Symbol.(keys(dict))...,) + vs = (collect(values(dict))...,) + return pairs(NamedTuple{ns}(vs)) +end + +fieldnts(T::Type) = ((fieldname(T, i), fieldtype(T, i)) for i in 1:fieldcount(T)) + +function parse_config(tomlfile) + config_dict = parsefile(tomlfile) + for (field, type) in fieldnts(Options) + if type == Union{Bool,Nothing} + field = string(field) + if get(config_dict, field, "") == "nothing" + config_dict[field] = nothing + end + end + end + if (style = get(config_dict, "style", nothing)) !== nothing + if style ∉ ("default", "yas", "blue", "sciml", "minimal") + error( + "currently $(CONFIG_FILE_NAME) accepts only \"default\" or \"yas\", \"blue\", \"sciml\", or \"minimal\" for the style configuration", + ) + end + config_dict["style"] = if style == "yas" + YASStyle() + elseif style == "blue" + BlueStyle() + elseif style == "sciml" + SciMLStyle() + elseif style == "minimal" + MinimalStyle() + else + DefaultStyle() + end + end + return config_dict +end + +function find_config_file(path) + dir = dirname(path) + if (path == dir || isempty(path)) + return NamedTuple() + end + configpath = joinpath(dir, CONFIG_FILE_NAME) + if isfile(configpath) + return parse_config(configpath) + end + return find_config_file(dir) +end + +function isignored(path, options) + ignore = get(options, "ignore", String[]) + return any(x -> occursin(Glob.FilenameMatch("*$x"), path), ignore) +end + +include("app.jl") + +@setup_workload let + dir = joinpath(@__DIR__, "..") + sandbox_dir = joinpath(tempdir(), join(rand('a':'z', 24))) + mkdir(sandbox_dir) + cp(dir, sandbox_dir; force = true) + chmod(sandbox_dir, 0o777; recursive = true) + str = """ + true + false + 10.0 + "hello" + a + b + a == b == c + a^10 + !cond + f(a,b,c) + @f(a,b,c) + (a,b,c) + [a,b,c] + begin + a + b + end + quote + a + b + end + :(a+b+c+d) + """ + + @compile_workload begin + format(sandbox_dir) + for style in [DefaultStyle(), BlueStyle(), SciMLStyle(), YASStyle(), MinimalStyle()] + format_text(str, style) + end + + redirect_stdout(devnull) do + redirect_stderr(devnull) do + main(String["--help"]) + main(String["--check", "--verbose", sandbox_dir]) + end + end + end +end + +end # module JuliaFormatter diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/src/align.jl b/.julia-depot/packages/JuliaFormatter/zLsPw/src/align.jl new file mode 100644 index 0000000..436bfb0 --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/src/align.jl @@ -0,0 +1,422 @@ +function align_fst!(fst::FST, opts::Options) + if is_leaf(fst) + return + end + assignment_inds = Int[] + pair_arrow_inds = Int[] + + for (i, n) in enumerate(fst.nodes) + if is_leaf(n) + continue + elseif opts.align_struct_field && (n.typ === Struct || n.typ === Mutable) + align_struct!(n) + elseif opts.align_conditional && n.typ === Conditional + align_conditional!(n) + elseif opts.align_matrix && ( + n.typ === Vcat || n.typ === TypedVcat || n.typ === Ncat || n.typ === TypedNcat + ) + align_matrix!(n) + else + align_fst!(n, opts) + end + + if opts.align_assignment && (is_assignment(n) || n.typ === Kw) + # Gather all assignments within the current code block + # they will be aligned at the end + push!(assignment_inds, i) + elseif opts.align_pair_arrow && n.typ === Binary && op_kind(n) === K"=>" + push!(pair_arrow_inds, i) + end + end + + align_binaryopcalls!(fst, assignment_inds) + align_binaryopcalls!(fst, pair_arrow_inds) +end + +""" + AlignGroup + +Group of FST node indices and required metadata to potentially align them. + + - `node_inds`. Indices of FST nodes affected by alignment. + - `nodes`. FST nodes affected by alignment. + - `line_offsets`. Line offset of the character nodes may be aligned to + in the source file. + - `lens`. Length of the FST node prior to the alignment character. Used + to calculate extra whitespace padding. + - `whitespaces`. Number of whitespaces between the alignment character and + the prior FST node. If this is > 1 it signifies additional whitespace was + manually added by the user since the formatter would only use 0 or 1 whitespaces. +""" +struct AlignGroup + nodes::Vector{FST} + node_inds::Vector{Int} + line_offsets::Vector{Int} + lens::Vector{Int} + whitespaces::Vector{Int} +end +AlignGroup() = AlignGroup(FST[], Int[], Int[], Int[], Int[]) + +function Base.push!(g::AlignGroup, n::FST, ind::Int, line_offset::Int, len::Int, ws::Int) + push!(g.nodes, n) + push!(g.node_inds, ind) + push!(g.line_offsets, line_offset) + push!(g.lens, len) + push!(g.whitespaces, ws) + return +end + +function Base.show(io::IO, g::AlignGroup) + println(io, "AlignGroup:") + println(io, " node_inds: ", g.node_inds) + println(io, " line_offsets: ", g.line_offsets) + println(io, " lens: ", g.lens) + println(io, " whitespaces: ", g.whitespaces) +end + +function align_to(g::AlignGroup)::Union{Nothing,Int} + if !(length(g.lens) > 0) + return nothing + end + # determine whether alignment might be warranted + max_len, max_ind = findmax(g.lens) + max_inds = findall(==(g.line_offsets[max_ind]), g.line_offsets) + if !(length(max_inds) > 1) + return nothing + end + + # Is there custom whitespace? + # Formatter would only add 0 or 1 whitespaces. + # > 2 implies a manual edit in the source file. + for i in max_inds + if g.whitespaces[i] > 1 + return max_len + end + end + + return nothing +end + +function align_binaryopcall!(fst::FST, diff::Int) + # insert whitespace before and after operator + find = findfirst(x -> x.typ === WHITESPACE, fst.nodes) + lind = findlast(x -> x.typ === WHITESPACE, fst.nodes) + + if find === nothing + insert!(fst, 2, Whitespace(diff)) + else + fst[find] = Whitespace(diff) + end + + if lind === nothing + insert!(fst, 4, Whitespace(1)) + end +end + +# we need to use ncodeunits +function node_align_length(n::FST) + if is_leaf(n) + return ncodeunits(n.val) + end + margin = 0 + for nn in n.nodes + margin += node_align_length(nn) + end + return margin +end + +function node_align_length(nodes::Vector{FST}) + margin = 0 + for nn in nodes + margin += node_align_length(nn) + end + return margin +end + +""" + align_binaryopcalls!(fst::FST, op_inds::Vector{Int}) + +Aligns binary operator expressions. + +Additionally handles the case where a keyword such as `const` is used +prior to the binary op call. +""" +function align_binaryopcalls!(fst::FST, op_inds::Vector{Int}) + if !(length(op_inds) > 1) + return + end + prev_endline = fst[op_inds[1]].endline + groups = AlignGroup[] + g = AlignGroup() + + for i in op_inds + n = fst[i] + if n.startline - prev_endline > 1 + push!(groups, g) + g = AlignGroup() + end + + binop, nlen, ws = if n.typ === Binary || n.typ === Kw + nlen = node_align_length(n[1]) + n, nlen, (n[3].line_offset - n.line_offset) - nlen + else + binop::Union{FST,Nothing} = nothing + sn = n + nlen = 0 + ws = 0 + + # the binary op may not be at the top level + # for instance, @call1 @call2 @call3 x = 10 + while sn.nodes !== nothing + binop_ind = findfirst(nn -> nn.typ === Binary, sn.nodes) + nlen += node_align_length(sn[1:(end-1)]) + if binop_ind === nothing + sn = (sn.nodes::Vector{FST})[end] + else + binop = (sn.nodes::Vector{FST})[binop_ind] + nlen += node_align_length(binop[1]) + ws = (binop[3].line_offset - n.line_offset) - nlen + break + end + end + binop, nlen, ws + end + + if binop === nothing + @warn "Binary operator not found in node" n.typ + continue + end + + push!(g.nodes, binop) + push!(g.node_inds, i) + push!(g.line_offsets, binop[3].line_offset) + push!(g.lens, nlen) + push!(g.whitespaces, ws) + + prev_endline = n.endline + end + push!(groups, g) + + for g in groups + align_len = align_to(g) + if isnothing(align_len) + continue + end + + for (i, n) in enumerate(g.nodes) + diff = align_len - g.lens[i] + 1 + align_binaryopcall!(n, diff) + n.nest_behavior = NeverNest + end + end + + return +end + +""" + align_struct!(fst::FST) + +Aligns struct fields. +""" +function align_struct!(fst::FST) + ind = findfirst(n -> n.typ === Block, fst.nodes) + if isnothing(ind) || length(fst[ind]) == 0 + return + end + + block_fst = fst[ind] + prev_endline = block_fst[1].endline + groups = AlignGroup[] + g = AlignGroup() + + for (i, n) in enumerate(block_fst.nodes) + if n.typ === Binary + if n.startline - prev_endline > 1 + push!(groups, g) + g = AlignGroup() + end + + nlen = node_align_length(n[1]) + ind = findfirst(x -> x.typ === OPERATOR, n.nodes) + # issue 757 + # "foo + # """ + # a::B + # + # This is parsed as a concatenated string of "foo" and "" + if ind === nothing + continue + end + + ws = n[ind].line_offset - (n.line_offset + nlen) + + push!(g.nodes, n) + push!(g.node_inds, i) + push!(g.line_offsets, n[ind].line_offset) + push!(g.lens, nlen) + push!(g.whitespaces, ws) + + prev_endline = n.endline + elseif n.typ === Const && n[end].typ === Binary + if n.startline - prev_endline > 1 + push!(groups, g) + g = AlignGroup() + end + + nlen = node_align_length(n[1]) + node_align_length(n[2]) + binop = n[end] + nlen += node_align_length(binop[1]) + ind = findfirst(x -> x.typ === OPERATOR, binop.nodes) + if ind === nothing + continue + end + ws = binop[ind].line_offset - (n.line_offset + nlen) + + push!(g.nodes, binop) + push!(g.node_inds, i) + push!(g.line_offsets, binop[ind].line_offset) + push!(g.lens, nlen) + push!(g.whitespaces, ws) + + prev_endline = n.endline + end + end + push!(groups, g) + + for g in groups + align_len = align_to(g) + if align_len === nothing + continue + end + for (i, n) in enumerate(g.nodes) + diff = align_len - g.lens[i] + 1 + align_binaryopcall!(n, diff) + n.nest_behavior = NeverNest + end + end +end + +""" + align_conditional!(fst::FST) + +Aligns a conditional expression. +""" +function align_conditional!(fst::FST) + nodes = flatten_conditionalopcall(fst) + + cond_group = AlignGroup() + cond_prev_endline = 0 + + colon_group = AlignGroup() + colon_prev_endline = 0 + + for (i, n) in enumerate(nodes) + if n.typ === OPERATOR && n.val == "?" + if cond_prev_endline != n.endline + nlen = node_align_length(nodes[i-2]) + ws = n.line_offset - (nodes[i-2].line_offset + nlen) + + push!(cond_group.nodes, n) + push!(cond_group.node_inds, i) + push!(cond_group.line_offsets, n.line_offset) + push!(cond_group.lens, nlen) + push!(cond_group.whitespaces, ws) + end + cond_prev_endline = n.endline + elseif n.typ === OPERATOR && n.val == ":" + if colon_prev_endline != n.endline + nlen = node_align_length(nodes[i-2]) + ws = n.line_offset - (nodes[i-2].line_offset + nlen) + + push!(colon_group.nodes, n) + push!(colon_group.node_inds, i) + push!(colon_group.line_offsets, n.line_offset) + push!(colon_group.lens, nlen) + push!(colon_group.whitespaces, ws) + end + colon_prev_endline = n.endline + end + end + if !(length(cond_group.lens) > 1) + return + end + + cond_len = align_to(cond_group) + colon_len = align_to(colon_group) + + if cond_len === nothing && colon_len === nothing + return + end + + if cond_len !== nothing + for (i, ind) in enumerate(cond_group.node_inds) + diff = cond_len - cond_group.lens[i] + 1 + nodes[ind-1] = Whitespace(diff) + end + end + + for (i, ind) in enumerate(colon_group.node_inds) + # the placeholder would be i+1 if not for a possible inline comment + nind = findnext(n -> n.typ === PLACEHOLDER, nodes, ind + 1)::Int + if nodes[nind+1].startline != nodes[nind].startline + nodes[nind] = Newline(; nest_behavior = AlwaysNest) + end + + if colon_len !== nothing + diff = colon_len - colon_group.lens[i] + 1 + nodes[ind-1] = Whitespace(diff) + end + end + + fst.nodes = nodes + fst.nest_behavior = NeverNest + fst.indent = fst.line_offset - 1 + + return +end + +""" +Adjust whitespace in between matrix elements such that it's the same as the original source file. +""" +function align_matrix!(fst::FST) + rows = filter(n -> n.typ === Row, fst.nodes::Vector{FST}) + if length(rows) == 0 + return + end + + min_offset = minimum(map(rows) do r + r[1].line_offset + end) + + line = 0 + # add whitespace prior to initial element if elements are aligned to the right and + # it's the first row on that line. + for r in rows + if r[1].line_offset > min_offset && line != r.startline + diff = r[1].line_offset - min_offset + if diff > 0 + insert!(r.nodes::Vector{FST}, 1, Whitespace(diff)) + end + end + line = r.startline + end + + for r in rows + for (i, n) in enumerate(r.nodes) + # skip whitespace nodes appearing before initial element + if i > 1 && n.typ === WHITESPACE + n1 = r[i-1] + n2 = r[i+1] + + diff = n2.line_offset - n1.line_offset - node_align_length(n1) + + # fix #694 and #713 + if diff > 0 + r[i] = Whitespace(diff) + end + end + end + end + + return +end diff --git a/.julia-depot/packages/JuliaFormatter/zLsPw/src/app.jl b/.julia-depot/packages/JuliaFormatter/zLsPw/src/app.jl new file mode 100644 index 0000000..6d2bbdb --- /dev/null +++ b/.julia-depot/packages/JuliaFormatter/zLsPw/src/app.jl @@ -0,0 +1,953 @@ +# SPDX-License-Identifier: MIT + +# For thread-safe printing +const print_lock = ReentrantLock() + +supports_color(io) = get(io, :color, false) + +macro tryx(ex, fallback) + return :( + try + $(esc(ex)) + catch + $(esc(fallback)) + end + ) +end + +# Scan directory for Julia files recursively +function scandir!(files, root) + # Don't recurse into `.git` + if occursin(".git", root) && ".git" in splitpath(root) + @assert endswith(root, ".git") + return + end + @tryx(isdir(root), false) || return + dirs = Vector{String}() + for f in @tryx(readdir(root), String[]) + jf = joinpath(root, f) + if @tryx(isdir(jf), false) + push!(dirs, f) + elseif (@tryx(isfile(jf), false) || @tryx(islink(jf), false)) + # Check for .jl, .md, .jmd, .qmd files + if endswith(jf, ".jl") || + endswith(jf, ".md") || + endswith(jf, ".jmd") || + endswith(jf, ".qmd") + push!(files, jf) + end + end + end + for dir in dirs + scandir!(files, joinpath(root, dir)) + end + return +end + +function panic( + msg::String, + err::Union{Exception, Nothing} = nothing, + bt::Union{Vector{Base.StackFrame}, Nothing} = nothing, + ) + printstyled(stderr, "ERROR: "; color = :red, bold = true) + print(stderr, msg) + if err !== nothing + print(stderr, sprint(showerror, err)) + end + if bt !== nothing + Base.show_backtrace(stderr, bt) + end + println(stderr) + return 1 +end + +function okln(io::IO, msg::String = "✓") + printstyled(io, msg; color = :green, bold = true) + println(io) + return +end + +function errln(io::IO, msg::String = "✗") + printstyled(io, msg; color = :red, bold = true) + println(io) + return +end + +function print_help() + io = stdout + printstyled(io, "NAME"; bold = true) + println(io) + println(io, " jlfmt - An opinionated code formatter for Julia.") + println(io) + printstyled(io, "SYNOPSIS"; bold = true) + println(io) + println(io, " jlfmt [] ...") + println(io, " jlfmt [] -") + println(io, " ... | jlfmt []") + println(io) + printstyled(io, "DESCRIPTION"; bold = true) + println(io) + println( + io, + """ + `jlfmt` formats Julia source code using JuliaFormatter.jl. + This tool can also be invoked as `julia -m JuliaFormatter`. + """, + ) + printstyled(io, "OPTIONS"; bold = true) + println(io) + println( + io, + """ + ... + Input path(s) (files and/or directories) to process. For directories, + all files (recursively) with the '*.jl' suffix are used as input files + (also '*.md', '*.jmd', '*.qmd' if --format-markdown is specified). + If no path is given, or if path is `-`, input is read from stdin. + + -c, --check + Do not write output and exit with a non-zero code if the input is not + formatted correctly. + + -d, --diff + Print the diff between the input and formatted output to stderr. + Requires `git` to be installed. + + -h, --help + Print this message. + + -i, --inplace + Format files in place. + + -o , --output= + File to write formatted output to. If no output is given, or if the file + is `-`, output is written to stdout. + + --stdin-filename= + Assumed filename when formatting from stdin. Used for error messages. + + --config-dir= + Directory path to use for .JuliaFormatter.toml config file lookup when + formatting from stdin. By default, stdin input does not use config files. + With this option, the formatter will search for .JuliaFormatter.toml in + the specified directory and its parent directories. + + -v, --verbose + Enable verbose output. + + --version + Print JuliaFormatter and julia version information. + + --prioritize-config-file + Prioritize .JuliaFormatter.toml config file options over command-line options. + By default, command-line options override config file options. This flag + reverses that precedence, useful for language server integration where + project configuration should take precedence over editor settings. + + FORMATTING OPTIONS + + --style=