Metadata-Version: 2.5
Name: markwright
Version: 0.3.0
Summary: Python-Markdown extensions ported from DigitalOcean's do-markdownit
Project-URL: Homepage, https://github.com/MasonEgger/markwright
Project-URL: Repository, https://github.com/MasonEgger/markwright
Project-URL: Documentation, https://masonegger.github.io/markwright/
Author-email: Mason Egger <mason@masonegger.com>
License-Expression: MIT
License-File: LICENSE
License-File: LICENSE-Apache-2.0
License-File: NOTICE
Keywords: do-markdownit,hugo,markdown,mkdocs,python-markdown
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Text Processing :: Markup :: Markdown
Requires-Python: >=3.11
Requires-Dist: markdown>=3.4
Requires-Dist: pydantic>=2.14.1
Requires-Dist: pymdown-extensions>=11.0.1
Description-Content-Type: text/markdown

# markwright

markwright is a set of [Python-Markdown](https://python-markdown.github.io/) extensions plus a companion command-line tool, `mw`, for author-friendly markdown: highlighted text, labeled code fences, and a set of media embeds.
Use the extensions in any tool built on Python-Markdown (including [MkDocs](https://www.mkdocs.org/), Flask, or a plain script), or the `mw` pipeline in toolchains that are not, like Hugo.

The author-facing syntax and HTML output are derived from DigitalOcean's [`do-markdownit`](https://github.com/digitalocean/do-markdownit), so rendered pages match what DigitalOcean produces.
markwright ports those extensions to Python-Markdown and adds its own pieces on top, most notably the `mw` CLI, which runs the same extensions as pre and post filters around any renderer.

Full documentation and a live demo: https://masonegger.github.io/markwright/

## Features

Each extension is standalone and can be loaded on its own or alongside the others.

- **Highlight** wraps `<^>text<^>` in `<mark>`, and works inside inline code and fenced code blocks where `==text==` cannot reach.
- **Fence** adds labels, secondary labels, environment classes, and command-line prefixes (line numbers, `$`/`#` prompts, custom prefixes) to code blocks.
- **YouTube** turns `[youtube ID]` into a responsive iframe embed.
- **CodePen** embeds a pen with theme, default-tab, and layout options.
- **Twitter** embeds a tweet with theme and alignment options.
- **Instagram** embeds a post with caption and alignment options.
- **Slideshow** builds an image slideshow with navigation arrows.
- **Image Compare** renders two images with a draggable before/after slider.

The embeds that contact a third party (YouTube, CodePen, Twitter, Instagram) take a `load` option.
`load = "click"` renders an inert preview so nothing reaches the provider until the reader asks; see [Click-to-Load](https://masonegger.github.io/markwright/click-to-load/).
A host tool can validate a markwright config table from its own config file with `markwright.config_from_mapping`; see [Configuration](https://masonegger.github.io/markwright/config/).

## Installation

```bash
uv add markwright
```

or

```bash
pip install markwright
```

To work against a local checkout, install it editable:

```bash
uv add --editable ../markwright
```

## Usage

### With MkDocs

Add the extensions to `mkdocs.yml`.
Load `markwright.fence` after `pymdownx.superfences` and `pymdownx.highlight` so the code-block HTML is in the shape the fence postprocessor expects.

```yaml
markdown_extensions:
  - pymdownx.superfences
  - pymdownx.highlight:
      pygments_lang_class: true
  - markwright.highlight
  - markwright.fence:
      allowed_environments:
        - local
        - second
        - third
  - markwright.youtube
  - markwright.codepen
  - markwright.twitter
  - markwright.instagram
  - markwright.slideshow
  - markwright.image_compare
```

### Standalone

The extensions work with Python-Markdown directly, so you can use them in any Python program.

```python
import markdown

md = markdown.Markdown(
    extensions=[
        "pymdownx.superfences",
        "pymdownx.highlight",
        "markwright.highlight",
        "markwright.fence",
        "markwright.youtube",
        "markwright.codepen",
        "markwright.twitter",
        "markwright.instagram",
        "markwright.slideshow",
        "markwright.image_compare",
    ]
)

html = md.convert("This has a <^>highlighted word<^> in it.")
print(html)
```

Load only what you need:

```python
import markdown

# Just YouTube embeds
md = markdown.Markdown(extensions=["markwright.youtube"])
html = md.convert("[youtube dQw4w9WgXcQ]")
```

The fence extension expects `pymdownx.superfences` and `pymdownx.highlight` to be loaded too.
Without them the preprocessor still extracts directives, but the code-block HTML may not match what the postprocessor rewrites.

## Command-Line Interface (`mw`)

For a toolchain that is not built on Python-Markdown, the `mw` command runs the same extensions as a pair of Unix filters around any renderer: a pre stage on the Markdown source, and a post stage on the rendered HTML.

```bash
mw pre < in.md | your-renderer | mw post > out.html
```

- `mw pre` expands the embeds and extracts fence directives into an `mw-fence` comment.
- `mw post` applies the fence styling, resolves the highlights, and injects each embed script once.
- `mw render` runs the full pipeline in one shot for callers without their own renderer.
- `mw config` prints the resolved configuration and the source of each value.
- `mw list` prints every extension and the stages it provides.

Which extensions run, and how each is tuned, come from a `markwright.toml` (or a `[tool.markwright]` table in `pyproject.toml`) that the CLI discovers by walking up from the current directory.
See the [configuration docs](https://masonegger.github.io/markwright/config/).

Your renderer must pass raw HTML and HTML comments through.
Hugo is a worked, tested example: see the [Hugo guide](https://masonegger.github.io/markwright/integrations/hugo/).
The full command and flag reference is in the [CLI docs](https://masonegger.github.io/markwright/cli/).

## Syntax at a Glance

````text
Highlight:       <^>important<^>

Fenced code with a label and command prompts:
    ```command
    [label deploy.sh]
    ssh root@server
    apt update
    ```

YouTube:         [youtube dQw4w9WgXcQ]
                 [youtube dQw4w9WgXcQ 360 640]
CodePen:         [codepen MattCowley vwPzeX]
                 [codepen MattCowley vwPzeX dark css]
Twitter:         [twitter https://twitter.com/github/status/1234567890]
Instagram:       [instagram https://www.instagram.com/p/CkQuv3_LRgS]
Slideshow:       [slideshow https://picsum.photos/id/10/480/270 https://picsum.photos/id/20/480/270]
Image Compare:   [compare before.jpg after.jpg]
````

See the [extension docs](https://masonegger.github.io/markwright/) for every flag and the exact HTML each one produces.

## Development

This project uses [`uv`](https://docs.astral.sh/uv/) and [`just`](https://github.com/casey/just).

```bash
just check             # the gate: ruff check, ruff format --check, mypy strict, pytest
just fmt               # format and auto-fix
just test              # pytest (integration tests skip without hugo on PATH)
just test-all          # pytest across Python 3.11 through 3.15
just test-integration  # only the end-to-end Hugo and clean-install tests
just docs-serve        # serve the docs site at localhost:8000
```

`just check` must pass before a change is complete.
Coverage is reported on every run.

## License

markwright is released under the [MIT License](LICENSE).

It is a port of [`do-markdownit`](https://github.com/digitalocean/do-markdownit) by DigitalOcean, which is licensed under the Apache License 2.0.
See the [NOTICE](NOTICE) file for attribution details.
