diff options
author | Karl Berry <karl@freefriends.org> | 2024-02-21 21:10:10 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2024-02-21 21:10:10 +0000 |
commit | e534302325fefa02f44cfb0c723f38194ebeea6f (patch) | |
tree | fd00ccd3519cc3c59b9159708e253baeb1101ac5 /Master | |
parent | d2809b2028ad011468161045e74d908f59e65022 (diff) |
robust-externalize (21feb24)
git-svn-id: svn://tug.org/texlive/trunk@70046 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.pdf | bin | 1596591 -> 1630257 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.tex | 120 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/robust-externalize/robust-externalize.sty | 175 |
3 files changed, 290 insertions, 5 deletions
diff --git a/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.pdf b/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.pdf Binary files differindex 58ea1ff7146..4eca1dad3fd 100644 --- a/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.pdf +++ b/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.pdf diff --git a/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.tex b/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.tex index f06333b9fea..93d7f664e07 100644 --- a/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.tex +++ b/Master/texmf-dist/doc/latex/robust-externalize/robust-externalize.tex @@ -105,7 +105,7 @@ {\Large\bfseries Cache anything (\tikzname, tikz-cd, python…),\\in a robust, efficient and pure way.} \vspace{1em} - {Léo Colisson \quad Version 2.5}\\[3mm] + {Léo Colisson \quad Version 2.6}\\[3mm] {\href{https://github.com/leo-colisson/robust-externalize}{\texttt{github.com/leo-colisson/robust-externalize}}} \end{center} @@ -2000,6 +2000,89 @@ We provide a list of placeholders that are useful to escape parts of the strings \end{pgfmanualentry} \begin{pgfmanualentry} + \extractcommand\placeholderRemoveSpacesUntil\marg{placeholder}\opt{\oarg{nb of additional letters to remove}}\marg{separator}\@@ + \makeatletter% + \def\extrakeytext{style, } + \extractkey/robExt/placeholder remove spaces until=\marg{placeholder}\marg{separator}\@nil + \extractkey/robExt/remove spaces until=\marg{separator}\@nil + \extractkey/robExt/placeholder strictly remove spaces until=\marg{placeholder}\marg{separator}\@nil + \extractkey/robExt/strictly remove spaces until=\marg{separator}\@nil + \makeatother% + \pgfmanualbody + (new in v2.6) Removes all the spaces before |separator|, together with the separator itself and the next character (unless you use the |strictly| version, in that case the next character is not dropped, or if you change the default value of |additional letters to remove| that defaults to 1). Note that |prepend all lines| automatically apply it to the |__ROBEXT_MAIN_CONTENT_ORIG__| placeholder, i.e. the text typed by the user. + + This is useful, for instance, if your editor tends to automatically remove the indentation of your python code while indenting automatically the document. +\begin{codeAndResult} +%% See that the python code can be freely indented now: +\begin{CacheMeCode}{python print code and result, remove spaces until={>>>}} + >>> for i in range(2): + >>> print(f"Hello {i}") +\end{CacheMeCode} +\end{codeAndResult} +\end{pgfmanualentry} + + +\begin{pgfmanualentry} + \extractcommand\placeholderPrependAllLines\marg{placeholder}\marg{text}\@@ + \makeatletter% + \def\extrakeytext{style, } + \extractkey/robExt/placeholder prepend all lines=\marg{placeholder}\marg{text}\@nil + \extractkey/robExt/prepend all lines=\marg{text}\@nil + \makeatother% + \pgfmanualbody + (new in v2.6) Prepend all lines with |text|. This can be useful, for instance, if you want to indent a whole block of python code automatically. Note that the text is evaluated, so in case you want to insert multiple spaces, use |\space| like in:\\ + |prepend all lines={\space\space\space\space}|\\ +\begin{codeAndResult} +\begin{PlaceholderFromCode}{__TMP__} + >>> def f(x): % hye # 42 + >>> return 42 + >>> + >>> def g(z): + >>> return 48 +\end{PlaceholderFromCode} +\placeholderRemoveSpacesUntil{__TMP__}{>>>} +\placeholderPrependAllLines{__TMP__}{My text\space\space\space\space} +\printPlaceholderNoReplacement{__TMP__} +\end{codeAndResult} +Note that |prepend all lines| automatically adds the text to the |__ROBEXT_MAIN_CONTENT_ORIG__| placeholder, i.e. the text typed by the user. +\end{pgfmanualentry} + +\begin{pgfmanualentry} + \extractcommand\placeholderRemoveLeadingSpaces\marg{placeholder}\@@ + \makeatletter% + \def\extrakeytext{style, } + \extractkey/robExt/placeholder remove leading spaces=\marg{placeholder}\@nil + \extractkey/robExt/remove leading spaces\@nil + \extractkey/robExt/remove leading spaces if not disabled\@nil + \extractkey/robExt/do not remove leading spaces\@nil + \makeatother% + \pgfmanualbody + (new in v2.6) Remove the indentation of a placeholder (the |__ROBEXT_MAIN_CONTENT_ORIG__| placeholder, containing the content typed by the user, is used when not specified), by removing on each line the highest possible number of leading spaces (the same number of spaces is removed on all lines). +\begin{codeAndResult} +\begin{PlaceholderFromCode}{__TMP__} + def f(x): % hye # 42 + return 42 + + def g(z): + return 48 +\end{PlaceholderFromCode} +\placeholderRemoveLeadingSpaces{__TMP__} +\printPlaceholderNoReplacement{__TMP__} +\end{codeAndResult} +Note that |remove leading spaces if not disabled| is like |remove leading spaces|, except that it is not run if the |do not remove leading spaces| style is applied before. This is used inside some styles like |python| that cares about indentation to remove the leading spaces (before v2.6, it was forbidden to add any indentation to the python code), while allowing the user to disable it temporarily (who knows why?) by using the style: +\begin{verbatim} +do not remove leading spaces, python +\end{verbatim} +Since |remove leading spaces if not disabled| is enabled by default on python, it is therefore fine to indent your python code like in: +\begin{codeAndResult} +\begin{CacheMeCode}{python print code and result} + for i in range(3): + print(f"Hello {i}") +\end{CacheMeCode} +\end{codeAndResult} +\end{pgfmanualentry} + +\begin{pgfmanualentry} \extractcommand\placeholderHalveNumberHashesInplace\marg{placeholder}\@@ \extractcommand\placeholderDoubleNumberHashesInplace\marg{placeholder}\@@ \makeatletter% @@ -2074,6 +2157,30 @@ Compare \evalPlaceholder{__MACRO_EVALUATED__} and \evalPlaceholder{__MACRO_NOT_E Note that this works well for commands that expand completely, but some more complex commands might not expand properly (like |cref|). I need to investigate how to solve this issue, meanwhile you can still disable externalization for these pictures. \end{pgfmanualentry} +\begin{pgfmanualentry} + \extractcommand\lenToCm\opt{\oarg{unit}}\marg{expression}\@@ + \extractcommand\lenToCmNoUnit\opt{\oarg{unit}}\marg{expression}\@@ + \pgfmanualbody + |\lenToCm{.75\linewidth}| will output the length of |.75\linewidth| in cm by default, like |10cm|. If you want to change the unit, you can use the optional argument to specify a different unit (like |in| for inches, see |\dim_to_decimal_in_unit| for details). You can remove the unit at the end using |\lenToCmNoUnit{.75\linewidth}| (needs v2.6) to obtain something like |10| instead of |10cm|. These commands are helpful with |set placeholder eval| to send length from \LaTeX{} to your environment: +\begin{codeAndResult} +\begin{CacheMeCode}{python, set placeholder eval={__LINEWIDTH__}{\lenToCmNoUnit[in]{.75\linewidth}}} +import matplotlib.pyplot as plt +import matplotlib +from matplotlib.pyplot import figure +figure(figsize=(__LINEWIDTH__, __LINEWIDTH__)) +year = [2014, 2015, 2016, 2017, 2018, 2019] +tutorial_count = [39, 117, 111, 110, 67, 29] +plt.plot(year, tutorial_count, color="#6c3376", linewidth=2) +plt.title("Simple plot") +plt.xlabel('Year') +plt.ylabel('Number of futurestud.io Tutorials') +print(get_filename_from_extension(".pgf")) +# https://stackoverflow.com/a/52587591/4987648 +plt.savefig("__ROBEXT_OUTPUT_PDF__", bbox_inches="tight") +\end{CacheMeCode} +\end{codeAndResult} +\end{pgfmanualentry} + \subsubsection{Groups: the import system}\label{sec:importSystem} (This whole system was added v2.0.) @@ -2340,6 +2447,7 @@ This content is cached $\delta$. \def\extrakeytext{style, } \extractkey/robExt/new preset=\marg{name preset}\marg{preset options}\@nil \extractkey/robExt/add to preset=\marg{name preset}\marg{preset options}\@nil + \extractkey/robExt/add before preset=\marg{name preset}\marg{preset options}\@nil \makeatother% \pgfmanualbody You can then create your own style (or preset) in |\robExtConfigure| (that is basically an alias for |\pgfkeys{/robExt/.cd,#1}|) containing your template, add your own placeholders and commands to configure them etc. We provide two helper functions since v2.0:\\ @@ -2390,6 +2498,7 @@ This content is cached $\delta$. This content is cached $\delta$. \end{CacheMe} \end{codeexample} +The |before| variation (from 2.6) simply adds the style before the existing style. May be useful to disable default options of a style. \end{pgfmanualentry} \begin{pgfmanualentry} @@ -3837,7 +3946,7 @@ with open(get_verbatim_output(), "w") as f: \end{CacheMeCode} \end{codeAndResult} -\textbf{Importantly: you do not want to indent the whole content of CacheMeCode, or the spaces will also appear in the final code.} +Note that if you use a version before 2.6, you cannot indent further the python code (i.e.\ the first line must not start with any space). This is fixed in 2.6 with the addition of |remove leading spaces if not disabled| in the python preset by default, that will remove automatically any unnecessary indentation. If you use automatic indentation in your text editor, you might also like to use |remove spaces until| so that automatically indenting your whole document does not ruin the indentation of the python code. You can also generate some images. This code will produce the image in \cref{fig:pythonGeneratedImage2}: \begin{codeexample}[code only] @@ -4802,6 +4911,13 @@ Options > Configure TeXstudio > Editor > Replace tabs in text with spaces \section{Changelog} \begin{itemize} +\item v2.6: + \begin{itemize} + \item Added |\lenToCmNoUnit| + \item Added |\placeholderPrependAllLines| and alike + \item Added |remove spaces until| and alike + \item Added |placeholderRemoveLeadingSpaces| and alike + \end{itemize} \item v2.5: \begin{itemize} \item Add tikzit support diff --git a/Master/texmf-dist/tex/latex/robust-externalize/robust-externalize.sty b/Master/texmf-dist/tex/latex/robust-externalize/robust-externalize.sty index 0a36647946d..488cbb7c8f0 100644 --- a/Master/texmf-dist/tex/latex/robust-externalize/robust-externalize.sty +++ b/Master/texmf-dist/tex/latex/robust-externalize/robust-externalize.sty @@ -1,4 +1,4 @@ -\ProvidesPackage{robust-externalize}[2.5 Cache anything (tikz, latex, python) in a robust, efficient and pure way.] +\ProvidesPackage{robust-externalize}[2.6 Cache anything (tikz, latex, python) in a robust, efficient and pure way.] % todo: % change order argument replace from list, it is hard to read this way @@ -184,12 +184,17 @@ \cs_generate_variant:Nn \cs_replacement_spec:N { c } \cs_generate_variant:Nn \cs_argument_spec:N { c } +\cs_generate_variant:Nn \str_count_ignore_spaces:n { V } +\cs_generate_variant:Nn \str_count_spaces:n { e } + \cs_generate_variant:Nn \regex_extract_all:nnN { VVN, nVN, VVN } \cs_generate_variant:Nn \regex_extract_all:NnN { NVN } \cs_generate_variant:Nn \regex_match:nnTF { nVTF } +\cs_generate_variant:Nn \seq_set_split_keep_spaces:Nnn {Nnv} + %%% %%% String manipulation %%% @@ -234,6 +239,7 @@ \msg_new:nnn {robExt}{dependency does not exist}{The~dependency~#1~does~not~exist.} \msg_new:nnn {robExt}{missing compiled pdf parallel with log}{The~compilation~of~the~code~block~at~line~#2~failed:~the~following ~ file~is~indeed~missing: ~ #1.pdf. ~ The ~ compilation ~ command ~ "#3"~used~to~compile~the~environment~on~line~#2~ certainly ~ failed~with~errors:^^Jvvvvvv^^J\l__robExt_tmp_str^^J\string^\string^\string^\string^\string^\string^ ^^JSee~full~logs~#4~ or ~ in ~ #1-compilation.log.} +\msg_new:nnn {robExt}{remove spaces until non spaces characters}{The~placeholder~#1~contains~characters~other~than~spaces~(#2)~before~the~separator~#3.} \msg_new:nnn {robExt}{auto forward not in cachemecode}{Auto~forward~is~less~efficient~in~cacheMeCode.} @@ -674,7 +680,7 @@ if __name__ == '__main__': % For some reasons, newlines are displayed as \Omega. We need to replace them with \\ % https://tex.stackexchange.com/questions/694716/print-latex3-string-verbatim/694717 \tl_set_eq:Nc \l__robExt_tmp_str { l__robExt_placeholder_#2_str } - \tl_replace_all:Nnn \l__robExt_tmp_str {^^J} { \par } + \tl_replace_all:Nnn \l__robExt_tmp_str {^^J} { \mbox{}\par } % mbox is helpful to print empty lines \tl_replace_all:Nnn \l__robExt_tmp_str { ~ } { \ } \IfBooleanTF{#1}{\texttt{\use:c{l__robExt_placeholder_#2_str}}}{\begin{flushleft}\ttfamily% \l__robExt_tmp_str @@ -688,7 +694,7 @@ if __name__ == '__main__': % For some reasons, newlines are displayed as \Omega. We need to replace them with \\ % https://tex.stackexchange.com/questions/694716/print-latex3-string-verbatim/694717 \tl_set_eq:NN \l__robExt_tmp_str \l_robExt_result_str - \tl_replace_all:Nnn \l__robExt_tmp_str {^^J} { \par } + \tl_replace_all:Nnn \l__robExt_tmp_str {^^J} { \mbox{}\par } \tl_replace_all:Nnn \l__robExt_tmp_str { ~ } { \ } \IfBooleanTF{#1}{\texttt{\l__robExt_tmp_str}}{\begin{flushleft}\ttfamily% \l__robExt_tmp_str @@ -1300,6 +1306,128 @@ if __name__ == '__main__': } \let\placeholderReplaceInplaceEval\robExtPlaceholderReplaceInplaceEval + +% \group_begin: +% \char_set_catcode_other:N \^^I +% Usage: +% \robExtPlaceholderRemoveSpacesUntil{__MY_PLACEHOLDER__}{>>>} +\group_begin: +\char_set_catcode_other:N \^^I +\cs_new_protected:Npn \__robExt_replace_tabs:N #1 { + \str_replace_all:Nnn #1 { ^^I } { ~ } +} +\group_end: + +\NewDocumentCommand{\robExtPlaceholderRemoveSpacesUntil}{mO{1}m}{ + %% Cut the string in lines + \seq_set_split_keep_spaces:Nnv \l_tmpa_seq {^^J} { l__robExt_placeholder_#1_str } + \str_clear:c { l__robExt_placeholder_#1_str } + %% We iterate over the lines + \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl { + % \l_tmpa_tl contains the current line + \seq_set_split_keep_spaces:NnV \l_tmpb_seq {#3} \l_tmpa_tl + %% In any case, the first item must only contain spaces. + % The separator was present. Check that the line only contains spaces before the separator + \seq_get_left:NN \l_tmpb_seq \l_tmpb_tl + \__robExt_replace_tabs:N \l_tmpb_tl + %\str_replace_all:Nnn \l__robExt_tmp_str { ^^I } { ~ } + %\tl_replace_all:Nnn \l_tmpb_tl {^^I} {~} % we replace tabs with spaces, check if it works + % Save the size of the string + \int_set:Nn \l_tmpa_int {\str_count:N \l_tmpb_tl} + % we remove spaces + \tl_trim_spaces:N \l_tmpb_tl + \tl_if_empty:VTF \l_tmpb_tl { + \int_compare:nNnTF {\seq_count:N \l_tmpb_seq} > {1} { + % Empty line: we add it to the current placeholder + \str_put_right:cx { l__robExt_placeholder_#1_str } { + % the placeholder is a string, so I expect l_tmpa_tl to also be a string. No problem? + \str_range:Nnn \l_tmpa_tl {\l_tmpa_int + \str_count:n {#3} + 1 + #2} {-1} ^^J + } + } { + % No separator: it means the line is empty + \str_put_right:cn { l__robExt_placeholder_#1_str } {^^J} + } + }{ + % The string was not completely empty: raise an error + \msg_error:nnxxx{robExt}{remove spaces until non spaces characters}{#1}{\l_tmpa_tl}{#3} + } + } +} +\let\placeholderRemoveSpacesUntil\robExtPlaceholderRemoveSpacesUntil + +% Usage: +% \robExtPlaceholderPrependAllLines{__MY_PLACEHOLDER__}{ } +\NewDocumentCommand{\robExtPlaceholderPrependAllLines}{mm}{ + %% Cut the string in lines + \seq_set_split_keep_spaces:Nnv \l_tmpa_seq {^^J} { l__robExt_placeholder_#1_str } + \str_clear:c { l__robExt_placeholder_#1_str } + %% We iterate over the lines + \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl { + \str_put_right:cx { l__robExt_placeholder_#1_str } { + #2 + \l_tmpa_tl ^^J} + } +} +\let\placeholderPrependAllLines\robExtPlaceholderPrependAllLines + + +%% https://tex.stackexchange.com/questions/709973/latex3-efficient-way-to-remove-spaces-in-front-of-a-command/710006?noredirect=1#comment1765909_710006 +%% Modifies \l_tmpa_tl so that it contains the current number of spaces to remove +%% It also uses \l_tmpa_str +\group_begin: +\char_set_catcode_other:N \^^I +\cs_new_protected:Npn \__robExt_count_leading_whitespace:n #1 +{ + \str_set:Nn \l_tmpa_str {#1} + \str_replace_all:Nnn \l_tmpa_str { ^^I } { ~ } + \tl_if_blank:VF \l_tmpa_str + { + \int_set:Nn \l_tmpa_int + { + \int_min:nn + { \l_tmpa_int } + { + \str_count_spaces:N \l_tmpa_str - + \str_count_spaces:e + { \exp_last_unbraced:NV \use:n \l_tmpa_str {} } + } + } + } +} +\cs_generate_variant:Nn \__robExt_count_leading_whitespace:n { V } +\group_end: + +\NewDocumentCommand{\robExtPlaceholderRemoveLeadingSpaces}{m}{ + %% Cut the string in lines + \seq_set_split_keep_spaces:Nnv \l_tmpa_seq {^^J} { l__robExt_placeholder_#1_str } + %% Stores the number of spaces we can trim. Since we will take the minimum, we add infinity first + \int_set_eq:NN \l_tmpa_int \c_max_int + %% We iterate over the lines to find the minimum number of spaces to trim + \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl { + % If the line is empty, let's just remove it: + \int_compare:nNnTF {\str_count_ignore_spaces:V \l_tmpa_tl} > {0} { + % The line contains also letters, let us count the number of spaces. + \__robExt_count_leading_whitespace:V \l_tmpa_tl + } { + % line contains only spaces, we don't care + } + } + %% We check if the string was not all empty (e.g. if the content is empty) + \int_compare:nNnTF {\l_tmpa_int} = {\c_max_int} {} { + \str_clear:c { l__robExt_placeholder_#1_str } + %% We iterate over the lines to recreate the appropriate placeholder + \seq_map_variable:NNn \l_tmpa_seq \l_tmpa_tl { + \str_put_right:cx { l__robExt_placeholder_#1_str } { + \str_range:Nnn \l_tmpa_tl {\l_tmpa_int + 1} {-1} + ^^J + } + } + } +} +\let\placeholderRemoveLeadingSpaces\robExtPlaceholderRemoveLeadingSpaces + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%% Placeholders groups %%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2371,6 +2499,25 @@ if __name__ == '__main__': \robExtRemovePlaceholder{__ROBEXT_TMP__}% let us clean our variables \let\robExtCurrentlyDefiningPreset\undefined% }, + add before preset/.code 2 args={% + \robExtStrSetDoubleHash{\robExtTmpStr}{#2}% + % Sadly, \expanded{\noexpand } does not work, as I get extra {} around the def, creating a group + % so the simpler seems to use this library ^^ + \robExtPlaceholderFromString{__ROBEXT_TMP__}{\robExtTmpStr}% + \robExtEvalPlaceholderReplaceFromList{__ROBEXT_TMP__}{% + \pgfkeys{% + /robExt/.cd, + #1/.prefix style={% + % Some styles run differently if inside a preset or not, + % like if matches word. This macro helps with detecting it. + /utils/exec={\def\robExtCurrentlyDefiningPreset{}},% + __ROBEXT_TMP__% + },% + }% + }% + \robExtRemovePlaceholder{__ROBEXT_TMP__}% let us clean our variables + \let\robExtCurrentlyDefiningPreset\undefined% + }, new preset/.code 2 args={% \robExtStrSetDoubleHash{\robExtTmpStr}{#2}% % Sadly, \expanded{\noexpand } does not work, as I get extra {} around the def, creating a group @@ -2512,6 +2659,22 @@ if __name__ == '__main__': placeholder double number hashes in place/.code={\robExtPlaceholderDoubleNumberHashesInplace{#1}}, placeholder replace in place/.code n args={3}{\robExtPlaceholderReplaceInplace{#1}{#2}{#3}}, placeholder replace in place eval/.code n args={3}{\robExtPlaceholderReplaceInplaceEval{#1}{#2}{#3}}, + placeholder prepend all lines/.code 2 args={\robExtPlaceholderPrependAllLines{#1}{#2}}, + prepend all lines/.style={ + placeholder prepend all lines={__ROBEXT_MAIN_CONTENT_ORIG__}{#1}, + }, + placeholder remove spaces until/.code 2 args={\robExtPlaceholderRemoveSpacesUntil{#1}{#2}}, + remove spaces until/.style={ + placeholder remove spaces until={__ROBEXT_MAIN_CONTENT_ORIG__}{#1}, + }, + placeholder strictly remove spaces until/.code 2 args={\robExtPlaceholderRemoveSpacesUntil{#1}[0]{#2}}, + strictly remove spaces until/.style={ + placeholder remove spaces until nospace={__ROBEXT_MAIN_CONTENT_ORIG__}{#1}, + }, + placeholder remove leading spaces/.code={\robExtPlaceholderRemoveLeadingSpaces{#1}}, + remove leading spaces/.code={\robExtPlaceholderRemoveLeadingSpaces{__ROBEXT_MAIN_CONTENT_ORIG__}}, + remove leading spaces if not disabled/.code={\ifdefined\robExtDoNotRemoveLeadingSpaces\else\robExtPlaceholderRemoveLeadingSpaces{__ROBEXT_MAIN_CONTENT_ORIG__}\fi}, + do not remove leading spaces/.code={\def\robExtDoNotRemoveLeadingSpaces{}}, % Interface to set template set template/.style={ set placeholder first={__ROBEXT_TEMPLATE__}{#1}, @@ -3484,6 +3647,7 @@ finished_with_no_error() add import/.style={ add to placeholder no space={__ROBEXT_PYTHON_IMPORT__}{##1^^J}, }, + remove leading spaces if not disabled, } } @@ -3577,8 +3741,13 @@ print_file.close() { \dim_to_decimal_in_unit:nn { #2 } { 1 #1 } #1 } +\DeclareExpandableDocumentCommand{\robExtLenToCmNoUnit}{ O{cm} m } +{ + \dim_to_decimal_in_unit:nn { #2 } { 1 #1 } +} \ExplSyntaxOff \let\lenToCm\robExtLenToCm +\let\lenToCmNoUnit\robExtLenToCmNoUnit \robExtConfigure{ verbatim text/.style={ |