53

I have a Markdown string in JavaScript, and I'd like to display it (with bolding, etc) in a less (or, I suppose, more)-style viewer for the command line.

For example, with a string

"hello\n" + 
"_____\n" + 
"*world*!"

I would like to have output pop up with scrollable content that looks like

hello

world

Is this possible, and if so how?

fedorqui
  • 275,237
  • 103
  • 548
  • 598

9 Answers9

68

Pandoc can convert Markdown to groff man pages.

This (thanks to nenopera's comment):

 pandoc -s -f markdown -t man foo.md | man -l -

should do the trick. The -s option tells it to generate proper headers and footers.

There may be other markdown-to-*roff converters out there; Pandoc just happens to be the first one I found.

Another alternative is the markdown command (apt-get install markdown on Debian systems), which converts Markdown to HTML. For example:

markdown README.md | lynx -stdin

(assuming you have the lynx terminal-based web browser).

Or (thanks to Danny's suggestion) you can do something like this:

markdown README.md > README.html && xdg-open README.html

where xdg-open (on some systems) opens the specified file or URL in the preferred application. This will probably open README.html in your preferred GUI web browser (which isn't exactly "less-style", but it might be useful).

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 2
    Really great, and not only for markdown to man. But If you don't want to screw you up, this is the some-pandoc-command: pandoc -s -f markdown -t man . Really Important -s which add header of man (or it wont work) better use pandoc-command | man -l - (better page width) – albfan Jul 17 '12 at 06:24
  • 8
    Works for me on Linux, but the version of `man` in Mac OS X (and probably other BSDs) doesn't support the local-file mode (`man -l `). Here's the closest I could come for Mac OS X: pandoc -s -f markdown -t man foo.md | groff -T utf8 -man | less – metamatt Jan 08 '13 at 03:09
  • 1
    +1 for metamatt's comment - this can also be used to write a less filter. Try, for example, saving the following as .lessfilter
    
        #!/bin/sh
        
        case "$1" in
            *.md)
                extension-handler "$1"
                pandoc -s -f markdown -t man "$1"|groff -T utf8 -man -
                ;;
            *)
                # We don't handle this format.
                exit 1
        esac
        
        # No further processing by lesspipe necessary
        exit 0
    
    Then, you can type `less FILENAME.md` and it will be formatted like a manpage.
    – Joel Cross Nov 25 '13 at 15:44
  • if you have a browser that responds to the `open` command: `markdown README.md > ~/readme.html && open ~/readme.html` – Danny Mar 12 '14 at 15:43
  • @Danny: Good point, see my updated answer. (On my Ubuntu system, `open` is equivalent to `openvt`, which opens a virtual terminal; `xdg-open` works as described.) – Keith Thompson Mar 12 '14 at 15:56
  • 1
    Thanks to this answer I have `function md () { markdown $1 | lynx --stdin; }` in my `.bashrc` now. The needed dependencies have a low footprint, which is nice on constrained boxes. You may check, if `w3m` or `links` are already available on your machine. – Johannes Kohnen Sep 04 '14 at 13:31
  • +1 for `markdown` + `lynx` solution. Easiest to use with OS X & homebrew after `brew install markdown lynx` :) – Greg Dubicki Jan 28 '16 at 10:15
31

I tried to write this in a comment above, but I couldn't format my code block correctly. To write a 'less filter', try, for example, saving the following as ~/.lessfilter:

#!/bin/sh

case "$1" in
    *.md)
        extension-handler "$1"
        pandoc -s -f markdown -t man "$1"|groff -T utf8 -man -
        ;;
    *)
        # We don't handle this format.
        exit 1
esac

# No further processing by lesspipe necessary
exit 0

Then, you can type less FILENAME.md and it will be formatted like a manpage.

Dean Rather
  • 31,756
  • 15
  • 66
  • 72
