Markdown console viewer

Parse a markdown file and pretty-print to the terminal, including colors, glyphs, and text wrapping. Gives a manpage-like experience for markdown on console.

Despite being created already in 2004, the markdown markup syntax is still widely used for plain-text-based documentation purposes of various kinds. While new features were added, the basics are still largely the same until nowadays. The purpose is to provide a rich-text-like experience derived from a plaintext file – and there are several viewers, editors, and converters – but this falls short in a terminal environment, where for example README.md files are often encountered.

Almost all recent terminal emulators should support features such as colors, underlines, or drawing glyphs. This is all that mdcat needs to print markdown files in a pleasant way: Styled emphasis and hyperlinks, smart list and text wrapping, and glyphs for example for highlighting code blocks. This feature set should already cover most parts of most markdown files as found in documentation or wikis.

Output Example

mdcat comes only as a single python script with very few dependencies, and used with or without a pager, it can already provide a “manpage-like feeling” when reading markdown files.

Usage

In general, simply invoke mdcat with the markdown file to process.

usage: mdcat [-h] [--columns|-c COLUMNS] [--html] [--no-wrap-pre] [--pager|-p] file.md

Parse a markdown file and pretty-print to the terminal, including colors, glyphs, and text wrapping.
The supported Markdown syntax is given by: https://github.com/Python-Markdown/markdown

positional arguments:
  file.md               markdown file to print, '-' for stdin

optional arguments:
  -h, --help            show this help message and exit
  --columns|-c COLUMNS  terminal width, autodetect from $COLUMNS or ioctl() if not given, fallback 80 (default: None)
                        tip: export or set --columns=$COLUMNS to take the shell width when using a pager
  --html                print parsed HTML output instead, mostly useful for debugging (default: False)
  --no-wrap-pre         don't prefix and wrap code/quote blocks (default: False)
                        useful if you want to copy/paste or are using a pager with horizontal scroll
  --pager|-p            don't write to stdout but spawn a pager instead, as given by $PAGER or 'less' by default (default: False)

Pagers and Line Wrapping

TLDR: For convenience and a “manpage-like” experience, pass the --pager option, which will spawn the $PAGER environment variable or less -SR as discussed below.

The current terminal width gets determined by the corresponding TIOCGWINSZ ioctl(). This is usually reliable but does not work when all output (both stdout and stderr) is redirected or for example piped to a pager such as less.

If the width cannot be automatically determined, the --columns option or the $COLUMNS environment variable can be used to set one explicitly. As bash provides this shell variable (not as environment variable), it can be exported or --columns=$COLUMNS can be used or even aliased. The --pager option bypasses this problem as the width can be determined before connecting the output to the pager’s pipe.

If you want to copy/paste code blocks, use a pager for horizontal scrolling, or prefer code to be unwrapped/untouched in general, the --no-wrap-pre option can be used.

When using less, color codes are supported by the -R flag. Long (i.e. unwrapped) lines can be scrolled instead of wrapped by the -S flag.

Markdown Extensions

mdcat uses the python markdown package as its only dependency for parsing the input files. The resulting HTML DOM tree is then iterated on for printing terminal-friendly formatted strings. This means that the supported markdown syntax is basically given by this library. (See the --html option to print the HTML for debugging purposes.)

In addition, the following extensions for common but non-standard syntax are provided to the parser:

Also, utilities that correspond to ansiwrap.wrap and termcolor.colored are partly re-implemented to fix their behaviour or to suit the usecase at hand.

Installation

The most easy way to (un-)install the mdcat package is via pip. If not already done so, you can get the package manager with something equivalent to sudo apt-get install python3-pip. Recommended is a system install (by using e.g. sudo) with pip, which is also wrapped by the Makefile:

make install   # pip install .
make uninstall # pip uninstall mdcat

If this doesn’t work for you, (sudo) python3 setup.py install would be the “legacy” mechanism, which however does not support a clean uninstall method. (As well as the deprecated easy_install.)

The single source file mdcat.py is self-contained, so you can also directly invoke it or move it to a path of your choice beforehand. As it already has executable permissions set, the script should be callable without the python interpreter. The only python3 dependency is the markdown package, which might already be present or can be installed by (sudo) pip install markdown or (sudo) pip install -r requirements.txt.

For trying out or local development, a virtual environment can be used.

make deps # python3 -m venv venv ; pip3 install -r requirements.txt
make check # optionally check typing and run linter
. venv/bin/activate
./mdcat.py …

Or simply: make run MD_FILE=…

Code & Download