Articles Listings

Code Listings in LaTeX: Source Code Formatting and Syntax Highlighting

Format source code in LaTeX with the listings and minted packages: syntax highlighting, line numbering, custom languages, and algorithm typesetting, with working examples.

inscrive.io · Jan 30, 2025 · 21 min read
Code Listings in LaTeX: Source Code Formatting and Syntax Highlighting

Code Listings in LaTeX: Source Code Formatting and Syntax Highlighting

Drop a code snippet into a word processor and you get smart quotes where you wanted straight ones, autocorrect mangling your variable names, and indentation that drifts. LaTeX handles code listings properly: it preserves whitespace, highlights syntax, and numbers lines you can reference later. This guide covers the two packages that do the work, listings and minted, plus algorithms and a few formatting tricks worth knowing. For a second, more reference-style take on the same package, see the LaTeX code listings guide.

Why LaTeX for Code Documentation?

A few things LaTeX does well that a general-purpose editor doesn’t:

  • Consistent formatting across every snippet in the document
  • Syntax highlighting for a long list of languages, with the ability to define your own
  • Line numbering you can cross-reference like any other label
  • Preserved indentation and spacing, exactly as written
  • Typography tuned for readability rather than guesswork

The listings Package

Basic Setup

\usepackage{listings}
\usepackage{xcolor}  % For syntax coloring

% Basic code inclusion
\begin{lstlisting}
def hello_world():
    print("Hello, LaTeX!")
    return True
\end{lstlisting}

Language-Specific Formatting

