🌒

Markdown documentation

Posted at — Apr 04, 2022

Introduction

Documentation should live with the code. Therefore a common problem is to keep your code documentation beside your source code, in a Git-friendly manner, while also being able to transform it later in a user-friendly format. In other words, you want to keep your documentation written in easy-to-read and easy-to-modify text files while also being able to generate PDF files from it (or HTML).

You may want also to be able to include nice diagrams in your documentation, while also being able to version them in a Git-friendly manner.

The only drawback with the following method is that links internal to the documentation are hard to do right.

Presenting

Git

This document assumes you’re already familiar with Git. If not, it’s time to be, because it’s fabulous.

Markdown

Markdown is a lightweight markup language. It allows to create well formated text quickly and easily. It can be versionned with Git nicely. And most of all, it’s very easy to read back.

Pandoc

Pandoc is a document converter. It does support Markdown as input, and can generate various user-friendly output formats like PDF or HTML.

Plantuml

Plantuml is a tool able to generate diagrams from simple text descriptions.

Makefile

Combining all those tools makes some very heavy commands. The simpler way to keep track of those commands is to use them in a Makefile.

Continuous integration

Once you have a working Makefile, it’s easy to use Continuous Integration to generate the PDF file every time someone pushes in the repository. One advantage with that is that any good forge will allow you to download the generated PDF at an address that never changes (for instance https://gitlab.com/some_project/-/jobs/artifacts/master/raw/distribution/doc_technician.pdf?job=doc)

Converting Markdown into PDF

Pandoc can do it. However, if you want to customise the style of the PDF (or HTML), it’s actually to first generate LaTeX from the Markdown. Then you can add style personalisations to the LaTeX code (custom header, table of content, etc). Then you can turn the LaTeX into a PDF or HTML.

Show me the code !

Markdown + Plantuml

It’s important to be able to split the documentation into many markdown files for readability. However, your scripts must be able to figure out in which order they must be read. Therefore file names should be prefixed by a number.

For instance:

doc/dev/000_intro.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
![Some nice illustration](000_intro/doc.jpg)

# Introduction

## Stuff

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

## Overview

Here is a nice diagram explaining stuff:

```{ .plantuml width=25% }
@startuml
Room o- Student
Room *-- Chair
@enduml
```

doc/dev/001_first_chapter.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# First chapter

![Some_nice_image](001_first_chapter/img.jpg)

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

etc

Style personalisation

doc/head.tex

1
2
3
\let\oldtoc\tableofcontents
\renewcommand{\tableofcontents}{\oldtoc\newpage}
\setcounter{secnumdepth}{4}

Makefile

The document title is specified in the Makefile (included as meta-data in the PDF later)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
DOC_SRCS := $(wildcard doc/*.md)


doc.pdf: doc.tex
	# keep in mind the image paths are relative to doc/technician
	cd doc && pandoc \
		-T "A very nice documentation" \
		-H head.tex \
		-V subparagraph \
		-V colorlinks -V urlcolor=NavyBlue -V toccolor=NavyBlue \
		-V geometry:margin=1in --toc \
		-V papersize:a4 \
		--filter pandoc-plantuml \
		-s --pdf-engine=xelatex \
		-o ../$@ ../$<


doc.tex: $(DOC_SRCS)
	echo "---" > /tmp/metadata.yaml
	echo "title: \"A very nice documentation\"" >> /tmp/metadata.yaml
	echo "author: \"Myself\"" >> /tmp/metadata.yaml
	echo "date: `date +%Y-%m-%d`" >> /tmp/metadata.yaml
	echo "---" >> /tmp/metadata.yaml
	# keep in mind the image paths are relative to doc/
	cd doc && pandoc \
		-f markdown+yaml_metadata_block-raw_tex-implicit_figures -s \
		-o ../$@ \
		--filter pandoc-plantuml \
		/tmp/metadata.yaml \
		$(addprefix ../,$(sort $^))
	rm -f /tmp/metadata.yaml


clean:
	rm -f doc.pdf doc.tex


.PHONY: clean

It can run with make doc.pdf.

.gitlab-ci.yml

image: debian:bullseye

variables:
  DEBIAN_FRONTEND: noninteractive

doc:
  script:
    - apt-get update -qq
    - apt-get install -y -qq make
    - apt-get install -y -qq groff
    - apt-get install -y -qq librsvg2-bin
    - apt-get install -y -qq pandoc pandoc-citeproc
    - apt-get install -y -qq plantuml
    - apt-get install -y -qq python3
    - apt-get install -y -qq python3-pip
    - apt-get install -y -qq texlive-latex-recommended texlive-xetex
    - apt-get install -y -qq texlive-luatex texlive-latex-extra context
    - apt-get install -y -qq librsvg2-bin groff
    - pip3 install pandoc-plantuml-filter==0.1.2
    - make doc.pdf
  artifacts:
    paths:
      - doc.pdf
    expire_in: 7 days

Note: even with expire_in, Gitlab always keeps the latest build.