pax_global_header00006660000000000000000000000064145535736130014526gustar00rootroot0000000000000052 comment=4ca849a18057192601f15a3bee7d47936da6dfb1 markdown-callouts-0.4.0/000077500000000000000000000000001455357361300151755ustar00rootroot00000000000000markdown-callouts-0.4.0/.github/000077500000000000000000000000001455357361300165355ustar00rootroot00000000000000markdown-callouts-0.4.0/.github/FUNDING.yml000066400000000000000000000000201455357361300203420ustar00rootroot00000000000000github: oprypin markdown-callouts-0.4.0/.github/workflows/000077500000000000000000000000001455357361300205725ustar00rootroot00000000000000markdown-callouts-0.4.0/.github/workflows/ci.yml000066400000000000000000000036311455357361300217130ustar00rootroot00000000000000name: CI on: push: pull_request: schedule: - cron: '0 6 * * 6' defaults: run: shell: bash jobs: test: strategy: fail-fast: false matrix: include: - python: '^3.12' os: ubuntu-latest - python: '3.12' os: macos-latest - python: '3.11' os: windows-latest - python: '3.10' os: ubuntu-latest - python: '3.9' os: macos-latest - python: '3.8' os: windows-latest - python: '3.8' os: ubuntu-latest versions: minimal runs-on: ${{matrix.os}} steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v4 with: python-version: ${{matrix.python}} - name: Pin to lowest versions if: matrix.versions == 'minimal' run: | sed -i -E 's/#min //; s/\b >=([0-9])/ ==\1/' pyproject.toml - name: Install Hatch run: | pip install hatch - name: Install dependencies run: | hatch run test:pip freeze - name: Run tests run: | hatch run test:test style: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v4 with: python-version: '3.12' - name: Install Hatch run: | pip install hatch - name: Install dependencies run: | hatch run style:pip freeze hatch run types:pip freeze - name: Check style if: always() run: | hatch run style:fix - name: Check formatting if: always() run: | git diff --color --exit-code - name: Check types if: always() run: | hatch run types:check markdown-callouts-0.4.0/.github/workflows/deploy-docs.yml000066400000000000000000000020051455357361300235340ustar00rootroot00000000000000name: Deploy docs on: push: pull_request: schedule: - cron: '0 6 * * 6' jobs: build: runs-on: ubuntu-latest steps: - name: Download source uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: pip install --no-deps -r requirements/requirements-docs.txt && pip install . - name: Build site run: mkdocs build --strict - name: Upload to GitHub Pages uses: actions/upload-pages-artifact@v2 with: path: site deploy: if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch needs: build permissions: pages: write id-token: write runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v2 environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} markdown-callouts-0.4.0/.github/workflows/deploy-release.yml000066400000000000000000000007651455357361300242370ustar00rootroot00000000000000name: Deploy release on: push: tags: - '*' jobs: pypi: permissions: id-token: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: python-version: '3.12' - name: Install dependencies run: pip install -U build - name: Build package run: python -m build - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 markdown-callouts-0.4.0/.gitignore000066400000000000000000000001371455357361300171660ustar00rootroot00000000000000/dist/ site*/ .mypy_cache/ .pytest_cache/ __pycache__/ *.egg-info/ .venv/ poetry.lock .vscode/ markdown-callouts-0.4.0/.tools/000077500000000000000000000000001455357361300164135ustar00rootroot00000000000000markdown-callouts-0.4.0/.tools/release.sh000077500000000000000000000003741455357361300203760ustar00rootroot00000000000000#!/bin/bash set -e -u -x cd "$(dirname "$0")/.." git diff --staged --quiet git diff --quiet HEAD pyproject.toml rm -rf dist hatch version "$1" hatch build git add */__init__.py git commit -m "v$1" git tag -a -m "" "v$1" git push origin master --tags markdown-callouts-0.4.0/LICENSE.md000066400000000000000000000020731455357361300166030ustar00rootroot00000000000000MIT License Copyright (c) 2021 Oleh Prypin 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. markdown-callouts-0.4.0/README.md000066400000000000000000000057271455357361300164670ustar00rootroot00000000000000# markdown-callouts **Extension for [Python-Markdown][]: a classier syntax for [admonitions](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#usage)** [![PyPI](https://img.shields.io/pypi/v/markdown-callouts)](https://pypi.org/project/markdown-callouts/) [![GitHub](https://img.shields.io/github/license/oprypin/markdown-callouts)](https://github.com/oprypin/markdown-callouts/blob/master/LICENSE.md) [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/oprypin/markdown-callouts/ci.yml.svg)](https://github.com/oprypin/markdown-callouts/actions?query=event%3Apush+branch%3Amaster) [python-markdown]: https://python-markdown.github.io/ [admonition]: https://python-markdown.github.io/extensions/admonition/ [mkdocs]: https://www.mkdocs.org/ [documentation site]: https://oprypin.github.io/markdown-callouts/ ## Installation ```shell pip install markdown-callouts ``` If using MkDocs, [enable the extension in **mkdocs.yml**](https://www.mkdocs.org/user-guide/configuration/#markdown_extensions): ```yaml markdown_extensions: - callouts ``` **Continue to the [documentation site][].** ## Usage This adds a new block-level syntax to Markdown, to put a paragraph of text into a block that's specially highlighted and set apart from the rest of the text. **Example:** ```markdown NOTE: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ``` **Result**, [using *mkdocs-material*](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#usage): ![Screenshot](https://user-images.githubusercontent.com/371383/119063216-dc001700-b9d8-11eb-8092-763e5d02d9f4.png) Collapsible blocks also have a syntax for them: ```markdown >? NOTE: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod > nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor > massa, nec semper lorem quam in massa. ``` This instead shows up as an initially-closed `
` block. ### Graceful degradation This extension produces the same results as the *[admonition][]* extension, but with a syntax that is much less intrusive and has a very reasonable fallback look for "vanilla" renderers. E.g. compare what you would've seen above if we actually wrote that Markdown and fed it to GitHub's Markdown parser:
"Callouts" syntax
NOTE: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
"Admonition" syntax
!!! note Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
--- **Continue to the [documentation site][].** markdown-callouts-0.4.0/docs/000077500000000000000000000000001455357361300161255ustar00rootroot00000000000000markdown-callouts-0.4.0/docs/index.md000066400000000000000000000350641455357361300175660ustar00rootroot00000000000000# markdown-callouts **Extension for [Python-Markdown][]: a classier syntax for [admonitions](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#usage) and [collapsible blocks](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#collapsible-blocks)** [python-markdown]: https://python-markdown.github.io/ [admonition]: https://python-markdown.github.io/extensions/admonition/ [details]: https://facelessuser.github.io/pymdown-extensions/extensions/details/ [mkdocs]: https://www.mkdocs.org/ ## Installation ```shell pip install markdown-callouts ``` * If using MkDocs, [enable the extension in **mkdocs.yml**](https://www.mkdocs.org/user-guide/configuration/#markdown_extensions): ```yaml markdown_extensions: - callouts ``` * If using [Python-Markdown][] in some other way, [see its reference](https://python-markdown.github.io/extensions/). You can add this extension to the list of plugins: * as a string: `'callouts'` * as an object: `from markdown_callouts import CalloutsExtension` The extension is configurable as such: * `strip_period` (default `true`) - whether to strip the final period from [custom titles](#custom-titles) syntax. ## Usage This adds a new block-level syntax to Markdown, to put a paragraph of text into a block that's specially highlighted and set apart from the rest of the text. The syntax is: as the start of a paragraph, write a word in all capital letters, followed by a colon and a space. Then the rest of the text in that block will be used as the body of the "callout". For example, to get this ([using *mkdocs-material* theme](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#usage)): NOTE: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Write this Markdown with the "callouts" extension: ```markdown NOTE: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ```
Rather than this (with the "admonition" extension): ```markdown !!! note Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ```
The titular word of the callout, transformed from all-caps to just capitalized, becomes the title for the set-apart text. ### Custom titles If you don't like the deduced title text, you can specify a title of your own, after the all-caps word. For purposes of [graceful degradation](#project-goals), the syntax is exactly as if you wrote one sentence emphasized in bold at the start of the callout. For example, to get this: TIP: **Writing custom titles.** Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Write this Markdown with the "callouts" extension: ```markdown TIP: **Writing custom titles.** Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ```
Rather than this (with the "admonition" extension): ```markdown !!! tip "Writing custom titles" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ```
The linebreak after the title is optional. And it can be an actual linebreak with two spaces at the end of the line as well -- that has no effect on the output, but again can be relevant for [graceful degradation](#project-goals). ??? note "About the period at the end of the sentence" The period at the end of the sentence is always dropped from the final title. You are encouraged to write those periods anyway, because when using a "vanilla" renderer, the output will look weird. === "Markdown" ```markdown NOTE: **A few more thoughts** Lorem ipsum dolor sit amet, consectetur adipiscing elit. NOTE: **A few more thoughts.** Lorem ipsum dolor sit amet, consectetur adipiscing elit. ``` === "Intended result" NOTE: **A few more thoughts** Lorem ipsum dolor sit amet, consectetur adipiscing elit. NOTE: **A few more thoughts.** Lorem ipsum dolor sit amet, consectetur adipiscing elit. === "Result with vanilla Markdown" NOTE: **A few more thoughts** Lorem ipsum dolor sit amet, consectetur adipiscing elit. NOTE: **A few more thoughts.** Lorem ipsum dolor sit amet, consectetur adipiscing elit. If you want to keep the period in the title, you can escape it with a backslash. And to *always* keep periods in the titles, configure the extension with `strip_period: false`. ### Collapsible blocks (See first: [Block-level syntax](#block-level-syntax)) To get the following collapsed `
` block, just add a question mark right after the blockquote symbol: ??? tip "Click me to read more" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.
Write this Markdown with the "callouts" extension: ```markdown >? TIP: **Click me to read more.** > > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. > > Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec > semper lorem quam in massa. ```
Rather than this (with the "details" extension): ```markdown ??? tip "Click me to read more" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. ```
The block can alternatively be initially open. Just write `>!` instead of `>?`. ### Output The produced HTML is the same with [both][admonition] [extensions][details] that this replaces: === "Same as 'admonition'" ```html

