box.matto.nl
Enjoying Open Source Software

Convert Markdown-ish to PDF with Groff MOM

There are many ways one can generate a PDF file from a Markdown file. One example is to use Pandoc to generate LaTeX and use pdflatex to generate a PDF.

Groff can be a lot faster and require a lot less resources. TeX Live packages can be quite large and if you don't need a lot of features this can be overkill.

Mom Macros for GNU Troff is a nice toolbox to create beautiful documents.

I use this to convert small Markdown-ish meeting notes into a PDF document.

We all appreciate the plain text format, but for some people in our organization this is not the case.

A small awk script can do wonders.

Example document

This is a small example of the format I use for meeting notes.

# Notes of the meeting with a special name
- Date: 16 februari 2021
- Time: 14:00 - 15:00
## A nice header
Some information and some sentences. A lot more text. You can
never have enough text.
## Another nice header
Here we have another paragraph filled with very interesting
text.

This is another paragraph.

## Bullets are nice
- There can never be too much bullets.
- Some more are nice to look at
- Always have at least three bullets

### A lower header
This paragraph is right between a third level headers, because
we want a lot of headers.

#### Sublists
This is a small test of sublists. Remember that bullets are great.
- This is a bullet on the first level.
- This too is a bullet on the first level.
    - This is a bullet on the second level.
    - This too is a bullet on the second level.
    - This is the third bullet on the second level.
- This again is a bullet on the first level.
- This too is a bullet on the first level.

Small awk script

This is the awk script that I use to convert the Markdown-ish file to the Groff mom format.

BEGIN {
    inlisting = 0;
    inlisting2 = 0;
    inlisting3 = 0;
    inparagraph = 0;
    print ".PAPER A4"
    print ".TITLE_STYLE  COLOR YELLOW"
    print ".TITLE \"The Screaming Butterflies\"  \"Flower Power Workgroup\""
    print ".PDF_TITLE \"\\*[$TITLE]"
    print ".\\\" Formatting style, margins"
    print ".PRINTSTYLE TYPESET"
    print ".L_MARGIN   2.5c"
    print ".R_MARGIN   2.5c"
    print ".B_MARGIN   2.5c"
    print ".NEWCOLOR YELLOW #e36c0a"
    print ".HEADING_STYLE 1 COLOR YELLOW"
    print ".HEADING_STYLE 2 COLOR YELLOW"
    print ".\\\" General defaults"
    print ".FAMILY   P"
    print ".FT       R"
    print ".PT_SIZE  11"
    print ".AUTOLEAD 3 3"
    print ".PARA_INDENT 0 \\\" No indent because we're spacing paragraphs."
    print ".HYPHENATION 0 \\\" No hypenantion of words at end of line."
    print ".START"
}
{
    if ( $0 ~ /^# / ) { reset_list(); printf ".HEADING 1 \"%s\"\n", substr($0, 3); }
    else if ( $0 ~ /^## / ) { reset_list(); printf ".HEADING 2 \"%s\"\n", substr($0, 4); }
    else if ( $0 ~ /^### / ) { printf ".HEADING 3 \"%s\"\n", substr($0, 5); }
    else if ( $0 ~ /^#### / ) { printf ".HEADING 4 \"%s\"\n", substr($0, 6); }
    else if ( $0 ~ /^- / ) { 
        if ( inlisting2 == 1 ) {
            inlisting2 = 0;
            print ".LIST OFF"
        }
        if ( inlisting == 0 ) {
            inlisting = 1;
            print ".SP .25v"
            print ".LIST"
        }
        print ".ITEM"; print substr($0, 3) 
    }
    else if ( $0 ~ /^\t- / ) { 
        if ( inlisting == 0 ) {
            inlisting = 1;
            print ".SP .25v"
            print ".LIST"
        }
        if ( inlisting2 == 0 ) {
            inlisting2 = 1;
            print ".LIST"
        }
        print ".ITEM"; print substr($0, 4) 
    }
    else if ( $0 ~ /^\t\t- / ) { 
        if ( inlisting == 0 ) {
            inlisting = 1;
            print ".SP .25v"
            print ".LIST"
        }
        if ( inlisting2 == 0 ) {
            inlisting2 = 1;
            print ".LIST"
        }
        if ( inlisting3 == 0 ) {
            inlisting3 = 1;
            print ".LIST"
        }
        print ".ITEM"; print substr($0, 5) 
    }
    else if ( $0 ~ /^  / ) { 
            if ( inlisting == 1 || inlisting2 == 1  || inlisting3 == 1) {
                gsub("^ *", "", $0)
            }
        }
    else {
        if ( inlisting3 == 1 ) {
            inlisting3 = 0;
            print ".LIST OFF"
        }
        if ( inlisting2 == 1 ) {
            inlisting2 = 0;
            print ".LIST OFF"
        }
        if ( inlisting == 1 ) {
            inlisting = 0;
            print ".LIST OFF"
            print ".SP .25v"
        }
        if ( inparagraph == 0 ) {
            inparagraph = 1;
            print ".PP"
        }
        print $0
    }
}
function reset_list()
{
    if ( inlisting3 == 1 ) {
        inlisting3 = 0;
        print ".LIST OFF"
    }
    if ( inlisting2 == 1 ) {
        inlisting2 = 0;
        print ".LIST OFF"
    }
    if ( inlisting == 1 ) {
        inlisting = 0;
        print ".LIST OFF"
        print ".SP .25v"
    }
}

This script creates headers with a color and allows for three levels of lists.

I have just hacked it together in short time and stopped when it worked, so there is probably a lot of room for improvement.

Run the awk script and pdfmom

To use the script, this is the workflow:

awk -f name-of-the-awk-script > tempfile.mom
pdfmom tempfile.mom  > final.pdf

See also

Some very informative resources are:

Tags:

⇽ Script to convert OPML file to GNU recutils database Editing with mg ⇾