% 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[] ; [] 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 : ---.tex % and if necessary ----.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