{"id":14350,"date":"2026-07-13T01:00:00","date_gmt":"2026-07-13T05:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=14350"},"modified":"2026-06-29T19:34:08","modified_gmt":"2026-06-29T23:34:08","slug":"pretty-printing-source-code-with-pandoc","status":"publish","type":"post","link":"http:\/\/www.both.org\/?p=14350","title":{"rendered":"Pretty-printing source code with pandoc"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"14350\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p class=\"wp-block-paragraph\">When I first started using Unix systems in the 1990s, <em>printing<\/em> was still a popular method to share and review source code. These days, I still find it handy to print a program\u2019s source, so I can refer to it on paper. For example, I prefer to have a program listing next to me as a reference when giving a live demonstration, such as at a conference.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Printing a source file to the printer is rather plain. I find that adding some simple formatting can make the source code easier to read: italic text for comments, bold for function names, and so on. In the 1990s, I might use a special kind of program called a <em>pretty-printer<\/em> to add this extra formatting; for example, the <a href=\"https:\/\/www.gnu.org\/software\/a2ps\/\">GNU a2ps<\/a> program does a good job at this, but it has a ton of dependencies to handle all kinds of different files. Because it\u2019s so big, I don\u2019t often use it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, I discovered I can use <a href=\"https:\/\/pandoc.org\/\">pandoc<\/a> to convert a source file to LibreOffice format, which also formats it in a pretty-printed way. I can print the output very easily. Since I install pandoc and LibreOffice anyway, there\u2019s no need to install a different tool like a2ps to do the same thing. Here\u2019s how I do it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrap it with Markdown<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The key concept behind using pandoc to pretty-print my source code is that <em>pandoc\u2019s Markdown can recognize a variety of source file formats<\/em> and <em>automatically apply formatting<\/em> to make it look nice in a document.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In standard Markdown, you use a \u201ccode fence\u201d to format a block of text as verbatim text, such as source code. For example, to include a two-line Bash script in a Markdown document, just surround the source code sample with three &#8220;backticks&#8221;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>This Bash script prints \"hello world\"\nand immediately exits:\n\n```\n#!\/bin\/bash\necho \"hello world\"\n```<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When you process this Markdown document using pandoc, the source code is formatted as verbatim text, using a typewriter-like font. For example, pandoc would transform this into HTML using <code>&lt;pre><\/code> and <code>&lt;code><\/code> blocks:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p&gt;This Bash script prints \u201chello world\u201d and immediately exits:&lt;\/p&gt;\n&lt;pre&gt;&lt;code&gt;#!\/bin\/bash\necho &amp;quot;hello world&amp;quot;&lt;\/code&gt;&lt;\/pre&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">However, pandoc\u2019s Markdown also allows you to add a language identifier, immediately after the first code fence, to indicate a specific programming language. For a Bash script, we can add <code>bash<\/code> to the first code fence, like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>This Bash script prints \"hello world\"\nand immediately exits:\n\n```bash\n#!\/bin\/bash\necho \"hello world\"\n```<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When pandoc processes this document, it will format the verbatim text using certain rules that help certain features in the source code to stand out:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p&gt;This Bash script prints \u201chello world\u201d and immediately exits:&lt;\/p&gt;\n&lt;div class=\"sourceCode\" id=\"cb1\"&gt;&lt;pre\nclass=\"sourceCode bash\"&gt;&lt;code class=\"sourceCode bash\"&gt;&lt;span id=\"cb1-1\"&gt;&lt;a href=\"#cb1-1\" aria-hidden=\"true\" tabindex=\"-1\"&gt;&lt;\/a&gt;&lt;span class=\"co\"&gt;#!\/bin\/bash&lt;\/span&gt;&lt;\/span&gt;\n&lt;span id=\"cb1-2\"&gt;&lt;a href=\"#cb1-2\" aria-hidden=\"true\" tabindex=\"-1\"&gt;&lt;\/a&gt;&lt;span class=\"bu\"&gt;echo&lt;\/span&gt; &lt;span class=\"st\"&gt;&amp;quot;hello world&amp;quot;&lt;\/span&gt;&lt;\/span&gt;&lt;\/code&gt;&lt;\/pre&gt;&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But if we only want to pretty-print the Bash script, we don\u2019t need the introductory paragraph. We can just surround the Bash source with a code fence, and add the <code>bash<\/code> identifier to the opening fence. This is easy to do using the command line, or automated with a script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ (echo '```bash' ; cat hello.bash ; echo '```') | pandoc --from markdown --to html\n&lt;div class=\"sourceCode\" id=\"cb1\"&gt;&lt;pre\nclass=\"sourceCode bash\"&gt;&lt;code class=\"sourceCode bash\"&gt;&lt;span id=\"cb1-1\"&gt;&lt;a href=\"#cb1-1\" aria-hidden=\"true\" tabindex=\"-1\"&gt;&lt;\/a&gt;&lt;span class=\"co\"&gt;#!\/bin\/bash&lt;\/span&gt;&lt;\/span&gt;\n&lt;span id=\"cb1-2\"&gt;&lt;a href=\"#cb1-2\" aria-hidden=\"true\" tabindex=\"-1\"&gt;&lt;\/a&gt;&lt;span class=\"bu\"&gt;echo&lt;\/span&gt; &lt;span class=\"st\"&gt;&amp;quot;hello world&amp;quot;&lt;\/span&gt;&lt;\/span&gt;&lt;\/code&gt;&lt;\/pre&gt;&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The parentheses are a Bash extension that allow you to group several commands into one <em>subshell<\/em>. Here, the subshell prints the first code fence with the <code>bash<\/code> identifier, then displays the source file, and prints the trailing code fence. The output is sent to pandoc, which transforms it from Markdown into HTML.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>bash<\/code> identifier is just one format that pandoc recognizes. Others include <code>c<\/code> for C programming, <code>fortran<\/code> for FORTRAN 77 code, <code>perl<\/code> for Perl scripts, and <code>awk<\/code> for Awk and Gawk scripts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Converting to LibreOffice format<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">With that demonstration of how to use pandoc to format a source file, we can see how I <em>actually<\/em> pretty-print my files: I convert the output to LibreOffice format. This produces more interesting formatting, including colors, bold type, and italic text.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Bash script<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s an example that pretty-prints a Bash script that mimics the original Unix <strong>typo<\/strong> command, to identify misspelled words in a text document:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ (echo '```bash' ; cat ~\/bin\/typo ; echo '```') | pandoc --from markdown --to odt -o typo.odt<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"300\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/typo.png\" alt=\"Source code for a Bash script that finds misspelled words\" class=\"wp-image-14347\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">By default, pandoc formats the verbatim text using Courier. This looks good in print, but I don\u2019t like it. Fortunately, this is easy enough to change by modifying the <code>Preformatted Text<\/code> paragraph style in LibreOffice and choosing a new font. To modify a style in LibreOffice, right-click on the style name in the Styles sidebar, and select &#8220;Edit Style&#8221;:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"446\" height=\"284\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/preformatted-edit-style.png\" alt=\"Right-click on &quot;Preformatted Text&quot; style and select &quot;Edit Style&quot; to choose a new font\" class=\"wp-image-14346\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">I prefer IBM Plex Mono to display source code. The Plex Mono font is reminiscent of the IBM Selectric typewriter font, which looks great on screen and in print:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"300\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/typo-plex.png\" alt=\"Source code for a Bash script that finds misspelled words\" class=\"wp-image-14348\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Gawk script<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">We can do the same to format a Gawk script for printing. This script scans words on the input and only prints words that only use each letter <em>once<\/em>. For example, the script will print <strong>stare<\/strong> but not <strong>unique<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ (echo '```awk' ; cat ~\/bin\/uniqltr.gawk ; echo '```') | pandoc --from markdown --to odt -o uniqltr.odt<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"400\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/uniqltr-plex.png\" alt=\"source code for a Gawk script that prints words without repeated letters\" class=\"wp-image-14349\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">FORTRAN 77 program<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When pretty-printing my FORTRAN 77 programs, I sometimes save some space by removing any blank lines. This doesn\u2019t affect the program because old-style FORTRAN ignores empty lines anyway. For short programs, the pretty-printed output is still quite readable without the blank lines:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ (echo '```fortran' ; grep -v '^$' ~\/src\/fortran\/mand.f ; echo '```') | pandoc --from markdown --to odt -o mand.odt<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"450\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/mand-plex.png\" alt=\"Source code for a FORTRAN 77 program that generates the Mandelbrot data set\" class=\"wp-image-14345\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">C program<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When formatting C programs, I usually take the opportunity to reformat the source code so it is more readable. The <strong>indent<\/strong> program will do this for you automatically. The <strong>-linux<\/strong> option uses the Linux kernel coding style, which provides a good balance for readability without taking up too much vertical space, and <strong>-st<\/strong> prints the output to the standard output so it can be processed with pandoc:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ (echo '```c' ; indent -linux -st ~\/src\/guess.c ; echo '```') | pandoc --from markdown --to odt -o guess.odt<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"400\" src=\"http:\/\/www.both.org\/wp-content\/uploads\/2026\/06\/guess-plex.png\" alt=\"Source code for a C program where the user guesses a secret number\" class=\"wp-image-14344\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Formatted output with pandoc<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">While I don\u2019t often need to format printed output in this way, it\u2019s handy to know how to use pandoc and LibreOffice together to pretty-print source code. This makes it easier to read and review, which is helpful when I\u2019m using it as a reference during a presentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To see what other language identifiers you can use with pandoc&#8217;s Markdown, type<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ pandoc --list-highlight-languages<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Here\u2019s a new way to display source code using pandoc<\/p>\n","protected":false},"author":33,"featured_media":7028,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":"","_members_access_role":[],"_members_access_error":""},"categories":[237,590],"tags":[133,581],"class_list":["post-14350","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-libreoffice","category-pandoc","tag-libreoffice","tag-pandoc"],"modified_by":"Jim Hall","_links":{"self":[{"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/14350","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"http:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14350"}],"version-history":[{"count":10,"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/14350\/revisions"}],"predecessor-version":[{"id":14360,"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/14350\/revisions\/14360"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/7028"}],"wp:attachment":[{"href":"http:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14350"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14350"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14350"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}