11 March 2023

How to print any source code with Vim

Problems

You want to print source code from your project for quick review.

Solutions

You can leverage the power of Vim to print to source code via :TOhtml function. This produce the output as <your-file-name>.ext.xhtml that you can then use.

What you need to install:

  • wkhtmltopdf for generate the x(html) to pdf
  • ghostscript for generate table of content for combined pdf
  • Vim with appropriate colorscheme, for printing the source code (headless)
  • xpdfreader needed for pdfinfo command
  • GraalVM need to build native-image - need to set GRAALVM_HOME
  • Babashka native, fast starting Clojure interpreter for scripting
  • OpenJDK the JVM
  • asdf manage multiple runtime versions with a single CLI tool. (optional)
  • Clojure

Build self-executable binary

You will need to first build the code using Babashka

bb tasks

Which should gives you the following outputs

clean
build                     Build classes and uberjar
graalvm                   Checks GRAALVM_HOME env var
native-image-uber         Builds native image from uber
native-image-uber-test    Run native image built from uber
native-image-classes      Builds native image from classes
native-image-classes-test Run native image built from classes
native-image-test         Run integration tests

To actually build the native image that you can later copy/run locally try:

bb clean
bb build
bb native-image-test

This should give you the ouput binary that you can use in target/viip

You can then copy this file to your $PATH and use it with ease.

Sample Usage

To get the sample usage just type ~/bin/viip -h (assume that you copy the generated file to ~/bin/)

➜  viip git:(main) ~/bin/viip -h
viip - Vim Interactive Printing

Usage:
  viip [options] --base-dir=<base-dir> --exts=<exts> --output-file=<output-file> [ --preset=<preset> | --color-scheme=<color-scheme> --font-name=<font-name> ]
  viip --list-presets
  viip --version
  viip --help

Options:
  -b, --base-dir=<base-dir>          Base directory [default: .]
  -e, --exts=<exts>                  Extension to print [default: clj,cljc,cljs ]
  -p, --preset=<preset>              Preset to use [default: seoul256-dark]
  -o, --output-file=<output-file>    Output file [default: codes.pdf]
  -c, --color-scheme=<color-scheme>  Color scheme to use [default: jellybeans]
  -f, --font-name=<font-name>        Font name to use [default: Fira Code]
  -z, --paper-size=<paper-size>      Output paper size to use [default: letter]
  -n, --line-numbers                 Print line numbers
  -t, --title=<title>                Title to use [default: viip]
  -a, --author=<author>              Author for the document [default: viip ]
  -s, --tags=<tags>                  Tags to use [default: codes,pdf,command-line]
  -l, --list-presets                 List available presets
  -h, --help                         Print help
  -v, --version                      Display version information

  # ------------------------------------------------------------ ##
  # Common Usage:
  # ------------------------------------------------------------ ##
  ~/bin/viip -b . -e clj,cljc,cljs -c github -f "Fira Code"       -t viip-demo -a viip -o code-github-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c github -f "Fira Code Mono"  -t viip-demo -a viip -o code-github-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c github -f "Inconsolata"     -t viip-demo -a viip -o code-github-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c envy -f "Fira Code"       -t viip-demo -a viip -o code-envy-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c envy -f "Fira Code Mono"  -t viip-demo -a viip -o code-envy-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c envy -f "Inconsolata"     -t viip-demo -a viip -o code-envy-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c onehalflight -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-onehalflight-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalflight -f "Fira Code Mono"  -t viip-demo -a "Vim Interactive Printer" -o code-onehalflight-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalflight -f "Inconsolata"     -t viip-demo -a "Vim Interactive Printer" -o code-onehalflight-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Fira Code Mono"  -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Inconsolata"     -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Fira Code Mono"  -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Inconsolata"     -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c jellybeans  -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-jellybeans-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c jellybeans  -f "Fira Code Mono"  -t viip-demo -a "Vim Interactive Printer" -o code-jellybeans-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c jellybeans  -f "Inconsolata"     -t viip-demo -a "Vim Interactive Printer" -o code-jellybeans-inconsolata.pdf

  ~/bin/viip -b . -e clj,cljc,cljs -c PaperColor -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-papercolor-fira-code.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c PaperColor -f "Fira Code Mono"  -t viip-demo -a "Vim Interactive Printer" -o code-papercolor-fira-code-mono.pdf
  ~/bin/viip -b . -e clj,cljc,cljs -c PaperColor -f "Inconsolata"     -t viip-demo -a "Vim Interactive Printer" -o code-papercolor-inconsolata.pdf

  # ------------------------------------------------------------ ##
  ## Show help
  viip -h

  # ------------------------------------------------------------ ##
  ## Show version
  viip -v

To print the actual source code of a project you can then try:

➜  viip git:(main) ✗ ~/bin/viip -b . -e clj,cljc,cljs -c onehalfdark -f "Fira Code"       -t viip-demo -a "Vim Interactive Printer" -o code-onehalfdark-fira-code.pdf 

Convert files to -> xhtml -> pdf ...
"build.clj.xhtml" [New]
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<title>~/codes/viip/build.clj.xhtml</title>
<meta name="Generator" content="Vim/9.0" />
<meta name="plugin-version" content="vim8.1_v2" />
<meta name="syntax" content="clojure" />
<meta name="settings" content="no_progress,ignore_folding,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=fallback" /
>
<meta name="colorscheme" content="onehalfdark" />
<style type="text/css">
"build.clj.xhtml" [New] 71L, 5971B written
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done                                                                      
"src/net/b12n/viip/core.clj.xhtml" [New]
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<title>~/codes/viip/src/net/b12n/viip/core.clj.xhtml</title>
<meta name="Generator" content="Vim/9.0" />
<meta name="plugin-version" content="vim8.1_v2" />
<meta name="syntax" content="clojure" />
<meta name="settings" content="no_progress,ignore_folding,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=fallback" /
>
<meta name="colorscheme" content="onehalfdark" />
<style type="text/css">
"src/net/b12n/viip/core.clj.xhtml" [New] 432L, 65563B written
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done                                                                      
"test/net/b12n/viip/core_test.clj.xhtml" [New]
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<title>~/codes/viip/test/net/b12n/viip/core_test.clj.xhtml</title>
<meta name="Generator" content="Vim/9.0" />
<meta name="plugin-version" content="vim8.1_v2" />
<meta name="syntax" content="clojure" />
<meta name="settings" content="no_progress,ignore_folding,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=fallback" /
>
<meta name="colorscheme" content="onehalfdark" />
<style type="text/css">
"test/net/b12n/viip/core_test.clj.xhtml" [New] 35L, 1886B written
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done                                                                      
Combine multiple pdf files into one ...
Delete *.xhtml files ...
Delete :  build.clj.xhtml
Delete :  src/net/b12n/viip/core.clj.xhtml
Delete :  test/net/b12n/viip/core_test.clj.xhtml
Delete *.xhtml.pdf files ...
Delete :  build.clj.xhtml.pdf
Delete :  src/net/b12n/viip/core.clj.xhtml.pdf
Delete :  test/net/b12n/viip/core_test.clj.xhtml.pdf
Delete pdfmarks file ...
Your output file is  code-onehalfdark-fira-code.pdf

Sample Outputs

You should be able to see the sample output similar to the following:

Using onehalfdark color scheme sample page from pdf output (png)

Using papercolor color scheme

sample page from pdf output (png)

Source Code

You can find the complete source code in github/burinc/viip

Tags: tools clojure cli vim