Help us shape the future of Go! Take the 2026 Go Developer Survey

markout

command module
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: GPL-3.0 Imports: 15 Imported by: 0

README

markout

CI Release Latest release Go

A fast Markdown → DOCX / PDF converter with an interactive terminal UI (TUI).

No browser, no webview, no GUI toolkit — it runs entirely in your terminal, as a single binary with the fonts built in.

It reads Markdown the way the platform you wrote it for does: pick GitHub, GitLab, YouTrack, Azure DevOps, Obsidian, Pandoc or one of the other flavors, and that dialect's alerts, task lists, footnotes, tables of contents and the rest are understood. Formulas are typeset and Mermaid flowcharts are drawn (see Limits for what is not).

Install

From a release binary (no Go required)

Grab the binary for your platform from the latest release, or with curl (example for macOS Apple Silicon):

# Look up the latest release tag (or set VERSION=v1.9.0 to pin one).
VERSION=$(curl -fsSL https://api.github.com/repos/hkmt-sw/markout/releases/latest \
  | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
curl -fsSL -o markout \
  "https://github.com/hkmt-sw/markout/releases/download/$VERSION/markout_${VERSION}_darwin_arm64"
chmod +x markout
mv markout /usr/local/bin/        # or any directory on your $PATH, e.g. ~/.local/bin

Pick the asset that matches your system:

OS / CPU Asset
macOS Apple Silicon markout_<VERSION>_darwin_arm64
macOS Intel markout_<VERSION>_darwin_amd64
Linux x86-64 markout_<VERSION>_linux_amd64
Linux arm64 markout_<VERSION>_linux_arm64
Windows x86-64 markout_<VERSION>_windows_amd64.exe
Windows arm64 markout_<VERSION>_windows_arm64.exe

On macOS the binary is unsigned, so Gatekeeper may block the first run. Clear the quarantine flag once:

xattr -d com.apple.quarantine /usr/local/bin/markout

Optionally verify the download against the release's SHA256SUMS.txt, or check with the GitHub CLI that it was built by this repository's release workflow (releases from v1.1.2 on):

shasum -a 256 -c SHA256SUMS.txt    # (Linux: sha256sum -c)
gh attestation verify markout --repo hkmt-sw/markout
With Go
go install github.com/hkmt-sw/markout@latest
From source
git clone https://github.com/hkmt-sw/markout.git
cd markout
go build -o markout .   # produces ./markout
make install            # or install to $GOBIN (~/go/bin): go install .

If the install dir isn't on your PATH, add it to your shell profile:

export PATH="$(go env GOPATH)/bin:$PATH"

Other Makefile targets: make run (launch without installing), make test, make release (cross-compile all platforms into dist/), make uninstall, make clean.

Usage

Interactive TUI

Run with no arguments to launch the full-screen UI:

./markout

It's a single Midnight-Commander-style window: a file list on top, a docked Convert box below (flavor / theme / language / format / output / status), and a function-key bar at the bottom. Highlight a Markdown file and press Enter to convert it.

Key Action
↑ ↓ Move through the file list
→ / Enter Enter a directory
← Go up a directory
Enter Convert the highlighted .md file
F2 Settings: flavor, theme, language, update check
F3 Toggle output format (DOCX ⇄ PDF)
F4 Edit the output path by hand
o Open the last converted file
F10 / q Quit

The output path is derived automatically from the highlighted file and the selected format (PDF by default); F4 lets you override it. If the output file already exists, a popup asks you to confirm before overwriting it.

Direct (non-interactive)

The output format is inferred from the file extension:

./markout input.md output.docx
./markout input.md output.pdf
./markout --flavor gitlab input.md output.pdf   # interpret as a specific flavor
./markout --list-flavors                        # show the supported flavors
./markout --lang hu input.md output.docx        # the language, if the document names none
./markout --remote-images allow input.md out.pdf # download images referenced by URL

Themes

A theme decides how the output looks: page size and margins, fonts, sizes, spacing, colors, and headers and footers. Five come built in:

--theme Look
default The standard markout look
classic Serif type, wide margins, restrained color: like a book or a paper
modern Sans-serif and airy, with one vivid accent color
compact Small type and narrow margins: long technical documents on fewer pages
report A business report: title and date in the header, page numbers in the footer
classic modern report
classic modern report

Pick one on the Theme tab of the settings (F2, then Tab), or per conversion:

./markout --theme report input.md output.pdf
./markout --list-themes

The Theme tab of the settings dialog, listing the built-in themes with report selected

Your own theme is a small text file that lists what it changes:

extends = "default"

[fonts]
body = "serif"

[heading]
color = "#7A1E1E"

[footer]
center = "Page {page} of {pages}"
./markout --export-theme > mytheme.toml     # every setting, to start from
./markout --theme mytheme.toml input.md output.pdf

The theme guide walks through making one, with every setting, your own fonts, and headers and footers. To check a theme, convert fixtures/showcase.md: it contains every element with a note on what it should look like.

Language

A document says what language it is written in with lang in its front matter:

---
title: Mentési eljárásrend
lang: hu
---

The language is a tag such as hu, en-US or en-GB; en alone is taken as American English. It is written into the output: in a DOCX it is the language Word checks the spelling in and hyphenates by, in a PDF it is what a screen reader reads the text as. It is not shown among the fields of the front matter.

For documents that do not name their language, give one with --lang, or choose one on the Language tab of the settings (F2), which is saved. What a document says goes before both. With no language anywhere the output names none, as before.

The language is also what words are hyphenated by, in a theme that sets text justified or hyphenated. In PDF markout hyphenates Hungarian, American English and British English.

Update notifications

When a newer release exists, the TUI says so in its top border:

┌─ markout ──────────── v1.3.0 is available · github.com/hkmt-sw/markout/releases ──┐

It only tells you; installing the new version is up to you (download the binary again, or go install github.com/hkmt-sw/markout@latest).

To know, the TUI asks GitHub for the latest release when it starts, at most once a day. That request carries nothing but the markout version, though GitHub sees your IP address like any web server does. It is the one request markout makes without asking first, so you can turn it off: press F2, then u. Direct conversions from the command line never check. To look on demand:

./markout --check-update

Images from the internet

A document can reference images by URL. Downloading them tells the servers it names your IP address and that you opened the document, and a document from someone else can point at addresses on your own machine or local network. So markout never downloads an image without asking.

The dialog listing the servers a document would download images from, with the buttons Load images, Skip images and Cancel

  • In the TUI, converting such a document first shows every server it would contact and how many images are on each; addresses on your machine or local network are marked. Choose Load images, Skip images (the default: the conversion runs and those images become placeholders) or Cancel.
  • On the command line, the same list is printed and you are asked [y/N]. When there is nobody to ask (a script, a pipe, CI) the images are skipped and listed on standard error. --remote-images allow downloads without asking, --remote-images deny always skips.

The answer is not remembered: the question comes up for each conversion that needs it. Images stored on disk next to the document are not affected.

Markdown flavors

"Markdown" is a family of dialects: the same file renders differently on GitHub, GitLab, YouTrack or in Obsidian. markout has an interpreter for each of the flavors below, so a document converts the way it looks on the platform it was written for.

The settings dialog listing the Markdown flavors, with GitLab selected

Pick the flavor with F2 in the TUI. The choice is saved (in markout/config.json under your OS config directory, or the file named by $MARKOUT_CONFIG) and is also the default for direct conversions; --flavor overrides it for one run.

--flavor Flavor What it adds to CommonMark
markout Markout (universal, default) Every extension below that doesn't conflict with another; a good fit when you don't know where a file came from
commonmark CommonMark Nothing: the strict standard
github GitHub (GFM) Tables, task lists, strikethrough, autolinks, footnotes, > [!NOTE] alerts, $math$, Mermaid, :emoji:, color chips
gitlab GitLab (GLFM) GFM plus [[_TOC_]], alert titles, {+ inline +} {- diff -}, >>> quotes, [~] tasks, JSON/TOML front matter, json:table, ::include{file=…}, {width=…} images, definition lists
youtrack YouTrack Tables, checklists, strikethrough, autolinks, ```latex formulas, Mermaid, {width=…} images
azure Azure DevOps GFM plus [[_TOC_]], ::: mermaid, $math$, ![](img =500x250) sizes, :emoji:
bitbucket Bitbucket Tables, strikethrough, footnotes, definition lists, [TOC], [[wiki links]]; raw HTML is shown as text
obsidian Obsidian [[wiki links]], ![[image.png|300]] embeds, ==highlight==, callouts of any type (foldable, titled), %%comments%%, ^[inline notes], $math$
pandoc Pandoc (also Quarto, R Markdown) % title block, ::: fenced divs, ^super^ and ~sub~script, inline notes, [span]{.underline}, heading attributes, smart punctuation
multimarkdown MultiMarkdown Metadata header, {{TOC}}, CriticMarkup, \\(math\\), ^super^ and ~sub~script
extra Markdown Extra Tables, footnotes, definition lists, abbreviations, heading IDs
kramdown kramdown (Jekyll) Markdown Extra plus {:toc}, {: .class} attribute lists, $$math$$, smart punctuation
myst MyST (Sphinx, Jupyter Book) ```{directive} and :::{directive} blocks, {role}`text` , $math$
mkdocs MkDocs Material !!! note admonitions, === "Tab" tabs, [TOC], ==mark==, ^^insert^^, ^super^, ~sub~, CriticMarkup
docusaurus Docusaurus (MDX) :::note admonitions, {#heading-ids}; MDX imports, exports and comments are dropped

Text written by AI assistants is GitHub-style Markdown, often with math in LaTeX delimiters; the default flavor reads both $…$ and \(…\) / \[…\].

Syntax that a flavor doesn't define is left as plain text, exactly as that platform would show it (~~text~~ stays literal under CommonMark, for example).

Things that only make sense on the original platform have no document equivalent and stay as text: @mentions, issue references such as #123 or ABC-123, and links to other wiki pages.

Code blocks

A code block that names its language is syntax-highlighted, in PDF and in DOCX:

```python
def greet(name):
    return f"Hello, {name}"
```

Almost 300 languages are known, by the names GitHub uses for them. A block with no language, or one that is not known, is shown in one color. The colors are the theme's, under [code.syntax], where highlighting can also be turned off.

Math

Formulas written in LaTeX are typeset, in both formats:

The roots are $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$.

$$
\sum_{i=1}^{n} x_i^2 \le \int_0^\infty e^{-x}\,dx
$$
  • In PDF markout sets them itself: fractions, roots, sub- and superscripts, sums and integrals with their limits, brackets that grow, matrices, cases and aligned, accents, Greek and the usual symbols.
  • In DOCX they are Word equations, which Word typesets with its own math font and which can be edited there.

Which delimiters mark a formula ($…$, \(…\), ```math) depends on the flavor. What cannot be typeset is listed under Limits.

Examples

The examples directory has documents of the kinds people convert (a security policy, an incident procedure, an architecture description, a runbook, a risk assessment, meeting minutes), each using what such a document needs: tables, flowcharts, formulas, code, callouts, footnotes. Convert one to see what markout makes of it:

markout examples/technical/architecture.md architecture.pdf

Diagrams

A Mermaid flowchart is drawn, in both formats:

```mermaid
graph TD
    A[Read the file] --> B{Is it Markdown?}
    B -->|yes| C[Convert it]
    B -->|no| D([Stop])
```

Boxes of every shape, arrows and lines of every kind with their text, subgraphs, and the four directions (TD, BT, LR, RL) are understood. In PDF the chart is drawn as lines and text, sharp at any zoom; in DOCX it is a picture. A chart wider than the text is made smaller to fit.

Finding your way in the output

Both formats know where the headings are:

  • A PDF has bookmarks: its headings, nested by level, in the pane a viewer shows beside the pages.
  • Links to a heading ([text](#heading)) jump to it, in PDF and in DOCX. The heading can be named the way GitHub or GitLab names it, with accented letters kept. A link to a heading the document does not have is plain colored text.
  • The entries of a table of contents are such links too. In PDF each has the page its heading is on, at the end of a row of dots.

What a DOCX is made of

A DOCX from markout is a Word document to go on working in, not a picture of one:

  • Headings are in Word's Heading 1 to Heading 6 styles, so they show in the navigation pane, and changing a style changes every heading. Body text is in Normal. The styles look the way the theme says.
  • Lists are Word lists: add an item to a numbered list and the rest is renumbered.
  • A table of contents is a field Word can update, and its entries are links to the headings.

Limits

markout lays the document out itself, with no browser or TeX behind it. Some things are beyond it for now:

  • Math is typeset by markout itself in PDF, with far fewer rules than TeX has: the result is correct and readable, not TeX's typography. A formula on a line of its own that is wider than the text is made smaller to fit, and one in a paragraph can stand taller than its line. A formula that uses a command markout does not know, or that is not well-formed, is shown as its source in color, and the conversion says so.
  • Mermaid: only flowcharts (graph and flowchart) are drawn, laid out by markout itself, more plainly than Mermaid does: the same boxes and connections, not the same positions. Colors and styles set in the chart are not used; the theme's are. In DOCX a chart is a picture, which Word cannot edit. Sequence, class, state, Gantt and the other kinds of diagram, and a flowchart markout cannot read, are shown as their source in a labeled box, and the conversion says so.
  • Characters the PDF fonts lack. The built-in fonts cover Latin, Greek and Cyrillic. Other characters (Chinese, Japanese, Korean, Arabic, emoji) are left out of a PDF, and the conversion says which ones: as a warning on standard error for a direct conversion, in the status line in the TUI. A theme can use a font of your own that has them. DOCX keeps every character and leaves the choice of font to the word processor.
  • Right-to-left text (Hebrew, Arabic) is not laid out in PDF: its letters come out in reverse order. The conversion warns about this too.
  • Documentation-site Markdown (MyST, MkDocs Material, Docusaurus) is read for what a document can show: admonitions, tabs with their labels, code block titles, MyST tables, version notes, and the pages a toctree names, as a list. Some of what those sites build has no place in a single document:
    • MkDocs Material: a snippet (--8<-- "file.md") is put in if the file is in the document's directory or below it, and named in a warning if it cannot be read; keys (++ctrl+c++) are shown as Ctrl+C; icons (:material-…:) are pictures from a font and are left out, with a warning.
    • A MyST eval-rst block is shown as its source, since reStructuredText is not read.
    • raw blocks for a format other than HTML, bibliography and index, the video and query-table blocks of Azure DevOps, and JSX components that stand by themselves in MDX (<Chart />), are left out, and the conversion names them.
    • A directive markout does not know is shown as plain text, and the conversion names it.
    • MDX import and export lines and comments are dropped: they show nothing on the site either.
  • A table of contents in DOCX lists the headings without page numbers until Word is asked to update it (right-click it, Update Field); where the pages break is Word's decision, so markout cannot know the numbers.

Project layout

Path Purpose
main.go Entry point (TUI + direct CLI mode)
internal/tui Bubble Tea terminal UI
internal/flavor The supported Markdown flavors and their features
internal/parse Markdown → AST (goldmark), per-flavor syntax
internal/render AST → DOCX / PDF renderers
internal/convert Conversion orchestration
internal/theme Themes: the built-in ones and theme files
internal/lang Language tags
internal/hyphen Hyphenation, with the patterns of each language
internal/settings Saved preferences (flavor, theme, language)
fixtures Sample documents: showcase.md shows every element, flavors/ has one per flavor, corpus/ has real documents from public projects
examples Example documents: a policy, a runbook, a report, minutes and more, to convert and to copy from
docs The theme guide and pictures
cmd/debug Dumps the parsed AST as JSON for debugging

Contributing

Bug reports and pull requests are welcome; see CONTRIBUTING.md. Changes between versions are listed in CHANGELOG.md, and security problems are reported as described in SECURITY.md.

License

Copyright © 2026 Márton Tamás

markout is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License, version 3. It is distributed in the hope that it will be useful, but without any warranty.

The documents under examples are an exception: they are dedicated to the public domain (CC0 1.0), so that they can be copied as the start of your own.

It builds on these projects:

Documentation

Overview

Command markout is a terminal UI for converting Markdown files to DOCX or PDF.

Run it with no arguments to launch the interactive TUI:

markout

Or convert directly from the command line:

markout input.md output.docx
markout input.md output.pdf
markout --flavor gitlab input.md output.pdf

Directories

Path Synopsis
cmd
debug command
internal
ast
flavor
Package flavor describes the Markdown dialects markout can interpret.
Package flavor describes the Markdown dialects markout can interpret.
hyphen
Package hyphen says where words may be broken at the end of a line, in the languages it has patterns for.
Package hyphen says where words may be broken at the end of a line, in the languages it has patterns for.
lang
Package lang knows the languages a document can say it is written in.
Package lang knows the languages a document can say it is written in.
mathml
Package mathml reads LaTeX math into a tree of MathML elements, which is what the renderers typeset: PDF by laying the tree out itself, DOCX by turning it into a Word equation.
Package mathml reads LaTeX math into a tree of MathML elements, which is what the renderers typeset: PDF by laying the tree out itself, DOCX by turning it into a Word equation.
mermaid
Package mermaid reads Mermaid flowcharts and lays them out as a drawing: shapes, connecting lines and text with positions, which the renderers put on a page.
Package mermaid reads Mermaid flowcharts and lays them out as a drawing: shapes, connecting lines and text with positions, which the renderers put on a page.
settings
Package settings persists the user's markout preferences between runs.
Package settings persists the user's markout preferences between runs.
theme
Package theme describes how a converted document looks: page, fonts, sizes, spacing and colors.
Package theme describes how a converted document looks: page, fonts, sizes, spacing and colors.
tui
Package tui implements the interactive terminal UI for markout.
Package tui implements the interactive terminal UI for markout.
update
Package update finds out whether a newer markout release exists.
Package update finds out whether a newer markout release exists.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL