7

As shown in this thread and this thread it is possible to conditionally create lists of figures and tables only if these items are used in a document.

I would like to extends this to listings. Everything works fine as long as you use the lstlisting environment at least once in the document. Normally, I include code with \lstinputlisting. Therefore, the lstlisting environment is not used. Thus, the \AtEndEnvironmetis never called and the command \conditionalLoL is never set to true.

Is there a way modify the definition of \conditionalLoL to include \lstinputlisting ?


Code so far:

\documentclass[listof=totoc]{scrreprt}

\usepackage[latin1]{inputenx}
\usepackage[T1]{fontenc}
\usepackage[ngerman,english]{babel}
\usepackage{etoolbox}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{tabularx}

% https://tex.stackexchange.com/questions/33193/how-to-determine-whether-a-list-of-figures-is-empty-then-not-show-it-at-all
\makeatletter
  % Figure
  \AtEndEnvironment{figure}{\gdef\there@is@a@figure{}}%
  \AtEndDocument{\ifdefined\there@is@a@figure\label{fig:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoF}{\@ifundefined{r@fig:was:used:in:doc}{}{\listoffigures}}%
  % Table
  \AtEndEnvironment{table}{\gdef\there@is@a@table{}}%
  \AtEndDocument{\ifdefined\there@is@a@table\label{tab:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoT}{\@ifundefined{r@tab:was:used:in:doc}{}{\listoftables}}%
  % Listing
  \AtEndEnvironment{lstlisting}{\gdef\there@is@a@listing{}}%
  \AtEndDocument{\ifdefined\there@is@a@listing\label{lst:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoL}{\@ifundefined{r@lst:was:used:in:doc}{}{\lstlistoflistings}}%
  % 
\makeatother

\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{document}

\clearpage
\tableofcontents

\conditionalLoF
\let\LaTeXStandardClearpage\clearpage
\let\clearpage\relax
\conditionalLoT
\conditionalLoL
\let\clearpage\LaTeXStandardClearpage % Return to the old definition

\vspace{1cm}

A figure:

\begin{figure}[htbp]
\centering
\includegraphics[width=0.25\linewidth]{example-image-a}
\caption{A picture}
\label{fig:label}
\end{figure}

A table:

\begin{table}[htbp]
\centering
\caption{A table}
\label{tab:label}
\begin{tabularx}{\linewidth}{lX}
test & test test test test test test test test test test test test test test test test test test test test
\end{tabularx}
\end{table}

A listing environment:

% \begin{lstlisting}[label=lst:label1,caption=A listing]
% command
% command
% \end{lstlisting}

A lstinputlisting:

\lstinputlisting[label=lst:label2,caption=Another listing]{command.txt}

\end{document}

Result with lstlisting environment:

with lstlisting


Result only with listinputlisting:

enter image description here

Update

Using @Axel Sommerfeldt's answer I still got an empty list of tables for my original document. I found out that this is caused by a longtabu environment in my documentclass. Following is the MWE with longtabu causing an empty list of tables:

\documentclass[listof=totoc]{scrreprt}

\usepackage[latin1]{inputenx}
\usepackage[T1]{fontenc}
\usepackage[ngerman,english]{babel}
\usepackage{etoolbox}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{longtable}
\usepackage{tabu}
\usepackage{tabularx}
\usepackage[figure,table,lstlisting]{totalcount}

\newcommand\conditionalLoF{%
  \iftotalfigures\listoffigures\fi}
\newcommand\conditionalLoT{%
  \iftotaltables\listoftables\fi}
\newcommand\conditionalLoL{%
  \iftotallstlistings\lstlistoflistings\fi}

\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{document}

\clearpage
\tableofcontents

\conditionalLoF
\let\LaTeXStandardClearpage\clearpage
\let\clearpage\relax
\conditionalLoT
\conditionalLoL
\let\clearpage\LaTeXStandardClearpage % Return to the old definition

\vspace{1cm}

\newpage

\chapter{Tests}

\section{Figures}

A figure:

\begin{figure}[htbp]
\centering
\includegraphics[width=0.25\linewidth]{example-image-a}
\caption{A picture}
\label{fig:label}
\end{figure}

A non-floating picture:

\includegraphics[width=0.25\linewidth]{example-image-a}

\section{Tables}

% A table:
% 
% \begin{table}[htbp]
% \centering
% \caption{A table}
% \label{tab:label}
% \begin{tabularx}{\linewidth}{lX}
% test & test test test test test test test test test test test test test test test test test test test test
% \end{tabularx}
% \end{table}
% 
% A non-floating table:
% 
% \begin{tabularx}{\linewidth}{lX}
% test & test test test test test test test test test test test test test test test test test test test test
% \end{tabularx}

A non-floating longtabu

\begin{longtabu} to \textwidth {lX}
test & test test test test test test test test test test test test test test test test test test test test
\end{longtabu}

\section{Listings}

A listing environment:

\begin{lstlisting}[label=lst:label1,caption=A listing environment]
command
command
\end{lstlisting}

A lstinputlisting:

\lstinputlisting[label=lst:label2,caption=A lstinputlisting]{command.txt}

\end{document}

I had a quick look at the tabu package documentation. But I am not sure why the counter for tables is added to for an non-floating longtabu in the totalcount package.

Any ideas?

raedma
  • 1,794

3 Answers3

6

A solution using the totalcount package:

\usepackage[figure,table,lstlisting]{totalcount}

\newcommand\conditionalLoF{%
  \iftotalfigures\listoffigures\fi}
\newcommand\conditionalLoT{%
  \iftotaltables\listoftables\fi}
\newcommand\conditionalLoL{%
  \iftotallstlistings\lstlistoflistings\fi}

The complete example document:

\documentclass[listof=totoc]{scrreprt}

\usepackage[latin1]{inputenx}
\usepackage[T1]{fontenc}
\usepackage[ngerman,english]{babel}
\usepackage{etoolbox}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{tabularx}
\usepackage[figure,table,lstlisting]{totalcount}

\newcommand\conditionalLoF{%
  \iftotalfigures\listoffigures\fi}
\newcommand\conditionalLoT{%
  \iftotaltables\listoftables\fi}
\newcommand\conditionalLoL{%
  \iftotallstlistings\lstlistoflistings\fi}

\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{document}

\clearpage
\tableofcontents

\conditionalLoF
\let\LaTeXStandardClearpage\clearpage
\let\clearpage\relax
\conditionalLoT
\conditionalLoL
\let\clearpage\LaTeXStandardClearpage % Return to the old definition

\vspace{1cm}

A figure:

\begin{figure}[htbp]
\centering
\includegraphics[width=0.25\linewidth]{example-image-a}
\caption{A picture}
\label{fig:label}
\end{figure}

A table:

\begin{table}[htbp]
\centering
\caption{A table}
\label{tab:label}
\begin{tabularx}{\linewidth}{lX}
test & test test test test test test test test test test test test test test test test test test test test
\end{tabularx}
\end{table}

A listing environment:

% \begin{lstlisting}[label=lst:label1,caption=A listing]
% command
% command
% \end{lstlisting}

A lstinputlisting:

\lstinputlisting[label=lst:label2,caption=Another listing]{command.txt}

\end{document}

Opposite to the solutions given by the other answers this solution is actually based on the counter usage (instead of the environment usage). So for example this solution works when using \captionof, too, where the other ones fail:

\documentclass[listof=totoc]{scrreprt}

\usepackage{graphicx}

\usepackage{caption}
\usepackage[figure,table]{totalcount}

\newcommand\conditionalLoF{%
  \iftotalfigures\listoffigures\fi}

\begin{document}

\tableofcontents

\conditionalLoF

\vspace{1cm}

A figure:

\begin{minipage}{\textwidth}
\centering
\includegraphics[width=0.25\linewidth]{example-image-a}
\captionof{figure}{A picture}
\label{fig:label}
\end{minipage}

\end{document}

Some additional notes:

The main problem with your question is that there is no perfect solution.

If you add flags to the environments (like the solution from Werner does) you will miss entries to the list of figures/tables. You add a flag to table, longtable, and longtabu, you will miss threeparttable and wraptable and many others. If you add flags to them, too, you will miss \captionof{table} which is totally independent of the environment used. (And you will miss other entries as well.) And a table without \caption will lead to a wrong outcome, too.

If you use the counter approach (like my solution using totalcount) you have problems with code which increments the counter but does not place an entry within the List of Tables, e.g. longtable or longtabu without \caption. You can correct this by decrementing the counter after usage of these environments. But what about a table with \caption[]{...}? This does add a caption, does increment the table counter, but does not produce an entry in the List of Tables either.

A third approach would be patching \caption. But not every environment incrementing the figure or table counter does use \caption, e.g. the hvfigure environment offered by the hvfloat package. And what \caption to patch? There are many different \caption commands, for example a total different code will be used for table and longtable. My caption package tries to patch many flavors of \caption (the one of the LaTeX kernel and of 17 additional packages), but not all of them. So if I would offer a solution within my caption package it would not work with all environments, e.g. environments defined by the algorithm2e package since the caption package is not adapted to this package. (And I don't know longtabu, must take a closer look on the next week-end. And I will offer an alternate solution using my caption package on the next week-end, too.)

So unfortunately you have to choose a solution which fits your needs best. There is no perfect one since any package/environment/command is free to increment the counters, and free to add something to the List of Figures/Tables using its very own code.

Addendum 2016-03-13 As promised a different solution which patches \addcontentsline to handle conditional lists:

\documentclass{article}

\usepackage{caption}
\usepackage{listings,longtable,tabu}

\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{filecontents*}{iflistof.sty}
\NeedsTeXFormat{LaTeX2e}[1994/12/01]
\ProvidesPackage{iflistof}[2016/03/12 v0.1 Offers conditional "List of" (AS)]
\providecommand*\iflistof[1]{%
  \@ifundefined{iflistof@#1}\@secondoftwo\@firstoftwo}
\let\ORI@addcontentsline\addcontentsline
\renewcommand*\addcontentsline[2]{%
  \caption@iflistof{iflistof@#2}%
  \ORI@addcontentsline{#1}{#2}}
\newcommand*\caption@iflistof[1]{%
% \@nameuse{#1}{%
    \global\@namedef{#1}{\@secondoftwo}%
    \if@filesw
      \immediate\write\@mainaux{%
        \string\global\string\@namedef{#1}{\string\@firstoftwo}}%
    \fi}%{}}
\endinput
\end{filecontents*}

\usepackage{iflistof}

\begin{document}
\iflistof{figure}{\listoffigures}{}
\iflistof{table}{\listoftables}{}
\iflistof{lstlisting}{\lstlistoflistings}{}
\clearpage

%\begin{table}
%  \caption{A table}
%\end{table}

\begin{longtable}{ll}
\caption{A longtable}\\
\end{longtable}

\begin{longtabu}{ll}
\caption{A longtable}\\
\end{longtabu}

% \begin{lstlisting}[label=lst:label1,caption=A listing]
% command
% command
% \end{lstlisting}

\lstinputlisting[label=lst:label2,caption=Another listing]{command.txt}

\end{document}

This seems to be the best approach, but before praising it please play around with it a little bit and report. If it proves well I could add the iflistof package to my "caption package bundle".

See also: https://sourceforge.net/p/latex-caption/tickets/37/

  • Thanks. That works great for the MWE and adds flexibility. Unfortunately an empty list of tables is shown in case a non-floating longtabu is used. Please see my updated question. – raedma Mar 07 '16 at 12:08
  • longtabu (like longtable) always increases the table counter. If you don't have a caption you could use \addtocounter{table}{-1} afterwards to decrease the counter, and this way no LoT will be typeset since the totalcount package is only looking at the counter when being reset (e.g. by \chapter') and at the end of the document. And if you typeset alongtabuand decrease the counter afterwards, it will be 0 at the end of the document (as long as you don't have other tables), and therefore\iftotaltables` will be false. –  Mar 07 '16 at 16:31
  • Thanks for that information. Since I would like to start clean after the preamble, is there something like \setcounter{table}{0} that I can call before \begin{document} ? – raedma Mar 07 '16 at 16:36
  • Yes, exactly that works. Could you tell me why longtable and longtable increase the table counter? – raedma Mar 07 '16 at 16:42
  • I added some additional notes at the end of my solution (since this would be too long for getting a comment). –  Mar 07 '16 at 16:58
  • Regarding longtable: Usually \caption increments the counter. But a longtable can have many captions, for example one for every page typesetting a table spanning two pages results in two captions. But both captions must have the same counter value (since it's the same table), so the author of the longtable designed it this way: Every longtable increments the table counter at \begin{longtable}{...} (and not at \caption). This is confusing to users of LaTeX since there is no standard behavior anymore,table behaves different than longtable here. (Same problem with longtabu.) –  Mar 07 '16 at 17:04
  • I just added a third approach to my answer which patches \addcontentsline to reach its goal. –  Mar 13 '16 at 17:53
3

Try (well, my ;-)) package xassoccnt, which provides some of the totcount features and associated counters that are not reset if the figure etc. counter is set to zero, i.e. they are increased continously (unless manipulated directly) -- in conjunction with the Total counter feature the values are stored to the .aux file and are available in the second run.

A slight redefinition of \listof.... checks for the counter value to be greater than zero and loads the relevant original \listof... command. If the counter is zero, then nothing is included.

\documentclass{scrartcl}

\usepackage[latin1]{inputenx}
\usepackage[T1]{fontenc}
\usepackage[ngerman,english]{babel}
\usepackage{etoolbox}
\usepackage{xassoccnt}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{tabularx}

\NewTotalDocumentCounter{totalfigures}
\NewTotalDocumentCounter{totaltables}
\NewTotalDocumentCounter{totallistings}

\DeclareAssociatedCounters{lstlisting}{totallistings}
\DeclareAssociatedCounters{figure}{totalfigures}
\DeclareAssociatedCounters{table}{totaltables}

\makeatletter
\renewcommand{\TotalValue}[1]{%
  \value{xassoccnt@total@#1}%
}


\let\@@latex@@listoffigures\listoffigures
\let\@@latex@@listoftables\listoftables
\let\@@latex@@lstlistoflistings\lstlistoflistings

\renewcommand{\listoffigures}{%
  \ifnum\TotalValue{totalfigures} > 0 
  \@@latex@@listoffigures%
  \fi
}


\renewcommand{\listoftables}{%
  \ifnum\TotalValue{totaltables} > 0 
  \@@latex@@listoftables%
  \fi
}


\renewcommand{\lstlistoflistings}{%
  \ifnum\TotalValue{totallistings} > 0 
  \@@latex@@lstlistoflistings%
  \fi
}

\makeatother





\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{document}
\tableofcontents

\clearpage

\lstlistoflistings

\listoftables

\listoffigures


A figure:

\begin{figure}[htbp]
\centering
\includegraphics[width=0.25\linewidth]{example-image-a}
%\caption{A picture}
\label{fig:label}
\end{figure}

A table:

\begin{table}[htbp]
\centering
\caption{A table}
\label{tab:label}
\begin{tabularx}{\linewidth}{lX}
test & test test test test test test test test test test test test test test test test test test test test
\end{tabularx}
\end{table}

A listing environment:

\begin{lstlisting}[label=lst:label1,caption=A listing]
  command
  command
\end{lstlisting}

A lstinputlisting:

\lstinputlisting[label=lst:label2,caption=Another listing]{command.txt}

\end{document}
  • Thanks, but if I use your approach I get a list of tables in my original document even if no table environment is used throughout the document. – raedma Mar 06 '16 at 16:45
  • @krtek: Have you compiled twice? I don't get a list of table if there's no table (or just comment out the \caption of your table –  Mar 06 '16 at 16:49
  • of course. I compile three times by default with PDFLaTeX. Could this be an issue with the calc package? Despite I did not call the package explicitely, I initially received an error by xassoccnt. I modified my preamble according to xassoccnt documentation and not even get a warning right now. – raedma Mar 06 '16 at 16:50
  • Load calc before xassoccnt! calc does 'weird' setups! It's stated clearly in the xassoccnt documentation that calc must be loaded before. Either you have some strange setup, but your 'minimal' document runs without problems for me –  Mar 06 '16 at 16:55
  • I do. I had a look at the lot-file of my document. It is not empty. The thing is, I do use tabularx-tables but not inside a table environment and without label or caption. I got the following lines in my lot-file: \select@language {english} two times and afterwards seven times \addvspace {10\p@ } – raedma Mar 06 '16 at 16:57
  • @krtek: Remove all .lot etc. and .aux files, make a clean double run. My setup does not check whether .lot etc. is empty, just if the total... counter values are greater than zero. –  Mar 06 '16 at 16:58
  • I did, same result. – raedma Mar 06 '16 at 17:01
  • @krtek: Well, you seem to have a strange setup -- I can't help here then. I know that my setup work, for a minimal document, but I can't help on non-available code –  Mar 06 '16 at 17:04
  • @krtek: I switched to scrreprt and cannot reproduce your issue -- sorry, the issue must have another source –  Mar 06 '16 at 17:30
  • I think I found the problem. My original document builds up on scrreprt with the listof=totoc option. If I use scrreprt as documentclass with this option in my MWE the same problem occurs. It does not with scrartcl. New first line: \documentclass[listof=totoc]{scrreprt} – raedma Mar 06 '16 at 17:39
  • @krtek: Well, if you would have given this information before a lot of comments would have been unnecessary. There's not much I can do here. I don't provide support for weird settings in KOMA classes –  Mar 06 '16 at 17:43
1

It should be obvious that the code relies on the existence of a figure, table and lstlisting environment. However, \lstinputlisting doesn't use an lstlisting environment (internally), and therefore it doesn't function as expected.

The code below changes \lstinputlisting by prepending to it the conditional component for detecting the existence of a listing:

\makeatletter
\let\oldlstinputlisting\lstinputlisting
\renewcommand{\lstinputlisting}{\gdef\there@is@a@listing{}\oldlstinputlisting}
\makeatother

Here is a complete minimal example:

enter image description here

\documentclass{scrartcl}

\usepackage{etoolbox,listings}

% http://tex.stackexchange.com/questions/33193/how-to-determine-whether-a-list-of-figures-is-empty-then-not-show-it-at-all
\makeatletter
  % Figure
  \AtEndEnvironment{figure}{\gdef\there@is@a@figure{}}%
  \AtEndDocument{\ifdefined\there@is@a@figure\label{fig:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoF}{\@ifundefined{r@fig:was:used:in:doc}{}{\listoffigures}}%
  % Table
  \AtEndEnvironment{table}{\gdef\there@is@a@table{}}%
  \AtEndDocument{\ifdefined\there@is@a@table\label{tab:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoT}{\@ifundefined{r@tab:was:used:in:doc}{}{\listoftables}}%
  % Listing
  \AtEndEnvironment{lstlisting}{\gdef\there@is@a@listing{}}%
  \let\oldlstinputlisting\lstinputlisting
  \renewcommand{\lstinputlisting}{\gdef\there@is@a@listing{}\oldlstinputlisting}
  \AtEndDocument{\ifdefined\there@is@a@listing\label{lst:was:used:in:doc}\fi}%
  \newcommand{\conditionalLoL}{\@ifundefined{r@lst:was:used:in:doc}{}{\lstlistoflistings}}%
  % 
\makeatother

\begin{filecontents*}{command.txt}
Line 1
Line 2
\end{filecontents*}

\begin{document}

\clearpage
\tableofcontents

\conditionalLoF
\let\LaTeXStandardClearpage\clearpage
\let\clearpage\relax
\conditionalLoT
\conditionalLoL
\let\clearpage\LaTeXStandardClearpage % Return to the old definition

\vspace{1cm}

A figure:

\begin{figure}[htbp]
  \centering
  \caption{A picture}
\end{figure}

A table:

\begin{table}[htbp]
  \centering
  \caption{A table}
\end{table}

A listing environment:

% \begin{lstlisting}[label=lst:label1,caption=A listing]
% command
% command
% \end{lstlisting}

A lstinputlisting:

\lstinputlisting[label=lst:label2,caption=Another listing]{command.txt}

\end{document}
Werner
  • 603,163