% tkzexample.sty -- code and result side by side (used by the tkz-* docs)
% Copyright 2022-2026  Alain Matthes
% SPDX-License-Identifier: LPPL-1.3c
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% 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.3c 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 Alain Matthes.
%
% The author of the original code
% of the environment 'codeexample' is Till Tantau
% from the file pgfmanual-en-macros.tex
%  (Copyright 2006 by Till Tantau)
% See the file doc/generic/pgf/licenses/LICENSE for more details.
%
% v1.51 (2026/10/05) -- new key `break code` (auto|fill|always|never) :
%  a long code can be split across pages
%  - key `above skip` works (code inserted before the example)
% v1.50 (2026/10/05) -- corrections
%  - xcolor and pgfkeys are now loaded (the package failed without tikz)
%  - key `overhang` : `overhang=false` works again (duplicate key removed)
%  - keys `inner right margin` and `inner bottom margin` are now used
%  - tkzltxexample: `hsep` no longer overwrites the dimen \tkz@hsep
%  - option saved + `code only`: the code is printed, not the file name
%  - option saved: no overflow of 6pt when the code is placed below
%  - saved files: several examples in the same subsubsection no longer
%    overwrite each other (tkzFile-1-2-0.tex, tkzFile-1-2-0-2.tex, ...)
%  - keys `latex` and `vbox`: end of lines are spaces again and empty
%    lines make new paragraphs
%  - the optional argument [...] is now really optional
%<--------------------------------------------------------------------------->
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{tkzexample}[2026/10/20 v1.51 (code and graphic)]
\RequirePackage{calc,xcolor,pgfkeys,mdframed,fancyvrb}
\newif\iftkzcodesaved
\DeclareOption{saved}{\tkzcodesavedtrue}
\ProcessOptions\relax
%<--------------------------------------------------------------------------->
\colorlet{graphicbackground}{white}
\colorlet{codebackground}{white}
\colorlet{codeonlybackground}{white}
\colorlet{numbackground}{white}
\colorlet{textcodecolor}{black}
\colorlet{numcolor}{gray}
%<--------------------------------------------------------------------------->
\newcounter{code@cnt}%