Note

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

``` === "Same as 'details'" ```html
Note

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

``` You may notice that the HTML contains no explicit styling whatsoever. That is because that's supposed to be handled through CSS that accompanies it. In case of MkDocs, that's handled by themes -- if they choose to support styling for the classes `.admonition`, `.admonition-title` or the tags `details`, `summary`. In addition to the always-present class `admonition`, another CSS class will be added that is equal to the title of the "callout", in lowercase. The stylesheet can then choose to specially distinguish the style for a few select identifiers out of those. ([Example theme](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types)) ### Syntax details At the start of a block, there needs to be a word in all English capital letters, followed by a colon, space, then other text. === "Markdown" ```markdown Previous block will not be picked up. EXAMPLE: This text is all part of a single *admonition* block. Next block will not be picked up. ``` === "Result" Previous block will not be picked up. EXAMPLE: This text is all part of a single *admonition* block. Next block will not be picked up. === "HTML" ```html

Previous block will not be picked up.

Example

This text is all part of a single admonition block.

Next block will not be picked up.

``` Inline Markdown (links, italics, etc.) is handled normally for the rest of the text. Block-level Markdown (lists, quotes, etc.) is not allowed. The space after the colon can instead be a newline as well. #### Block-level syntax To allow putting multiple paragraphs into the same callout and enable all of Markdown features, use the block-level syntax, which works the same as a [blockquote](https://daringfireball.net/projects/markdown/syntax#blockquote), but with the mandatory all-caps word at the beginning of it: === "Markdown" ```markdown > EXAMPLE: Hello world! > > * Item 1 > * Item 2 > > Still going... Next block will not be picked up. ``` === "Result" > EXAMPLE: Hello world! > > * Item 1 > * Item 2 > > Still going... Next block will not be picked up. === "HTML" ```html

