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.
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:
- HTML-style comments: Comments like
<!-- … -->
that are embedded anywhere in markdown will be stripped - “Fenced” (```-style) code blocks: As the built-in
fenced_code
extension would be rather strict and doesn’t seem to properly work for me anyway, these blocks are supported by a custom extension.
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=…