# How to extend the \lstinputlisting command

With the answer from autogobble for lstinputlistings I've managed to create a command that gobbles \lstinputlisting and makes firstnumber to start by firstline. I would like to rewrite it as a package, so it hooks into \lstinputlisting, but as the code might reflect I have very little experience with programming in LaTeX.

My goal is to be able to write

\lstset{tabsize=3,numbers=left,frame=single,basicstyle=\footnotesize\ttfamilily,}
\lstinputlisting[levels=1,linerange={2-4},...]{hello.c}


where the dots are possible extra regular listings options.

or what could be even more nice:

\lstset{tabsize=3,numbers=left,frame=single,basicstyle=\footnotesize\ttfamilily,}
\lstinputlisting[autogobble,linerange={2-4},...]{hello.c}


where LaTeX automatically counted the number of tabs like in How to automatically skip leading white spaces in listings

MWE

\documentclass{article}
\usepackage{listings,xifthen}

\lstset{tabsize=3,numbers=left,frame=single,basicstyle=\Huge\ttfamily,columns=flexible}
\newlength{\gobble}
\newlength{\gobblea}
% The width of a single space. basicstyle from lstset should be used
\sbox0{\Huge\ttfamily \ }
\newcommand{\mylist}[5]{
%#1 is number of tabs, could be calculated like in listings-autogobble with autogobble=true or be an extra option
%#2 is tabsize, which is set in lstset
%#3 is firstline from lstset
%#4 is lastline from lstset
%#5 is the filename, the only thing which should be an argument and not an option.

% Remove a single space
\setlength{\gobble}{-\the\wd0}
% Reindent a bit by multiplying with 0.9, then multiply by tabsize and number of indentation levels
\setlength{\gobble}{0.9\gobble*#1*#2}
\setlength{\gobblea}{\gobble}
% Check if firstline is defined
\ifthenelse{\isempty{#3} \OR \equal{#3}{0}}{%
% Check if lastline is defined
\ifthenelse{\isempty{#4}}{%
\lstinputlisting[firstnumber=1,firstline=1,framexleftmargin=\gobble,xleftmargin=\gobble,numbersep=\gobblea]{#5}
}{
\lstinputlisting[firstnumber=1,firstline=1,lastline=#4,framexleftmargin=\gobble,xleftmargin=\gobble,numbersep=\gobblea]{#5}
}
}{
\ifthenelse{\isempty{#4}}{%
\lstinputlisting[firstnumber=#3,firstline=#3,framexleftmargin=\gobble,xleftmargin=\gobble,numbersep=\gobblea]{#5}
}{
\lstinputlisting[firstnumber=#3,firstline=#3,lastline=#4,framexleftmargin=\gobble,xleftmargin=\gobble,numbersep=\gobblea]{#5}
}
}
}
\begin{document}
%mylist{#tabs}{#tabsize}{firstline}{lastline}{filename}
\mylist{1}{3}{2}{4}{hello1.c}
\end{document}


edit:

I just modified the code from cyberSingularity a bit to use lst@basicstyle and lst@tabsize.

It should work with any:

• font size in document class
• font size in basicstyle
• tabsize

• It needs columns=flexible and basicstyle=\ttfamily.
• If tabsize or basicstyle is passed as options to \lstinputlisting, they must be written before widthgobble.
• If using XeLaTeX, the commands must be loaded before Polyglossia, othwerwise all text will be formatted with \ttfamily
• \documentclass[10pt]{article} \usepackage{listings}

\usepackage{filecontents}
\begin{filecontents*}{hello1.c}
if (a<b){
if (b<a){
printf("hello")
}
}
\end{filecontents*}

\lstset{tabsize=3,numbers=left,frame=single,basicstyle=\Huge\ttfamily,columns=flexible}

\makeatletter
\newlength{\singlespace}
\newlength{\gobble}
\newlength{\numbersep}
% The width of a single space.
\settowidth{\singlespace}{\lst@basicstyle \ }
\setlength{\singlespace}{-\singlespace}

\lst@Key{firstlineandnumber}\relax{\def\lst@firstline{#1\relax}\def\lst@firstnumber{#1\relax}}
\lst@Key{widthgobble}{0}{%
\setlength{\gobble}{0.9\singlespace}% reindent a bit
\setlength{\gobble}{\lst@tabsize\gobble}% multiply by tabsize
\setlength{\gobble}{#1\gobble}% multiply by number of tabs
\def\lst@xleftmargin{\gobble}% move left margin left
\def\lst@framexleftmargin{\gobble}% move left frameborder left
\setlength{\numbersep}{\gobble}%
\def\lst@numbersep{\numbersep}% distance between numbers and left frameborder
}
\makeatother

\begin{document}
%widthgobble=#tabs,firstlineandnumber sets firstline and firstnumber
\lstinputlisting[widthgobble=1,firstlineandnumber=2,lastline=4]{hello1.c}
\end{document}

-
...and the question exactly is? Or is this basically an answer to your question tex.stackexchange.com/questions/43686/… ? In the latter case, please post it there as an answer (self-ansering is perfectly acceptable!). Otherwise you might want to edit your question into a real question. –  Daniel Mar 22 '12 at 9:21
The previous question was how to do it. This is a request for a rewrite of the command to hook into listings, so I can parse extra options to the regular \lstinputlisting{} instead of my own mylist which is very limited in functionality since it can't take regular listing options. –  Jonas Nyrup Mar 22 '12 at 9:36
Thats find. You might, however, want to link to your previous question (to make the context clear), make your goal more explicit in the question title (e.g., "How to extend the \lstinputlisting command") and also in the question body. This just increases the chance to get answers :-) –  Daniel Mar 22 '12 at 10:16
@MartinScharrer: IIRC you are currently preparing your listings extension for submission to CTAN. Maybe you have already implemented autogobble for \lstinputlisting as well? –  Daniel Mar 22 '12 at 10:18

Are you after something like this? I have provided new keys:

• widthgobble, which takes as an argument #tabs*#tabsize
• firstlineandnumber, which sets both firstline and firstnumber

Note that I had some trouble using the * syntax for setting the length of \gobble so have implemented an ugly workaround (which currently means that the argument to widthgobble should always have two numbers separated by an asterisk):

\documentclass{article}
\usepackage{listings}

\usepackage{filecontents}
\begin{filecontents*}{hello1.c}
if (a<b){
if (b<a){
//do something
}
}
\end{filecontents*}

\errorcontextlines=\maxdimen

\lstset{tabsize=3,numbers=left,frame=single,basicstyle=\Huge\ttfamily,columns=flexible}
\newlength{\rawgobble}
\newlength{\gobble}
\newlength{\gobblea}
% The width of a single space. basicstyle from lstset should be used
\sbox0{\Huge\ttfamily \ }
% Remove a single space
\settowidth{\rawgobble}{\Huge\ttfamily \ }
\setlength{\rawgobble}{-\rawgobble}

\makeatletter
\def\sepstar#1*#2\relax{%
\def\sepstarone{#1}%
\def\sepstartwo{#2}%
}
\lst@Key{firstlineandnumber}\relax{\def\lst@firstline{#1\relax}\def\lst@firstnumber{#1\relax}}
\lst@Key{widthgobble}{0*0}{%
% Reindent a bit by multiplying with 0.9, then multiply by tabsize and number of indentation levels
\sepstar #1\relax
\setlength{\gobble}{0.9\rawgobble}%
\setlength{\gobble}{\sepstarone\gobble}%
\setlength{\gobble}{\sepstartwo\gobble}%
\setlength{\gobblea}{\gobble}%
\def\lst@xleftmargin{\gobble}%
\def\lst@framexleftmargin{\gobble}%
\def\lst@numbersep{\gobblea}%
}
\makeatother

\begin{document}
%widthgobble=#tabs*#tabsize,firstlineandnumber sets firstline and firstnumber
\lstinputlisting[widthgobble=1*3,firstlineandnumber=2,lastline=4]{hello1.c}
\end{document}

-
Thanks a lot cyberSingularity! That was very close to what I sought, but indeed a lot cleaner than my first attempt. I have edited my question to reflect the last changes needed. –  Jonas Nyrup Jan 6 '13 at 11:11
@JonasNyrup: Great! I am still interested in this autogobble idea, and I guess it should it detect based on the first displayed line rather than the first actual line in the file. I will take a look at this but expect it to be difficult... –  cyberSingularity Jan 6 '13 at 11:20