``` $$\ $$$$$$\ $$\ $$\ $$ |$$ __$$\ $$ | $$ | $$$$$$\$$$$\ $$$$$$$ |\__/ $$ |$$$$$$\ $$\ $$\ $$$$$$\ $$ _$$ _$$\ $$ __$$ | $$$$$$ |\_$$ _| \$$\ $$ |\_$$ _| $$ / $$ / $$ |$$ / $$ |$$ ____/ $$ | \$$$$ / $$ | $$ | $$ | $$ |$$ | $$ |$$ | $$ |$$\ $$ $$< $$ |$$\ $$ | $$ | $$ |\$$$$$$$ |$$$$$$$$\ \$$$$ |$$ /\$$\ \$$$$ | \__| \__| \__| \_______|\________| \____/ \__/ \__| \____/ ``` This repository contains the `md2txt` command line tool and supporting libraries for transforming Markdown into arcane formats that work well on retro hardware or constrained text viewers. A small plugin API lets you mix-and-match parsers and renderers so additional formats can plug into the same preprocessing pipeline. Install the CLI directly from GitHub with [uv](https://github.com/astral-sh/uv): ``` uv tool install --from git+https://codeberg.org/randogoth/md2txt/ md2txt ``` ## CLI - `md2txt` – converts Markdown into plain text with extensive formatting support. It ships with the default `markdown` parser and `text` renderer plugins, registers optional `micron`, `ama`, `gemini`, and `wml` renderers for Micron/Ancient Machine Book, Gemtext, or WML (WAP) output, and exposes the core pipeline so you can add your own parser or renderer modules: - FIGlet-rendered headings. - Emphasis styles converted to spaced or delimited characters. - Optional alignment and margin controls via HTML `
` attributes or MultiMarkdown attribute blocks (e.g. `{:.center margin=20px}`) applied as leading spaces.
- ASCII art injection with `#[label :align](art.txt)` syntax, supporting multiple art pieces per line and optional `{: .right}` style annotations.
- Per-document toggles for code block wrapping, numbering, blockquote decoration, and list indentation spacing.
- Link references can be emitted per block by setting `links_per_block: true` in frontmatter; otherwise they collect at the end of the document. Gemini output uses `=>` lines while the text renderer keeps numbered footnotes.
## Usage
```bash
md2txt input.md -o output.txt # convert to DOS-friendly text
md2txt input.md # write result to stdout
md2txt input.md --width 72 # override column width
md2txt input.md --renderer micron # emit Micron-formatted output for NomadNet
md2txt input.md --renderer ama # emit AMA markup for Ancient Machine Book
md2txt input.md --renderer gemini # emit Gemtext for Gemini capsules
md2txt input.md --renderer wml # emit a single-card WML deck for WAP browsers
md2txt input.md --renderer-option width=68 # pass column width to a renderer
```
- `--parser` and `--renderer` select a plugin by name (defaults are `markdown` and `text`).
- Repeatable `--parser-option KEY=VALUE` and `--renderer-option KEY=VALUE` pairs are forwarded to the plugin factories as keyword arguments in addition to the defaults supplied by the CLI.
- The CLI accepts `--help` for the full option list.
## Rendering Controls via Frontmatter
Fine-tune formatting by adding keys to frontmatter:
```yaml
---
h1_font: slant
h2_font: standard
h3_font: small
margin_left: 4
margin_right: 4
hyphenate: true
hyphen_lang: en_US
---
```
| Key | Description |
| --- | --- |
| `blockquote_bars: false` | Replace the default `|` prefix with three spaces. |
| `code_block_line_numbers: false` | Disable the `01 |` gutter in wrapped or unwrapped code blocks. |
| `code_block_wrap:
Centered paragraph with custom margins.
` referencing the original path/URL — no WBMP conversion is performed.
## Plugin Architecture
The conversion pipeline lives in `src/md2txt/conversion/core.py` and is exposed via `run_conversion`. It is designed around lightweight factories:
- **Parser factories** receive `base_style: BlockStyle` plus any extra keyword arguments and must return an object with a `parse(lines: Iterable[str]) -> Iterator[BlockEvent | StyleUpdateEvent]` method. The bundled `MarkdownParser` implements this interface.
- **Renderer factories** receive `frontmatter: FrontMatter` and arbitrary keyword arguments and must return an object that provides `handle_event(event)` and `finalize() -> Any`. The `TextRenderer` returns a list of DOS-friendly output lines; other renderers may return any data appropriate for their target format.
Plugins register themselves through the helpers in `md2txt.plugins`:
```python
from md2txt.plugins import register_parser, register_renderer
def my_parser_factory(*, base_style, **options):
return MyParser(base_style, **options)
register_parser("my-markdown", my_parser_factory)
```
```python
def my_renderer_factory(*, frontmatter, **options):
return MyRenderer(frontmatter, target=options.get("target"))
register_renderer("ansi", my_renderer_factory)
```
Once registered (for example in a small module that imports `md2txt.cli`), the new plugins are available via `--parser my-markdown` or `--renderer ansi`. The CLI lists registered plugin names in `--help`, and the helper functions `available_parsers()` / `available_renderers()` return the sorted names if you need to build higher-level tooling.
The shared preprocessing helpers—YAML frontmatter parsing, recursive include expansion, ASCII art sentinels, and pipe-table sentinels—also live in `src/md2txt/conversion/core.py`, allowing alternate front-ends to reuse exactly the same behaviour without duplicating code.
---
* Directed and vibe coded by Tobias Raayoni Last
* Programmed by `gpt-5-codex`