I came across an astonishing piece of text, which is called "Beautiful Code, Compelling Evidence" by J. R. Heard. I was wondering if there is a package or something that allows me to present my code similar to how J. R. Heard presented his code.

I would like line numbering though, but I figured first I need to find what he used to create a formatting like this. Note: the code is Haskell, but I would like to use it for pseudocode.

PS: it would be ideal if line numbering can be done after the vertical line. But I was also wondering whether it is possible to literally fix the width of the left column.

An example from his amazing work is shown below: Example from Beautiful Code by J. R. Heard

Thanks for your time and effort to help me!

  • listings or minted are the two usual packages for highlighted code listings – David Carlisle Nov 3 '14 at 9:51
  • Just to be clear, you are asking specifically how to format the comments as in the screen shot (to the left of the code, separated by a vertical line, automatic line wrapping)? – Christian Clason Nov 3 '14 at 10:49
  • Yes, that is correct. – Snowflake Nov 3 '14 at 11:29
  • 3
    After a lot of experiments and search for specific solutions I found a complete solution: tex.stackexchange.com/questions/15688/… – knut Nov 4 '14 at 9:08
  • 3
    While this is close to the mentioned duplicate, additional code is required to get line numbering working correctly. I am therefore voting that this question should be left open. – Andrew Swann Nov 4 '14 at 9:49
up vote 8 down vote accepted

I didn't use the Haskell highlighting offered by listings, because it highlights too many words (like List, etc.) which are not highlighted in the example.