Example

Hello world!

  • Item 1
  • Item 2

Still going...

Next block will not be picked up.

``` The fact that we used blockquote syntax doesn't mean any actual blockquote is involved, this is still just an admonition. We are just making a clear delineation for the block, but otherwise the angle quotes are discarded. However... if you'll also be viewing the same Markdown through a renderer that doesn't support this special syntax, it will indeed be a blockquote -- that is also [graceful degradation](#project-goals). ??? "Compare this to the [Admonition][] extension" === "Markdown" ```markdown !!! example Hello world! * Item 1 * Item 2 Still going... Next block will not be picked up. ``` === "Result without extensions" !!! example Hello world! * Item 1 * Item 2 Still going... Next block will not be picked up. You can find more examples (particularly how edge cases are handled) in the [test cases directory](https://github.com/oprypin/markdown-callouts/tree/master/tests/extension). #### Collapsible block syntax Collapsible block syntax is a simple extension of the block syntax. Instead of opening the blockquote with `>`: * write `>?` to get a `
` tag; * write `>!` to get a `
` tag. To allow putting multiple paragraphs into the same callout and enable all of Markdown features, use the block-level syntax, which works the same as a [blockquote](https://daringfireball.net/projects/markdown/syntax#blockquote), but with the mandatory all-caps word at the beginning of it: === "Markdown" ```markdown >? EXAMPLE: Hello world! > > * Item 1 > * Item 2 > > Still going... Next block will not be picked up. ``` === "Result" >? EXAMPLE: Hello world! > > * Item 1 > * Item 2 > > Still going... Next block will not be picked up. === "HTML" ```html
Example

Hello world!

  • Item 1
  • Item 2

Still going...