% Python code with syntax highlighting
\begin{lstlisting}[language=Python]
def fibonacci(n):
    """Calculate Fibonacci sequence"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# List comprehension example
squares = [x**2 for x in range(10)]
\end{lstlisting}

% JavaScript with highlighting
\begin{lstlisting}[language=JavaScript]
const fetchData = async (url) => {
    try {
        const response = await fetch(url);
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Error:', error);
    }
};
\end{lstlisting}

Advanced listings Configuration

Custom Style Definition

\lstdefinestyle{mystyle}{
    backgroundcolor=\color{gray!5},   
    commentstyle=\color{green!60!black},
    keywordstyle=\color{blue},
    numberstyle=\tiny\color{gray},
    stringstyle=\color{orange},
    basicstyle=\ttfamily\footnotesize,
    breakatwhitespace=false,         
    breaklines=true,                 
    captionpos=b,                    
    keepspaces=true,                 
    numbers=left,                    
    numbersep=5pt,                  
    showspaces=false,                
    showstringspaces=false,
    showtabs=false,                  
    tabsize=4,
    frame=single,
    rulecolor=\color{black!30},
    xleftmargin=10pt,
    framexleftmargin=10pt,
    framexrightmargin=5pt,
    framexbottommargin=5pt
}

\lstset{style=mystyle}

Language-Specific Styles

% C++ style
\lstdefinestyle{cpp}{
    language=C++,
    style=mystyle,
    keywordstyle=\color{blue}\bfseries,
    stringstyle=\color{red},
    commentstyle=\color{green!50!black}\itshape,
    morecomment=[l][\color{magenta}]{\#},
    morekeywords={override, final, constexpr, nullptr}
}

% Usage
\begin{lstlisting}[style=cpp]
#include <iostream>
#include <vector>

template<typename T>
class SmartContainer {
private:
    std::vector<T> data;
public:
    void add(const T& item) {
        data.push_back(item);
    }
    
    size_t size() const noexcept {
        return data.size();
    }
};
\end{lstlisting}

Including External Code Files

Direct File Inclusion

% Include entire file
\lstinputlisting[language=Python]{scripts/data_analysis.py}

% Include specific lines
\lstinputlisting[
    language=Java,
    firstline=10,
    lastline=25
]{src/Main.java}

% Include with custom caption
\lstinputlisting[
    language=C,
    caption={Memory allocation function},
    label={lst:malloc}
]{src/memory.c}

Automatic Language Detection

% Define file extensions
\lstset{
    inputencoding=utf8,
    extendedchars=true,
    literate={á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1,
    language=Python,
}

% Auto-detect from extension
\lstinputlisting[language={}]{script.py}  % Uses Python
\lstinputlisting[language={}]{style.css}  % Uses CSS

The minted Package: Modern Syntax Highlighting

Setup and Requirements

% Requires Python Pygments: pip install Pygments
% Compile with: pdflatex -shell-escape document.tex

\usepackage{minted}

% Basic usage
\begin{minted}{python}
import numpy as np
import matplotlib.pyplot as plt

def plot_function(f, x_range):
    x = np.linspace(*x_range, 1000)
    y = f(x)
    
    plt.figure(figsize=(10, 6))
    plt.plot(x, y, 'b-', linewidth=2)
    plt.grid(True, alpha=0.3)
    plt.show()
\end{minted}

Advanced minted Features

% Custom styling
\usemintedstyle{monokai}

% With line numbers and highlighting
\begin{minted}[
    linenos,
    numbersep=5pt,
    frame=lines,
    framesep=2mm,
    bgcolor=gray!5,
    fontsize=\footnotesize,
    highlightlines={3,5-7}
]{rust}
fn main() {
    let mut vec = Vec::new();
    vec.push(1);
    vec.push(2);
    
    for item in &vec {
        println!("Value: {}", item);
    }
}
\end{minted}

Professional Code Formatting Techniques

Inline Code

% Using listings
The function \lstinline{calculate_sum(a, b)} returns the sum.

% With custom style
\lstinline[style=mystyle]|vector<int> numbers;|

% Using minted
The \mintinline{python}{lambda x: x**2} function squares input.

Side-by-Side Code Comparison

\usepackage{multicol}

\begin{multicols}{2}
\begin{lstlisting}[language=Python, caption=Python Version]
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n-1)
\end{lstlisting}

\columnbreak

\begin{lstlisting}[language=C, caption=C Version]
int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n-1);
}
\end{lstlisting}
\end{multicols}

Algorithm Presentation

The algorithm2e Package

\usepackage[ruled,vlined]{algorithm2e}

\begin{algorithm}[H]
\DontPrintSemicolon
\SetAlgoLined
\KwResult{Sorted array}
\SetKwFunction{FQuickSort}{QuickSort}
\SetKwProg{Fn}{Function}{:}{}

\Fn{\FQuickSort{$A, low, high$}}{
    \If{$low < high$}{
        $pivot \gets$ \texttt{Partition}$(A, low, high)$\;
        \FQuickSort{$A, low, pivot-1$}\;
        \FQuickSort{$A, pivot+1, high$}\;
    }
}
\caption{QuickSort Algorithm}
\end{algorithm}

Pseudocode with algorithmicx

\usepackage{algorithm}
\usepackage{algpseudocode}

\begin{algorithm}
\caption{Binary Search}
\begin{algorithmic}[1]
\Procedure{BinarySearch}{$arr, target$}
    \State $left \gets 0$
    \State $right \gets \text{length}(arr) - 1$
    
    \While{$left \leq right$}
        \State $mid \gets \lfloor(left + right) / 2\rfloor$
        \If{$arr[mid] = target$}
            \State \Return $mid$
        \ElsIf{$arr[mid] < target$}
            \State $left \gets mid + 1$
        \Else
            \State $right \gets mid - 1$
        \EndIf
    \EndWhile
    
    \State \Return $-1$
\EndProcedure
\end{algorithmic}
\end{algorithm}

Code Organization and References

Listing Captions and Labels

\begin{lstlisting}[
    caption={RESTful API endpoint implementation},
    label={lst:api-endpoint}
]
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    user = User.query.get_or_404(user_id)
    return jsonify(user.to_dict())
\end{lstlisting}

% Reference in text
As shown in Listing~\ref{lst:api-endpoint}, the API endpoint...

Creating a List of Listings

% Add after \tableofcontents
\lstlistoflistings

% Custom title
\renewcommand{\lstlistlistingname}{Code Examples}

Syntax Highlighting for Custom Languages

Defining New Languages

\lstdefinelanguage{Docker}{
    keywords={FROM, RUN, CMD, LABEL, EXPOSE, ENV, WORKDIR, COPY, ADD, ENTRYPOINT, VOLUME, USER, ARG},
    keywordstyle=\color{blue}\bfseries,
    comment=[l]{\#},
    commentstyle=\color{green!50!black},
    stringstyle=\color{red},
    string=[b]",
    morestring=[b]',
    sensitive=false,
    morecomment=[l]{//},
}

\begin{lstlisting}[language=Docker]
FROM node:14-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
\end{lstlisting}

Enhancing Existing Languages

% Add keywords to Python
\lstdefinestyle{python-extended}{
    language=Python,
    morekeywords={async, await, yield, with, as},
    morekeywords=[2]{self, cls},
    keywordstyle=[2]\color{purple},
}

Performance Optimization

Managing Large Code Bases

listings is lighter to compile than minted, which shells out to Pygments for every listing. If a draft is slow, one easy win is to switch off the listings you aren’t actively reviewing with a conditional:

% Conditional inclusion
\newif\ifincludecode
\includecodetrue  % or \includecodefalse

\ifincludecode
    \lstinputlisting{large-file.cpp}
\else
    \texttt{[Code omitted for brevity]}
\fi

If you do need minted, its caching is on by default and stores compiled output under a _minted-<jobname> directory, so repeated builds only reprocess listings that changed.


Code Documentation Best Practices

Effective Code Comments

\lstset{
    morecomment=[s][\color{blue}\bfseries]{@}{@},  % Highlight special comments
}

\begin{lstlisting}[language=Java]
public class DatabaseConnection {
    @ Important: Always close connections @
    private Connection conn;
    
    // Regular comment
    public void connect(String url) {
        /* Multi-line comment
           explaining the connection process */
        conn = DriverManager.getConnection(url);
    }
}
\end{lstlisting}

Code Annotations

% Using line notes
\begin{lstlisting}[
    language=Python,
    escapechar=|
]
def process_data(data):
    cleaned = data.strip()  |\colorbox{yellow}{Step 1}|
    validated = validate(cleaned)  |\colorbox{orange}{Step 2}|
    return transform(validated)  |\colorbox{green}{Step 3}|
\end{lstlisting}

Documenting Code in the Browser

minted is the nicer of the two packages, but it needs Python, Pygments, and a -shell-escape build, which is exactly the kind of local setup people get stuck on. A browser-based editor sidesteps that. With inscrive.io you write LaTeX in the browser and compile on their servers, so a minted document just works without you installing a toolchain.

For a paper or manual full of listings, the practical wins are mundane: real-time collaboration so two people can edit the same source without merge conflicts, version history to rewind a listing that broke the build, and a shared template library so a team’s code style stays consistent. The free tier covers up to 10 projects with a 60-second compile window; Pro stretches that to 480 seconds, which helps when minted reprocesses a long file. Everything is stored in the EU (Hetzner, Germany and Finland) under a signed DPA, and your documents are never used to train AI models.

Team Code Standards

% Define team coding style
\lstdefinestyle{company-style}{
    % Company-specific formatting
    basicstyle=\ttfamily\small,
    keywordstyle=\color{companyblue},
    commentstyle=\color{companygreen},
    % ... more settings
}

% Enforce consistent usage
\lstset{style=company-style}

Advanced Features

Code Folding Representation

\begin{lstlisting}[language=JavaScript]
class UserManager {
    constructor() {
        // ... constructor code ...
    }
    
    addUser(userData) {
        // ... validation ...
        // ... database operation ...
        // ... logging ...
    }
    
    // ... more methods ...
}
\end{lstlisting}

Diff Highlighting

\lstdefinestyle{diff}{
    morecomment=[f][\color{red}]-,
    morecomment=[f][\color{green}]+,
    morecomment=[f][\color{gray}]{@@},
}

\begin{lstlisting}[style=diff]
@@ -10,7 +10,7 @@
 function calculate(x, y) {
-    return x + y;
+    return x * y;
 }
\end{lstlisting}

Troubleshooting Common Issues

Character Encoding

% Fix UTF-8 issues
\lstset{
    inputencoding=utf8,
    extendedchars=true,
    literate=
        {á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1
        {ó}{{\'o}}1 {ú}{{\'u}}1 {ñ}{{\~n}}1
}

Long Lines

% Handle long lines
\lstset{
    breaklines=true,
    breakatwhitespace=true,
    prebreak=\mbox{\textcolor{red}{$\searrow$}},
    postbreak=\mbox{\textcolor{red}{$\hookrightarrow$}\space},
}

Integration with Development Workflows

Automated Documentation

#!/bin/bash
# Extract code examples for LaTeX

find ./src -name "*.py" -exec echo "lstinputlisting[language=Python]{{}}" ; > code-listings.tex

CI/CD Integration

# .github/workflows/docs.yml
- name: Generate Code Documentation
  run: |
    python scripts/extract_examples.py
    pdflatex -shell-escape main.tex

Accessibility Considerations

Screen Reader Friendly

% Provide alternative text
\begin{lstlisting}[
    caption={[Function to calculate factorial]Recursive factorial implementation},
    label={lst:factorial}
]
def factorial(n):
    return 1 if n <= 1 else n * factorial(n-1)
\end{lstlisting}

Wrapping Up

Pick listings when you want a fast, dependency-free build and don’t mind defining the odd language yourself. Pick minted when you want Pygments-grade highlighting and can run a -shell-escape build. Either way, the habits that matter are the same: caption and label your listings so you can reference them, keep one style across the document, and break long lines sensibly.

If a local TeX setup is the part standing in your way, inscrive.io compiles listings and minted documents in the browser, free to start, with EU-hosted storage and no install.

Further reading

Sign up for our newsletter

Roadmap progress, announcements and exclusive discounts — straight to your inbox.

We care about the protection of your data. Read our privacy policy.