\documentclass[12pt,DIV13]{scrartcl}
\usepackage{fontspec,listings,xcolor,lipsum}
% Fonts
\defaultfontfeatures{Ligatures=TeX}
\setmainfont{Gill Sans Std}
\setmonofont{Lucida Sans Typewriter OT}
% Colors
\definecolor{darkgray}{HTML}{404040}
\definecolor{rulegray}{HTML}{DADADA}
\definecolor{keywordblue}{HTML}{1F497C}
% Listings
\lstdefinestyle{code}{
  basicstyle=\ttfamily,
  keywordstyle=\color{keywordblue},
  keywords={import,qualified,as,do,where}
}
\newcommand\clearlines[1]{%
  \if#10\else%
    \leavevmode\\%
    \expandafter\clearlines\expandafter{\the\numexpr#1-1}%
  \fi}
\begin{document}

\lipsum[1]
\begin{center}
  \footnotesize
  \begin{minipage}{.25\linewidth}
    \color{darkgray}\raggedleft\itshape
    imports, aliases (1-3) \clearlines{5}
    Split all lines in the file. (6-7) \clearlines{3}
    Insert them into the map (9)
  \end{minipage}
  \hfill{\color{rulegray}\vrule}\hfill
  \begin{minipage}{.73\linewidth}
    \begin{lstlisting}[style=code]
import Data.List (foldl')
import qualified Data.ByteString.Lazy.Char8 as BStr
import qualified Data.Map as Map

readDatafile name = do
    sheet <- (map (BStr.split '\t') . BStr.lines) `fmap`
              BStr.readFile name
    return $ foldl’ go Map.empty sheet
  where go m (x:xs) = Map.insert (BStr.unpack x) xs m
    \end{lstlisting}
  \end{minipage}
\end{center}
\lipsum[1]

\end{document}

enter image description here


Adapting Martin Scharrer's answer to a similar question one can obtain a simpler version:

\documentclass[12pt,DIV13]{scrartcl}
\usepackage{fontspec,listings,xcolor,lipsum}
% Fonts
\defaultfontfeatures{Ligatures=TeX}
\setmainfont{Gill Sans Std}
\setmonofont{Lucida Console}
% Colors
\definecolor{darkgray}{HTML}{404040}
\definecolor{rulegray}{HTML}{DADADA}
\definecolor{keywordblue}{HTML}{1F497C}
% Listings
\lstnewenvironment{beautifulcode}{
  \lstset{
    basicstyle=\footnotesize\ttfamily,
    keywordstyle=\color{keywordblue},
    keywords={import,qualified,as,do,where},
    frame=l,rulecolor=\color{rulegray},framesep=.5em,
    escapeinside={(*@}{@*)},
    escapebegin={\begin{lrbox}{0}\normalfont\itshape\footnotesize\color{darkgray}},
    escapeend={\end{lrbox}\llap{\box0\hspace{1em}}}
  }
  \hspace*{.25\linewidth}
  \minipage{.75\linewidth}
}{
  \endminipage
}
\begin{document}

\lipsum[1]

\begin{beautifulcode}
(*@imports, aliases (1-3)@*)import Data.List (foldl')
import qualified Data.ByteString.Lazy.Char8 as BStr
import qualified Data.Map as Map

readDatafile name = do
(*@Split all lines in the file. (6-7)@*)    sheet <- (map (BStr.split '\t') . BStr.lines) `fmap`
              BStr.readFile name
    return $ foldl’ go Map.empty sheet
(*@Insert them into the map (9)@*)  where go m (x:xs) = Map.insert (BStr.unpack x) xs m
\end{beautifulcode}

\lipsum[1]

\end{document}

May be you want to try with a tcblisting from tcolorbox. Next it's just an starting point which will need a lot of customization.

enter image description here

\documentclass{article}
\usepackage[most]{tcolorbox}

\newtcblisting{Heardlisting}[2][]{%
empty,
boxsep=0pt,left=0pt,right=0pt,boxrule=2pt,leftrule=0pt,rightrule=0pt,
lefthand width=.4\linewidth,
segmentation engine=path,
segmentation style={solid,line width=1pt},
comment side listing,
fontupper=\itshape\sffamily,
listing options={% put any listing options here
    language={Haskell},
    aboveskip=0pt, belowskip=0pt,
    basicstyle=\ttfamily,columns=fullflexible},
comment={#2},#1
}

\begin{document}
\noindent%
\begin{Heardlisting}{%
   \begin{tabular}{r}% 
      imports, aliases (1-3)\\ \\ \\ \\ \\ 
      Split all lines in the file. (6-7)\\ \\ \\ 
      Insert them into the map (9)
   \end{tabular}
}
import data.List (foldl`)
import qualified Data.ByteString.Lazy.Char8 as BStr
import qualified Data.Map as Map

readDatafile name = do
       sheet <- (mat (BStr.split `\t`) . BStr.lines) `fmap
                      BStr.readFile name
       return $ foldl`go Map.empty sheet
  where go m (x:xs) = Map.insert (BStr.unpack x) xs m
\end{Heardlisting}
\end{document}

In this approach, I introduce the pcodeinput environment to set up the parameters, while lines of code are introduced with \pcode[comment]{code} within the environment. This has the advantage over other approaches of co-locating the comment with the code in your source document.

User parameters include

\leftcodesize=1.7in\relax
\leftcodegap=8pt\relax
\rightcodegap=10pt\relax
\coderulewidth=1pt\relax
\def\codecolor{blue!30!black!65}
\def\highlightcolor{blue!70!black!99}

to define the width of comments, the gaps around the bar separator, the separator-bar width, and the colors of code and highlighted code.

My twist for this approach was adapting the \titlecap routine of the titlecaps package for text highlighting. In that package, \titlecap capitalizes each word except those provided for in a user-specified lower-case-word list. Here, \titlecap gets transformed into \colorize, where highlight words are added with the syntax \AddHighlightWords{import qualified as do where}. Words not in the list get colorized with \codecolor, whereas words on the list get colorized with \highlightcolor. Note that \colorize is built into the \pcode[]{} definition and so it is transparent to the user.

This is not a verbatim environment, so special provisions need to be taken. For example, I made $ which appears in the OP's example into catcode 12. This can be done for other needed symbols, as well, except for the backslash. In this case (since it seemed a rare occcurence in the OP's code), I entered it as \textbackslash in the code listing.

\documentclass{article}
\usepackage{xcolor,lipsum}
\usepackage[margin=1in]{geometry}
\newlength\leftcodesize
\newlength\leftcodegap
\newlength\rightcodegap
\newlength\coderulewidth
%%% USER PARAMETERS
\leftcodesize=1.7in\relax
\leftcodegap=8pt\relax
\rightcodegap=10pt\relax
\coderulewidth=1pt\relax
\def\codecolor{blue!30!black!65}
\def\highlightcolor{blue!70!black!99}
%%%
\newcommand\pcode[2][]{%
  \fboxsep=0pt%
  \fboxrule=.5\coderulewidth%
  \makebox[\leftcodesize][r]{%
    \scriptsize\sffamily\itshape#1\hspace{\leftcodegap}}%
  \smash{\fbox{\strut}}%
  \hspace{\rightcodegap}%
  \ttfamily\small\colorize[n]{#2}\par%
}
\newenvironment{pcodeinput}
{\parindent 0pt\parskip 0pt\color{\codecolor}\medskip%
  \catcode`$=12}
{\medskip}
%%
\makeatletter
% ADAPT THE \titlecap ROUTINE FROM titlecaps PACKAGE
\usepackage{titlecaps}
\newcommand\colorize[2][P]{%
  \digest@sizes%
  \if T\converttilde\def~{ }\fi%
  \redefine@tertius%
  \get@argsC{#2}%
  \seek@lcwords{#1}%
  \if P#1%
    \redefine@primus%
    \get@argsC{#2}%
    \protected@edef\primus@argi{\argi}%
  \else%
  \fi%
  \setcounter{word@count}{0}%
  \redefine@secundus%
  \def\@thestring{}%
  \get@argsC{#2}%
  \if P#1\protected@edef\argi{\primus@argi}\fi%
  \whiledo{\value{word@count} < \narg}{%
    \addtocounter{word@count}{1}%
    \if F\csname found@word\roman{word@count}\endcsname%
      \textcolor{\codecolor}{\csname arg\roman{word@count}\endcsname}
      \expandafter\protected@edef\csname%
           arg\roman{word@count}\endcsname{\@thestring}%
    \else
      \textcolor{\highlightcolor}{\csname arg\roman{word@count}\endcsname}
      \expandafter\protected@edef\csname%
           arg\roman{word@count}\endcsname{\@thestring}%
    \fi%
  }%
  \def\@thestring{}%
  \setcounter{word@count}{0}%
  \whiledo{\value{word@count} < \narg}{%
    \addtocounter{word@count}{1}%
    \ifthenelse{\value{word@count} = 1}%
   {}{\add@space}%
    \protected@edef\@thestring{\@thestring%
      \csname arg\roman{word@count}\endcsname}%
  }%
  \let~\SaveHardspace%
  \@thestring%
  \restore@sizes%
\un@define}
\makeatother
\let\AddHighlightWords\Addlcwords
\begin{document}
\lipsum[1]
\AddHighlightWords{import qualified as do where}
\begin{pcodeinput}
\pcode[imports, aliases (1-3)]
{import Data,List (foldl')}
\pcode%
{import qualified Data.ByteString.Lazy.Char8 as BStr}
\pcode
{import qualified Data.Map as map}
\pcode
{}
\pcode
{readDatafile name do}
\pcode[Split all lines in the file. (6-7)]
{    sheet <- (map (BStr.split `\textbackslash t') . BStr.lines) `fmap'}
\pcode
{             BStr.readFile name}
\pcode
{    return $ foldl' go Map.empty sheet}
\pcode[Insert them into the map (9)]
{  where go m (x:xs) = Map.insert (BStr.unpack x) xs m}
\end{pcodeinput}
\lipsum[2]

\end{document}

enter image description here

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.