Joel Cross
  • 1,400
  • 15
  • 22
  • 5
    Don't forget to `chmod +x` `.lessfilter`. Also, `less -R` may be needed. – Raman Mar 01 '14 at 05:23
  • This is an excellent answer. Not only solves the original problem, but added a new skill to my bag of tricks! Bring on the less filters! – Dean Rather Jul 27 '15 at 19:27
  • 1
    I had to add `-K utf8` switch to groff (https://stackoverflow.com/a/24969648/1581629) or my lists would diplay things such as "â âââ" – Matteo Gamboz Mar 06 '19 at 10:49
9

If you are into colors then maybe this is worth checking as well:

terminal_markdown_viewer

It can be used straightforward also from within other programs, or python modules.

And it has a lot of styles, like over 200 for markdown and code which can be combined.

pic2

Disclaimer

  • It is pretty alpha there may be still bugs

  • I'm the author of it, maybe some people like it ;-)

Red Pill
  • 511
  • 6
  • 15
5

A totally different alternative is mad. It is a shell script I've just discovered. It's very easy to install and it does render markdown in a console pretty well.

Alban
  • 1,915
  • 1
  • 14
  • 17
3

I wrote a couple functions based on Keith's answer:

mdt() {
    markdown "$*" | lynx -stdin
}

mdb() {
    local TMPFILE=$(mktemp)
    markdown "$*" > $TMPFILE && ( xdg-open $TMPFILE > /dev/null 2>&1 & )
}

If you're using zsh, just place those two functions in ~/.zshrc and then call them from your terminal like

mdt README.md
mdb README.md

"t" is for "terminal", "b" is for browser.

Community
  • 1
  • 1
mpen
  • 272,448
  • 266
  • 850
  • 1,236
1

Using OSX I prefer to use this command

brew install pandoc
pandoc -s -f markdown -t man README.md | groff -T utf8 -man | less

Convert markupm, format document with groff, and pipe into less

credit: http://blog.metamatt.com/blog/2013/01/09/previewing-markdown-files-from-the-terminal/

random-forest-cat
  • 33,652
  • 11
  • 120
  • 99
1

This is an alias that encapsulates a function:

alias mdless='_mdless() { if [ -n "$1" ] ; then if [ -f "$1" ] ; then cat <(echo ".TH $1 7 `date --iso-8601` Dr.Beco Markdown") <(pandoc -t man $1) | groff -K utf8 -t -T utf8 -man 2>/dev/null | less ; fi ; fi ;}; _mdless '

Explanation

  • alias mdless='...' : creates an alias for mdless
  • _mdless() {...}; : creates a temporary function to be called afterwards
  • _mdless : at the end, call it (the function above)

Inside the function:

  • if [ -n "$1" ] ; then : if the first argument is not null then...
  • if [ -f "$1" ] ; then : also, if the file exists and is regular then...
  • cat arg1 arg2 | groff ... : cat sends this two arguments concatenated to groff; the arguments being:
    • arg1: <(echo ".TH $1 7date --iso-8601Dr.Beco Markdown") : something that starts the file and groff will understand as the header and footer notes. This substitutes the empty header from -s key on pandoc.
    • arg2: <(pandoc -t man $1) : the file itself, filtered by pandoc, outputing the man style of file $1
  • | groff -K utf8 -t -T utf8 -man 2>/dev/null : piping the resulting concatenated file to groff:
    • -K utf8 so groff understands the input file code
    • -t so it displays correctly tables in the file
    • -T utf8 so it output in the correct format
    • -man so it uses the MACRO package to outputs the file in man format
    • 2>/dev/null to ignore errors (after all, its a raw file being transformed in man by hand, we don't care the errors as long as we can see the file in a not-so-much-ugly format).
  • | less : finally, shows the file paginating it with less (I've tried to avoid this pipe by using groffer instead of groff, but groffer is not as robust as less and some files hangs it or do not show at all. So, let it go through one more pipe, what the heck!

Add it to your ~/.bash_aliases (or alike)

DrBeco
  • 11,237
  • 9
  • 59
  • 76
0

I personally use this script:

#!/bin/bash
id=$(uuidgen | cut -c -8)
markdown $1 > /tmp/md-$id
google-chrome --app=file:///tmp/md-$id

It renders the markdown into HTML, puts it into a file in /tmp/md-... and opens that in a kiosk chrome session with no URI bar etc.. You just pass the md file as an argument or pipe it into stdin. Requires markdown and Google Chrome. Chromium should also work but you need to replace the last line with

chromium-browser --app=file:///tmp/md-$id

If you wanna get fancy about it, you can use some css to make it look nice, I edited the script and made it use Bootstrap3 (overkill) from a CDN.

#!/bin/bash
id=$(uuidgen | cut -c -8)
markdown $1 > /tmp/md-$id
sed -i "1i <html><head><style>body{padding:24px;}</style><link rel=\"stylesheet\" type=\"text/css\" href=\"http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css\"></head><body>" /tmp/md-$id
echo "</body>" >> /tmp/md-$id
google-chrome --app=file:///tmp/md-$id > /dev/null 2>&1 &
sammko
  • 197
  • 6
  • 2
    I'd suggest to replace the uuid hack with `mktemp` which is actually safe and best practice; also it would give you a full pathname which you can `rm` afterwards. – Johannes Kohnen Sep 04 '14 at 13:40
0

I'll post my unix page answer here, too:

An IMHO heavily underestimated command line markdown viewer is the markdown-cli.

Installation

npm install markdown-cli --global

Usage

markdown-cli <file>

Features

Probably not noticed much, because it misses any documentation...
But as far as I could figure out by some example markdown files, some things that convinced me:

  • handles ill formatted files much better (similarly to atom, github, etc.; eg. when blank lines are missing before lists)
  • more stable with formatting in headers or lists (bold text in lists breaks sublists in some other viewers)
  • proper table formatting
  • syntax highlightning
  • resolves footnote links to show the link instead of the footnote number (not everyone might want this)

Screenshot

example.png

Drawbacks

I have realized the following issues

  • code blocks are flattened (all leading spaces disappear)
  • two blank lines appear before lists
orzechow
  • 1,210
  • 2
  • 13
  • 18