Listing for file folder-structure as text not working

For my documentation, I need to provide a way on how to structure some Python code in a project. My approach to show it was to simply use a structure of text like this:

app/
├─ ...
├─ controllers/
│  ├─ ...
├─ services/
│  ├─ __init__.py
│  ├─ issuesService.py
│  ├─ projectsService.py
│  ├─ sprintsServices.py
│  ├─ ...
│  ├─ providerService.py
├─ providers/
│  ├─ ...
├─ ...


As I am also show off some Python code in the documentation, I make use of the lstlisting like this:

\begin{lstlisting}[language=Python, caption=A fancy caption]
some code here
\end{lstlisting}


This works completely fine, although it works not for the txt input from above...

The configuration styles for my lstlistings look like this:

%JetBrains Mono-Font für Code
\setmonofont{JetBrains Mono}[
Path = ./Fonts/Code/,
Extension = .ttf,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Italic,
BoldItalicFont = *-BoldItalic,
Contextuals = Alternate,
]
\lstset{
basicstyle = \ttfamily,
columns = flexible,
aboveskip=\baselineskip,
belowskip=\baselineskip
}
\makeatletter
\renewcommand*\verbatim@nolig@list{}
\makeatother

\definecolor{codegreen}{HTML}{067D17}
\definecolor{codegray}{HTML}{969696}
\definecolor{codepurple}{HTML}{871094}
\definecolor{codeblue}{HTML}{0086B3}
\definecolor{codeblack}{HTML}{333333}

\definecolor{background}{HTML}{F5F5F5}

\lstdefinestyle{codestyle}{
backgroundcolor=\color{background},
keywordstyle=\color{codeblue},
identifierstyle=\color{codeblack},
stringstyle=\color{codegreen},
numberstyle=\small\color{codegray},
basicstyle=\ttfamily\small,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
frame=single,
tabsize=2
}

\lstset{style=codestyle}

\definecolor{delim}{RGB}{20,105,176}
\definecolor{numb}{RGB}{106, 109, 32}
\definecolor{string}{rgb}{0.64,0.08,0.08}

\lstdefinelanguage{JSON}{
rulecolor=\color{black},
postbreak=\raisebox{0ex}[0ex][0ex]{\ensuremath{\color{gray}\hookrightarrow\space}},
upquote=true,
morestring=[b]",
stringstyle=\color{string},
literate=
*{0}{{{\color{numb}0}}}{1}
{1}{{{\color{numb}1}}}{1}
{2}{{{\color{numb}2}}}{1}
{3}{{{\color{numb}3}}}{1}
{4}{{{\color{numb}4}}}{1}
{5}{{{\color{numb}5}}}{1}
{6}{{{\color{numb}6}}}{1}
{7}{{{\color{numb}7}}}{1}
{8}{{{\color{numb}8}}}{1}
{9}{{{\color{numb}9}}}{1}
{\{}{{{\color{delim}{\{}}}}{1}
{\}}{{{\color{delim}{\}}}}}{1}
{[}{{{\color{delim}{[}}}}{1}
{]}{{{\color{delim}{]}}}}{1},
}


It doesn't work either for any other language... I assume an issue with ├─ and | in the listing. Does anyone know where the issue lies or can recommend another package for this?

• You could try something like tex.stackexchange.com/questions/598393/… Jan 14 at 13:44
• Also related tex.stackexchange.com/questions/129377/… Jan 14 at 13:48
• Similar to the 1st: tex.stackexchange.com/questions/362093/… Jan 14 at 13:51
• @Marijn I think the problem is not just the white space between the lines but the way the unicode characters ├─ and | are treated. Jan 14 at 14:50
• @gernot I think they are related because the unicode characters increase the line height but the background color is not sufficiently adjusted, which is also illustrated in the related questions for math or for fboxes or large font line numbers (not all of them linked in my comments above). But I'm not 100% sure that is the (only) problem here, I'll try it out to see. Jan 14 at 15:44

This answer consists of two parts. First: for listings to properly recognize and position characters like ├ and │ in XeLaTeX or LuaLaTeX with Fontspec you need to add the Unicode character codes to the list of letters using by listings, following https://tex.stackexchange.com/a/25396/. The characters ├ and ─ and │ have the code 251c, 2500, 2502 respectively (see https://www.compart.com/en/unicode/block/U+2500). You also need extendedchars=true in the listings options.

MWE:

\documentclass{article}
\usepackage{xcolor}
\usepackage{fontspec}
\usepackage{listings}
\setmonofont{Go Mono}

