% \iffalse meta-comment (by the way, this file is contains UTF-8) % % Written in 2010, 2011 by Manuel Pégourié-Gonnard % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Manuel Pégourié-Gonnard % % This work consists of the main source file luacode.dtx % and the derived files % luacode.sty luacode.pdf % % Unpacking: % tex luacode.dtx % Documentation: % pdflatex luacode.dtx % %<*ignore> \begingroup \def\x{LaTeX2e}% \expandafter\endgroup \ifcase 0\ifx\install y1\fi\expandafter \ifx\csname processbatchFile\endcsname\relax\else1\fi \ifx\fmtname\x\else 1\fi\relax \else\csname fi\endcsname % %<*install> \input docstrip.tex \keepsilent \askforoverwritefalse \preamble See the source file for author and licensing information. \endpreamble \generate{% \usedir{tex/lualatex/luacode}% \file{luacode.sty}{\from{luacode.dtx}{texpackage}}% } \generate{% \usedir{doc/lualatex/luacode}% \file{test-luacode.tex}{\from{luacode.dtx}{testlatex}}% } \obeyspaces \Msg{************************************************************************} \Msg{*} \Msg{* To finish the installation you have to move the following} \Msg{* files into a directory searched by TeX:} \Msg{*} \Msg{* luacode.sty} \Msg{*} \Msg{* Happy TeXing!} \Msg{*} \Msg{************************************************************************} \endbatchfile % %<*ignore> \fi % %<*driver> \documentclass{ltxdoc} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{textcomp} \usepackage{lmodern} \usepackage{fixltx2e} \usepackage{booktabs} \usepackage{xspace} \usepackage[a4paper]{geometry} \usepackage[english]{babel} \usepackage[colorlinks]{hyperref} \usepackage{bookmark} \newcommand*\email [1] {<\href{mailto:#1}{#1}>} \newcommand \file {\nolinkurl} \newcommand \pk {\textsf} \newcommand \cmdname {\texttt} \pdfstringdefDisableCommands{% \def\cs#1{\@backslashchar #1}} \MakeShortVerb\| \begin{document} \DocInput{luacode.dtx}% \end{document} % % \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 \~} % % \title{The \pk{luacode} package} % \author{Manuel P\'egouri\'e-Gonnard \email{mpg@elzevir.fr}} % \date{v1.0 2010/11/08} % % \maketitle % % \begin{abstract} % Executing Lua code from within \TeX\ with |\directlua| can sometimes be % tricky: there is no easy way to use the percent character, counting % backslashes may be hard, and Lua comments don't work the way you expect. % This package provides the |\luaexec| command and the |luacode(*)| % environments to help with these problems. % \end{abstract} % % \tableofcontents % % \section{Documentation} % % For an introduction to the most important gotchas of |\directlua|, see % \file{lualatex-doc.pdf}. Before presenting the tools in this package, let me % insist that the best way to manage a non-trivial piece of Lua code is % probably to use an external file and source it from Lua, as explained in the % cited document. % % \medskip % % First, the exact syntax of |\directlua| has changed along version of % Lua\TeX, so this package provides a |\luadirect| command which is an exact % synonym of |\directlua| except that it doesn't have the funny, changing % parts of its syntax.\footnote{And it expands in two steps If you don't known % what it means, then you hopefully don't need to.} % % The problems with |\directlua| (or |\luadirect|) are mainly with \TeX\ % special characters. Actually, things are not that bad, since most special % characters do work, namely: |_|, |^|, |&|, \verb+$+, |{|, |}|. Three are a % bit tricky but they can be managed with |\string|: |\| and |~|. Only |%| is % really hard to obtain. Also, \TeX\ macros are expanded, which is good since % it allows to pass information from \TeX\ to Lua, but you must be careful % and use only purely expandable macros. % % The |\luaexec| command is similar to |\luadirect| but with a few additional % features:\footnote{And one major drawback: it is not purely expandable. See % above.} |\\| gives a double backslash (convenient in Lua strings), |\%| a % percent character, and |~| just works. If you happen to need a single % backslash, you can still use a construct like |\string\n| just as with % |\luadirect|. Also, \TeX\ macros are expanded. % % The |luacode| environment is similar, except that you can use |%| and other % special characters directly (but |\%| also works). Only the backslash and % the braces keep their special meaning, so that macros still work as usual, % and you still need to use a |\string| trick to get a single backslash. % % A variant |luacode*| goes further and makes even backslash a normal % character, so that you don't need any trick to obtain a single backslash. On % the other end, macros don't work any more. % % In addition, the line breaks in the environments are respected, so that you % can use line-wise Lua comments in the normal way, without mistakenly % commenting the rest of the chunk. % % \begin{center} % \begin{tabular}{rcccc} % \toprule % & |\luadirect| & |\luaexec| & |luacode| & |luacode*| \\ % \midrule % Macros & Yes & Yes & Yes & No \\ % Single backslash & Using |\string| & Using |\string| & Using |\string| & Just |\| \\ % Double backslash & |\string\\| & |\\| & |\\| & |\\| \\ % Tilde & |\string~| & |~| & |~| & |~| \\ % Sharp & |\string#| & |\#| & |\#| or |#| & |#| \\ % Percent & No easy way & |\%| & |\%| or |%| & |%| \\ % \TeX\ line comments & Yes & Yes & No & No \\ % Lua line comments & No & No & Yes & Yes \\ % \bottomrule % \end{tabular} % \end{center} % % Note that you cannot use the environments inside the argument of a command % (just as with verbatim commands and environments). If you wish to define % derived environments, you'll need to use |\luacode| \dots |\endluacode| % instead of the usual |\begin| |\end| pair in your environment's definition. % For the stared variant, use |\luacodestar| and |\endluacodestar|. % % The test file (section~\ref{test}, or \file{test-luacode.tex} in the same % directory as this document) provides stupid but complete examples. % % \section{Implementation} % % \begin{macrocode} %<*texpackage> % \end{macrocode} % % \subsection{Preliminaries} % % Catcode defenses. % % \begin{macrocode} \begingroup\catcode61\catcode48\catcode32=10\relax% = and space \catcode123 1 % { \catcode125 2 % } \catcode 35 6 % # \toks0{\endlinechar\the\endlinechar}% \edef\x{\endlinechar13}% \def\y#1 #2 {% \toks0\expandafter{\the\toks0 \catcode#1 \the\catcode#1}% \edef\x{\x \catcode#1 #2}}% \y 13 5 % carriage return \y 61 12 % = \y 32 10 % space \y 123 1 % { \y 125 2 % } \y 35 6 % # \y 64 11 % @ (letter) \y 39 12 % ' \y 40 12 % ( \y 41 12 % ) \y 42 12 % * \y 45 12 % - \y 46 12 % . \y 47 12 % / \y 91 12 % [ \y 93 12 % ] \y 94 7 % ^ \y 96 12 % ` \y 126 13 % ~ \toks0\expandafter{\the\toks0 \relax\noexpand\endinput}% \edef\y#1{\noexpand\expandafter\endgroup% \noexpand\ifx#1\relax \edef#1{\the\toks0}\x\relax% \noexpand\else \noexpand\expandafter\noexpand\endinput% \noexpand\fi}% \expandafter\y\csname luacode@sty@endinput\endcsname% % \end{macrocode} % % Package declaration. % % \begin{macrocode} \ProvidesPackage{luacode}[2011/05/24 v1.0 lua-in-tex helpers (mpg)] % \end{macrocode} % % Make sure Lua\TeX\ is used. % % \begin{macrocode} \RequirePackage{ifluatex} \ifluatex\else \PackageError{luacode}{LuaTeX is required for this package. Aborting.}{% This package can only be used with the LuaTeX engine\MessageBreak (command `lualatex'). Package loading has been stopped\MessageBreak to prevent additional errors.} \expandafter\luacode@sty@endinput \fi % \end{macrocode} % % Use \pk{luatexbase} for catcode tables. % % \begin{macrocode} \RequirePackage{luatexbase} % \end{macrocode} % % \subsection{Internal code} % % Execute a piece of code, with shortcuts for double-backslash, percent and % tilde, and trying to preserve newlines. This internal macro is long so % that we can use in the environment, while the corresponding user command % will be short. Make sure |~| is active. % % \begin{macrocode} \begingroup \catcode`\~\active \expandafter\endgroup \@firstofone{% \newcommand*\luacode@execute [1] {% \begingroup \escapechar92 \newlinechar10 \edef\\{\string\\}% \edef~{\string~}% \let\%=\luacode@percentchar \let\#=\luacode@sharpchar \expandafter\expandafter\expandafter\endgroup \luatexbase@directlua{#1}} } % \end{macrocode} % % Catcode 12 percent and sharp characters for use in the previous command. % % \begin{macrocode} \begingroup \escapechar\m@ne \edef\aux{\endgroup \unexpanded{\newcommand\luacode@percentchar}{\string\%}% \unexpanded{\newcommand\luacode@sharpchar }{\string\#}% }\aux % \end{macrocode} % % Generic code for environments; the argument is the name of a catcode % table. We're normally inside a group, but let's open a new one in case % we're called directly rather that using |\begin|. Define the end marker % to be |\end{}| with current catcodes. % % \begin{macrocode} \newcommand*\luacode@begin [1] {% \begingroup \escapechar92 \luatexcatcodetable#1\relax \edef\luacode@endmark{\string\end{\@currenvir}}% \expandafter\def \expandafter\luacode@endmark \expandafter{% \luatexscantextokens \expandafter{\luacode@endmark}}% \luacode@grab@body} % \end{macrocode} % % We'll define the body grabber in a moment, but let's see how the % environment ends now. % % \begin{macrocode} \newcommand\luacode@end{% \edef\luacode@next{% \noexpand\luacode@execute{\the\luacode@lines}% \noexpand\end{\@currenvir}}% \expandafter\endgroup \luacode@next} % \end{macrocode} % % It is not possible to grab the body using a macro with delimited % argument, since the end marker may contains open-group characters, % depending on the current catcode regime. So we collect it linewise and % check each line against the end marker. % % Storage for lines. % % \begin{macrocode} \newtoks\luacode@lines \newcommand*\luacode@addline [1] {% \luacode@lines\expandafter{\the\luacode@lines^^J#1}} % \end{macrocode} % % Loop initialisation. Set endlinechar explicitely so that we can use it % as a delimiter (and later when writing the code to Lua). % % \begin{macrocode} \newcommand \luacode@grab@body { \luacode@lines{}% \endlinechar10 \luacode@grab@lines} % \end{macrocode} % % The actual line-grabbing loop. % % \begin{macrocode} \long\def\luacode@grab@lines#1^^J{% \def\luacode@curr{#1}% \luacode@strip@spaces \ifx\luacode@curr\luacode@endmark \expandafter\luacode@end \else \expandafter\luacode@addline\expandafter{\luacode@curr}% \expandafter\luacode@grab@lines \fi} % \end{macrocode} % % Strip catcode 12 spaces from the beginning the token list inside % |\luacode@curr|. First we need catcode 12 space, then we % procede in the usual way. % % \begin{macrocode} \begingroup\catcode32 12 \expandafter\endgroup \@firstofone{\newcommand\luacode@spaceother{ }} \newcommand \luacode@strip@spaces {% \expandafter\luacode@strip@sp@peek\luacode@curr\@nil} \newcommand \luacode@strip@sp@peek {% \futurelet\@let@token\luacode@strip@sp@look} \newcommand \luacode@strip@sp@look {% \expandafter\ifx\luacode@spaceother\@let@token \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi{% \afterassignment\luacode@strip@sp@peek \let\@let@token= }{% \luacode@strip@sp@def }} \@ifdefinable \luacode@strip@sp@def \relax \def \luacode@strip@sp@def #1\@nil{% \def\luacode@curr{#1}} % \end{macrocode} % % Finally, we need a custom catcode table for the default environment: % everything other, except backslash, braces and letters which retain their % natural catcodes. % % Be carefull about the name of the macro for setting catcode ranges which % is currently changing in luatexbase. The group here doesn't matter since % catcode table settings are always global. % % \begin{macrocode} \newluatexcatcodetable \luacode@table@soft \begingroup \ifdefined\SetCatcodeRange \else \let\SetCatcodeRange\setcatcoderange \fi \setluatexcatcodetable \luacode@table@soft {% \luatexcatcodetable\CatcodeTableOther \catcode 92 0 \catcode 123 1 \catcode 125 2 \SetCatcodeRange {65}{90} {11} \SetCatcodeRange {97}{122}{11} } \endgroup % \end{macrocode} % % \subsection{Public macros and environments} % % The |\luadirect| and |\luaexec| macro. % % \begin{macrocode} \@ifdefinable\luadirect {\let\luadirect\luatexbase@directlua} \newcommand*\luaexec [1] {\luacode@execute{#1}} % \end{macrocode} % % Environments using different catcode tables. % % \begin{macrocode} \newenvironment {luacode} {\luacode@begin\luacode@table@soft} {} \newenvironment {luacode*} {\luacode@begin\CatcodeTableOther} {} \newcommand \luacodestar {\@nameuse{luacode*}} \def \endluacodestar {\@nameuse{endluacode*}} % \end{macrocode} % % We're already done! % % \begin{macrocode} \luacode@sty@endinput % % \end{macrocode} % % \section{Test file} \label{test} % % \begin{macrocode} %<*testlatex> \documentclass{minimal} \usepackage{luacode} \begin{document} \newcommand\foo{3} \( \luadirect{ texio.write_nl("Special chars: _ ^ & $ { } working.\string\n" .. "Backslashes need a bit of care.\string\n" .. "Sharps and tildes too: # doubled, but \string# and \string~") % a tex comment: no easy way to get a % tex.sprint("\string\\pi \string\\neq", tostring(math.pi)) % we can use TeX macros tex.sprint("-", math.sqrt(\foo)) } \) \( \luaexec{ texio.write_nl("Special chars: _ ^ & $ { } ~ working.\string\n" .. "Backslashes still need a bit of care.\string\n" .. "Single sharps are easier now: \#") % a tex comment: we also get a % below tex.sprint("\\pi \\neq ", tostring(math.pi):gsub('\%.', '+')) % we can use TeX macros tex.sprint("-", math.sqrt(\foo)) } \) \[ \begin{luacode} texio.write_nl("Special chars: _ ^ & $ { } ~ # % working.\string\n" .. "Only backslashes still need a bit of care.\string\n") -- a lua comment: we could use \% below, too tex.sprint("\\pi \\neq ", tostring(math.pi):gsub('%.', '+')) -- we can use TeX macros tex.sprint("-", math.sqrt(\foo)) \end{luacode} \] \[ \begin{luacode*} texio.write_nl("Special chars: _ ^ & $ { } ~ # % \\ working.\n") -- a lua comment: the backlash is doubled as in normal Lua code tex.sprint("\\pi \\neq ", tostring(math.pi):gsub('%.', '+')) -- no way to use a TeX variable here \end{luacode*} \] \newenvironment{mathluacode} { \[ \luacode }{ \endluacode \] } \newenvironment{mathluacode*}{ \[ \luacodestar }{ \endluacodestar \] } \begin{mathluacode} local foo = "A full line.\string\n" tex.sprint("\\pi \\neq ", tostring(math.pi):gsub('%.', '+')) -- a lua comment: we could have used \% above, too tex.sprint("-", math.sqrt(\foo)) \end{mathluacode} \begin{mathluacode*} local foo_bar = "A full line.\n" tex.sprint("\\pi \\neq ", tostring(math.pi):gsub('%.', '+')) -- a lua comment: no way to use a TeX variable here \end{mathluacode*} \end{document} % % \end{macrocode} % % % \Finale \endinput