Problem

I am planning to read source code of a open-source project. With a (perhaps weird) habit, I often print all the source codes according to the way they are organized (in particular, the hierarchy) and this was previously done manually. However, I encountered a rather large project and it involves more than 100 files. Therefore, I have been trying to automate this process.

Now I have read all the file names into a text file that look that the following

I use package minted to typeset code and it provides \inputminted[<options>]{<language>}{<filename>} to include the entire file. Additionally, it could be used together with listing environment that looks like

\begin{listing}
\inputminted{python}{<filename>.py}
\caption{xxx}
\end{listing}


Now I would like to use LaTeX to read all the filenames and recursively use the previous code snippet to typeset all of these files into a bunch of listing environments. In this way, I could

• Easily include all the codes without tiresome copy-and-paste.
• Know the dependency relations among codes by reading the caption.

However, I am not sure if there is easy way to do this.

Solution

I really like @SergeiGolovan's solution, which might be a good fit for complicated task. However, for a (relatively simple) application like mine, I figured out that a simpler solution is to directly use datatool package.

datatool has pretty sophisticated functionalities like making table, drawing plots from input file, etc. But I just need it to read external file

\documentclass{article}

\usepackage{datatool}
\usepackage{minted}

\begin{document}
\DTLsetseparator{,}
\DTLforeach{mydb}{\path=path,\name=name}{
\begin{listing}[H]
\inputminted[linenos, breaklines]{python}{\path}
\caption{\name}
\end{listing}
}
\end{document}


Note that

• The underscore _'s are replaced with \underscore when writing filename.txt file.
• To avoid potentially long absolute path, an additional column name is added, which is just filename relative to root of the code repo.
• I don't think LaTeX itself can do recursive queries for files, so you would either have to call an external script/binary with --shell-escape or use LuaLaTeX. If the document doesn't contain a lot more than just the source code or the software project you could consider generating the .tex file from Python or Bash who have access to the file systems more easily. – moewe Jun 28 at 5:49

What I would do for this task is not use LaTeX for it, but employ an external script which would generate the list of listings. And then glue it to the LaTeX document using make. An example code can be the following:

1) The outer document listings.tex (a portion of code which breaks listings between pages is taken from Pagebreak for minted in figure):

\documentclass[a4paper,12pt]{article}
\usepackage{minted}
\usepackage{caption}
\usepackage[margin=2cm]{geometry}

% Create a new environment for breaking code listings across pages.
% See https://tex.stackexchange.com/questions/368864/pagebreak-for-minted-in-figure
\newenvironment{longlisting}{\captionsetup{type=listing}}{}

\begin{document}
\input{mylistings.tex}
\end{document}


2) The list generating script genlistings.py in Python (it's very basic, you can add anything you like to it):

#!/usr/bin/python3

import sys
import os

directory = sys.argv[1]

def Escape(string):
return string.replace("_", r"\textunderscore ")

def PrintListing(filename):
if os.path.splitext(filename)[1] == '.py':
print(r'\begin{longlisting}\inputminted{python}{%s}\caption{\texttt{%s}}\end{longlisting}' % (filename, Escape(filename)))

for root, dirs, files in os.walk(directory):
for name in files:
PrintListing(os.path.join(root, name))


3) The Makefile to put them together (it searches for Python files in the sampleproject directory and creates a document with listings for all found files. It uses latexmk.):

DIR = sampleproject
PYTHONSOURCES = $(find$(DIR) -name '*.py')

all: listings.pdf

listings.pdf: listings.tex mylistings.tex
latexmk -pdf -pdflatex='pdflatex -shell-escape %O %S' $< mylistings.tex: genlistings.py$(PYTHONSOURCES)
python3 genlistings.py $(DIR) >$@

clean:
rm -rf mylistings.tex listings.fdb_latexmk listings.fls listings.pdf listings.aux listings.log _minted-listings/

.PHONY: listings.pdf clean


Simply executing make, you'll get the required listings. If anything changes (the code in the Python scripts, the genlistings.py script, the listings.tex itself), another make will recreate the list.