\definecolor{background}{HTML}{F5F5F5}

\makeatletter
\lst@InputCatcodes
\def\lst@DefEC{%
\lst@CCECUse \lst@ProcessLetter
^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f%
^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f%
^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf%
^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf%
^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df%
^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef%
^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff%
^^^^251c^^^^2500^^^^2502% box drawing characters
^^00}
\lst@RestoreCatcodes
\makeatother

\lstdefinestyle{codestyle}{
backgroundcolor=\color{background},
basicstyle=\ttfamily\small,
captionpos=b,
numbers=left,
numbersep=5pt,
columns=flexible,
keepspaces,
frame=single,
tabsize=2,
extendedchars=true,
}

\lstset{style=codestyle}

\begin{document}
\begin{lstlisting}[caption=A fancy caption]
app/
├─ ...
├─ controllers/
│  ├─ ...
├─ services/
│  ├─ __init__.py
│  ├─ issuesService.py
│  ├─ projectsService.py
│  ├─ sprintsServices.py
│  ├─ ...
│  ├─ providerService.py
├─ providers/
│  ├─ ...
├─ ...
\end{lstlisting}
\end{document}


Result:

The second part of the answer is about the vertical gaps between the lines.

This issue is caused by the extra line height introduced by the box draw characters. This extra line height is not taken into account properly by the listings background drawing.

A solution for this which also has a continuous appearance for the box drawing characters is to use the pmboxdraw package and specify a replacement command in \lstset{} for each of the characters using the literate option, as in How to use extended ASCII characters in the lstlisting environment?. The pmboxdraw commands are not counted for the height of the line so the lines can be drawn with the same height as the background.

Code:

% ... add unicode character handling code as above ...
\usepackage{pmboxdraw}
% ... other lstset definitions as above ...
\lstset{literate=
{┐}{\textSFiii}1%
{└}{\textSFii}1%
{┴}{\textSFvii}1%
{┬}{\textSFvi}1%
{├}{\textSFviii}1%
{─}{\textSFx}1%
{┼}{\textSFv}1%
{│}{\textSFxi}1%
}
\begin{lstlisting}[caption=A fancy caption]
app/
├─ ...
├─ controllers/
% ...


Result:

If you look closely you can still see a very small gap (dependent on the viewer and zoom level). To completely solve this issue you can draw the frame and background with mdframed instead, as in Adding a Caption to \lstnewenvironment using \mdframed. In that case the full frame is colored instead of single lines. You can use this approach with or without pmboxdraw.

MWE:

\documentclass{article}
\usepackage{xcolor}
\usepackage{fontspec}
\usepackage{listings}
\usepackage{mdframed}
\usepackage{caption}
\setmonofont{Go Mono}

\definecolor{background}{HTML}{F5F5F5}

\makeatletter
\lst@InputCatcodes
\def\lst@DefEC{%
\lst@CCECUse \lst@ProcessLetter
^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f%
^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f%
^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf%
^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf%
^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df%
^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef%
^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff%
^^^^251c^^^^2500^^^^2502% box drawing characters
^^00}
\lst@RestoreCatcodes
\makeatother

\lstdefinestyle{codestyle}{
backgroundcolor=\color{background},
basicstyle=\ttfamily\small,
captionpos=b,
numbers=left,
numbersep=5pt,
columns=flexible,
keepspaces,
frame=single,
tabsize=2,
extendedchars=true,
}

\lstset{style=codestyle}

\lstnewenvironment{mylisting}[1]{%
\lstset{
backgroundcolor=,
frame=none,
}%
\mdframed[backgroundcolor=background,innerleftmargin=2pt,innertopmargin=-0.3Em, innerbottommargin=-0.3Em]%
}{%
\endmdframed%
\captionsetup[lstlisting]{skip=-8pt}%
\captionof{lstlisting}{#1}
\ignorespaces
}
\begin{document}

\begin{mylisting}{A fancy caption}
app/
├─ ...
├─ controllers/
│  ├─ ...
├─ services/
│  ├─ __init__.py
│  ├─ issuesService.py
│  ├─ projectsService.py
│  ├─ sprintsServices.py
│  ├─ ...
│  ├─ providerService.py
├─ providers/
│  ├─ ...
├─ ...
\end{mylisting}
\end{document}


Result:

• wow - thanks a lot for your effort! it works fine now :)
– Remo
Jan 14 at 20:15