% \iffalse meta-comment % (The MIT License) % % Copyright (c) 2021-2022 Yegor Bugayenko % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the 'Software'), to deal % in the Software without restriction, including without limitation the rights % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell % copies of the Software, and to permit persons to whom the Software is % furnished to do so, subject to the following conditions: % % The above copyright notice and this permission notice shall be included in all % copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE % SOFTWARE. % \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 \~} % \GetFileInfo{docshots.dtx} % \DoNotIndex{\endgroup,\begingroup,\let,\else,\s,\n,\r,\\,\1,\fi} % \iffalse %<*driver> \ProvidesFile{docshots.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{docshots} %<*package> [2022-10-18 0.0.4 TeX Samples Next to Their PDF Snapshots in DTX] % %<*driver> \documentclass{ltxdoc} \usepackage[tt=false, type1=true]{libertine} \usepackage{microtype} \usepackage[dtx]{docshots} \usepackage{href-ul} \usepackage{xcolor} \PageIndex \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{docshots.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % \title{|docshots|: \LaTeX{} Package that Renders \\ \TeX{} Samples Next to Their \\ PDF Snapshots\thanks{The sources are in GitHub at \href{https://github.com/yegor256/docshots}{yegor256/docshots}}} % \author{Yegor Bugayenko \\ \texttt{yegor256@gmail.com}} % \date{\filedate, \fileversion} % % \maketitle % % \textbf{\color{red}NB!} % This package doesn't work on Windows! % Also, you must run \TeX{} processor with |--shell-escape| option. % Also, you must have % |pdlaftex|, % \href{https://www.perl.org}{Perl}, % \href{https://www.ghostscript.com}{Ghostscript}, % and \href{https://ctan.org/pkg/pdfcrop}{pdfcrop} % installed. % \section{Introduction} % % When you want to demonstrate to the readers of your documentation % how to use certain \TeX{} commands, the best way would be % to show exactly how the entire document will be rendered in PDF, % using a subprocess that would render it (via |pdflatex|, for example). % To \href{https://tex.stackexchange.com/questions/661027}{my best} % knowledge, there were no packages that would allow % you do exactly this. That's why I created this simple package. % For example, this code: % %\iffalse %<*verb> %\fi \begin{verbatim} \begin{docshot} \documentclass{article} \usepackage{xcolor} \pagestyle{empty} \begin{document} Hello, {\color{orange}\LaTeX}! \end{document} \end{docshot} \end{verbatim} %\iffalse % %\fi % is rendered as such: % \begin{docshot} % \documentclass{article} % \usepackage{xcolor} % \pagestyle{empty} % \begin{document} % Hello, {\color{orange}\LaTeX}! % \end{document} % \end{docshot} % Here is a more complex example: % \begin{docshot} % \documentclass{article} % \usepackage{tikz} % \pagestyle{empty} % \begin{document} % \begin{tikzpicture} % \node [circle,draw] (v0) {$v_0$}; % \node [circle,draw=orange,thick, % below right of=v0] (v1) {$v_1$}; % \draw [->] (v0) -- (v1); % \end{tikzpicture} % \end{document} % \end{docshot} % The picture you see on the left side is rendered by a subprocess % executing |pdflatex| with the |.tex| content taken from the source file. % After a successful processing of \TeX{} sources, we use % \href{https://ctan.org/pkg/pdfcrop}{pdfcrop} to trim the document. % We execute |pdflatex| with |-interaction=batchmode| and |-halt-on-error| options. % This means that % \TeX{} processing will stop at the first error. Check your \TeX{} log % to understand what went wrong. % When you render a text instead of a single picture, it's recommended to use % \href{https://ctan.org/pkg/geometry}{geometry} package to change the size % of the page and then |empty| page style to remove page numbering: % \begin{docshot} % \documentclass{article} % \usepackage[paperwidth=2in]{geometry} % \pagestyle{empty} % \begin{document} % ``There is no sadder thing than % a young pessimist, except an old % pessimist'' --- \emph{Mark Twain} % \end{document} % \end{docshot} % \section{Package Options} % \DescribeMacro{pdflatex} % The default command line tool for turning |.tex| into % |.pdf| is |pdflatex|. However, you can change that by using |pdflatex| package option, % for example: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage[pdflatex=/usr/local/bin/pdflatex]{docshot} \begin{document} \begin{docshot} Hello, world! \end{docshot} \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{gs} % The default location of Ghostscript is just |gs|. % You can change that by using |gs| package option, % for example: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[gs=/usr/bin/ghostscript]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{pdfcrop} % The default location of |pdfcrop| is just |pdfcrop|. % You can change that by using |pdfcrop| package option, % for example: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[pdfcrop=/bin/pdfcrop]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{margin} % When we crop the PDF rendered, we leave a margin around the content. The % default value may be changed by the package option |margin|: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[margin=10]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{hspace} % The horizontal distance between the image and its verbatim \TeX{} source % may be configured via |hspace| package option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[hspace=1em]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{left} % \DescribeMacro{right} % The default width of the image may be changed by |left| option, while % the width of the verbatim \TeX{} source may be modified by |right| option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[left=2in,right=.5\linewidth]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{dtx} % If you use this package inside |.dtx| documentation, add |dtx| package option. Thanks % to this option all comment symbols will be removed from line starts: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[dtx]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{tmpdir} % The default location of temp files is |\docshots@tmpdir|. You can change this using |tmpdir| option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[tmpdir=/tmp/foo]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{runs} % By default, we run |pdflatex| just once for each docshot. You can change this number using the package % option |runs|. This may be helpful if you need Bib\TeX{} processing, for example: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[runs=3]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{small} % \DescribeMacro{tiny} % You don't have too much freedom in formatting of verbatim texts, but you can make % their font a bit smaller using |small| package option. You can also make it very % small using |tiny| option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[small]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{log} % With |log| option you can make us print all possible logs to the main \TeX{} log. % By default, we don't do this and you won't see the output of |pdflatex| compilation, for example. % Just use it like this: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[log]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{inputminted} % By default, we render the verbatim text using |\VerbatimInput| command. You % can change that and make us use |\inputminted| % from \href{https://ctan.org/pkg/minted}{minted} package instead, for example: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage{minted} \setminted[java]{frame=lines,framesep=2mm} \usepackage[inputminted=java]{docshot} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{lstinputlisting} % By default, we render the verbatim text using |\VerbatimInput| command. You % can change that and make us use |\lstinputlisting| from % \href{https://ctan.org/pkg/listings}{listings} package instead, for example: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage{listings} \lstset{basicstyle=\small} \usepackage[lstinputlisting]{docshot} \end{verbatim} %\iffalse % %\fi % \section{Prerequisites} % \DescribeMacro{\docshotPrerequisite} % If you need some files to be present next to the |.tex| snippet while % it's rendered by |pdflatex|, you can use |\docshotPrerequisite| with % a single mandatory argument. The argument is the name of a file you need % to be copied from current directory to the temporary directory, where % all snippets are rendered. The command can be used either in the body % of the document or in the preamble --- it doesn't matter, as long as % it shows up before the docshot that needs the prerequisite. For example: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{docshot} \docshotPrerequisite{duck.jpg} \begin{document} \begin{docshot} \documentclass{article} \usepackage{graphicx} \pagestyle{empty} \begin{document} This is my favorite picture of a duck: \includegraphics[width=2in]{duck.jpg} \end{document} \end{docshot} \end{document} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{\docshotAfter} % If you need something to happen after each |pdflatex| run of a docshot, you may use % |\docshotAfter| command right before |docshot| environment. For example, you have a bibliography file that % you want to be visible for all snippets and you want all of them to % run \href{https://ctan.org/pkg/biber}{biber} in order to process citations: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{docshot} \docshotPrerequisite{main.bib} \begin{document} \docshotAfter{biber $2} \begin{docshot} \documentclass{acmart} \usepackage[natbib=true]{biblatex} \addbibresource{main.bib} \pagestyle{empty} \begin{document} You must read the book of \citet{knuth1984}. \printbibliography \end{document} \end{docshot} \end{document} \end{verbatim} %\iffalse % %\fi % The script you specify in the first argument of |\docshotAfter| will get % three arguments when it runs: % \begin{description}\setlength\itemsep{0em} % \item[|\$1|] the cycle of |pdflatex| processing (1, 2, ...), % \item[|\$2|] the hash of the snippet, % \item[|\$3|] the name of the |.tex| file. % \end{description} % |$2| is basically equals to |$1| with an % attached |.tex| suffix. |\docshotAfter| applies only to the first |docshot| % environment that goes after it! You must specify |\docshotAfter| before % each |docshot| where you want such post-processing to happen. % \StopEventually{} % \section{Implementation} % \changes{v0.0.1}{2022/10/09}{Initial version} % First, we include a few packages: % \begin{macrocode} \RequirePackage{iexec} \RequirePackage{fancyvrb} \RequirePackage{xcolor} \RequirePackage{graphicx} \RequirePackage{tikz} \usetikzlibrary{shadows.blur} % \end{macrocode} % Then, we process package options: % \begin{macrocode} \RequirePackage{pgfopts} \pgfkeys{ /docshots/.cd, dtx/.store in=\docshots@dtx, log/.store in=\docshots@log, log/.default=, lstinputlisting/.store in=\docshots@lstinputlisting, inputminted/.store in=\docshots@inputminted, tmpdir/.store in=\docshots@tmpdir, tmpdir/.default=_docshots, small/.store in=\docshots@small, tiny/.store in=\docshots@tiny, runs/.store in=\docshots@runs, runs/.default=1, pdflatex/.store in=\docshots@pdflatex, pdflatex/.default=pdflatex, gs/.store in=\docshots@gs, gs/.default=gs, pdfcrop/.store in=\docshots@pdfcrop, pdfcrop/.default=pdfcrop, margin/.store in=\docshots@margin, margin/.default=5, hspace/.store in=\docshots@hspace, hspace/.default=.05\linewidth, left/.store in=\docshots@left, left/.default=.3\linewidth, right/.store in=\docshots@right, right/.default=.55\linewidth, tmpdir,pdflatex,gs,pdfcrop,margin,hspace,left,right,runs,log } \ProcessPgfOptions{/docshots} % \end{macrocode} % Then, we print the version of |pdflatex| to \TeX{} log: % \begin{macrocode} \iexec[\docshots@log,quiet]{\docshots@pdflatex\space --version}% % \end{macrocode} % Then, we print the version of \href{https://ctan.org/pkg/pdfcrop}{pdfcrop} to \TeX{} log: % \begin{macrocode} \iexec[\docshots@log,quiet]{\docshots@pdfcrop\space --version}% % \end{macrocode} % Then, we print the version of |ghostscript| to \TeX{} log: % \begin{macrocode} \iexec[\docshots@log,quiet]{\docshots@gs\space --version}% % \end{macrocode} % Then, we make a directory where all temporary files will be kept: % \begin{macrocode} \iexec[null]{mkdir -p \docshots@tmpdir/\jobname}% % \end{macrocode} % \begin{macro}{docshot} % Then, we define |docshot| environment: % \begin{macrocode} \newenvironment{docshot} {\VerbatimEnvironment\begin{VerbatimOut} {\docshots@tmpdir/\jobname/verbatim.tex}} {\end{VerbatimOut}% % \end{macrocode} % If we are in |dtx| mode, leading percent characters must be removed: % \begin{macrocode} \ifdefined\docshots@dtx% \iexec[null]{perl -i -0777pe "s/(\\n|^)\\x{25} /\\1/g" \docshots@tmpdir/\jobname/verbatim.tex}% \fi% % \end{macrocode} % We calculate MD5 hashsum of the file content: % \begin{macrocode} \def\hash{\pdfmdfivesum file {\docshots@tmpdir/\jobname/verbatim.tex}}% % \end{macrocode} % If the PDF with the required name already exists, we ignore this step. % Otherwise, we copy |verbatim.tex| into new file and run |pdflatex|: % \begin{macrocode} \IfFileExists{\docshots@tmpdir/\jobname/\hash.pdf} {\message{docshots: won't render, the PDF already exists (\docshots@tmpdir/\jobname/\hash.pdf)^^J}} {\iexec[\docshots@log,quiet]{cp \docshots@tmpdir/\jobname/verbatim.tex \docshots@tmpdir/\jobname/\hash.tex}% \foreach \n in {1,...,\docshots@runs}{ \iexec[\docshots@log,quiet]{cd \docshots@tmpdir/\jobname; \docshots@pdflatex\space -interaction=errorstopmode -halt-on-error -shell-escape \hash.tex} \message{docshots: pdflatex run no.\n^^J} \IfFileExists{\docshots@tmpdir/\jobname/after.sh} {\iexec[\docshots@log,quiet]{chmod a+x \docshots@tmpdir/\jobname/after.sh} \iexec[\docshots@log,quiet]{cd \docshots@tmpdir/\jobname; ./after.sh \n\space \hash\space \hash.tex}} {}}}% % \end{macrocode} % Here we delete |after.sh| which may exist here after the last % compilation of |pdflatex|: % \begin{macrocode} \iexec[\docshots@log,quiet]{rm -f \docshots@tmpdir/\jobname/after.sh} % \end{macrocode} % If a cropped version of the PDF with the required name already exists, we ignore this step. % Otherwise, we ask |pdfcrop| to crop the PDF: % \begin{macrocode} \IfFileExists{\docshots@tmpdir/\jobname/\hash.crop.pdf} {\message{docshots: on't pdfcrop, the PDF already exists (\docshots@tmpdir/\jobname/\hash.crop.pdf)^^J}} {\iexec[\docshots@log,quiet]{\docshots@pdfcrop\space --margins \docshots@margin\space \docshots@tmpdir/\jobname/\hash.pdf \docshots@tmpdir/\jobname/\hash.crop.pdf}}% % \end{macrocode} % We configure |fancyvrb|: % \begin{macrocode} \fvset{numbers=left,numbersep=3pt}% \fvset{frame=leftline,framerule=.4pt,rulecolor=\color{gray}}% \fvset{samepage=true}% \fvset{baselinestretch=1}% \ifdefined\docshots@small% \fvset{fontsize=\small}% \fi% \ifdefined\docshots@tiny% \fvset{fontsize=\scriptsize}% \fi% % \end{macrocode} % We render the two column content: % \begin{macrocode} \begingroup% \par% \tikz[baseline=(a.north)] \node (a) [draw=gray] {\includegraphics[width=\docshots@left] {\docshots@tmpdir/\jobname/\hash.crop.pdf}};% \hspace{\docshots@hspace}% \begin{minipage}[t]{\docshots@right}% \vspace{0pt}% \ifdefined\docshots@lstinputlisting% \lstinputlisting{\docshots@tmpdir/\jobname/\hash.tex}% \else\ifdefined\docshots@inputminted% \inputminted{\docshots@inputminted} {\docshots@tmpdir/\jobname/\hash.tex}% \else% \VerbatimInput{\docshots@tmpdir/\jobname/\hash.tex}% \fi\fi% \vspace{0pt}% \end{minipage}% \par% \endgroup% } % \end{macrocode} % \end{macro} % \begin{macro}{\docshotPrerequisite} % Then, we define |\docshotPrerequisite| command: % \begin{macrocode} \newcommand\docshotPrerequisite[1]{ \iexec[\docshots@log,quiet]{cp #1 \docshots@tmpdir/\jobname}% \message{docshots: file #1 copied to \docshots@tmpdir/\jobname/#1^^J}% } % \end{macrocode} % \end{macro} % \begin{macro}{\docshotAfter} % Finally, we define |\docshotAfter| command: % \begin{macrocode} \newcommand\docshotAfter[1]{ \iexec[\docshots@log,quiet]{/bin/echo -n '\detokenize{#1}' > \docshots@tmpdir/\jobname/after.sh}% \message{docshots: file \docshots@tmpdir/\jobname/after.sh created^^J}% } % \end{macrocode} % \end{macro} % \Finale %\clearpage %\PrintChanges %\clearpage %\PrintIndex