% \iffalse meta-comment
%<=*COPYRIGHT>
%% Copyright (c) 2011-2022 by Martin Scharrer <martin.scharrer@web.de>
%% -----------------------------------------------------------------------
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `maintained'.
%%
%% The Current Maintainer of this work is Martin Scharrer.
%%
%% This work consists of the files lstautogobble.dtx and lstaddons.ins
%% and the derived filebase lstautogobble.sty.
%%
%<=/COPYRIGHT>
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{lstautogobble.dtx}[%
%<=*DATE>
    2012/05/03
%<=/DATE>
%<=*VERSION>
    v0.1
%<=/VERSION>
    DTX file for 'lstautogobble']
\documentclass{ydoc}
\GetFileInfo{lstautogobble.dtx}
\usepackage{lstautogobble}[\filedate]
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{\jobname.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{0}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v0.1}{2012/05/03}{Initial release.}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \GetFileInfo{lstautogobble.dtx}
% \author{Martin Scharrer}
% \email{martin.scharrer@web.de}
% \ifdefined\repository
%   \repository{https://github.com/MartinScharrer/lstaddons/}
% \fi
%
% \maketitle
%
% \begin{abstract}\noindent
% This add-on package to \pkg{listings} provides a boolean \Key{autogobble}
% setting which will automatically set the \Key{gobble} setting to indention
% of the first line.
%
% This package was created as response to the question
% \href{http://tex.stackexchange.com/q/19953/2975}{``How to automatically skip leading white spaces in listings?''}
% on \href{http://tex.stackexchange.com/}{\TeX\ Stack Exchange}.
% \end{abstract}
%
% \section{Introduction}
% The \pkg{listings} package has a setting \Key{gobble}'='<number> which allows to remove a certain number
% of characters from the beginning of every line in the listing. This can be used to indent the listing
% in the source code without affecting the printed result. However, this forces the user to set a suitable
% value manually. An incorrect value will lead either to an indented listing or to missing leading characters.
%
% A solution for this is to automatically detect the used indention of the listing and that the \Key{gobble} setting
% to this value. This functionality is provided by this package.
% For this it reads and scans the first listing line and reinserts it again afterwards.
%
%
% \section{Usage}
% After loading \pkg{lstautogobble} the following new \pkg{listings} setting
% is available:
%
% \DescribeKey{autogobble}'=true|false'
% This boolean setting switches the autogobble feature on or off.
% If no value is used the default is `|true|'. The initial setting is `|false|'.
% One enabled the first line of any \pkg{lstlisting} is scanned and the amount
% of spaces or tabulators is used to set the \Key{gobble} setting.
% If \Key{gobble} is set manually it will not be overwritten and \Key{autogobble}'=true'
% is ignored.
%
% \section{Examples / Tests}
% The following code is intended as examples and also for testing the package.
% Here the \Key{autogobble} feature is globally enabled.
%
% \lstdefinestyle{exampleresult}{basicstyle=\ttfamily,columns=fullflexible,autogobble=true}%
%
% \begin{example}
%   \caption{Only environment (with \Key{autogobble} enabled globally).}
%   \begin{examplecode}
%   \begin{lstlisting}
%     test
%     it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{With options (must be skipped and reinserted).}
%   \begin{examplecode}
%   \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
%       test
%       it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{Manual gobble option (override). Intentionally set to an incorrect value.}
%   \begin{examplecode}
%   \begin{lstlisting}[gobble=7]
%         test
%         it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{Locally turned-off \Key{autogobble}.}
%   \begin{examplecode}
%   \begin{lstlisting}[autogobble=false]
%       test
%       it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{With some material on the same line as \texttt{\string\begin} (dropped by listings. The warning message got preserved).}
%   \begin{examplecode}
%   \begin{lstlisting} some text at the first line
%       test
%       it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{As before, but with optional argument.}
%   \begin{examplecode}
%   \begin{lstlisting}[] some text at the first line
%       test
%       it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{Different indention levels.}
%   \begin{examplecode}
%   \begin{lstlisting}
%       test
%       it
%   \end{lstlisting}
%   \end{examplecode}
%   \begin{examplecode}
%       \begin{lstlisting}
%           test
%           it
%       \end{lstlisting}
%   \end{examplecode}
%   \begin{examplecode}
%       \begin{lstlisting}
%   test
%   it
%       \end{lstlisting}
%   \end{examplecode}
%   \begin{examplecode}
%           \begin{lstlisting}
%                           test
%                           it
%           \end{lstlisting}
%   \end{examplecode}
%   \begin{examplecode}
%   \begin{lstlisting}
%                   test
%                   it
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \begin{example}
%   \caption{Some real C Code.}
%   \begin{examplecode}
%   \begin{lstlisting}[autogobble]
%      #include <stdio.h>
%      int main(){
%        printf("tex.stackexchange.com: the coolest community ever!\n");
%      }
%   \end{lstlisting}
%   \end{examplecode}
% \end{example}
%
% \StopEventually{}
% \clearpage
% \section{Implementation}
%
% \iffalse
%<*lstautogobble.sty>
% \fi
%    \begin{macrocode}
%<!COPYRIGHT>
\ProvidesPackage{lstautogobble}[%
%<!DATE>
%<!VERSION>
%<*DRIVER>
    2099/01/01 develop
%</DRIVER>
    Implements 'autogobble' option for 'listings']
