summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/didactic/didactic.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/didactic/didactic.dtx')
-rw-r--r--macros/latex/contrib/didactic/didactic.dtx1241
1 files changed, 1241 insertions, 0 deletions
diff --git a/macros/latex/contrib/didactic/didactic.dtx b/macros/latex/contrib/didactic/didactic.dtx
new file mode 100644
index 0000000000..a11b78ebc2
--- /dev/null
+++ b/macros/latex/contrib/didactic/didactic.dtx
@@ -0,0 +1,1241 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2019--2020, 2022, 2024 by Daniel Bosk <daniel@bosk.se>
+% -------------------------------------------------------
+%
+% This file 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.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\ProvidesFile{didactic.dtx}
+%</driver>
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{didactic}
+%<*package>
+ [2024/04/08 v1.7 didactic]
+%</package>
+%<package>\RequirePackage{xparse}
+%<package>\RequirePackage{xkeyval}
+%<package>\RequirePackage{xstring}
+%<package>\RequirePackage{etoolbox}
+%<package>\RequirePackage{pythontex}
+%<package>\RequirePackage{minted}
+%<package>\RequirePackage{babel}
+%<package>\RequirePackage{translations}
+%<package>\RequirePackage{amsthm}
+%<package>\RequirePackage{thmtools}
+%<package>\PassOptionsToPackage{unq}{unique}
+%<package>\RequirePackage{unique}
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[utf8]{inputenc}
+\usepackage[swedish,british]{babel}
+\usepackage{pythontex}
+\usepackage[notheorems]{beamerarticle}
+\usepackage[marginparmargin=left]{didactic}
+\usepackage{lipsum}
+\usepackage{hyperref}
+\usepackage{cleveref}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+ \DocInput{didactic.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{v1.0}{2019/01/29}{Initial version}
+% \changes{v1.1}{2019/03/26}{Adds summary environment}
+% \changes{v1.2}{2019/10/26}{Adds lightblock, darkblock and coloured blocks}
+% \changes{v1.3}{2019/01/29}{Renames to didactic; adds tools for code examples}
+% \changes{v1.4}{2023/03/20}{%
+% Adds settings for memoir and beamer, contrasting code examples,
+% translations.
+% }
+% \changes{v1.5}{2023/03/25}{Adds |\ProvideSemanticEnv|}
+% \changes{v1.6}{2024/04/07}{%
+% Sets beamer bibliography item correctly.
+% Adds |fullwidth| environment, handles margins better.
+% Adds |sidecaption| environment and |\flushscap| command.
+% }
+% \changes{v1.7}{2024/04/08}{%
+% Adds |\NewNoteType| that improves |\newnotetype| with toggles.
+% }
+%
+% \GetFileInfo{didactic.dtx}
+%
+% \DoNotIndex{\newcommand,\newenvironment}
+%
+%
+% \title{The \textsf{didactic} package\thanks{This document
+% corresponds to \textsf{didactic}~\fileversion, dated \filedate.
+% Licensed under the terms of LPPL, version 1.3c or later.}}
+% \author{Daniel Bosk\\\texttt{daniel@bosk.se}}
+%
+% \maketitle
+%
+% \tableofcontents
+%
+% \section{Introduction}
+%
+% This package introduces some environments that are useful for writing
+% teaching material.
+% It also provides a few settings for |beamer| and |memoir| to make the
+% resulting document more readable.
+%
+% \section{Usage}
+%
+% The package automatically detects if |beamer| or |memoir| is loaded and
+% customizes the document accordingly.
+% \DescribeEnv{nobeamer}
+% \DescribeEnv{noarticle}
+% \DescribeEnv{nomemoir}
+% That can be prevented, however, by using the |nobeamer| or |nomemoir|
+% options.
+% The |noarticle| is to prevent the article versions of the (|beamer|)
+% environments to be defined.
+%
+% \DescribeEnv{notheorems}
+% The package also provides a few environments for |beamer| and |article| mode.
+% Particularly, it can define theorems and definitions, which might be defined
+% also by other packages.
+% To prevent this, use the |notheorems| option.
+%
+% \DescribeEnv{inner}
+% \DescribeEnv{outer}
+% \DescribeEnv{top}
+% \DescribeEnv{bottom}
+% When the package customizes |memoir| it sets the inner and outer margins to
+% fit margin notes better.
+% The |inner| and |outer| options can be used to set the inner and outer
+% margins to be used.
+% The |top| and |bottom| options can be used to set the top and bottom margins.
+%
+% \subsection{Beamer blocks and semantic environments for papers}
+%
+% \DescribeEnv{assumption}
+% \DescribeEnv{idea}
+% \DescribeEnv{question}
+% \DescribeEnv{exercise}
+% \DescribeEnv{activity}
+% \DescribeEnv{remark}
+% These environments provides wrappers around Beamer's |block| environment.
+% The idea is to complement the blocks provided by Beamer, such as |theorem|,
+% |definition| and |example|, with some more useful blocks.
+% Each of them provides a block with an appropriate title and optional subtitle
+% and is of a suitable colour.
+% For instance, consider the following.
+% \input{idea.tex}
+% That can be produced by the following code.
+% \inputminted[linenos]{latex}{idea.tex}
+%
+% \DescribeMacro{\ProvideSemanticEnv}
+% We can create new such block environments, that work both with |beamer| and
+% without, by using the |\ProvideSemanticEnv| command.
+% This command takes five arguments:
+% \begin{enumerate}
+% \item the name of the environment,
+% \item the name of the block environment to use (optional),
+% \item the title of the block,
+% \item options to pass to |thmtools| (optional),
+% \item the key of the translation of the refname of the block,
+% \item the key of the translation of the refnames of the block.
+% \item the key of the translation of the Refname of the block,
+% \item the key of the translation of the Refnames of the block.
+% \end{enumerate}
+% For example, the |idea| block above was created by the following code:
+% \inputminted{latex}{ProvideSemanticEnv.tex}
+%
+% \DescribeEnv{lightblock}
+% \DescribeEnv{darkblock}
+% We provide two shades of boxes, light coloured and dark coloured boxes.
+% These can be used to create boxes of various colours easily.
+% These two environments take two mandatory arguments: the first one is a
+% colour, the second is the title.
+%
+% In the text (not slides) the blocks are not coloured.
+% For instance, consider the following.
+% \input{lightblock.tex}
+% That can be produced by the following code.
+% \inputminted[linenos]{latex}{lightblock.tex}
+%
+% \DescribeEnv{blackblock}
+% \DescribeEnv{whiteblock}
+% \DescribeEnv{bwblock}
+% For instance, we provide a black block, white block and a black-white block.
+% These take only one mandatory argument: a title.
+%
+% \DescribeEnv{redblock}
+% \DescribeEnv{blueblock}
+% \DescribeEnv{purpleblock}
+% \DescribeEnv{greenblock}
+% \DescribeEnv{yellowblock}
+% \DescribeEnv{orangeblock}
+% We also provide a few predefined blocks in various common colours.
+% They all take a title as mandatory argument.
+%
+% \subsection{Tools for code examples}
+%
+% We also provide two commands for working with code examples: |lstexample| and
+% |runpython|.
+%
+% \DescribeMacro{\lstexample}
+% The |\lstexample| command allows us to typeset the source code of the
+% example.
+% For instance, |\lstexample{python}{hello.py}| produces the following:
+% \lstexample{python}{hello.py}
+%
+% We can also pass optional arguments directly to |minted| that is used to
+% typeset the code.
+% \begin{example}
+% |\lstexample[linenos,highlightlines=4]{python}{hello.py}| produces the
+% following.
+% \lstexample[linenos,highlightlines=4]{python}{hello.py}
+% \end{example}
+%
+% \DescribeMacro{\runpython}
+% We can also run the example code and include its output using the
+% |\runpython| macro.
+% \begin{example}
+% For instance, |\runpython{hello.py}| produces the following.
+% \runpython{hello.py}
+% \end{example}
+%
+% \DescribeMacro{\codebycode}
+% The |\codebycode| command is simply two |\lstexample| commands side by side:
+% |\codebycode[opt1]{lang1}{file1}[opt2]{lang2}{file2}|.
+% \codebycode
+% [breaklines,linenos]{python}{hello.py}
+% [breaklines,linenos,highlightlines=4]{python}{hello.py}
+%
+% \DescribeMacro{\runbyrun}
+% We can also put the output side by side using
+% |\runbyrun{hello.py}{hello.py}|.
+% \runbyrun{hello.py}{hello.py}
+%
+% \subsection{Adding margin notes of different kinds}
+%
+% \DescribeMacro{\indentedmarginpar}
+% We want to be able to put quite some content in the margins.
+% For this reason we want to have indented paragraphs in the margin notes.
+% We can use the |\indentedmarginpar{text}| command to do this.
+% For instance, consider the output in the margin.
+% \indentedmarginpar{%
+% This is an example of an indented margin paragraph.
+%
+% It can contain multiple paragraphs.
+% }
+%
+% \DescribeMacro{\newnotetype}
+% \DescribeMacro{\ltnote}
+% We also want to be able to use titled notes of different kinds.
+% We can use the |\newnotetype[fmtcmd]{type}{title}| command to define a new
+% type of note.
+% For instance |\ltnote| is defined as
+% \begin{center}
+% |\newnotetype{\ltnote}{\GetTranslationWarn{Learning theory}}|.
+% \end{center}
+% \ltnote{This is an example of a learning theory note.}
+%
+% We can also change the formatting of the title.
+% |\newnotetype[\textbf]{\bfnote}{Bold note}| and
+% |\bfnote{This is a bold note.}| gives us the note in the margin.
+% \newnotetype[\textbf]{\bfnote}{Bold note}
+% \bfnote{This is a bold note.}
+% \ltnote{Another example of a learning theory note.}
+%
+% \DescribeMacro{\NewNoteType}
+% We also have |\NewNoteType| which is almost synonymous to |\newnotetype|.
+% The difference is that |\NewNoteType| doesn't take a command as argument, but
+% just a name:
+% |\NewNoteType{ltnote}{Learning theory}| instead.
+% Then we also get |\ltnoteoff| to turn off the note and |\ltnoteon| to turn it
+% back on.
+%
+% Notes are off by default in |beamer|, but on by default otherwise.
+%
+% \StopEventually{}
+%
+% \section{Implementation}
+%
+% Let's start with the options.
+%
+% \subsection{Options}
+%
+% We have a few negative options, that is, if specified we don't want to do
+% them.
+% This means that we'll need to use conditionals.
+% So each option definition consists first of a |\newif| then setting it to
+% true, and finnally, a |\DeclareOption|.
+% The body of the |\DeclareOption| then sets the |\if| to false.
+% After all the options are declared we'll use |\ProcessOptions|.
+% After that we can have all code actually doing the work, all wrapped in |\if|
+% statements.
+%
+% \begin{environment}{nobeamer}
+% \begin{environment}{nobeamertheme}
+% \begin{environment}{noarticle}
+% This option is used to disable the |beamer| specific parts of the package.
+% Meaning that we don't customize |beamer| even when we find that it is loaded.
+% \begin{macrocode}
+\newif\if@didactic@beamer
+\@ifclassloaded{beamer}{\@didactic@beamertrue}{\@didactic@beamerfalse}
+\DeclareOptionX{nobeamer}{\@didactic@beamerfalse}
+\newif\if@didactic@article
+\@ifclassloaded{beamer}{\@didactic@articlefalse}{\@didactic@articletrue}
+\newif\if@didactic@beamertheme
+\@didactic@beamerthemetrue
+\DeclareOptionX{nobeamertheme}{\@didactic@beamerthemefalse}
+\DeclareOptionX{noarticle}{\@didactic@articlefalse}
+% \end{macrocode}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+% \begin{environment}{nomemoir}
+% This option is used to disable the |memoir| specific parts of the package.
+% Meaning that we don't customize |memoir| even when we find that it is loaded.
+% \begin{macrocode}
+\newif\if@didactic@memoir
+\@ifclassloaded{memoir}{\@didactic@memoirtrue}{\@didactic@memoirfalse}
+\DeclareOptionX{nomemoir}{\@didactic@memoirfalse}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{notheorems}
+% This option is used to disable defining the usual environments provided by
+% |amsmath|: definition, theorem, etc.
+% \begin{macrocode}
+\newif\if@didactic@theorems
+\@didactic@theoremstrue
+\DeclareOptionX{notheorems}{\@didactic@theoremsfalse}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{environment}{inner}
+% \begin{environment}{outer}
+% \begin{environment}{top}
+% \begin{environment}{bottom}
+% We also have some key--value options to control the margins.
+% \begin{macrocode}
+\newcommand\@didactic@margin@inner{20mm}
+\newcommand\@didactic@margin@outer{70mm}
+\newcommand\@didactic@margin@top{25mm}
+\newcommand\@didactic@margin@bottom{40mm}
+\DeclareOptionX{inner}[25mm]{\renewcommand\@didactic@margin@inner{#1}}
+\DeclareOptionX{outer}[65mm]{\renewcommand\@didactic@margin@outer{#1}}
+\DeclareOptionX{top}[25mm]{\renewcommand\@didactic@margin@top{#1}}
+\DeclareOptionX{bottom}[40mm]{\renewcommand\@didactic@margin@bottom{#1}}
+% \end{macrocode}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+% \begin{environment}{marginparmargin}
+% We also have an option to set the marginpar margin.
+% We simply pass this on to |memoir| and keep a record ourselves too.
+% We know that the default in |memoir| is |outer|.
+% \begin{macrocode}
+\newcommand\@didactic@marginparmargin{outer}
+\DeclareOptionX{marginparmargin}{%
+ \renewcommand\@didactic@marginparmargin{#1}
+ \@ifclassloaded{memoir}{%
+ \marginparmargin{#1}
+ \strictpagechecktrue
+ \checkandfixthelayout
+ }{}
+}
+% \end{macrocode}
+% \end{environment}
+%
+% Now that we've declared the options we can process them.
+% \begin{macrocode}
+\ProcessOptionsX\relax
+% \end{macrocode}
+%
+% \subsection{Customizing \texttt{beamer}}
+%
+% If |beamer| is loaded we want to customize it.
+% However, only if the user hasn't disabled this with the |nobeamer| option.
+% \begin{macrocode}
+\if@didactic@beamer
+% \end{macrocode}
+
+% If we use |beamer| we want to use the Berlin theme.
+% This theme guides the viewer very nicely, how must is left and where we are
+% in the presentation.
+% (The same is true for the presenter.)
+% \begin{macrocode}
+\if@didactic@beamertheme
+ \usetheme{Berlin}
+% \end{macrocode}
+% However, we want to customize the footline.
+% We want to add two lines in the footline.
+% We want to add the author (left) and institute (right) to the first line.
+% Then we add the title (left) and page number (right) to the bottom line.
+% \begin{macrocode}
+ \setbeamertemplate{footline}%{miniframes theme}
+ {%
+ \begin{beamercolorbox}[colsep=1.5pt]{upper separation line foot}
+ \end{beamercolorbox}
+ \begin{beamercolorbox}[ht=2.5ex,dp=1.125ex,%
+ leftskip=.3cm,rightskip=.3cm plus1fil]{author in head/foot}%
+ \leavevmode{\usebeamerfont{author in head/foot}\insertshortauthor}%
+ \hfill%
+ {\usebeamerfont{institute in head/foot}%
+ \usebeamercolor[fg]{institute in head/foot}\insertshortinstitute}%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[ht=2.5ex,dp=1.125ex,%
+ leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}%
+ {\usebeamerfont{title in head/foot}\insertshorttitle}%
+ \hfill%
+ \insertframenumber%
+ \end{beamercolorbox}%
+ \begin{beamercolorbox}[colsep=1.5pt]{lower separation line foot}
+ \end{beamercolorbox}
+ }
+% \end{macrocode}
+%
+% We also want to set the transparency of the covered items.
+% We also want to set the bibliography item to text, we need this to get proper
+% references (not icons) in the bibliography.
+% (We need that for certain bibliography styles.)
+% \begin{macrocode}
+ \setbeamercovered{transparent}
+ \setbeamertemplate{bibliography item}{\relax}
+\fi
+% \end{macrocode}
+%
+% Finally, we want to add a table of contents at the beginning of each section
+% and subsection.
+% We want these to be shaded, so that the current section is highlighted.
+% We also want to hide the subsections of the other sections.
+% \begin{macrocode}
+\AtBeginSection[]{%
+ \begin{frame}<beamer>
+ \tableofcontents[currentsection,
+ subsectionstyle=show/show/hide]
+ \end{frame}
+}
+\AtBeginSubsection[]{%
+ \begin{frame}<beamer>
+ \tableofcontents[currentsection,
+ subsectionstyle=show/shaded/hide]
+ \end{frame}
+}
+\fi% end \if@didactic@beamer
+% \end{macrocode}
+%
+% \subsection{Customizing \texttt{memoir}}
+%
+% If |memoir| is loaded we want to customize it.
+% However, only if the user hasn't disabled this with the |nomemoir| option.
+% \begin{macrocode}
+\if@didactic@memoir
+% \end{macrocode}
+%
+% We want to set up |memoir| to use the Tufte style.
+% This means that we want to put a lot of text in the margin.
+% We'll use margin notes and put all the footnotes in the margin.
+% We also want to use footnotes for references so that they also appear in the
+% margin.
+%
+% We want to use the |marginfix| package to fix the margin notes.
+% \begin{macrocode}
+\RequirePackage{marginfix}
+\setlrmarginsandblock{\@didactic@margin@inner}
+ {\@didactic@margin@outer}
+ {*}
+\setulmarginsandblock{\@didactic@margin@top}
+ {\@didactic@margin@bottom}
+ {*}
+
+\footnotesinmargin
+
+\RequirePackage{ragged2e}
+\renewcommand{\sidefootform}{\RaggedRight}
+\renewcommand{\foottextfont}{\footnotesize\RaggedRight}
+
+\setmpjustification{\RaggedRight}{\RaggedRight}
+
+% margin figure and caption typeset ragged against text block
+\setfloatadjustment{marginfigure}{\mpjustification}
+\setmarginfloatcaptionadjustment{figure}{\captionstyle{\mpjustification}}
+
+% side captions
+% https://tex.stackexchange.com/a/275626/17418
+\sidecapmargin{outer}
+\setsidecappos{t}
+\checkandfixthelayout
+\setsidecaps{\marginparsep}{\marginparwidth}
+\renewcommand{\sidecapstyle}{%
+ \captionstyle{\RaggedRight}
+}
+
+% From https://tex.stackexchange.com/a/324757/17418
+% Palatino for main text and math
+\RequirePackage[osf,sc]{mathpazo}
+% Helvetica for sans serif
+% (scaled to match size of Palatino)
+\RequirePackage[scaled=0.90]{helvet}
+% Bera Mono for monospaced
+% (scaled to match size of Palatino)
+\RequirePackage[scaled=0.85]{beramono}
+\setlxvchars\setxlvchars
+\checkandfixthelayout
+\nouppercaseheads
+% \end{macrocode}
+%
+% We also want to adapt the citation commands of a few packages to use
+% footnotes.
+% For these, we check if the package is loaded, if it is, we do the changes.
+% We don't load the packages ourselves, we assume the user has done that.
+% This also means that the |didactic| package should be loaded last.
+% \begin{macrocode}
+\@ifpackageloaded{biblatex}{%
+ \ExecuteBibliographyOptions{%
+ autocite=footnote,
+ singletitle=false,
+ %style=verbose,
+ %citestyle=verbose,
+ maxbibnames=99,
+ isbn=false,doi=false,url=false
+ }
+ % from https://tex.stackexchange.com/a/374059/17418
+ \DeclareCiteCommand{\fullauthorcite}
+ {\usebibmacro{prenote}}
+ {\usedriver
+ {\setcounter{maxnames}{99}% use up to 99 authors
+ \DeclareNameAlias{sortname}{default}}
+ {\thefield{entrytype}}}
+ {\multicitedelim}
+ {\usebibmacro{postnote}}
+}{}
+\@ifpackageloaded{csquotes}{%
+ \SetCiteCommand{\footcite}
+}{}
+% \end{macrocode}
+%
+% And that concludes the |memoir| part.
+% \begin{macrocode}
+\fi% end \if@didactic@memoir
+% \end{macrocode}
+%
+% \subsection{A side-caption environment for \texttt{beamer}}
+%
+% \begin{environment}{sidecaption}
+% When using |memoir|, we can use the |sidecaption| environment to put the
+% caption in the margin.
+% However, when using |beamer| we don't have this environment, so we need to
+% provide it with a suitable behaviour.
+% It's suitable to just translate it to a normal caption, as usually used in
+% |beamer|.
+% \begin{macrocode}
+\ProvideDocumentEnvironment{sidecaption}{omo+b}{%
+ #4
+ \caption{#2\IfValueT{#3}{\label{#3}}}
+}{\relax}
+% \end{macrocode}
+% \end{environment}
+%
+% \begin{macro}{\flushscap}
+% We also want to provide a command to flush a figure towards the caption.
+% \begin{macrocode}
+\NewDocumentCommand{\flushscap}{O{\centering}}{%
+ \@ifclassloaded{memoir}{%
+ \ifscapmargleft%
+ \flushleft%
+ \else%
+ \flushright%
+ \fi%
+ }{%
+ #1%
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{More semantic environments}
+%
+% We want to provide a set of environments (blocks) for |beamer|.
+% We want the names of the blocks to be translated.
+% We'll use the |translations| package for this.
+% That way we get the language used through the normal use of |babel|.
+%
+% We also want to have the same environments for the article mode, but in a
+% nicer format that the default of |beamerarticle|.
+% For instance, instead of
+% \begin{block}{Example}
+% This is an example.
+% \end{block}
+% we want something like
+% \begin{example}
+% This is an example.
+% \end{example}
+%
+% This means that we'll need to do one thing if |beamer| is loaded and another
+% if |beamerarticle| is loaded---or rather, when |beamer| is not loaded, we
+% should be able to use this without |beamer| and |beamerarticle|.
+%
+% We want to provide environments like this one:
+% \begin{exercise}\label{exercise}
+% This is an exercise.
+% \end{exercise}
+% \begin{exercise}\label{anotherexercise}
+% This is another exercise.
+% \end{exercise}
+% We can use |\cref| to refer to them, getting something like \cref{exercise} or
+% \cref{exercise,anotherexercise}.
+%
+% We also want it to work with different languages, provided there is a
+% translation.
+% We do Swedish here.
+%
+% \selectlanguage{swedish}
+% Vi kan också skapa exempel på svenska.
+% \begin{exercise}\label{exempel}
+% Detta är ett exempel.
+% \end{exercise}
+% \begin{exercise}\label{ytterligareexempel}
+% Detta är ytterligare ett exempel.
+% \end{exercise}
+% Vi kan referera till dem med |\cref|, vilket ger något som \cref{exempel}
+% eller \cref{exempel,ytterligareexempel}.
+% \selectlanguage{british}
+%
+% Let's also add another idea, but in Swedish.
+%
+% \selectlanguage{swedish}
+% \begin{idea}\label{ide}
+% Detta är en idé.
+% \end{idea}
+% Då har vi \cref{ide}, men vi hade även tidigare \cref{theidea}.
+% Tillsammans är de \cref{ide,theidea}.
+% \selectlanguage{british}
+%
+% We can also refer to them in English, \cref{ide} and \cref{theidea}
+% separately and together as \cref{ide,theidea}.
+%
+% \begin{macro}{\ProvideSemanticEnv}
+% We provide a command to create such environments.
+% This way we just run this command in the preamble, if |beamer| is loaded it
+% creates the block environments for |beamer|, otherwise it creates the
+% environments for the article.
+%
+% It can be used like this:
+% \begin{center}
+% |\ProvideSemanticEnv{test}[alertblock]{Test}[style=definition]|\\
+% \qquad|{test}{tests}{Test}{Tests}|
+% \end{center}
+% \begin{macrocode}
+\ProvideDocumentCommand{\ProvideSemanticEnv}{m o m o mmmm}{%
+ \@ifundefined{#1}{%
+ \@ifclassloaded{beamer}{% beamer
+% \end{macrocode}
+% For |beamer| we want to use the |block| environment, or one of the coloured
+% blocks that we provide below.
+% We let the second argument (optional) be the name of the block environment to
+% use.
+% This will be the easiest way to set the colour of the block.
+%
+% Lastly, we let the third argument be the title of the block.
+% This is the English title and also the key used to translate the title of the
+% block.
+% \begin{macrocode}
+ \IfValueTF{#2}{%
+ \ProvideDocumentEnvironment{#1}{o}{%
+ \begin{#2}{\GetTranslationWarn{#3}\IfValueT{##1}{: ##1}}
+ }{%
+ \end{#2}
+ }
+ }{%
+ \ProvideDocumentEnvironment{#1}{o}{%
+ \begin{block}{\GetTranslationWarn{#3}\IfValueT{##1}{: ##1}}
+ }{%
+ \end{block}
+ }
+ }
+% \end{macrocode}
+%
+% If we don't use |beamer|, we want to use the |thmtools| package to define the
+% environments.
+% The fourth argument (optional), will be passed as options to
+% |\declaretheorem|.
+% The fifth to eighth arguments are the keys of (meaning English) translations
+% of the refnames of the block.
+% \begin{macrocode}
+ }{% not beamer
+ \IfValueTF{#4}{%
+ \declaretheorem[
+ name=\GetTranslationWarn{#3},
+ refname={{\GetTranslationWarn{#5}},{\GetTranslationWarn{#6}}},
+ Refname={{\GetTranslationWarn{#7}},{\GetTranslationWarn{#8}}},
+ #4
+ ]{#1}
+ }{%
+ \declaretheorem[
+ style=definition,
+ name=\GetTranslationWarn{#3},
+ refname={{\GetTranslationWarn{#5}},{\GetTranslationWarn{#6}}},
+ Refname={{\GetTranslationWarn{#7}},{\GetTranslationWarn{#8}}}
+ ]{#1}
+ }
+ }
+% \end{macrocode}
+%
+% Since the |refname| and |Refname| options of |thmtools| doesn't seem to work
+% we will add the necessary |\crefname| and |\Crefname| commands at the
+% beginning of the document, for both |beamer| and non-|beamer| case.
+% \begin{macrocode}
+ \AtBeginDocument{%
+ \@ifpackageloaded{cleveref}{%
+ \crefname{#1}
+ {\GetTranslationWarn{#5}}
+ {\GetTranslationWarn{#6}}
+ \Crefname{#1}
+ {\GetTranslationWarn{#7}}
+ {\GetTranslationWarn{#8}}
+ }{%
+ \relax
+ }
+ }
+ }{\relax} % \@ifundefined{#1}
+} % \ProvideSemanticEnv
+% \end{macrocode}
+% \end{macro}
+% \begin{environment}{assumption}
+% \begin{environment}{idea}
+% \begin{environment}{question}
+% \begin{environment}{exercise}
+% \begin{environment}{activity}
+% \begin{environment}{remark}
+% \begin{environment}{summary}
+% Then let's define some useful environments.
+% \begin{macrocode}
+\ProvideSemanticEnv{assumption}[alertblock]{Assumption}
+ {assumption}{assumptions}{Assumption}{Assumptions}
+\ProvideSemanticEnv{idea}[greenblock]{Idea}
+ {idea}{ideas}{Idea}{Ideas}
+\ProvideSemanticEnv{question}[orangeblock]{Question}
+ {question}{questions}{Question}{Questions}
+\ProvideSemanticEnv{exercise}[yellowblock]{Exercise}
+ {exercise}{exercises}{Exercise}{Exercises}
+\ProvideSemanticEnv{activity}[yellowblock]{Activity}
+ {activity}{activities}{Activity}{Activities}
+\ProvideSemanticEnv{remark}[alertblock]{Remark}[%
+ numbered=no,style=remark
+ ]{remark}{remarks}{Remark}{Remarks}
+\ProvideSemanticEnv{summary}[block]{Summary}[%
+ numbered=no,style=remark
+ ]{summary}{summaries}{Summary}{Summaries}
+% \end{macrocode}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+% We also want to provide the normal environments for theorems and definitions
+% and such.
+% \begin{macrocode}
+\if@didactic@theorems
+ \ProvideSemanticEnv{definition}[block]{Definition}
+ {definition}{definitions}{Definition}{Definitions}
+ \ProvideSemanticEnv{theorem}[block]{Theorem}[%
+ numbered=unless unique,style=theorem
+ ]{theorem}{theorems}{Theorem}{Theorems}
+ \ProvideSemanticEnv{corollary}[block]{Corollary}[%
+ numbered=unless unique,style=theorem
+ ]{corollary}{corollaries}{Corollary}{Corollaries}
+ \ProvideSemanticEnv{lemma}[block]{Lemma}[%
+ numbered=unless unique,style=theorem
+ ]{lemma}{lemmas}{Lemma}{Lemmas}
+ \ProvideSemanticEnv{proof}[block]{Proof}[%
+ numbered=no,style=proof
+ ]{proof}{proofs}{Proof}{Proofs}
+ \ProvideSemanticEnv{solution}[block]{Solution}[%
+ numbered=no,style=proof
+ ]{solution}{solutions}{Solution}{Solutions}
+ \ProvideSemanticEnv{example}[exampleblock]{Example}
+ {example}{examples}{Example}{Examples}
+\fi
+% \end{macrocode}
+%
+%
+% \subsection{Translations}
+%
+% We also want to provide translations for the environments.
+% We want to provide those even if none of the packages above are loaded.
+% \begin{macrocode}
+\ProvideTranslation{swedish}{Assumption}{Antagande}
+\ProvideTranslation{swedish}{Assumptions}{Antagandena}
+\ProvideTranslation{swedish}{assumption}{antagande}
+\ProvideTranslation{swedish}{assumptions}{antagandena}
+\ProvideTranslation{swedish}{Idea}{Idé}
+\ProvideTranslation{swedish}{Ideas}{Idéerna}
+\ProvideTranslation{swedish}{idea}{idé}
+\ProvideTranslation{swedish}{ideas}{idéerna}
+\ProvideTranslation{swedish}{Question}{Fråga}
+\ProvideTranslation{swedish}{Questions}{Frågor}
+\ProvideTranslation{swedish}{question}{fråga}
+\ProvideTranslation{swedish}{questions}{frågor}
+\ProvideTranslation{swedish}{Exercise}{Övningsuppgift}
+\ProvideTranslation{swedish}{Exercises}{Övningsuppgifterna}
+\ProvideTranslation{swedish}{exercise}{övningsuppgift}
+\ProvideTranslation{swedish}{exercises}{övningsuppgifterna}
+\ProvideTranslation{swedish}{Activity}{Aktivitet}
+\ProvideTranslation{swedish}{Activities}{Aktiviteter}
+\ProvideTranslation{swedish}{activity}{aktivitet}
+\ProvideTranslation{swedish}{activities}{aktiviteter}
+\ProvideTranslation{swedish}{Note}{Anmärkning}
+\ProvideTranslation{swedish}{Notes}{Anmärkningar}
+\ProvideTranslation{swedish}{note}{anmärkning}
+\ProvideTranslation{swedish}{notes}{anmärkningar}
+\ProvideTranslation{swedish}{Remark}{Anmärkning}
+\ProvideTranslation{swedish}{Remarks}{Anmärkningar}
+\ProvideTranslation{swedish}{remark}{anmärkning}
+\ProvideTranslation{swedish}{remarks}{anmärkningar}
+\ProvideTranslation{swedish}{Summary}{Sammanfattning}
+\ProvideTranslation{swedish}{Summaries}{Sammanfattningar}
+\ProvideTranslation{swedish}{summary}{sammanfattning}
+\ProvideTranslation{swedish}{summaries}{sammanfattningar}
+\ProvideTranslation{swedish}{definition}{definition}
+\ProvideTranslation{swedish}{definitions}{definitionerna}
+\ProvideTranslation{swedish}{Definition}{Definition}
+\ProvideTranslation{swedish}{Definitions}{Definitionerna}
+\ProvideTranslation{swedish}{theorem}{sats}
+\ProvideTranslation{swedish}{theorems}{satserna}
+\ProvideTranslation{swedish}{Theorem}{Sats}
+\ProvideTranslation{swedish}{Theorems}{Satserna}
+\ProvideTranslation{swedish}{corollary}{följdsats}
+\ProvideTranslation{swedish}{Corollary}{Följdsats}
+\ProvideTranslation{swedish}{corollaries}{följdsatser}
+\ProvideTranslation{swedish}{Corollaries}{Följdsatser}
+\ProvideTranslation{swedish}{lemma}{hjälpsats}
+\ProvideTranslation{swedish}{lemmas}{hjälpsatserna}
+\ProvideTranslation{swedish}{Lemma}{Hjälpsats}
+\ProvideTranslation{swedish}{Lemmas}{Hjälpsatserna}
+\ProvideTranslation{swedish}{proof}{bevis}
+\ProvideTranslation{swedish}{Proof}{Bevis}
+\ProvideTranslation{swedish}{proofs}{bevisen}
+\ProvideTranslation{swedish}{Proofs}{Bevisen}
+\ProvideTranslation{swedish}{Solution}{Lösningsförslag}
+\ProvideTranslation{swedish}{Solutions}{Lösningsförslagen}
+\ProvideTranslation{swedish}{solution}{lösningsförslag}
+\ProvideTranslation{swedish}{solutions}{lösningsförslagen}
+\ProvideTranslation{swedish}{Example}{Exempel}
+\ProvideTranslation{swedish}{Examples}{Exempelen}
+\ProvideTranslation{swedish}{example}{exempel}
+\ProvideTranslation{swedish}{examples}{exempelen}
+% \end{macrocode}
+%
+%
+% \subsection{Coloured blocks}
+%
+% \begin{environment}{lightblock}
+% \begin{environment}{darkblock}
+% \begin{environment}{blackblock}
+% \begin{environment}{whiteblock}
+% \begin{environment}{bwblock}
+% \begin{environment}{redblock}
+% \begin{environment}{blueblock}
+% \begin{environment}{purpleblock}
+% \begin{environment}{greenblock}
+% \begin{environment}{yellowblock}
+% \begin{environment}{orangeblock}
+% Now we have the coloured blocks.
+% These we want to define even if |beamer| is not loaded, but for this we need
+% |beamerarticle| instead.
+% \begin{macrocode}
+\ProvideDocumentEnvironment{lightblock}{mm}{%
+ \setbeamercolor{block body}{bg=#1!10,fg=black}
+ \setbeamercolor{block title}{bg=#1,fg=black}
+ \setbeamercolor{local structure}{fg=#1}
+ \begin{block}{#2}
+}{%
+ \end{block}
+}
+\ProvideDocumentEnvironment{darkblock}{mm}{%
+ \setbeamercolor{block body}{bg=#1!10,fg=black}
+ \setbeamercolor{block title}{bg=#1,fg=white}
+ \setbeamercolor{local structure}{fg=#1}
+ \begin{block}{#2}
+}{%
+ \end{block}
+}
+\ProvideDocumentEnvironment{blackblock}{m}
+{\begin{darkblock}{black}{#1}}
+{\end{darkblock}}
+\ProvideDocumentEnvironment{whiteblock}{m}{%
+ \setbeamercolor{block body}{bg=white!10,fg=black}
+ \setbeamercolor{block title}{bg=white,fg=black}
+ \setbeamercolor{local structure}{fg=black}
+ \begin{block}{#1}
+}{%
+ \end{block}
+}
+\ProvideDocumentEnvironment{bwblock}{m}{%
+ \setbeamercolor{block body}{bg=white!10,fg=black}
+ \setbeamercolor{block title}{bg=black,fg=white}
+ \setbeamercolor{local structure}{fg=black}
+ \begin{block}{#1}
+}{%
+ \end{block}
+}
+\ProvideDocumentEnvironment{redblock}{m}
+{\begin{darkblock}{red}{#1}}
+{\end{darkblock}}
+\ProvideDocumentEnvironment{blueblock}{m}
+{\begin{darkblock}{blue}{#1}}
+{\end{darkblock}}
+\ProvideDocumentEnvironment{purpleblock}{m}
+{\begin{darkblock}{purple}{#1}}
+{\end{darkblock}}
+\ProvideDocumentEnvironment{greenblock}{m}
+{\begin{lightblock}{green}{#1}}
+{\end{lightblock}}
+\ProvideDocumentEnvironment{yellowblock}{m}
+{\begin{lightblock}{yellow}{#1}}
+{\end{lightblock}}
+\ProvideDocumentEnvironment{orangeblock}{m}
+{\begin{lightblock}{orange}{#1}}
+{\end{lightblock}}
+% \end{macrocode}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+% \subsection{Adding margin notes of different kinds}
+%
+% We want to add titled margin notes.
+% These margin notes should use indentation since they might contains several
+% paragraphs.
+%
+% \begin{macro}{\indentedmarginpar}
+% We start with the indented margin notes.
+% They simply take a text as argument and typeset it in the margin:
+% |\indentedmarginpar{this is the text}|.
+% \indentedmarginpar{this is the text}
+% \begin{macrocode}
+% Gives us indentation in the margin notes.
+% Adapted from https://tex.stackexchange.com/a/257171
+\NewDocumentCommand{\indentedmarginpar}{+m}{%
+ \@ifclassloaded{memoir}{\strictpagecheck}{\relax}%
+ \marginpar{%
+ \setlength{\parindent}{1.0em}\footnotesize
+ \@afterindentfalse\@afterheading #1
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\newnotetype}
+% Now, let's add a command to add margin notes with a title.
+% The |\newnotetype{\titlenote}{Title]| command creates a new command
+% |\titlenote| that takes a text as argument and typesets it in the margin with
+% the title |Title|: |\titlenote{this is the text}|.
+% \newnotetype{\titlenote}{Title}
+% \titlenote{this is the text}
+% \begin{macrocode}
+\NewDocumentCommand{\newnotetype}{omm}{%
+ \@ifclassloaded{beamer}{%
+ \NewDocumentCommand{#2}{+m}{\relax}
+ }{%
+ \IfValueTF{#1}
+ {\NewDocumentCommand{#2}{+m}{%
+ \indentedmarginpar{#1{#3:} ##1}%
+ }}
+ {\NewDocumentCommand{#2}{+m}{%
+ \indentedmarginpar{\emph{#3:} ##1}%
+ }}%
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\NewNoteType}
+% It can also be useful to be able to turn the notes off.
+% For instance, we might want notes to appear in one version, but not in
+% others.
+% Then we'd like a switch to simply turn them off.
+% Also, we don't want these notes to appear in |beamer|, so we define them to
+% be off by default in that case.
+%
+% However, to achieve this, we must change the behaviour when creating new
+% notes: we need the name, not the |\command| as an argument.
+% This is why we have the |\NewNoteType| command.
+%
+% \ltnote{This is a note with a title, using the note defined by the package.}
+% We can use it like this:
+% |\NewNoteType{lt}{Learning theory}|
+% \NewNoteType{lt}{Learning theory}
+% This creates a new note type |\lt|.
+% |\lt{This is a note}| yields the note on the side.
+% \lt{This is a note}
+%
+% We can also turn the notes off and on with |\ltoff| and |\lton|.
+% \ltoff
+% \lt{This is another note while off.}
+% \lton
+% \lt{This is another note while on, we didn't see the one we used while off.}
+% \ltnote{This is a note with a title, using the note defined by the package.}
+%
+% Let's look at the implementation.
+% We first create a new boolean for the note type.
+% This will keep track of whether the note type is on or off, should be typeset
+% in the margin or if it does nothing.
+% As mentioned above, we want to turn the notes off by default in |beamer|.
+% \begin{macrocode}
+\NewDocumentCommand{\NewNoteType}{omm}{%
+ \newbool{#2}
+ \@ifclassloaded{beamer}
+ {\boolfalse{#2}}
+ {\booltrue{#2}}
+% \end{macrocode}
+% Then we create the commands to turn the notes off and on.
+% These must be created with |\expandafter\newcommand| to get the name of the
+% note type.
+% (|\NewDocumentCommand| can't accept names constructed with |\csname|.)
+% \begin{macrocode}
+ \expandafter\newcommand\csname #2off\endcsname{\boolfalse{#2}}
+ \expandafter\newcommand\csname #2on\endcsname{\booltrue{#2}}
+% \end{macrocode}
+% We define the command differently depending on whether we want a custom
+% formatting for the title of not.
+% Same as before, we must use |\expandafter\newcommand| to construct these
+% commands.
+% \begin{macrocode}
+ \IfValueTF{#1}{%
+ \expandafter\newcommand\csname #2\endcsname[1]{%
+ \ifbool{#2}{%
+ \indentedmarginpar{#1{#3:} ##1}%
+ }{\relax}%
+ }}{%
+ \expandafter\newcommand\csname #2\endcsname[1]{%
+ \ifbool{#2}{%
+ \indentedmarginpar{\emph{#3:} ##1}%
+ }{\relax}%
+ }}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ltnote}
+% We provide a few different types of margin notes.
+% That way we can also include translations for them.
+% \begin{macrocode}
+\ProvideTranslation{swedish}{Learning theory}{Lärandeteori}
+\NewNoteType{ltnote}{\GetTranslationWarn{Learning theory}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Listing and running code examples}
+%
+% Let's turn our focus to |\lstexample| and |\runpython|.
+% We want to make it easy to typeset and print the output of example Python
+% programs in slides and texts.
+% We want to use PythonTeX to automatically run the code and typeset the source
+% code using |minted|.
+%
+% These are the same for both |beamer| and article mode.
+%
+% \begin{macro}{\lstexample}
+% The first part is easy.
+% To typeset the source file we simply need to use the minted package.
+% We provide an optional argument to pass options to minted.
+% \begin{macrocode}
+\NewDocumentCommand{\lstexample}{omm}{%
+ \IfValueTF{#1}
+ {\inputminted[escapeinside=||,#1]{#2}{#3}}
+ {\inputminted[escapeinside=||]{#2}{#3}}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\runpython}
+% Now, for the second part, printing the output, we do this in two steps.
+% First, we create a function using PythonTeX that runs a Python program and
+% prints it output.
+% We can use it like |\runpython{hello.py}| to run the program in |hello.py|.
+% The output is printed in verbatim mode.
+% Alternatively we could use |\runpython[opt]{hello.py}| to pass |opt| to the
+% underlying |fancyvrb| environment.
+%
+% Let's create that function in PythonTeX to run the example program file.
+% We simply execute it with Python 3 and capture its output.
+% Then we print the output to stdout, which is then captured by PythonTeX.
+% We use |pytex.add_dependencies| to add the file as a dependency to rerun the
+% code when necessary.
+% \begin{macrocode}
+\begin{pycode}
+import subprocess
+
+def run_module(m):
+ result = subprocess.run(["python3", m], capture_output=True)
+ print(result.stdout.decode("utf8").strip())
+ pytex.add_dependencies(m)
+
+def mintedoutput(m, opt):
+ if opt:
+ print(r'\begin{minted}[{}]{{text}}'.format(opt))
+ else:
+ print(r'\begin{minted}{text}')
+ run_module(m)
+ print(r'\end{minted}')
+\end{pycode}
+% \end{macrocode}
+%
+% Then we simply create a command that run that function with the file as
+% argument.
+% Then print the output in verbatim mode.
+% \begin{macrocode}
+\NewDocumentCommand{\runpython}{om}{%
+ \setpythontexautoprint{false}%
+ \pyc{run_module("#2")}%
+ \printpythontex[verbatim]%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Contrasting code examples}
+%
+% Sometimes we want to contrast two code examples side by side.
+% \begin{macro}{\textbytext}
+% For example |\textbytext{\lipsum[1]}{\lipsum[1]}| should typeset the two
+% examples side by side.
+% \textbytext{\lipsum[1]}{\lipsum[1]}
+% If we use the |memoir| class and our settings (|\if@didactic@memoir|), we
+% want to use the |adjustwidth| environment to expand the text block to better
+% fit them.
+% Otherwise we use the standard text block.
+%
+% To do this we first add a |fullwidth| environment\footnote{%
+% Similarly to \url{https://tex.stackexchange.com/a/350944/17418}.
+% }.
+% We can get the |adjustwidth| environment from the |changepage| package
+% whenever |memoir| isn't used.
+% \begin{macrocode}
+\RequirePackage{changepage}
+\newlength{\@didactic@textbytext@oldcolumnwidth}
+\NewDocumentEnvironment{fullwidth}{+b}{%
+ \setlength{\@didactic@textbytext@oldcolumnwidth}{\columnwidth}
+ \setlength{\columnwidth}{\textwidth+2em+\marginparwidth+\marginparsep}
+ \IfStrEqCase{\@didactic@marginparmargin}{%
+ {inner}{\begin{adjustwidth*}{-\marginparwidth-\marginparsep}{-2em}}
+ {left}{\begin{adjustwidth}{-\marginparwidth-\marginparsep}{-2em}}
+ {outer}{\begin{adjustwidth*}{-2em}{-\marginparwidth-\marginparsep}}
+ {right}{\begin{adjustwidth}{-2em}{-\marginparwidth-\marginparsep}}
+ }[\relax]
+ #1
+ \IfStrEqCase{\@didactic@marginparmargin}{%
+ {inner}{\end{adjustwidth*}}
+ {left}{\end{adjustwidth}}
+ {outer}{\end{adjustwidth*}}
+ {right}{\end{adjustwidth}}
+ }[\relax]
+ \setlength{\columnwidth}{\@didactic@textbytext@oldcolumnwidth}
+}{\relax}
+% \end{macrocode}
+%
+% Now to the |\textbytext| command.
+% We simply set up a |tabularx| environment with two columns and use it inside
+% a |fullwidth| environment.
+% \begin{macrocode}
+\NewDocumentCommand{\textbytext}{+m+m}{%
+ \begin{fullwidth}
+ \begin{tabularx}{\columnwidth}{XX}
+ #1 & #2
+ \end{tabularx}
+ \end{fullwidth}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\codebycode}
+% When we deal with code, we deal with verbatim data.
+% The easiest way to deal with this is to simply keep the code in files and
+% supply the file names to |\inputminted|.
+% The |\codebycode| command is simply two |\inputminted| commands side by side:
+% |\codebycode[opt1]{lang1}{file1}[opt2]{lang2}{file2}|.
+% \codebycode
+% [breaklines,linenos]{python}{hello.py}
+% [breaklines,linenos]{python}{hello.py}
+%
+% This gives us the following implementation.
+% We can reuse |\textbytext| to typeset the two examples side by side.
+% \begin{macrocode}
+\RequirePackage{tabularx}
+\RequirePackage{minted}
+\NewDocumentCommand{\codebycode}{ommomm}{%
+ \textbytext{%
+ \IfValueTF{#1}
+ {\lstexample[#1]{#2}{#3}}
+ {\lstexample{#2}{#3}}%
+ }{%
+ \IfValueTF{#4}
+ {\lstexample[#4]{#5}{#6}}
+ {\lstexample{#5}{#6}}%
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\runbyrun}
+% We also want to typeset the runs (|\runpython|).
+% We can use |\textbytext| to typeset the two outputs side by side.
+% \begin{macrocode}
+\NewDocumentCommand{\runbyrun}{mm}{%
+ \textbytext{\runpython{#1}}{\runpython{#2}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \Finale
+\endinput