``` You can find more examples (particularly how edge cases are handled) in the [test cases directory](https://github.com/oprypin/markdown-callouts/tree/master/tests/details). #### Custom titles A callout block with a custom title is just an extension of the base syntax, where after the capital word and a colon, the first item of the main body must be in bold. This `**strong emphasis**` syntax (or also with `__`) is directly used as the delimitation for the title, according to normal rules of how Markdown handles it. The actual `` tag will be excluded from the output and its contents will be moved from the paragraph and become the title instead. You can use any inline Markdown formatting within that main delimiter, and *that* will be preserved. Single newlines are allowed within the delimited title part, again as per normal Markdown rules. You can find more examples (particularly how edge cases are handled) in the [test cases directory](https://github.com/oprypin/markdown-callouts/tree/master/tests/extension/title). #### Avoiding callouts syntax There are several ways of avoiding triggering the "callouts" syntax, in case you actually want to just write a word in all-capital letters followed by a colon. In that case, precede the line with one space (which will not be represented in the final HTML): ```markdown EXAMPLE: Hi. ``` And if you happen to need to start your callout with a sentence in bold (without picking it up as the title), make sure to put a newline first: === "Markdown" ```markdown NOTE: **This is a title.** Body. NOTE: **Not a title actually.** Body. ``` === "Result" NOTE: **This is a title.** Body. NOTE: **Not a title actually.** Body. ## Further features ### Custom look As [mentioned](#output), styling is handled through CSS, not from the extension itself. And in CSS, you can indeed completely re-define the look for each particular keyword. Adding a new keyword requires no action, other than possibly adding CSS for it. This is well documented [for *mkdocs-material* theme](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#custom-admonitions). And see another example for inspiration: [Source](https://github.com/mkdocstrings/crystal/commit/53db1592e771eb0d918b1aafbd52eb7111479f75#diff-607e5fcb5247b2ab8b856864d7dc86fa66f24d82cb5b7ef2269a522344b650e2) → [Result](https://mkdocstrings.github.io/crystal/extras.html#callouts-extension) ## Project goals The goal of this project is to support the same features as the [admonition][] extension, under an alternate syntax that allows for **graceful degradation** (you can search for mentions of that on this page). That means that the page can be previewed in a "vanilla" Markdown renderer and still look fully legible, though missing some styling. That can be useful to keep your documents nicely viewable on Web source hosting such as GitHub even if that won't be your primary hosting. markdown-callouts-0.4.0/markdown_callouts/000077500000000000000000000000001455357361300207255ustar00rootroot00000000000000markdown-callouts-0.4.0/markdown_callouts/__init__.py000066400000000000000000000004411455357361300230350ustar00rootroot00000000000000from __future__ import annotations __version__ = "0.4.0" def __getattr__(name: str): if name in {"CalloutsExtension", "makeExtension"}: from . import callouts return getattr(callouts, name) raise AttributeError(f"module {__name__!r} has no attribute {name!r}") markdown-callouts-0.4.0/markdown_callouts/callouts.py000066400000000000000000000134211455357361300231260ustar00rootroot00000000000000from __future__ import annotations import re import xml.etree.ElementTree as etree from markdown import Markdown, util from markdown.blockprocessors import BlockQuoteProcessor from markdown.extensions import Extension from markdown.treeprocessors import Treeprocessor # Based on https://github.com/Python-Markdown/markdown/blob/4acb949256adc535d6e6cd84c4fb47db8dda2f46/markdown/blockprocessors.py#L277 class _CalloutsBlockProcessor(BlockQuoteProcessor): REGEX = re.compile(r"(^ {0,3}>([!?])? ?|\A)([A-Z]{2,}):([ \n])(.*)", flags=re.M) def test(self, parent: etree.Element, block: str) -> bool: m = self.REGEX.search(block) return ( m is not None and (m[1] or not self.parser.state.isstate("blockquote")) and not util.nearing_recursion_limit() # type: ignore ) def run(self, parent: etree.Element, blocks: list[str]) -> None: block = blocks.pop(0) m = self.REGEX.search(block) if not m: return before = block[: m.start()] self.parser.parseBlocks(parent, [before]) block = block[m.start(5) :] if m[1]: block = "\n".join(self.clean(line) for line in block.split("\n")) kind = m[3] if m[2]: admon = etree.SubElement(parent, "details", {"class": kind.lower()}) if m[2] == "!": admon.set("open", "open") else: admon = etree.SubElement(parent, "details", {"class": "admonition " + kind.lower()}) title = etree.SubElement(admon, "summary", {"class": "admonition-title"}) title.text = kind.title() self.parser.state.set("blockquote") self.parser.parseChunk(admon, block) self.parser.state.reset() if m[4] == "\n": admon[1].text = "\n" + (admon[1].text or "") class _CalloutsTreeprocessor(Treeprocessor): def __init__(self, strip_period: bool) -> None: super().__init__() self.strip_period = strip_period def run(self, doc: etree.Element): for root in doc.iter("details"): # Expecting this: #
# Note #

Custom title. Body

#
# And turning it into this: #
# Custom title #

Body

# # Or this: #
#

Custom title

#

Body

#
if not root.get("class"): continue title = root[0] if title.tag != "summary" or title.get("class") != "admonition-title": continue # Change
back to
if it was a normal admonition. if root.get("class", "").startswith("admonition "): root.tag = "div" title.tag = "p" else: title.attrib.pop("class", None) # Find the first paragraph and a element in it. if len(root) < 2: continue paragraph = root[1] if ( paragraph.tag != "p" or not len(paragraph) or (paragraph.text and paragraph.text.strip()) ): continue strong = paragraph[0] if strong.tag != "strong": continue if paragraph.text == "\n": continue # Move everything from the bold element into the title. title.text = strong.text and strong.text.lstrip() title[:] = strong # Remove last dot at the end of the text (which might instead be the last child's tail). if len(title): # Has any child elements last = title[-1] if last.tail: last.tail = last.tail.rstrip() if self.strip_period and last.tail.endswith("."): last.tail = last.tail[:-1] else: if title.text: title.text = title.text.rstrip() if self.strip_period and title.text.endswith("."): title.text = title.text[:-1] # Make sure any text immediately following the bold element isn't lost. if strong.tail: paragraph.text = (paragraph.text or "") + strong.tail # Finally, remove the original element, also drop a possible linebreak afterwards. paragraph.remove(strong) if len(paragraph) and not paragraph.text: br = paragraph[0] if br.tag == "br": paragraph.text = br.tail paragraph.remove(br) if not len(paragraph) and not paragraph.text and not paragraph.tail: root.remove(paragraph) class CalloutsExtension(Extension): def __init__(self, **kwargs) -> None: self.config = { "strip_period": [ True, "Remove the period (dot '.') at the end of custom titles - Default: True", ], } super().__init__(**kwargs) def extendMarkdown(self, md: Markdown) -> None: parser = md.parser # type: ignore parser.blockprocessors.register( _CalloutsBlockProcessor(parser), "callouts", 21, # Right before blockquote ) md.treeprocessors.register( _CalloutsTreeprocessor(self.getConfig("strip_period")), "callouts", 19, # Right after inline ) makeExtension = CalloutsExtension markdown-callouts-0.4.0/markdown_callouts/github_callouts.py000066400000000000000000000036421455357361300244740ustar00rootroot00000000000000from __future__ import annotations import re import xml.etree.ElementTree as etree from markdown import Markdown, util from markdown.blockprocessors import BlockQuoteProcessor from markdown.extensions import Extension # Based on https://github.com/Python-Markdown/markdown/blob/4acb949256adc535d6e6cd84c4fb47db8dda2f46/markdown/blockprocessors.py#L277 class _GitHubCalloutsBlockProcessor(BlockQuoteProcessor): REGEX = re.compile( r"((?:^|\n) *(?:[^>].*)?(?:^|\n)) {0,3}> *\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\] *\n(?: *> *\n)*() *(?:> *[^\s\n]|[^\s\n>])", flags=re.IGNORECASE, ) def test(self, parent, block): return ( bool(self.REGEX.search(block)) and not self.parser.state.isstate("blockquote") and not util.nearing_recursion_limit() ) def run(self, parent: etree.Element, blocks: list[str]) -> None: block = blocks.pop(0) m = self.REGEX.search(block) assert m before = block[: m.end(1)] block = "\n".join(self.clean(line) for line in block[m.end(3) :].split("\n")) self.parser.parseBlocks(parent, [before]) kind = m[2] css_class = kind.lower() if css_class == "caution": css_class = "danger" admon = etree.SubElement(parent, "div", {"class": "admonition " + css_class}) title = etree.SubElement(admon, "p", {"class": "admonition-title"}) title.text = kind.title() self.parser.state.set("blockquote") self.parser.parseChunk(admon, block) self.parser.state.reset() class GitHubCalloutsExtension(Extension): def extendMarkdown(self, md: Markdown) -> None: parser = md.parser # type: ignore parser.blockprocessors.register( _GitHubCalloutsBlockProcessor(parser), "github-callouts", 21.1, # Right before blockquote ) makeExtension = GitHubCalloutsExtension markdown-callouts-0.4.0/markdown_callouts/py.typed000066400000000000000000000000001455357361300224120ustar00rootroot00000000000000markdown-callouts-0.4.0/mkdocs.yml000066400000000000000000000021771455357361300172070ustar00rootroot00000000000000site_name: "markdown-callouts" site_description: "Markdown extension: a classier syntax for admonitions" site_url: "https://oprypin.github.io/markdown-callouts" repo_url: "https://github.com/oprypin/markdown-callouts" edit_uri: blob/master/docs/ use_directory_urls: false theme: name: material features: - content.action.edit - navigation.tabs - toc.integrate icon: repo: fontawesome/brands/github palette: primary: teal accent: purple markdown_extensions: - pymdownx.details - pymdownx.tabbed: alternate_style: true - pymdownx.highlight - pymdownx.magiclink - pymdownx.saneheaders - pymdownx.superfences - pymdownx.snippets: check_paths: true base_path: - !relative $config_dir - callouts - md_in_html - toc: permalink: "#" validation: omitted_files: warn absolute_links: warn unrecognized_links: warn nav: absolute_links: ignore nav: - section-index: /mkdocs-section-index/ - literate-nav: /mkdocs-literate-nav/ - gen-files: /mkdocs-gen-files/ - same-dir: /mkdocs-same-dir/ - code-validator: /mkdocs-code-validator/ - callouts: index.md markdown-callouts-0.4.0/pyproject.toml000066400000000000000000000071331455357361300201150ustar00rootroot00000000000000[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "markdown-callouts" description = "Markdown extension: a classier syntax for admonitions" readme = "README.md" license = "MIT" keywords = ["markdown", "extensions"] authors = [ {name = "Oleh Prypin", email = "oleh@pryp.in"}, ] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Documentation", "Topic :: Software Development :: Documentation", "Topic :: Text Processing :: Markup :: Markdown", "Typing :: Typed", ] dynamic = ["version"] requires-python = ">=3.8" dependencies = [ "Markdown >=3.3.3", #min "importlib_metadata >=4.3", ] [project.urls] Documentation = "https://oprypin.github.io/markdown-callouts/" Source = "https://github.com/oprypin/markdown-callouts" Issues = "https://github.com/oprypin/markdown-callouts/issues" History = "https://github.com/oprypin/markdown-callouts/releases" [project.entry-points."markdown.extensions"] callouts = "markdown_callouts.callouts:CalloutsExtension" github-callouts = "markdown_callouts.github_callouts:GitHubCalloutsExtension" [tool.hatch.version] path = "markdown_callouts/__init__.py" [tool.hatch.build.targets.sdist] include = ["/markdown_callouts", "/tests"] [tool.hatch.env] requires = [ "hatch-mkdocs", "hatch-pip-compile", ] [tool.hatch.envs.default.scripts] all = [ "hatch run style:fix", "hatch run types:check", "hatch run test:test", ] [tool.hatch.envs.test] dependencies = [ "pytest", "pytest-golden", "beautifulsoup4", ] [tool.hatch.envs.test.scripts] test = [ "pytest -q", ] [tool.hatch.envs.types] dependencies = [ "mypy", "types-Markdown >=3.4.2", ] [tool.hatch.envs.types.scripts] check = [ "mypy markdown_callouts" ] [tool.hatch.envs.style] skip-install = true dependencies = [ "ruff", ] [tool.hatch.envs.style.scripts] fix = [ "ruff check --fix markdown_callouts tests", "format", ] format = [ "ruff format -q markdown_callouts tests", ] [tool.hatch.env.collectors.mkdocs.docs] [tool.hatch.envs.docs] type = "pip-compile" pip-compile-hashes = false [tool.ruff] line-length = 100 select = [ "I", "F", "W", "E", "UP", "YTT", "C4", "DTZ", "FA", "ISC", "PIE", "T20", "RSE", "TCH", "B002", "B003", "B005", "B007", "B009", "B012", "B013", "B014", "B015", "B018", "B020", "B021", "B023", "B026", "B033", "B034", "B905", "COM818", "PERF101", "PGH002", "PGH004", "PGH005", "FLY002", "PLC", "PLE", "PLR0124", "PLR0133", "PLR0206", "PLR0402", "PLR1701", "PLR1722", "PLW0120", "PLW0127", "PLW0129", "PLW0131", "PLW0406", "PLW0602", "PLW0603", "PLW0711", "RUF001", "RUF005", "RUF007", "RUF010", "RUF013", "RUF100", "RUF200", "SIM101", "SIM107", "SIM201", "SIM202", "SIM208", "SIM210", "SIM211", "SIM300", "SIM401", "SIM910", ] ignore = ["E501", "E731"] [tool.ruff.flake8-comprehensions] allow-dict-calls-with-keyword-arguments = true [tool.mypy] warn_unreachable = true allow_redefinition = true [tool.pytest.ini_options] addopts = "--tb=native" enable_assertion_pass_hook = true filterwarnings = ["ignore::DeprecationWarning:.*:", "default::DeprecationWarning:markdown_callouts.*:"] testpaths = ["tests"] markdown-callouts-0.4.0/requirements/000077500000000000000000000000001455357361300177205ustar00rootroot00000000000000markdown-callouts-0.4.0/requirements/requirements-docs.txt000066400000000000000000000027361455357361300241420ustar00rootroot00000000000000# # This file is autogenerated by hatch-pip-compile with Python 3.11 # # - markdown-callouts # - mkdocs # - mkdocs-material # - pymdown-extensions # babel==2.13.1 # via mkdocs-material certifi==2023.7.22 # via requests charset-normalizer==3.3.1 # via requests click==8.1.7 # via mkdocs colorama==0.4.6 # via mkdocs-material ghp-import==2.1.0 # via mkdocs idna==3.4 # via requests jinja2==3.1.2 # via # mkdocs # mkdocs-material markdown==3.5 # via # markdown-callouts # mkdocs # mkdocs-material # pymdown-extensions markdown-callouts==0.3.0 # via -r - markupsafe==2.1.3 # via # jinja2 # mkdocs mergedeep==1.3.4 # via mkdocs mkdocs==1.5.3 # via # -r - # mkdocs-material mkdocs-material==9.4.7 # via -r - mkdocs-material-extensions==1.3 # via mkdocs-material packaging==23.2 # via mkdocs paginate==0.5.6 # via mkdocs-material pathspec==0.11.2 # via mkdocs platformdirs==3.11.0 # via mkdocs pygments==2.16.1 # via mkdocs-material pymdown-extensions==10.3.1 # via # -r - # mkdocs-material python-dateutil==2.8.2 # via ghp-import pyyaml==6.0.1 # via # mkdocs # pymdown-extensions # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs regex==2023.10.3 # via mkdocs-material requests==2.31.0 # via mkdocs-material six==1.16.0 # via python-dateutil urllib3==2.0.7 # via requests watchdog==3.0.0 # via mkdocs markdown-callouts-0.4.0/setup.py000066400000000000000000000004141455357361300167060ustar00rootroot00000000000000"""Installation using setup.py is not supported. Use `pip install .` instead.""" import sys from setuptools import setup sys.exit(__doc__) # Fake reference so GitHub still considers it a real package for statistics purposes. setup( name="markdown-callouts", ) markdown-callouts-0.4.0/tests/000077500000000000000000000000001455357361300163375ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/all/000077500000000000000000000000001455357361300171075ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/all/adjacent.yml000066400000000000000000000004471455357361300214100ustar00rootroot00000000000000input: | > [!Note] > foo NOTE: bar output: |-

Note

foo

Note

bar

markdown-callouts-0.4.0/tests/callouts/000077500000000000000000000000001455357361300201655ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/callouts/adjacent-1.yml000066400000000000000000000004371455357361300226230ustar00rootroot00000000000000input: | TEST: foo TEST: bar output: |-

Test

foo

Test

bar

markdown-callouts-0.4.0/tests/callouts/adjacent-2.yml000066400000000000000000000004411455357361300226170ustar00rootroot00000000000000input: | TEST: foo > TEST: bar output: |-

Test

foo

Test

bar

markdown-callouts-0.4.0/tests/callouts/adjacent-3.yml000066400000000000000000000004431455357361300226220ustar00rootroot00000000000000input: | > TEST: foo > TEST: bar output: |-

Test

foo

Test

bar

markdown-callouts-0.4.0/tests/callouts/adjacent-nope.yml000066400000000000000000000002621455357361300234200ustar00rootroot00000000000000input: | TEST: foo TEST: bar output: |-

Test

foo TEST: bar

markdown-callouts-0.4.0/tests/callouts/adjacent-text-block.yml000066400000000000000000000003021455357361300245260ustar00rootroot00000000000000input: | aaa > NOTE: bbb ccc output: |-

aaa

Note

bbb ccc

markdown-callouts-0.4.0/tests/callouts/adjacent-text-nope.yml000066400000000000000000000001231455357361300243760ustar00rootroot00000000000000input: | aaa NOTE: bbb ccc output: |-

aaa NOTE: bbb ccc

markdown-callouts-0.4.0/tests/callouts/basic.yml000066400000000000000000000002551455357361300217730ustar00rootroot00000000000000input: | NOTE: Hello, world! output: |-

Note

Hello, world!

markdown-callouts-0.4.0/tests/callouts/blockquotes-many-joined.yml000066400000000000000000000006071455357361300254560ustar00rootroot00000000000000input: | > NOTE: > Foo. > a > Bar. > WARNING: > Baz. output: |-

Note

Foo.

a Bar.

Warning

Baz.

markdown-callouts-0.4.0/tests/callouts/blockquotes-split-by-comments.yml000066400000000000000000000006611455357361300266320ustar00rootroot00000000000000input: | > NOTE: > Foo. > a > Bar. > WARNING: > Baz. output: |-

Note

Foo.

a Bar.

Warning

Baz.

markdown-callouts-0.4.0/tests/callouts/blockquotes-together.yml000066400000000000000000000004251455357361300250630ustar00rootroot00000000000000input: | > NOTE: > Foo. > > a > Bar. > > WARNING: > Baz. output: |-

Note

Foo.

a Bar.

WARNING: Baz.

markdown-callouts-0.4.0/tests/callouts/details/000077500000000000000000000000001455357361300216125ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/callouts/details/basic-open.yml000066400000000000000000000003141455357361300243530ustar00rootroot00000000000000input: | >! TIP: test > test > > hi output: |-
Tip

test test

hi

markdown-callouts-0.4.0/tests/callouts/details/basic.yml000066400000000000000000000002201455357361300234100ustar00rootroot00000000000000input: | >? NOTE: hello output: |-
Note

hello

markdown-callouts-0.4.0/tests/callouts/details/extra-space-nope.yml000066400000000000000000000001501455357361300255040ustar00rootroot00000000000000input: | > ?NOTE: hello output: |-

?NOTE: hello

markdown-callouts-0.4.0/tests/callouts/details/nested.yml000066400000000000000000000011131455357361300236130ustar00rootroot00000000000000input: | >! TIP: test > > > >! NOTE: cool > > > cool > > > > interesting > > >? NOTE: hmm output: |-
Tip

test

Note

cool cool

interesting

Note

hmm

markdown-callouts-0.4.0/tests/callouts/details/no-space.yml000066400000000000000000000002401455357361300240360ustar00rootroot00000000000000input: | >?NOTE: hello >world output: |-
Note

hello world

markdown-callouts-0.4.0/tests/callouts/extra-space.yml000066400000000000000000000003551455357361300231270ustar00rootroot00000000000000input: | TEST: foo TEST : foo TEST: foo output: |-

Test

foo

TEST : foo

TEST: foo

markdown-callouts-0.4.0/tests/callouts/just-callout.yml000066400000000000000000000002531455357361300233360ustar00rootroot00000000000000input: | WARNING: WARNING: output: |-

WARNING:

Warning

markdown-callouts-0.4.0/tests/callouts/linebreak-after.yml000066400000000000000000000003031455357361300237370ustar00rootroot00000000000000input: | NOTE: Body. More. output: |-

Note

Body.
More.

markdown-callouts-0.4.0/tests/callouts/lowercase-nope.yml000066400000000000000000000000731455357361300236330ustar00rootroot00000000000000input: | note: foo output: |-

note: foo

markdown-callouts-0.4.0/tests/callouts/nested-block.yml000066400000000000000000000004701455357361300232630ustar00rootroot00000000000000input: | > TEST: foo > > > TEST: bar output: |-

Test

foo

Test

bar

markdown-callouts-0.4.0/tests/callouts/newline-first.yml000066400000000000000000000002471455357361300235010ustar00rootroot00000000000000input: | TEST: foo bar output: |-

Test

foo bar

markdown-callouts-0.4.0/tests/callouts/one-letter.yml000066400000000000000000000000651455357361300227670ustar00rootroot00000000000000input: | A: foo output: |-

A: foo

markdown-callouts-0.4.0/tests/callouts/title/000077500000000000000000000000001455357361300213065ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/callouts/title/avoid-bold-after-text.yml000066400000000000000000000004711455357361300261340ustar00rootroot00000000000000input: | WARNING: Due to **foo bar** consider **baz**. output: |-

Warning

Due to foo bar consider baz .

markdown-callouts-0.4.0/tests/callouts/title/avoid-title.yml000066400000000000000000000007331455357361300242550ustar00rootroot00000000000000input: | NOTE: **Not a title actually.** Body. NOTE: **Not a title actually.** Body. output: |-

Note

Not a title actually. Body.

Note

Not a title actually. Body.

markdown-callouts-0.4.0/tests/callouts/title/basic.yml000066400000000000000000000002731455357361300231140ustar00rootroot00000000000000input: | TEST: **Custom title.** Testing output: |-

Custom title

Testing

markdown-callouts-0.4.0/tests/callouts/title/blockstyle-interrupted.yml000066400000000000000000000003711455357361300265500ustar00rootroot00000000000000input: | > TEST: **Some > > title.** > > bar output: |-

Test

**Some

title.**

bar

markdown-callouts-0.4.0/tests/callouts/title/blockstyle.yml000066400000000000000000000002771455357361300242120ustar00rootroot00000000000000input: | > TEST: **Some > title.** > > bar output: |-

Some title

bar

markdown-callouts-0.4.0/tests/callouts/title/inline-formatting.yml000066400000000000000000000003561455357361300254630ustar00rootroot00000000000000input: | TEST: **Custom *fancy* title.** Testing output: |-

Custom fancy title

Testing

markdown-callouts-0.4.0/tests/callouts/title/linebreak-after-title.yml000066400000000000000000000002661455357361300262070ustar00rootroot00000000000000input: | NOTE: **Some title** Body. output: |-

Some title

Body.

markdown-callouts-0.4.0/tests/callouts/title/link-ref-as-title.yml000066400000000000000000000004451455357361300252630ustar00rootroot00000000000000input: | > QUOTE: **[foo]** > > bar > > baz [foo]: https://example.org output: |-

foo

bar

baz

markdown-callouts-0.4.0/tests/callouts/title/multiline-title.yml000066400000000000000000000006251455357361300251550ustar00rootroot00000000000000input: | NOTE: **Custom multiline title.** Body. NOTE: **Custom multiline title.** Body. output: |-

Custom multiline title

Body.

Custom multiline title

Body.

markdown-callouts-0.4.0/tests/callouts/title/nested-block.yml000066400000000000000000000005301455357361300244010ustar00rootroot00000000000000input: | > TEST: **Title 1.** foo > > > TEST: **Title 2.** foo output: |-

Title 1

foo

Title 2

foo

markdown-callouts-0.4.0/tests/callouts/title/no-body.yml000066400000000000000000000002201455357361300233720ustar00rootroot00000000000000input: | TEST: **Some title.** output: |-

Some title

markdown-callouts-0.4.0/tests/callouts/title/no-dot.yml000066400000000000000000000004521455357361300232320ustar00rootroot00000000000000input: | NOTE: **A few more thoughts** Lorem ipsum dolor sit amet, consectetur adipiscing elit. output: |-

A few more thoughts

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

markdown-callouts-0.4.0/tests/callouts/title/no-strip-period.yml000066400000000000000000000005571455357361300250730ustar00rootroot00000000000000input: | NOTE: **Some title.** Body. NOTE: **Some title.** Body. strip_period: false output: |-

Some title.

Body.

Some title.

Body.

markdown-callouts-0.4.0/tests/callouts/title/preserve-dot-double.yml000066400000000000000000000003371455357361300257230ustar00rootroot00000000000000input: | NOTE: **Custom title..** Body. Continuing body. output: |-

Custom title.

Body. Continuing body.

markdown-callouts-0.4.0/tests/callouts/title/preserve-dot-escape.yml000066400000000000000000000003371455357361300257110ustar00rootroot00000000000000input: | NOTE: **Custom title\.** Body. Continuing body. output: |-

Custom title.

Body. Continuing body.

markdown-callouts-0.4.0/tests/callouts/title/preserve-dot-format.yml000066400000000000000000000004001455357361300257300ustar00rootroot00000000000000input: | NOTE: **Custom title*.*** Body. Continuing body. output: |-

Custom title .

Body. Continuing body.

markdown-callouts-0.4.0/tests/callouts/title/text-after.yml000066400000000000000000000005501455357361300241140ustar00rootroot00000000000000input: | TEST: **Custom title.**Testing TEST: **Custom title**. Testing output: |-

Custom title

Testing

Custom title

. Testing

markdown-callouts-0.4.0/tests/callouts/with-list.yml000066400000000000000000000006001455357361300226300ustar00rootroot00000000000000input: | * TEST: foo TEST: * foo output: |-
  • Test

    foo

Test

  • foo
markdown-callouts-0.4.0/tests/github/000077500000000000000000000000001455357361300176215ustar00rootroot00000000000000markdown-callouts-0.4.0/tests/github/adjacent-nope.yml000066400000000000000000000003061455357361300230530ustar00rootroot00000000000000input: | > [!Note] > foo > [!Note] > bar output: |-

Note

foo [!Note] bar

markdown-callouts-0.4.0/tests/github/adjacent-text-block.yml000066400000000000000000000003101455357361300241610ustar00rootroot00000000000000input: | aaa > [!Note] > bbb ccc output: |-

aaa

Note

bbb ccc

markdown-callouts-0.4.0/tests/github/adjacent-text-nope.yml000066400000000000000000000002101455357361300240270ustar00rootroot00000000000000input: | > aaa > [!Note] > bbb > ccc output: |-

aaa [!Note] bbb ccc

markdown-callouts-0.4.0/tests/github/adjacent.yml000066400000000000000000000004571455357361300221230ustar00rootroot00000000000000input: | > [!Note] > foo > [!Note] > bar output: |-

Note

foo

Note

bar

markdown-callouts-0.4.0/tests/github/barely-callout.yml000066400000000000000000000005271455357361300232670ustar00rootroot00000000000000input: | > [!Warning] a > [!Warning] >> output: |-

Warning

a

Warning

markdown-callouts-0.4.0/tests/github/basic.yml000066400000000000000000000002651455357361300214300ustar00rootroot00000000000000input: | > [!Note] > Hello, world! output: |-

Note

Hello, world!

markdown-callouts-0.4.0/tests/github/blockquotes-many-joined.yml000066400000000000000000000006131455357361300251070ustar00rootroot00000000000000input: | > [!Note] > Foo. > a > Bar. > [!Warning] > Baz. output: |-

Note

Foo.

a Bar.

Warning

Baz.

markdown-callouts-0.4.0/tests/github/blockquotes-split-by-comments.yml000066400000000000000000000006651455357361300262720ustar00rootroot00000000000000input: | > [!Note] > Foo. > a > Bar. > [!Warning] > Baz. output: |-

Note

Foo.

a Bar.

Warning

Baz.

markdown-callouts-0.4.0/tests/github/blockquotes-together.yml000066400000000000000000000004331455357361300245160ustar00rootroot00000000000000input: | > [!Note] > Foo. > > a > Bar. > > [!Warning] > Baz. output: |-

Note

Foo.

a Bar.

[!Warning] Baz.

markdown-callouts-0.4.0/tests/github/classes-nope.yml000066400000000000000000000002501455357361300227350ustar00rootroot00000000000000input: | > [!INFO] > foo > [!TIPSY] > foo output: |-

[!INFO] foo

[!TIPSY] foo

markdown-callouts-0.4.0/tests/github/classes.yml000066400000000000000000000013661455357361300220070ustar00rootroot00000000000000input: | > [!NOTE] > foo > [!TIP] > foo > [!IMPORTANT] > foo > [!WARNING] > foo > [!CAUTION] > foo output: |-

Note

foo

Tip

foo

Important

foo

Warning

foo

Caution

foo

markdown-callouts-0.4.0/tests/github/empty-nope.yml000066400000000000000000000001541455357361300224410ustar00rootroot00000000000000input: | > [!Warning] > > output: |-

[!Warning]

markdown-callouts-0.4.0/tests/github/extra-space.yml000066400000000000000000000005071455357361300225620ustar00rootroot00000000000000input: | > [!Note] > foo > [!Note] > foo output: |-

Note

foo

Note

foo

markdown-callouts-0.4.0/tests/github/just-callout-nope.yml000066400000000000000000000004711455357361300237330ustar00rootroot00000000000000input: | > [!Warning] hi > [!Warning] > >[!Warning] output: |-

[!Warning]

hi

[!Warning]

[!Warning]

markdown-callouts-0.4.0/tests/github/linebreak-after.yml000066400000000000000000000003171455357361300234000ustar00rootroot00000000000000input: | > [!Note] > > Body. > More. output: |-

Note

Body.
More.

markdown-callouts-0.4.0/tests/github/lowercase-nope.yml000066400000000000000000000002161455357361300232660ustar00rootroot00000000000000input: | > **note**: foo output: |-

note : foo

markdown-callouts-0.4.0/tests/github/nested-block-nope.yml000066400000000000000000000004111455357361300236510ustar00rootroot00000000000000input: | > [!Note] > foo > > > [!Note] > bar output: |-

Note

foo

[!Note] bar

markdown-callouts-0.4.0/tests/github/varied-case.yml000066400000000000000000000007111455357361300225260ustar00rootroot00000000000000input: | > [!important] > Foo > [!TIP] > Foo > [!NoTe] > Foo output: |-

Important

Foo

Tip

Foo

Note

Foo

markdown-callouts-0.4.0/tests/github/with-italic-nope.yml000066400000000000000000000004421455357361300235210ustar00rootroot00000000000000input: | > *[!Note]* > foo > [*!Note*] > foo output: |-

[!Note] foo

[ !Note ] foo

markdown-callouts-0.4.0/tests/github/with-list.yml000066400000000000000000000010521455357361300222660ustar00rootroot00000000000000input: | * > [!Note] > foo > * [!Note] foo > [!Note] > * foo output: |-
  • Note

    foo

  • [!Note] foo

Note

  • foo
markdown-callouts-0.4.0/tests/test_extension.py000066400000000000000000000016721455357361300217720ustar00rootroot00000000000000import re import bs4 import pytest from markdown import Markdown from markdown_callouts.callouts import CalloutsExtension from markdown_callouts.github_callouts import GitHubCalloutsExtension extension_styles = { "callouts": CalloutsExtension, "github": GitHubCalloutsExtension, } @pytest.mark.golden_test("callouts/**/*.yml", "github/**/*.yml", "all/**/*.yml") def test_extension(request, golden): config = {k: golden[k] for k in ["strip_period"] if golden.get(k) is not None} extensions = [ extension(**config) for key, extension in extension_styles.items() if f"{key}/" in request.node.name or "all/" in request.node.name ] md = Markdown(extensions=extensions) output = md.convert(golden["input"]) soup = bs4.BeautifulSoup(output, features="html.parser") html = soup.prettify().rstrip("\n") html = re.sub(r"^( *)", r"\1\1", html, flags=re.M) assert html == golden.out["output"]