%    \end{macrocode}
%    \begin{macrocode}

% This is an add-on to the `listings` package
\RequirePackage{listings}

% Counter for leading spaces
\newcount\lstag@spacecount

% Some macros for comparison:
\def\lstag@activespace{\lst@ProcessSpace}%  Definition of an active space
\def\lstag@tabulator{\lst@ProcessTabulator}%  Definition of an tabulator

\begingroup
\catcode`\^^M=\active%
\gdef\lstag@activenl{^^M}%  Active CR (ASCII 13) character which is used as line break
\endgroup


% Define `autogobble` option as boolean (by default off)
\lst@Key{autogobble}{false}[t]{\lstKV@SetIf{#1}\lst@ifautogobble}

% `ungobble` option
\lst@Key{ungobble}{0}{\def\lst@ungobble{#1}}

% Insert required code at environment init
\lst@AddToHook{Init}{\lst@autogobble}

% Autogobble init macro.
% If the option is active and `gobble` is not set, init vars and overwrite the process macro with own definition.
\def\lst@autogobble{%
    \lst@ifautogobble
        \ifnum\lst@gobble>0\else
            \def\lst@gobble{\lstag@gobble}%
            \def\lstag@gobble{0}%
            \lstag@spacecount\z@
            \def\lstag@spaceaccu{}%
            \let\lstag@restofline\empty
            \let\lstag@origlstenv@Process\lstenv@Process
            \let\lstenv@Process\lstag@countleadingspaces
        \fi
    \fi
}

% Checks if the next following character (read as argument) is a line break (as it is supposed to be)
% Otherwise there is some text direct after the `\begin{<env>}[<options>]` which is dropped by `listings`.
\def\lstag@countleadingspaces#1{%
    \expandafter\ifx\lstag@activenl#1\relax
        \expandafter\lstag@countleadingspaces@
    \else
        \def\lstag@restofline{Dummy replacement of text after begin of listing to trigger original warning message}%
        \expandafter\lstag@countleadingspaces
    \fi
}

% After the new line is found this macro counts the spaces and tabulators
\def\lstag@countleadingspaces@#1{%
    \ifx\lstag@activespace#1\relax
        \advance\lstag@spacecount by \@ne
        % Accumulate spaces (i.e. their definitions) for later re-insertion:
        \expandafter\def\expandafter\lstag@spaceaccu\expandafter{\lstag@spaceaccu\lst@ProcessSpace}%
        \let\next\lstag@countleadingspaces@
    \else% Character wasn't a space
    \ifx\lstag@tabulator#1\relax
        \advance\lstag@spacecount by \lst@tabsize\relax
        % Accumulate spaces (i.e. their definitions) for later re-insertion:
        \@tempcnta=\lst@tabsize\relax
        \loop
        \ifnum\@tempcnta>\z@
            \expandafter\def\expandafter\lstag@spaceaccu\expandafter{\lstag@spaceaccu\lst@ProcessSpace}%
            \advance\@tempcnta\m@ne
        \repeat
        \let\next\lstag@countleadingspaces@
    \else% Character wasn't a tabulator either
        % Set gobble option (indirect):
        \xdef\lstag@gobble{\the\numexpr\lstag@spacecount-\lst@ungobble\relax}%
        % Restore original definition of process macro:
        \global\let\lstenv@Process\lstag@origlstenv@Process
        % Re-insert all collected material or appropriate replacement material:
        \edef\next{\noexpand\lstenv@Process\lstag@restofline\expandafter\noexpand\lstag@activenl\expandafter\unexpanded\expandafter{\lstag@spaceaccu}\noexpand#1}%
    \fi\fi
    \next
}
%    \end{macrocode}
% \iffalse
%</lstautogobble.sty>
% \fi
%
% \Finale
\endinput