% Define \find@tkzexample such that it doesn't destroy catcodes:
\begingroup
\catcode`|=0
\catcode`[= 1
\catcode`]=2
\catcode`\{=12
\catcode `\}=12
\catcode`\\=12 |gdef|find@tkzexample#1\end{tkzexample}[|endoftkzexample[#1]]
|endgroup

\begingroup
\catcode`|=0
\catcode`[= 1
\catcode`]=2
\catcode`\{=12
\catcode `\}=12
\catcode`\\=12 |gdef|find@tkzltxexample#1\end{tkzltxexample}[|endoftkzltxexample[#1]]
|endgroup

% define \returntospace.
%
% It should define NEWLINE as {}, spaces and tabs as \space.
\begingroup
\catcode`\^=7
\catcode`\^^M=13
\catcode`\^^I=13
\catcode`\ =13%
\gdef\returntospace{\catcode`\ =13\def {\space}\catcode`\^^I=13\def^^I{\space}\catcode`\^^M=13\def^^M{}}%
\endgroup

\begingroup
\catcode`\%=13
\catcode`\^^M=13
\gdef\commenthandler{\catcode`\%=13\def%{\@gobble@till@return}}
\gdef\@gobble@till@return#1^^M{}
\gdef\@gobble@till@return@ignore#1^^M{\ignorespaces}
\gdef\typesetcomment{\catcode`\%=13\def%{\@typeset@till@return}}
\gdef\@typeset@till@return#1^^M{{\def%{\char`\%}\textsl{\char`\%#1}}\par}
\gdef\typesetcommentnum{\catcode`\%=13\def%{\@typeset@till@return@num}}
\gdef\@typeset@till@return@num#1^^M{{\def%{\char`\%}\textsl{\char`\%#1}} \@@par}
\endgroup

% \tkz@ifopt\macro : calls \macro[<options>] ; [] is added if the user
% gives no option. The end of line is made active *before* looking ahead,
% so that the first line of the code is not tokenized too early.
\def\tkz@ifopt#1{%
  \begingroup
  \catcode`\^^M=\active
  \@ifnextchar[{\endgroup#1}{\endgroup#1[]}}

% keys latex and vbox : before \scantokens, in the code (\code@temp)
% two ends of line (an empty line) become \par and an end of line becomes
% a space. The ends of line are active characters ^^M.
\ExplSyntaxOn
\group_begin:
\char_set_catcode_active:N \^^M
\cs_gset_protected:Npn \tkz@fixeol #1
  {
    \tl_greplace_all:Nnn #1 { ^^M ^^M } { ~ \par ~ }
    \tl_greplace_all:Nnn #1 { ^^M } { ~ }
  }
\group_end:
\ExplSyntaxOff
\def\tkz@textcode{\tkz@fixeol\code@temp\catcode`\^^M=9\relax}

\let\tkz@frameset\colorbox
\let\tkz@frameltxset\colorbox
\newwrite\fileexample
\newdimen\tkzexamplewidth
\newdimen\tkz@hsep
\tkz@hsep=0pt
\newif\ifcode@execute
\newif\ifcode@saved\code@savedfalse
\newif\ifnum@show \num@showfalse
\newif\ifcode@overhang
\newbox\tkzexamplebox
\newif\ifcode@vbox \code@vboxfalse
%
\pgfqkeys{/tkzexample}{%
  execute code/.is if        = code@execute,
  show num/.is if            = num@show,
  overhang/.is if            = code@overhang,
  code only/.code            = {\code@executefalse},
  width/.code                = {\setlength\tkzexamplewidth{#1}},
  code/.code                 = {\colorlet{codebackground}{#1}},
  graphic/.code              = {\colorlet{graphicbackground}{#1}},
  num/.code                  = {\num@showtrue\setcounter{code@cnt}{1}},
  numcolor/.code             = {\colorlet{numcolor}{#1}},
  numbkgcolor/.code          = {\colorlet{numbackground}{#1}},
  global num/.code           = {\num@showtrue},
  code style/.code           = {\def\code@style{#1}},
  normal/.code               = {\def\code@size{\normalsize}},
  small/.code                = {\def\code@size{\small}},
  very small/.code           = {\def\code@size{\footnotesize}},
  right margin/.code         = {\def\tkz@rightmargin{#1}},
  left margin/.code          = {\def\tkz@leftmargin{#1}},
  inner left margin/.code    = {\def\tkz@innerleftmargin{#1}},
  inner right margin/.code   = {\def\tkz@innerrightmargin{#1}},
  inner top margin/.code     = {\def\tkz@innertopmargin{#1}},
  inner bottom margin/.code  = {\def\tkz@innerbottommargin{#1}},
  line frame width/.code     = {\def\tkz@linewidth{#1}},
  frame code/.code           = {\def\tkz@frameset{\fcolorbox{#1}}%
                                \def\tkz@framecolor{#1}%
                                \def\tkz@framerule{\fboxrule}},
  break code/.is choice,
  break code/.default        = fill,
  break code/auto/.code      = {\chardef\tkz@breakmode=0 },
  break code/fill/.code      = {\chardef\tkz@breakmode=1 },
  break code/always/.code    = {\chardef\tkz@breakmode=2 },
  break code/never/.code     = {\chardef\tkz@breakmode=3 },
  frame tex/.code            = {\def\tkz@frameltxset{\fcolorbox{#1}}},
  above skip/.code           = {\def\tkz@above{#1}},
  below skip/.code           = {\def\tkz@below{#1}},
  hsep/.code                 = {\setlength\tkz@hsep{#1}},
  pre/.code                  = {\def\code@pre{#1}},
  post/.code                 = {\def\code@post{#1}},
  latex/.code                = {\setlength\tkzexamplewidth{#1}%
                                \let\code@eolsetup\tkz@textcode
                                \def\code@preadd{\begin{minipage}{#1}}%
                                \def\code@postadd{\end{minipage}}},
  vbox/.code                 = {\code@vboxtrue
                                \let\code@eolsetup\tkz@textcode
                                \def\code@preadd{\noindent
                                \vbox\bgroup
                                \setlength{\hsize}{\linewidth-6pt}%
                                }%
                                \def\code@postadd{\egroup}},
  every tkzexample/.style={width=6cm},
}%
\def\code@style{\small\ttfamily}%
\def\tkz@framecolor{black}%
\def\tkz@framerule{0pt}%
\chardef\tkz@breakmode=0 % auto
\def\code@size{}%
\def\code@pre{}%
\def\code@post{}%
\def\code@preadd{}%
\def\code@postadd{}%
\def\code@catcode@hook{}%
% end of lines when the code is executed :
% ignored for graphics, for text (keys latex and vbox) an end of line
% is a space and an empty line is \par
\def\code@eolsetup{\catcode`\^^M=9\relax}%
\def\tkz@above{\par}%
\def\tkz@below{\par}%

% default values of the frame (the same for both environments)
% inner right and inner bottom margins = defaults of mdframed
\def\tkz@initkeys#1{%
  \pgfqkeys{#1}{%
    right margin        = 0pt,
    left margin         = 0pt,
    line frame width    = 0pt,
    inner left margin   = 0pt,
    inner right margin  = 10pt,
    inner top margin    = 6pt,
    inner bottom margin = .4\baselineskip}}

% execution du code
\def\tkz@result{%
 \begin{minipage}[t]{\wd\tkzexamplebox}%
   \hrule width0pt
   \code@size
   \box\tkzexamplebox
   \leavevmode
 \end{minipage}%
}%

% common settings to typeset the code (verbatim, numbers, comments)
\def\tkz@codesetup{%
  \let\do\@makeother
  \dospecials
  \frenchspacing
  \code@style\code@size
  \obeylines
  \@vobeyspaces
  \@tempswafalse
  \ifnum@show
    \typesetcommentnum
    \def\par{%
      \if@tempswa
        \leavevmode\null\@@par\penalty\interlinepenalty
        \tkz@numlines
      \else
        \@tempswatrue
        \ifhmode\@@par\penalty\interlinepenalty\fi
      \fi}%
    \tkz@numlines
  \else
    \typesetcomment
    \def\par{%
      \if@tempswa
        \leavevmode\null\@@par\penalty\interlinepenalty
      \else
        \@tempswatrue
        \ifhmode\@@par\penalty\interlinepenalty\fi
      \fi}%
  \fi
  \obeylines}

\def\tkz@numlines{%
  \everypar{\setlength\fboxsep{1pt}%
            \noindent\parskip=\z@
            \llap{\colorbox{numbackground}{\textcolor{numcolor}{%
            \footnotesize\number\value{code@cnt}}}\enspace}%
            \stepcounter{code@cnt}}}

\newcommand\tkz@code[1]{%
\begin{minipage}[t]{\code@width}{%
\color{textcodecolor}%
\parskip=\z@
\hrule width\z@
\vskip-.25em
\tkz@codesetup
\tkz@quiet
\ifcode@saved\input{#1}\else#1\fi%
}% end of content for the minipage
\end{minipage}%
}%

\newcommand\tkz@codesplit[1]{%
\begin{mdframed}[linewidth        = \tkz@linewidth,
                 leftmargin       = \tkz@leftmargin,
                 rightmargin      = \tkz@rightmargin,
                 backgroundcolor  = codeonlybackground,
                 innerleftmargin  = \tkz@innerleftmargin,
                 innerrightmargin = \tkz@innerrightmargin,
                 innertopmargin   = \tkz@innertopmargin,
                 innerbottommargin= \tkz@innerbottommargin]
\begingroup
\color{textcodecolor}%
\parskip=\z@
\hrule width0pt
\tkz@codesetup
\ifcode@saved\input{#1}\else #1\fi
\endgroup
\end{mdframed}%
}%

% breakable code (mdframed) placed below (or above) the result
\newcommand\tkz@codebreak[1]{%
\begin{mdframed}[linewidth        = \tkz@framerule,
                 linecolor        = \tkz@framecolor,
                 leftmargin       = 0pt,
                 rightmargin      = 0pt,
                 skipabove        = 0pt,
                 skipbelow        = 0pt,
                 backgroundcolor  = codebackground,
                 innerleftmargin  = \fboxsep,
                 innerrightmargin = \fboxsep,
                 innertopmargin   = \fboxsep,
                 innerbottommargin= \fboxsep]
\begingroup
\color{textcodecolor}%
\parskip=\z@
\hrule width0pt
\tkz@codesetup
\ifcode@saved\input{#1}\else #1\fi
\endgroup
\end{mdframed}%
}%

% break code : 0 auto   = the code is split only if the example is
%                         higher than a page (\textheight)
%              1 fill   = split if the example does not fit in the
%                         space left on the current page
%              2 always = result, then breakable code below
%              3 never  = old behaviour (unbreakable box)
\newbox\tkz@codebox
\let\tkz@quiet\relax
\newif\iftkz@break
\newif\iftkz@wide % the code is below the result
\newcount\tkz@cntsave
\newdimen\tkz@avail

% measure the code box and decide if the code must be split
\def\tkz@measurecode#1{%
  \tkz@cntsave=\value{code@cnt}%
  \begingroup
  \def\tkz@quiet{\hfuzz\maxdimen\hbadness\@M}% no warning while measuring
  \global\setbox\tkz@codebox=\hbox{\tkz@frameset{codebackground}{\tkz@code{#1}}}%
  \endgroup
  \setcounter{code@cnt}{\tkz@cntsave}%
  \dimen@=\ht\tkz@codebox
  \advance\dimen@\dp\tkz@codebox
  \dimen@ii=\ht\tkzexamplebox
  \advance\dimen@ii\dp\tkzexamplebox
  \advance\dimen@ii2\fboxsep
  \iftkz@wide % code below the result : heights are added
    \advance\dimen@\dimen@ii
  \else
    \ifdim\dimen@ii>\dimen@ \dimen@=\dimen@ii\fi
  \fi
  \ifdim\pagegoal=\maxdimen
    \tkz@avail=\textheight
  \else
    \tkz@avail=\pagegoal
    \advance\tkz@avail-\pagetotal
  \fi
  \tkz@breakfalse
  \ifcase\tkz@breakmode
    \ifdim\dimen@>\textheight\tkz@breaktrue\fi
  \or
    \ifdim\dimen@>\tkz@avail\tkz@breaktrue\fi
  \or
    \tkz@breaktrue
  \fi}

% places the result and the code (#1 : code or file name)
\def\tkz@layout#1{%
  \par
  \tkz@measurecode{#1}%
  \iftkz@break
    \setbox\tkz@codebox=\box\voidb@x
    \ifcode@overhang
      \tkz@codebreak{#1}\par
      \nointerlineskip\vskip\fboxsep
      \noindent\tkz@frameltxset{graphicbackground}{\tkz@result}%
    \else
      \noindent\tkz@frameltxset{graphicbackground}{\tkz@result}\par
      \vskip\fboxsep
      \tkz@codebreak{#1}%
    \fi
  \else
    % typeset again, without hiding the warnings (overfull lines)
    \setbox\tkz@codebox=\hbox{\tkz@frameset{codebackground}{\tkz@code{#1}}}%
    \noindent
    \ifcode@overhang
      \box\tkz@codebox
      \code@mid
      \tkz@frameltxset{graphicbackground}{\tkz@result}%
    \else
      \tkz@frameltxset{graphicbackground}{\tkz@result}%
      \code@mid
      \box\tkz@codebox
    \fi
  \fi}

%<--------------------------------------------------------------------------->
% names of the saved files : <prefix>-<sec>-<subsec>-<subsubsec>.tex
% and if necessary <prefix>-<sec>-<subsec>-<subsubsec>-<n>.tex (n = 2, 3 ...)
\def\tkzFileSavedPrefix{tkzFile}%
\def\tkzref{\arabic{section}-\arabic{subsection}-\arabic{subsubsection}}%
\def\tkz@ref{\arabic{section}-\arabic{subsection}-\arabic{subsubsection}}%
\newcount\tkz@savedcnt
\def\tkz@lastsaved{}%
\def\tkz@savedname{\tkzFileSavedPrefix-\tkz@ref}%
\def\tkz@File@Saved@Name{\tkz@savedname}%
\def\tkz@setsavedname{%
  \edef\tkz@tmpsaved{\tkzFileSavedPrefix-\tkz@ref}%
  \ifx\tkz@tmpsaved\tkz@lastsaved
    \global\advance\tkz@savedcnt\@ne
    \xdef\tkz@savedname{\tkz@tmpsaved-\the\tkz@savedcnt}%
  \else
    \global\tkz@savedcnt\@ne
    \global\let\tkz@lastsaved\tkz@tmpsaved
    \global\let\tkz@savedname\tkz@tmpsaved
  \fi}

\newcommand\killienc{}
\@tempcnta128
\@whilenum\@tempcnta<\@cclvi\do{%
  \edef\killienc{\killienc\catcode\the\@tempcnta=12}%
  \advance\@tempcnta\@ne}

%<--------------------------------------------------------------------------->
\iftkzcodesaved
\def\tkzexample{\tkz@ifopt\tkz@savedexample}
\long\def\tkz@savedexample[#1]{%
\code@executetrue
\normalsize
\tkz@initkeys{/tkzexample}%
\pgfqkeys{/tkzexample}{every tkzexample,#1}%
\parindent0pt
\tkz@setsavedname
\bgroup
\VerbatimEnvironment
\killienc\begin{VerbatimOut}{\tkz@savedname.tex}}%
\def\endtkzexample{\end{VerbatimOut}%
\egroup
\code@savedtrue
\tkz@above
\ifcode@execute
  \setbox\tkzexamplebox=\hbox{\input{\tkz@savedname.tex}}%
  \ifdim\wd\tkzexamplebox>\tkzexamplewidth
     \def\code@mid{\parskip2pt\par}\tkz@widetrue
     \def\code@width{\linewidth-6pt}%
  \else
     \ifdim\tkz@hsep=0pt
        \def\code@mid{\hfill}%
     \else
        \def\code@mid{\hskip\tkz@hsep}%
     \fi
     \def\code@width{\linewidth-1.5em-\tkz@hsep-\tkzexamplewidth}%
  \fi
  \tkz@layout{\tkz@savedname.tex}%
\else% code only
  \par\vskip1em
  \tkz@codesplit{\tkz@savedname.tex}%
\fi
\tkz@below
}%
\else% code not saved
\def\tkzexample{\tkz@ifopt\tkz@example}
\long\def\tkz@example[#1]{%
\begingroup
\code@executetrue
\tkz@initkeys{/tkzexample}%
\pgfqkeys{/tkzexample}{every tkzexample,#1}%
\parindent0pt
\begingroup
\let\do\@makeother
\dospecials
\obeylines
\@vobeyspaces
\catcode`\%=13 %
\catcode`\^^M=13 %
\find@tkzexample}% #1 est tout ce qui se trouve dans l'environnement
\def\endoftkzexample#1{%
\endgroup
\tkz@above
\ifcode@execute
  \setbox\tkzexamplebox=\hbox{%
        {\commenthandler
         \protected@xdef\code@temp{#1}}%
  \code@eolsetup
  {\ignorespaces\code@preadd\code@pre
   \expandafter\scantokens\expandafter{\code@temp\ignorespaces}%
   \code@post\code@postadd\ignorespaces}%
  }%
  \ifdim\wd\tkzexamplebox>\tkzexamplewidth
     \def\code@mid{\par}\tkz@widetrue
     \def\code@width{\linewidth-6pt}%
  \else
     \ifdim\tkz@hsep=0pt
        \def\code@mid{\hfill}%
     \else
        \def\code@mid{\hskip\tkz@hsep}%
     \fi
     \def\code@width{\linewidth-1.5em-\tkz@hsep-\tkzexamplewidth}%
  \fi
  \tkz@layout{#1}%
\else% code only
  \par\vskip1em
  \tkz@codesplit{#1}%
\fi
\tkz@below
\end{tkzexample}%
}%
\def\endtkzexample{\endgroup}%
\fi
%<--------------------------------------------------------------------------->
\newdimen\tkzltxexamplewidth
\newbox\tkzltxexamplebox

\pgfqkeys{/tkzltxexample}{%
  % width and hsep have no effect here (kept for compatibility)
  width/.code                = {\setlength\tkzltxexamplewidth{#1}},
  code/.code                 = {\colorlet{codeonlybackground}{#1}},
  show num/.is if            =  num@show,
  num/.code                  = {\num@showtrue\setcounter{code@cnt}{1}},
  global num/.code           = {\num@showtrue},
  numcolor/.code             = {\colorlet{numcolor}{#1}},
  numbkgcolor/.code          = {\colorlet{numbackground}{#1}},
  code style/.code           = {\def\code@style{#1}},
  normal/.code               = {\def\code@size{\normalsize}},
  small/.code                = {\def\code@size{\small}},
  very small/.code           = {\def\code@size{\footnotesize}},
  right margin/.code         = {\def\tkz@rightmargin{#1}},
  left margin/.code          = {\def\tkz@leftmargin{#1}},
  inner left margin/.code    = {\def\tkz@innerleftmargin{#1}},
  inner right margin/.code   = {\def\tkz@innerrightmargin{#1}},
  inner top margin/.code     = {\def\tkz@innertopmargin{#1}},
  inner bottom margin/.code  = {\def\tkz@innerbottommargin{#1}},
  line frame width/.code     = {\def\tkz@linewidth{#1}},
  hsep/.code                 = {\setlength\tkz@hsep{#1}},
  typeset listing/.code      = {#1},
  frame code/.code           = {\def\tkz@frameset{\fcolorbox{#1}}},
  ignorespaces/.code         = {\let\@gobble@till@return =%
                                \@gobble@till@return@ignore},
  leave comments/.code       = {\def\code@catcode@hook{\catcode`\%=12}%
                                \let\commenthandler=\relax%
                                \let\typesetcomment=\relax},
  every tkzltxexample/.style = {width=8cm},
  vbox/.code                 = {\def\code@preadd{\noindent
                               \vbox\bgroup\setlength{\hsize}{\linewidth}}%
                               \def\code@postadd{\egroup}}%
}

\def\tkzltxexample{\tkz@ifopt\tkz@ltxexample}
\long\def\tkz@ltxexample[#1]{%
\begingroup
\tkz@initkeys{/tkzltxexample}%
\pgfqkeys{/tkzltxexample}{every tkzltxexample,#1}%
\parindent0pt
\begingroup%
\let\do\@makeother
\dospecials
\obeylines
\@vobeyspaces
\catcode`\%=13 %
\catcode`\^^M=13 %
\code@catcode@hook%
\relax%
\find@tkzltxexample}
\def\endoftkzltxexample#1{%
\endgroup%
\par\vskip1em
\tkz@codesplit{#1}%
\par
\code@post
\end{tkzltxexample}%
}%
\def\endtkzltxexample{\endgroup}

%<--------------------------------------------------------------------------->
\pgfkeys{
/tkzsavedcode/.cd,
  prefix/.code    = {\def\tkzFileSavedPrefix{#1}}}

\newcommand{\tkzSavedCode}[1][]{%
\pgfqkeys{/tkzsavedcode}{prefix = tkzFile,#1}%
\def\tkzexample{\tkz@ifopt\tkz@onlysavedexample}%
\def\endtkzexample{\endVerbatimOut}}
\long\def\tkz@onlysavedexample[#1]{%
\tkz@setsavedname
\killienc\VerbatimOut{\tkz@savedname.tex}}
\endinput
