summaryrefslogtreecommitdiff
path: root/macros
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-07-13 03:00:55 +0000
committerNorbert Preining <norbert@preining.info>2021-07-13 03:00:55 +0000
commit4ac920a9909dd7d233ed3662bb576e1ae4ade873 (patch)
tree946aeeae5a3e59d9ec5aec51ee0520dbc712af55 /macros
parent1caaed73030c69f9f96c5138594089e2689e768b (diff)
CTAN sync 202107130300
Diffstat (limited to 'macros')
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/Changes3
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/README13
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.pdfbin0 -> 71043 bytes
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.tex102
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.bbx45
-rw-r--r--macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.cbx14
-rw-r--r--macros/latex/contrib/easybook/easybook.dtx320
-rw-r--r--macros/latex/contrib/easybook/easybook.pdfbin564912 -> 569332 bytes
-rw-r--r--macros/latex/contrib/iexec/README.md3
-rw-r--r--macros/latex/contrib/iexec/iexec.pdfbin108202 -> 108132 bytes
-rw-r--r--macros/latex/contrib/iexec/iexec.sty8
-rw-r--r--macros/latex/contrib/iexec/iexec.tex12
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-cn.pdfbin326597 -> 326597 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-en.pdfbin202124 -> 202113 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc-fr.pdfbin204110 -> 203801 bytes
-rw-r--r--macros/latex/contrib/projlib/ProjLib-doc.dtx10
-rw-r--r--macros/latex/contrib/projlib/ProjLib.dtx22
-rw-r--r--macros/luatex/latex/pyluatex/README.md56
-rw-r--r--macros/luatex/latex/pyluatex/interpreter.py71
-rw-r--r--macros/luatex/latex/pyluatex/json.lua388
-rw-r--r--macros/luatex/latex/pyluatex/pyluatex.lua137
-rw-r--r--macros/luatex/latex/pyluatex/pyluatex.pdfbin0 -> 64341 bytes
-rw-r--r--macros/luatex/latex/pyluatex/pyluatex.sty45
-rw-r--r--macros/luatex/latex/pyluatex/pyluatex.tex168
24 files changed, 1280 insertions, 137 deletions
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/Changes b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/Changes
new file mode 100644
index 0000000000..49fc0d39a0
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/Changes
@@ -0,0 +1,3 @@
+--- biblatex-spbasic.bbx|cbx
+
+0.01 2021/07/12 - first CTAN version
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/README b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/README
new file mode 100644
index 0000000000..326382c436
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/README
@@ -0,0 +1,13 @@
+Copyright (c) 2021- Herbert Voß hvoss@tug.org
+****************************************************************
+
+This is biblatex-spbasic,
+it provides a custom citation-style for biblatex/biber, for
+typesetting an article for Springer.
+
+It requires the main package biblatex.
+
+This material is subject to the LaTeX Project Public License.
+See https://latex-project.org/lppl/
+for the details of that license.
+
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.pdf
new file mode 100644
index 0000000000..820bf91239
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.pdf
Binary files differ
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.tex b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.tex
new file mode 100644
index 0000000000..c9b17c5883
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/doc/biblatex-spbasic.tex
@@ -0,0 +1,102 @@
+% biblatex-spbasic documentation 2021/07/11
+%
+% Copyright (c) 2021 Herbert Voß hvoss@tug.org
+
+\documentclass[toc=graduated,parskip=half-,DIV=13,fontsize=11pt,paper=a4]{scrartcl}
+
+\usepackage{eurosym} % Damit das Euro-Symbol dargestellt werden kann
+\usepackage{libertinus-otf} % Damit LaTex Umlaute usw. erkennt
+\setmonofont[Scale=MatchLowercase,FakeStretch=0.9]{AnonymousPro}
+\usepackage[english]{babel}
+\usepackage{listings}
+\lstset{basicstyle=\ttfamily}
+\usepackage{dtk-logos}
+\usepackage{enumitem}
+\setlist{nosep}
+
+\usepackage[babel]{csquotes}
+\usepackage{xurl}
+\usepackage[style=biblatex-spbasic]{biblatex}
+
+\usepackage{xspace}
+\addbibresource{biblatex-examples.bib}
+
+\def\bibsp{\texttt{biblatex-spbasic}\xspace}
+\def\bib{\texttt{biblatex}\xspace}
+\def\cs#1{\texttt{\textbackslash#1}}
+
+\usepackage{mdframed,xcolor}
+\def\showbib#1{%
+\begin{mdframed}[
+ leftmargin=0pt,
+ rightmargin=0pt,
+ linecolor=black,
+ backgroundcolor=black!10]
+\vspace{-\normalbaselineskip}
+\printbibliography
+\end{mdframed}}
+
+\usepackage[colorlinks,linktocpage]{hyperref}
+
+\begin{document}
+
+\title{biblatex-spbasic}
+\subtitle{Ver. 0.01}
+\author{Herbert Voß}
+
+\maketitle
+
+\vfill
+Thanks to: Moritz Wemheuer;
+\newpage
+
+\section{Introduction}
+This documentation briefly explains the adaptations of the \texttt{biblatex-spbasic}
+bibliography style and how it can be used. Some of the functions of \texttt{biblatex}
+that are based on are also indirectly explained. If you have any questions about the
+functions of \texttt{biblatex}, you should always consult the very good and detailed
+\texttt{biblatex} documentation.
+
+%Biblatex and biblatex-spbasic cannot be used meaningfully without at least skimming through the user guide in the biblatex documentation.
+For a quick start, the requirements for using \texttt{biblatex-spbasic} are briefly explained in the following section.
+
+
+\section{Installation}
+
+If you do have an official installation of \MiKTeX\ or \TeXLive, then everything would be there anyway, otherwise
+use the package manager and install \texttt{biblatex-spbasic}. If you do not have such an official distribution
+installed, then copy the two files
+
+\begin{verbatim}
+biblatex-spbasic.bbx
+biblatex-spbasic.cbx
+\end{verbatim}
+
+into your local \TeX\ directory and update the so-called file name database by running \texttt{texhash}.
+
+\section{Using the style}
+
+\texttt{biblatex-spbasic} is based on the packages from biblatex and especially the style \texttt{authoryear}.
+The reason for this is that \texttt{biblatex} provides all functions that make it possible to develop individual
+styles. However, the way in which »Springer Verlag« cites is so special compared to what is otherwise usual
+that additional functions are required to map them completely. These can be found in \texttt{authoryear.bbx}.
+You could have taken these out of the package and integrated them into \texttt{biblatex-spbasic}, but the
+effort involved seemed too great to me. In addition, the well-maintained \texttt{biblatex} package ensures
+that the functions provided by it are reliably retained and compatible despite the very rapid development of \texttt{biblatex}.
+
+It is obvious that using \texttt{biblatex-spbasic} needs the \texttt{biblatex} package, too.
+\texttt{biblatex-spbasic}is loaded by
+
+\begin{verbatim}
+\usepackage[style=biblatex-spbasic]{biblatex}
+\end{verbatim}
+
+It is possible to load additional optional arguments which refer to \texttt{biblatex}, the package
+\texttt{biblatex-spbasic} itself has no special arguments.
+
+\nocite{*}
+\printbibliography[title=Example-Bibliography]
+
+
+\end{document}
+
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.bbx b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.bbx
new file mode 100644
index 0000000000..65c09bc05b
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.bbx
@@ -0,0 +1,45 @@
+% biblatex-spbasic.bbx, Herbert Voß
+% Herbert Voß -- 2021
+% this style is an biblatex style for Springer's spbasic.bst
+%
+%% This material is subject to the LaTeX Project Public License.
+%% See https://latex-project.org/lppl/ for the details of that license.
+%%
+%
+\ProvidesFile{biblatex-spbasic.bbx}[2021/07/12 v0.01 biblatex bibliography style]
+% Release Notes can be found in the README
+
+\RequireBibliographyStyle{authoryear}
+\ExecuteBibliographyOptions{maxnames=3,minnames=1,terseinits,giveninits}
+
+\DeclareDelimFormat[bib,biblist]{nametitledelim}{\space}
+\renewbibmacro*{in:}{}
+
+\renewcommand*{\finentrypunct}{}% abschliessenden Punkt entfernen
+\renewcommand*{\newunitpunct}{\addspace}% Punkte entfernen
+
+\DeclareFieldFormat[article]{title}{#1.\isdot}% keine Anfuehrungsstriche und .
+\DeclareFieldFormat{title}{\mkbibemph{#1}.}% Punkt hinter Titel
+\DeclareFieldFormat[article]{number}{\mkbibparens{#1}}% (No)
+
+\renewbibmacro*{publisher+location+date}{% Reihenfolge aendern
+ \printlist{publisher}\setunit*{\addcomma\space}\printlist{location}\newunit}
+
+\renewbibmacro*{journal+issuetitle}{% Punkt zwischen Volume und Number entfernen
+ \usebibmacro{journal}\setunit*{\addspace}%
+ \iffieldundef{series}{}{\newunit\printfield{series}\setunit{\addspace}}%
+ \printfield{volume}\printfield{number}\setunit{\addcomma\space}%
+ \printfield{eid}\setunit{\addspace}%
+ \usebibmacro{issue+date}\setunit{\addcolon\space}\usebibmacro{issue}\newunit}
+
+\DeclareNameAlias{sortname}{family-given}
+\renewcommand*{\revsdnamepunct}{}
+\renewrobustcmd*{\bibinitperiod}{}
+\renewrobustcmd*{\bibinitdelim}{}
+\renewrobustcmd*{\bibinithyphendelim}{\mbox{-}}
+
+\DeclareDelimAlias{finalnamedelim}{multinamedelim}
+
+
+\endinput
+
diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.cbx b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.cbx
new file mode 100644
index 0000000000..aa2c6ce23c
--- /dev/null
+++ b/macros/latex/contrib/biblatex-contrib/biblatex-spbasic/latex/biblatex-spbasic.cbx
@@ -0,0 +1,14 @@
+% biblatex-spbasic.cbx, Herbert Voß
+% Herbert Voß -- 2021
+% this style is an biblatex style for Springer's spbasic.bst
+%
+%% This material is subject to the LaTeX Project Public License.
+%% See https://latex-project.org/lppl/ for the details of that license.
+%%
+\ProvidesFile{biblatex-spbasic.cbx}[2021/07/12 v0.01 biblatex bibliography style]
+% Release Notes can be found in the README
+
+\RequireCitationStyle{authoryear}
+
+\endinput
+
diff --git a/macros/latex/contrib/easybook/easybook.dtx b/macros/latex/contrib/easybook/easybook.dtx
index afcbe2f704..28934e5a5f 100644
--- a/macros/latex/contrib/easybook/easybook.dtx
+++ b/macros/latex/contrib/easybook/easybook.dtx
@@ -28,7 +28,7 @@
%
% \title{\sffamily easybook 文档类手册}
% \author{瞿毅}
-% \date{2021/07/11\hskip\ccwd\relax v1.27b\thanks{\url{https://gitee.com/texl3/easybook}}}
+% \date{2021/07/12\hskip\ccwd\relax v1.27c\thanks{\url{https://gitee.com/texl3/easybook}}}
%
% \maketitle
% \begin{abstract}
@@ -41,7 +41,7 @@
% 您在使用 \cls{easybook} 文档类编写文档前可能需要满足以下的条件:
% \begin{itemize}
% \item 使用 \hologo{XeLaTeX}(推荐)或 \hologo{LuaLaTeX} 两种编译方式。
-% \item 由于用到了一些 \LaTeX 和宏包较新的功能,建议安装最新的 \TeX 发行版,例如 \TeX Live 2021 或 \hologo{MiKTeX} 21.2 之后的版本。
+% \item 由于用到了一些 \LaTeX 和宏包较新的功能,建议安装最新的 \TeX 发行版,例如 \TeX~Live 2021 或 \hologo{MiKTeX} 21.2 之后的版本。
% \item 虽然手册对基本用法做了介绍,但这并不是入门教程,您应当具有一定的 \LaTeX 使用基础。
% \end{itemize}
%
@@ -60,7 +60,7 @@
% \end{document}
% \end{frameverb}
%
-% 或者直接使用 \pkg{easybase} 宏包,它的宏包选项有 \opt{class}、\opt{draft}、\opt{paper} 和 \opt{floatpage},包含了节 \ref{sec:interface options} 所示各个模块接口命令的功能,目前只适用于 \cls{ctexbook} 和 \cls{ctexart} 文档类。
+% 或者直接使用 \pkg{easybase} 宏包,目前适用于 \cls{ctexbook}、\cls{ctexrep}、\cls{ctexart} 以及标准文档类。它的宏包选项有 \opt{class}、\opt{draft}、\opt{paper} 和 \opt{floatpage},包含了节 \ref{sec:interface options} 所示各个模块接口命令的功能。当在 \textbf{标准文档类} 后载入时还可以使用 \pkg{ctex} 宏包的选项,将会传递给 \pkg{ctex} 宏包。
% \begin{frameverb}
% \documentclass{ctexbook}
%
@@ -88,17 +88,6 @@
% 当然也可以使用 \opt{latexmk} 及一些软件自带的编译工具,这里就不做介绍。 \\
% \ding{72} 需要注意正确 \textbf{编译索引} 要增加 \opt{-shell-escape} 命令行选项。
%
-% \subsection{字体设置}
-% \label{subsec:font settings}
-% 默认使用 \CTeX 预置中文字库,当开启 \opt{font = noto} 选项时需要安装开源字体,中文使用方正系列的{\songti 方正书宋}、{\heiti 方正黑体}、{\kaishu 方正楷体}和{\fangsong 方正仿宋},英文使用思源系列的{\rmfamily Noto Serif}、{\sffamily Noto Sans}和{\ttfamily Noto Sans Mono},数学字体默认使用 \pkg{notomath}。相关选项可以见节 \ref{sec:document class options} 中的 \opt{font} 选项,字体点击此处下载\href{https://wwe.lanzoui.com/b01ns361i}{下载地址}。
-%
-% 如果您不想使用 \CTeX 默认字体和方正、思源字体,\textbf{自定义字体} 需启用选项 \opt{font = none},并可在导言区设置中文字体,粗体与斜体不设置会产生警告。
-% \begin{ctexexam}
-% \setCJKmainfont{SimSun}[BoldFont = SimHei,ItalicFont = KaiTi]
-% \setCJKsansfont{SimHei}
-% \setCJKmonofont{FangSong}
-% \end{ctexexam}
-%
% \section{文档类选项}
% \label{sec:document class options}
% 标准 \cls{book} 文类与 \cls{ctexbook} 文类的选项同样适用于本文档。除此之外选项分为两类
@@ -108,7 +97,7 @@
% \end{itemize}
%
% \begin{function}[rEXP,added = 2021-01-05]{draft}
-% 开启草稿模式会加快编译速度,表现有显示页面边框、行溢出的地方显示黑色方块、图片变成占位方框、显示当前日期和关闭超链接渲染。不载入 \pkg{tcolorbox} 宏包支持盒子环境也会提高编译速度,详情见小节 \ref{subsec:box}。
+% 开启草稿模式会加快编译速度,表现有显示页面边框、行溢出的地方显示黑色方块、图片变成占位方框、显示当前日期和关闭超链接渲染。不载入 \pkg{tcolorbox} 宏包使用盒子环境也会提高编译速度,详情见小节 \ref{subsec:box}。
% \end{function}
%
% \begin{function}[rEXP,added = 2021-01-05]{newline}
@@ -130,15 +119,6 @@
% 同时开启 \opt{newline} 和 \opt{scheme = plain} 选项以符合英文原生风格。
% \end{function}
%
-% \begin{function}[rEXP,added = 2021-01-05,updated = 2021-06-18]{font}
-% \begin{syntax}
-% font = <adobe|fandol|mac|windows|linux|noto|(auto)|none>
-% \end{syntax}
-% 传递给 \cls{ctexbook} 设置字体,最好不要使用原有的 \opt{fontset} 选项,默认情况下使用自定义字体而不开启这个选项,可根据安装的字体及电脑系统选取。\opt{noto} 与 \opt{none} 选项的相关描述见小节 \ref{subsec:font settings},\opt{auto} 是一个各系统通用选项,会检测系统环境选取对应字体。
-% \changes{v1.21}{2021/01/12}{默认字体与 \CTeX 一致,不再是自定义字体。}
-% \changes{v1.25}{2021/05/04}{修复使用 \pkg{xeCJK} 与 \pkg{fontspec} 宏包的字体设置命令在 \hologo{LuaLaTeX} 下失效的问题。}
-% \end{function}
-%
% \begin{function}[rEXP,added = 2021-01-05,updated = 2021-01-13]{paper}
% \begin{syntax}
% paper = <(a4paper)|b5paper|c5paper|letterpaper|...>
@@ -162,6 +142,47 @@
% \changes{v1.26}{2021/06/15}{增加浮动环境比例参数选项 \opt{floatpage}。}
% \end{function}
%
+% \subsection{中文字体}
+% \begin{function}[rEXP,added = 2021-07-12]{cjkfont}
+% \begin{syntax}
+% cjkfont = <adobe|fandol|founder|mac|macnew|macold|ubuntu|windows|none>
+% \end{syntax}
+% 中文字体采用 \CTeX 宏集包含的字库并与其一致,具体配置方案可以查看 \CTeX 使用手册。它与 \opt{fontset} 选项是等效的,如果没有指定 \opt{cjkfont} 的值,将会自动检测用户的操作系统并选择相应的字体。
+% \changes{v1.27c}{2021/07/12}{新增 \opt{cjkfont} 选项设置中文字体,原 \opt{font} 选项设置英文字体,中文字体使用 \CTeX 的字库。}
+% \end{function}
+%
+% 如果需要使用其它中文字体,可以在启用选项 \opt{cjkfont = none} 后,再使用 \pkg{xeCJK} 宏包的相关命令设置字体以及声明字体族:
+% \begin{ctexexam}
+% \setCJKmainfont{SimSun}[BoldFont = SimHei,ItalicFont = KaiTi]
+% \setCJKsansfont{SimHei}
+% \setCJKmonofont{FangSong}
+% \newCJKfontfamily[song]\songti{SimSun}
+% \end{ctexexam}
+%
+% \subsection{英文字体}
+% \begin{function}[rEXP,added = 2021-01-05,updated = 2021-07-12]{font}
+% \begin{syntax}
+% font = <noto|garamond|times|libertine|palatino||(auto)|>
+% \end{syntax}
+% 预置的英文字体相关配置方案如下表所示,这些字体已经包含在了 \TeX~Live 发行版中,所以通常不需要再专门安装。如果您想使用其他英文字体,可以使用 \pkg{fontspec} 宏包的相关命令进行设置。
+% \changes{v1.21}{2021/01/12}{默认字体与 \CTeX 一致,不再是自定义字体。}
+% \changes{v1.25}{2021/05/04}{修复使用 \pkg{xeCJK} 与 \pkg{fontspec} 宏包的字体设置命令在 \hologo{LuaLaTeX} 下失效的问题。}
+% \end{function}
+%
+% \begin{center}
+% \begin{tabular}{cccc}
+% \toprule
+% & \sffamily{正文字体} & \sffamily{无衬线字体} & \sffamily{等宽字体} \\
+% \midrule
+% \opt{noto} & Noto Serif & Noto Sans & Noto Sans Mono \\
+% \opt{garamond} & EB Garamond & Libertinus Sans & LM Mono \\
+% \opt{palatino} & TG Pagella & Libertinus Sans & LM Mono \\
+% \opt{libertine} & TG Pagella & Libertinus Sans & LM Mono \\
+% \opt{times} & XITS & TG Heros & TG Cursor \\
+% \bottomrule
+% \end{tabular}
+% \end{center}
+%
% \subsection{article 模式}
% \begin{function}[rEXP,added = 2021-03-16]{class}
% \begin{syntax}
@@ -351,7 +372,7 @@
% \label{subsec:hyperlinks}
% \begin{function}[EXP,added = 2021-01-05,updated = 2021-07-03]{linktype,linkcolor,linkcol-all,linktoc}
% \begin{syntax}
-% linktype = <(edge)|various|none>
+% linktype = <(edge)|colors|none>
% linkcolor = <fresh|cutepink|(navyblue)|crimson>
% linkcol-all = <HTML颜色代码>
% linktoc = <none|section|page|(all)>
@@ -413,7 +434,7 @@
% listing-cap = <(\tn{sffamily}\tn{small})>
% footnote = <(\tn{rmfamily})>
% marginpar = <(\tn{rmfamily}\tn{footnotesize})>
-% math = <times|(noto)|notosans|scholax|stix|charter|ebgaramond|libertine|none>
+% math = <times|(noto)|notosans|nc|stix|charter|garamond|libertine|none>
% \end{syntax}
% \ding{229} 以上选项路径为 \opt{subfont/...}
% \changes{v1.10}{2021/01/08}{加入自定义非正文字体选项。}
@@ -835,7 +856,7 @@
% \tn{end}\{hangparas\}
% \end{syntax}
% \tn{hangpara} 命令使其后的一个段落保持悬挂缩进,\env{hangparas} 环境使其中的段落均保持悬挂缩进。缩进将以 \meta{缩进长度} 从每个段落的 \meta{缩进开始行数} 开始。
-% \changes{v1.27b}{2021/07/11}{增加悬挂缩进段落命令 \tn{hangpara} 和环境 \env{hangparas}。}
+% \changes{v1.27c}{2021/07/11}{增加悬挂缩进段落命令 \tn{hangpara} 和环境 \env{hangparas}。}
% \end{function}
%
% \subsection{代码}
@@ -1082,7 +1103,7 @@
% \section{载入的宏包}
% 以下为 \cls{easybook} 直接调用的关键宏包,带有 \ding{75} 符号的宏包并未载入它们,仅做了预配置和兼容性处理,可根据需要在导言区手动载入以实现相关的功能。
% \begin{description}
-% \item[ctexbook] 提供中文排版的通用框架。
+% \item[ctex] 提供中文排版的通用框架。
% \item[xcolor] 提供任意颜色的设定与混合,已载入了 \opt{svgnames} 颜色库。
% \item[footmisc] 更改脚注排版的方法的集合。
% \item[amsmath] 提供 \LaTeX 中的数学功能。
@@ -1164,7 +1185,7 @@
%<*class>
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
\RequirePackage{l3keys2e}
-\ProvidesExplClass{easybook}{2021/07/11}{1.27b}
+\ProvidesExplClass{easybook}{2021/07/12}{1.27c}
{Typeset Chinese theses or books}
\bool_set_false:N \l__eb_compile_draft_bool
@@ -1173,6 +1194,7 @@
\bool_set_true:N \l__eb_page_twoside_bool
\bool_set_true:N \l__eb_class_book_bool
\tl_new:N \g__eb_config_tl
+\tl_new:N \l__eb_font_choice_tl
\clist_new:N \g__eb_options_clist
\cs_new_protected:Npn \eb_put_ctexbook:n #1
{ \PassOptionsToClass{#1}{ctexbook} }
@@ -1184,17 +1206,11 @@
enmode .meta:n = { newline,scheme = plain },
font .choices:nn =
- { adobe,fandol,mac,windows,none }
- { \eb_put_ctexbook:n { fontset = \l_keys_choice_tl } },
- font/noto .code:n =
- {
- \bool_set_true:N \l__eb_font_noto_bool
- \eb_put_ctexbook:n { fontset = none }
- },
- font/auto .code:n = { },
- font/linux .code:n = \eb_put_ctexbook:n { fontset = ubuntu },
+ { noto,garamond,times,libertine,palatino,auto }
+ { \tl_set:Nn \l__eb_font_choice_tl {#1} },
font .value_required:n = true,
font .initial:n = auto,
+ cjkfont .code:n = \eb_put_ctexbook:n { fontset = #1 },
paper .choice:,
paper .value_required:n = true,
@@ -1239,28 +1255,19 @@
\RequirePackage{easybase}
\ctex_at_end:n
{
+ \use:c { eb@font@load@\l__eb_font_choice_tl }
\tl_if_empty:NF \g__eb_config_tl
{ \file_input:n { \g__eb_config_tl } }
}
\sys_if_engine_xetex:TF
{
- \cs_new_eq:NN \eb_set_family:nnn \xeCJK_set_family:nnn
+ \cs_new_eq:NN \eb_set_family:nnn \xeCJK_set_family:nnn
\cs_new_eq:NN \eb_switch_family:n \xeCJK_switch_family:n
- }
- {
- \cs_new_eq:NN \eb_set_family:nnn \ctex_ltj_set_family:nnn
+ }{
+ \cs_new_eq:NN \eb_set_family:nnn \ctex_ltj_set_family:nnn
\cs_new_eq:NN \eb_switch_family:n \ctex_ltj_switch_family:n
}
-\cs_new_protected:Npn \eb_font_double_engine_set:n #1
- {
- \exp_args:Nc \RenewDocumentCommand {set#1font}{O{}mO{}}
- {\use:c { eb_set#1font:nn } {##2} {##1,##3}}
- }
-\eb_clist_map_function:nN
- { main,sans,mono,CJKmain,CJKsans,CJKmono }
- \eb_font_double_engine_set:n
-
\cs_new_protected:Npn \eb_setmainfont:nn #1#2
{ \__fontspec_main_setmainfont:nn {#2} {#1} }
\cs_new_protected:Npn \eb_setsansfont:nn #1#2
@@ -1273,33 +1280,24 @@
{ \eb_set_family:nnn { \CJKsfdefault } {#2} {#1} }
\cs_new_protected:Npn \eb_setCJKmonofont:nn #1#2
{ \eb_set_family:nnn { \CJKttdefault } {#2} {#1} }
-\cs_new_protected:Npn \eb_set_zhfont_songti:nn #1#2
- { \eb_set_family:nnn { songti } {#2} {#1} }
-\cs_new_protected:Npn \eb_set_zhfont_heiti:nn #1#2
- { \eb_set_family:nnn { heiti } {#2} {#1} }
-\cs_new_protected:Npn \eb_set_zhfont_kaishu:nn #1#2
- { \eb_set_family:nnn { kaishu } {#2} {#1} }
-\cs_new_protected:Npn \eb_set_zhfont_fangsong:nn #1#2
- { \eb_set_family:nnn { fangsong } {#2} {#1} }
-
-\tl_const:Nn \eb_option_zhfont_tl
- { UprightFont = *,AutoFakeBold = 1.5,ItalicFont = * }
-\cs_new_protected:Npx \eb_setCJKmainfont:n #1
- { \eb_setCJKmainfont:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_setCJKsansfont:n #1
- { \eb_setCJKsansfont:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_setCJKmonofont:n #1
- { \eb_setCJKmonofont:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_set_zhfont_songti:n #1
- { \eb_set_zhfont_songti:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_set_zhfont_heiti:n #1
- { \eb_set_zhfont_heiti:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_set_zhfont_kaishu:n #1
- { \eb_set_zhfont_kaishu:nn {#1} { \eb_option_zhfont_tl } }
-\cs_new_protected:Npx \eb_set_zhfont_fangsong:n #1
- { \eb_set_zhfont_fangsong:nn {#1} { \eb_option_zhfont_tl } }
-
-\bool_if:NT \l__eb_font_noto_bool
+\cs_new_protected:Npn \eb_font_double_engine_set:n #1
+ {
+ \exp_args:Nc \RenewDocumentCommand { set#1font }{O{}mO{}}
+ {\use:c { eb_set#1font:nn } {##2} {##1,##3}}
+ }
+\eb_clist_map_function:nN
+ { main,sans,mono,CJKmain,CJKsans,CJKmono }
+ \eb_font_double_engine_set:n
+\RenewDocumentCommand{\newCJKfontfamily}{omO{}mO{}}
+ {
+ \tl_set:Nx \l_tmpa_tl
+ { \tl_if_novalue:nTF {#1} { \cs_to_str:N #2 } {#1} }
+ \cs_new_protected:Npx #2
+ { \eb_switch_family:n { \l_tmpa_tl } }
+ \eb_set_family:nnn { \l_tmpa_tl } {#3,#5} {#4}
+ }
+
+\cs_new_protected:Npn \eb@font@load@noto
{
\eb_setmainfont:nn { NotoSerif }
{
@@ -1321,22 +1319,94 @@
UprightFont = *-Regular,
BoldFont = *-Bold
}
- \eb_setCJKmainfont:nn { FZShuSong-Z01S }
+ }
+\cs_new_protected:Npn \eb@font@load@times
+ {
+ \eb_setmainfont:nn { XITS }
+ {
+ Extension = .otf,
+ UprightFont = *-regular,
+ BoldFont = *-bold,
+ ItalicFont = *-italic,
+ BoldItalicFont = *-bolditalic
+ }
+ \eb_setsansfont:nn { texgyreheros }
{
- UprightFont = *,
- BoldFont = FZHei-B01S,
- ItalicFont = FZKai-Z03S
+ Extension = .otf,
+ UprightFont = *-regular,
+ BoldFont = *-bold,
+ ItalicFont = *-italic,
+ BoldItalicFont = *-bolditalic
+ }
+ \eb_setmonofont:nn { texgyrecursor }
+ {
+ Extension = .otf,
+ UprightFont = *-regular,
+ BoldFont = *-bold,
+ ItalicFont = *-italic,
+ BoldItalicFont = *-bolditalic,
+ Ligatures = CommonOff
}
- \eb_setCJKsansfont:n { FZHei-B01S }
- \eb_setCJKmonofont:n { FZFangSong-Z02S }
- \eb_set_zhfont_songti:n { FZShuSong-Z01S }
- \eb_set_zhfont_heiti:n { FZHei-B01S }
- \eb_set_zhfont_kaishu:n { FZKai-Z03S }
- \eb_set_zhfont_fangsong:n { FZFangSong-Z02S }
- \cs_new_protected:Npn \songti { \eb_switch_family:n { songti } }
- \cs_new_protected:Npn \heiti { \eb_switch_family:n { heiti } }
- \cs_new_protected:Npn \kaishu { \eb_switch_family:n { kaishu } }
- \cs_new_protected:Npn \fangsong { \eb_switch_family:n { fangsong } }
+ }
+\cs_new_protected:Npn \eb_font_load_libertinus_sans:
+ {
+ \eb_setsansfont:nn { LibertinusSans }
+ {
+ Extension = .otf,
+ UprightFont = *-Regular,
+ BoldFont = *-Bold,
+ ItalicFont = *-Italic
+ }
+ }
+\cs_new_protected:Npn \eb_font_load_lmmonolt_mono:
+ {
+ \eb_setmonofont:nn { lmmonolt10 }
+ {
+ Extension = .otf,
+ UprightFont = *-regular,
+ BoldFont = *-bold,
+ ItalicFont = *-oblique,
+ BoldItalicFont = *-boldoblique
+ }
+ }
+\cs_new_protected:Npn \eb@font@load@garamond
+ {
+ \eb_setmainfont:nn { EBGaramond }
+ {
+ Extension = .otf,
+ UprightFont = *-Regular,
+ BoldFont = *-Bold,
+ ItalicFont = *-Italic,
+ BoldItalicFont = *-BoldItalic
+ }
+ \eb_font_load_libertinus_sans:
+ \eb_font_load_lmmonolt_mono:
+ }
+\cs_new_protected:Npn \eb@font@load@libertine
+ {
+ \eb_setmainfont:nn { LibertinusSerif }
+ {
+ Extension = .otf,
+ UprightFont = *-Regular,
+ BoldFont = *-Bold,
+ ItalicFont = *-Italic,
+ BoldItalicFont = *-BoldItalic
+ }
+ \eb_font_load_libertinus_sans:
+ \eb_font_load_lmmonolt_mono:
+ }
+\cs_new_protected:Npn \eb@font@load@palatino
+ {
+ \eb_setmainfont:nn { texgyrepagella }
+ {
+ Extension = .otf,
+ UprightFont = *-regular,
+ BoldFont = *-bold,
+ ItalicFont = *-italic,
+ BoldItalicFont = *-bolditalic
+ }
+ \eb_font_load_libertinus_sans:
+ \eb_font_load_lmmonolt_mono:
}
\ctex_set:n
@@ -1398,7 +1468,6 @@
afterskip = \parskip
}
}
-
\bool_if:NF \l__eb_title_newline_bool
{
\ctex_set:n
@@ -1410,8 +1479,8 @@
%</class>
%<*package>
\NeedsTeXFormat{LaTeX2e}[2020/10/01]
-\RequirePackage{etoolbox}
-\ProvidesExplPackage{easybase}{2021/07/11}{1.27b}
+\RequirePackage{l3keys2e,etoolbox}
+\ProvidesExplPackage{easybase}{2021/07/12}{1.27c}
{Typeset Chinese theses or books}
\cs_generate_variant:Nn \ctex_define:nn { nx }
@@ -1476,12 +1545,12 @@
}
\NewDocumentCommand{\LoadPackage}{O{}m}
{
- \seq_set_split:Nnn \l__eb_package_names_seq { + } {#2}
+ \seq_set_split:Nnn \l_tmpb_seq { + } {#2}
\int_compare:oNnT
- { \seq_count:N \l__eb_package_names_seq } = { 1 }
+ { \seq_count:N \l_tmpb_seq } = { 1 }
{ \PassOptionsToPackage{#1}{#2} }
\seq_map_function:NN
- \l__eb_package_names_seq \eb_match_load_package:n
+ \l_tmpb_seq \eb_match_load_package:n
}
\cs_new_protected:Npn \eb_at_end_preamble:n
{ \BeforeBeginEnvironment{document} }
@@ -1493,6 +1562,7 @@
{ \bool_set_true:N \l__eb_page_twoside_bool }
\bool_if_exist:NF \l__eb_compile_draft_bool
{ \bool_set_false:N \l__eb_compile_draft_bool }
+\clist_new:N \g__eb_ctex_options_clist
\keys_define:nn { easybase }
{
@@ -1516,7 +1586,10 @@
},
class .initial:n = book,
book .meta:n = { class = #1 },
- article .meta:n = { class = #1 }
+ article .meta:n = { class = #1 },
+
+ unknown .code:n =
+ { \clist_gput_right:NV \g__eb_ctex_options_clist \CurrentOption }
}
\clist_map_inline:nn
@@ -1529,6 +1602,15 @@
}
{ \PassOptionsToPackage #1 }
\ProcessKeysOptions{easybase}
+\PassOptionsToPackage{\g__eb_ctex_options_clist}{ctex}
+\@ifclassloaded{ctexbook}{}
+ {
+ \@ifclassloaded{ctexart}{}
+ {
+ \@ifclassloaded{ctexrep}{}
+ {\RequirePackage[heading]{ctex}}
+ }
+ }
\bool_new:N \l__eb_toc_multi_column_bool
\bool_new:N \l__eb_mark_uppercase_bool
@@ -2241,7 +2323,17 @@
listing-con = #1,
equation-con = #1
},
- number-con .initial:n = { . }
+ number-con .initial:n = { . },
+ unknown .code:n =
+ {
+ \msg_warning:nnx
+ { easybase } { ignore-style } { \l_keys_key_str }
+ }
+ }
+\msg_new:nnn { easybase } { ignore-style }
+ {
+ #1~is~an~unknown~style~option. \\
+ Please~check~the~user~manual~for~the~supported~options.
}
\eb_clist_map_inline:nn
{ figure,table,lstlisting,equation }
@@ -2475,8 +2567,8 @@
math .choices:nn =
{
- noto,notosans,times,scholax,stix,
- charter,ebgaramond,libertine,none
+ noto,notosans,times,libertine,
+ charter,garamond,none,nc,stix
}
{
\tl_gset_eq:NN
@@ -2494,11 +2586,11 @@
{
{ noto } { \eb_put_newtxmath:n { noto } }
{ notosans } { \eb_put_newtxmath:n { notosans } }
- { ebgaramond } { \eb_put_newtxmath:n { ebgaramond } }
+ { garamond } { \eb_put_newtxmath:n { ebgaramond } }
{ times } { \eb_put_newtxmath:n { noOT1 } }
{ libertine } { \eb_put_newtxmath:n { libertine,noOT1 } }
{ stix } { \eb_put_newtxmath:n { stix2,noOT1 } }
- { scholax } { \eb_put_newtxmath:n { nc,noOT1 } }
+ { nc } { \eb_put_newtxmath:n { nc,noOT1 } }
{ charter } { \eb_put_newtxmath:n { charter,noOT1 } }
}
{ \LoadPackage{newtxmath+bm} }
@@ -2998,7 +3090,7 @@
% numbers = left,
numberstyle = \footnotesize,
aboveskip = 1.5ex plus .2ex minus .1ex,
- belowskip = 1ex plus .2ex minus .1ex,
+ belowskip = 1.5ex plus .2ex minus .1ex,
keepspaces = true,
framerule = \l__eb_rule_width_dim,
columns = flexible,
@@ -3054,13 +3146,17 @@
{
linktype .choice:,
linktype .value_required:n = true,
- linktype/edge .code:n = { },
- linktype/none .code:n = \eb_put_hyperref:n { hidelinks },
- linktype/various .code:n =
+ linktype/edge .code:n =
+ { \AtBeginDocument[hyperref]{\tl_set:Nn \@pdfborder { 0~0~1 }} },
+ linktype/none .code:n =
+ { \AtBeginDocument[hyperref]{\tl_set:Nn \@pdfborder { 0~0~0 }} },
+ linktype/colors .code:n =
{
\bool_set_true:N \l__eb_toc_number_color_bool
\eb_put_hyperref:n { colorlinks }
},
+ linktype/various .meta:n = linktype/colors,
+ linktype .initial:n = edge,
linktoc .choice:,
linktoc/unknown .code:n =
@@ -3107,7 +3203,7 @@
\clist_map_function:nN
{
{ none, 000000,000000,000000 },
- { seaside, 4169e1,708090,9932cc },
+ { seaside, 4169e1,007130,9932cc },
{ energy, f39800,00a0e9,893895 },
{ cyberpunk, 601986,eb6877,a4005b }
}
@@ -3130,13 +3226,13 @@
abcdefghijklmnopqrstuvwxyz
0123456789
}
-\AtBeginDocument[hyperref]
+\ctex_at_end_preamble:n
{
\LoadPackage{hyperref}
\urlstyle{same}
\eb_allow_urlbreak:
- \ctex_hypersetup:n { pdfstartview = FitH }
\exp_args:NV \hypersetup \l__eb_hyperref_clist
+ \use:c { makeindex }
}
\labelformat{part}{\CTEXthepart}
@@ -3178,7 +3274,7 @@
}
%</package>
%<*tcolorbox>
-\ProvidesExplFile{eb-tcolorbox.cfg}{2021/07/11}{1.27b}
+\ProvidesExplFile{eb-tcolorbox.cfg}{2021/07/12}{1.27c}
{Customization of tcolorbox for easybook}
\cs_new_protected:Npn \eb_tcb_theorem_set:n #1
diff --git a/macros/latex/contrib/easybook/easybook.pdf b/macros/latex/contrib/easybook/easybook.pdf
index f21fed288b..9126c42467 100644
--- a/macros/latex/contrib/easybook/easybook.pdf
+++ b/macros/latex/contrib/easybook/easybook.pdf
Binary files differ
diff --git a/macros/latex/contrib/iexec/README.md b/macros/latex/contrib/iexec/README.md
index 2025d21ebd..226069a29f 100644
--- a/macros/latex/contrib/iexec/README.md
+++ b/macros/latex/contrib/iexec/README.md
@@ -2,7 +2,8 @@
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/iexec/blob/master/LICENSE.txt)
This LaTeX package helps you execute commands from the document and then input
-their output. The package uses [`ShellEscape`](https://ctan.org/pkg/ShellEscape) package.
+their output. The package uses [`shellesc`](https://ctan.org/pkg/shellesc) package.
+The development of this package was motivated by [this](https://stackoverflow.com/questions/3252957).
First, [install it](https://en.wikibooks.org/wiki/LaTeX/Installing_Extra_Packages)
from [CTAN](https://ctan.org/pkg/iexec)
diff --git a/macros/latex/contrib/iexec/iexec.pdf b/macros/latex/contrib/iexec/iexec.pdf
index 044e9bea67..a47a9869fd 100644
--- a/macros/latex/contrib/iexec/iexec.pdf
+++ b/macros/latex/contrib/iexec/iexec.pdf
Binary files differ
diff --git a/macros/latex/contrib/iexec/iexec.sty b/macros/latex/contrib/iexec/iexec.sty
index 91d10955c3..34898e324c 100644
--- a/macros/latex/contrib/iexec/iexec.sty
+++ b/macros/latex/contrib/iexec/iexec.sty
@@ -21,7 +21,7 @@
% SOFTWARE.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{iexec}[2021/07/10 0.3.0 Inputable Shell Executions]
+\ProvidesPackage{iexec}[2021/07/12 0.3.1 Inputable Shell Executions]
\RequirePackage{shellesc}
@@ -33,12 +33,14 @@
\makeatletter\newcommand\iexec[2][iexec.tmp]{%
\begingroup%
\let\%\@percentchar%
+ \let\\\@backslashchar%
\let\{\@charlb%
\let\}\@charrb%
\ShellEscape{#2 > #1}%
+ \message{iexec executed shell command: [#2 > #1]}%
\endgroup%
- \input{#1}\unskip%
- \iftrace\else\exec{rm #1}\fi%
+ \input{#1}%
+ \iftrace\else\ShellEscape{rm #1}\fi%
}\makeatother
\endinput
diff --git a/macros/latex/contrib/iexec/iexec.tex b/macros/latex/contrib/iexec/iexec.tex
index 150c8fa882..098a297045 100644
--- a/macros/latex/contrib/iexec/iexec.tex
+++ b/macros/latex/contrib/iexec/iexec.tex
@@ -27,7 +27,7 @@
\usepackage{ffcode}
\title{\ff{iexec}: \LaTeX{} Package \\ for Inputable Shell Executions}
\author{Yegor Bugayenko}
-\date{0.3.0 2021/07/10}
+\date{0.3.1 2021/07/12}
\begin{document}
\pagenumbering{gobble}
\raggedbottom
@@ -47,17 +47,17 @@ document and then put their output to the document:
\documentclass{article}
\usepackage{iexec}
\begin{document}
-Today is \iexec{date +\%e-\%b-\%Y}.
+Today is \iexec{date +\%e-\%b-\%Y}
\end{document}
\end{ffcode}
\columnbreak
-Today is \iexec{date +\%e-\%b-\%Y}.
+Today is \iexec{date +\%e-\%b-\%Y | tr -d '\\n'}
\end{multicols}
You have to run \ff{pdflatex} (or just \ff{latex}) with the \ff{--shell-escape} flag
-in order to let \ff{ShellEscape} (the package we use) to run shell.
+in order to let \ff{shellesc} (the package we use) to run shell.
If you don't want the output to be visible,
use \ff{\char`\\phantom\char`\{\char`\\iexec\char`\{...\char`\}\char`\}}.
@@ -66,9 +66,11 @@ The output of your code is saved into the file provided as the
second optional argument of \ff{\char`\\iexec} (the default value is \ff{iexec.tmp}):
\begin{ffcode}
-Today is \iexec[date.txt]{date +\%e-\%b-\%Y}.
+Today is \iexec[date.txt]{date +\%e-\%b-\%Y | tr -d '\\n'}.
\end{ffcode}
+The tailing part of the command here removes all ends-of-line.
+
The file specified will be deleted right after its usage. If you don't
want this to happen, use \ff{trace} package option: all files will remain
in the directory.
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf b/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
index f549886755..b237591ac0 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-cn.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-en.pdf b/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
index 8fc8f0c44d..ece459f91d 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-en.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf b/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
index 5d296b3e12..eb34d5f83e 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
+++ b/macros/latex/contrib/projlib/ProjLib-doc-fr.pdf
Binary files differ
diff --git a/macros/latex/contrib/projlib/ProjLib-doc.dtx b/macros/latex/contrib/projlib/ProjLib-doc.dtx
index b50fb72adb..6932d8bf52 100644
--- a/macros/latex/contrib/projlib/ProjLib-doc.dtx
+++ b/macros/latex/contrib/projlib/ProjLib-doc.dtx
@@ -109,7 +109,7 @@
%<*ProjLib-doc-cn>
\title{\ProjLib{} 工具集\\[.3\baselineskip]\normalsize 使用指南}
\author{许锦文}
-\thanks{对应版本.~~\texttt{\ProjLib{}~2021/07/11}}
+\thanks{对应版本.~~\texttt{\ProjLib{}~2021/07/12}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{2021年7月,北京}
%</ProjLib-doc-cn>
@@ -117,7 +117,7 @@
%<*ProjLib-doc-en>
\title{\ProjLib{}~\,Toolkit\\[.3\baselineskip]\normalsize User Manual}
\author{Jinwen XU}
-\thanks{Corresponding to: \texttt{\ProjLib{}~2021/07/11}}
+\thanks{Corresponding to: \texttt{\ProjLib{}~2021/07/12}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{July 2021, Beijing}
%</ProjLib-doc-en>
@@ -125,7 +125,7 @@
%<*ProjLib-doc-fr>
\title{La boîte à outils~\,\ProjLib{}\\[.3\baselineskip]\normalsize Manuel d'utilisation}
\author{Jinwen XU}
-\thanks{Correspondant à : \texttt{\ProjLib{}~2021/07/11}}
+\thanks{Correspondant à : \texttt{\ProjLib{}~2021/07/12}}
\email{\href{mailto:ProjLib@outlook.com}{ProjLib@outlook.com}}
\date{juillet 2021, à Pékin}
%</ProjLib-doc-fr>
@@ -211,7 +211,7 @@ The \ProjLib{} toolkit is composed of the main package \ProjLibPackage{} and a s
Le nom \ProjLib{} peut être considéré comme l'abréviation de \emph{Project Library} en anglais ou de \emph{Projet Libre} en français (l'auteur préfère l'interprétation française). Son objectif principal est de fournir un support multilingue et des environnements de type théorème avec des références intelligentes. De plus, certaines fonctionnalités supplémentaires sont fournies, telles que le bloc auteur amélioré, les marques de brouillon, les symboles mathématiques et les raccourcis, etc.
-La boîte à outils \ProjLib{} est composée du package principal \ProjLibPackage{} et d'une série de composants dont les noms commencent par l'abréviation "PJL". Vous pouvez apprendre à l'utiliser à travers les exemples d'utilisation dans la section suivante.
+La boîte à outils \ProjLib{} est composée du package principal \ProjLibPackage{} et d'une série de composants dont les noms commencent par l'abréviation « PJL ». Vous pouvez apprendre à l'utiliser à travers les exemples d'utilisation dans la section suivante.
%</ProjLib-doc-fr>
%<*ProjLib-doc-cn>
@@ -795,7 +795,7 @@ For details on how to select a language, please refer to the section on \PJLlang
%<*ProjLib-doc-fr>
\subsection{PJLdate : traitement de date-heure}
-\PJLdatePackage{} propose la macro \lstinline|\PLdate|\meta{yyyy-mm-dd} (ou \lstinline|\PJLdate|\meta{yyyy-mm-dd}) pour convertir \meta{yyyy-mm-dd} dans le format de date de la langue actuellement sélectionnée. Par exemple, dans le contexte français actuel, \lstinline|\PLdate{2022-04-01}| deviendrait ``\PLdate{2022-04-01}'', tandis que dans le contexte anglais ``\UseOtherLanguage{English}{\PLdate{2022-04-01}}''.
+\PJLdatePackage{} propose la macro \lstinline|\PLdate|\meta{yyyy-mm-dd} (ou \lstinline|\PJLdate|\meta{yyyy-mm-dd}) pour convertir \meta{yyyy-mm-dd} dans le format de date de la langue actuellement sélectionnée. Par exemple, dans le contexte français actuel, \lstinline|\PLdate{2022-04-01}| deviendrait « \PLdate{2022-04-01} », tandis que dans le contexte anglais « \UseOtherLanguage{English}{\PLdate{2022-04-01}} ».
Pour plus de détails sur la façon de sélectionner une langue, veuillez vous référer à la section sur \PJLlang{}.
%</ProjLib-doc-fr>
diff --git a/macros/latex/contrib/projlib/ProjLib.dtx b/macros/latex/contrib/projlib/ProjLib.dtx
index d343daece7..b48967e488 100644
--- a/macros/latex/contrib/projlib/ProjLib.dtx
+++ b/macros/latex/contrib/projlib/ProjLib.dtx
@@ -18,57 +18,57 @@
%
%<*ProjLib>
\ProvidesPackage{ProjLib}
- [2021/07/11 The collective interface of ProjLib toolkit]
+ [2021/07/12 The collective interface of ProjLib toolkit]
%</ProjLib>
%
%<*PJLamssim>
\ProvidesPackage{PJLamssim}
- [2021/07/11 Simulate some features of amsart]
+ [2021/07/12 Simulate some features of amsart]
%</PJLamssim>
%
%<*PJLauthor>
\ProvidesPackage{PJLauthor}
- [2021/07/11 Enhanced author information block]
+ [2021/07/12 Enhanced author information block]
%</PJLauthor>
%
%<*PJLdate>
\ProvidesPackage{PJLdate}
- [2021/07/11 Convert yyyy-mm-dd to normal datetime format]
+ [2021/07/12 Convert yyyy-mm-dd to normal datetime format]
%</PJLdate>
%
%<*PJLdraft>
\ProvidesPackage{PJLdraft}
- [2021/07/11 Some useful macros for the draft stage]
+ [2021/07/12 Some useful macros for the draft stage]
%</PJLdraft>
%
%<*PJLlang>
\ProvidesPackage{PJLlang}
- [2021/07/11 Multi-language configuration]
+ [2021/07/12 Multi-language configuration]
%</PJLlang>
%
%<*PJLlogo>
\ProvidesPackage{PJLlogo}
- [2021/07/11 The ProjLib logo]
+ [2021/07/12 The ProjLib logo]
%</PJLlogo>
%
%<*PJLmath>
\ProvidesPackage{PJLmath}
- [2021/07/11 Useful math macros and shortcuts]
+ [2021/07/12 Useful math macros and shortcuts]
%</PJLmath>
%
%<*PJLpaper>
\ProvidesPackage{PJLpaper}
- [2021/07/11 Paper style configuration]
+ [2021/07/12 Paper style configuration]
%</PJLpaper>
%
%<*PJLthm>
\ProvidesPackage{PJLthm}
- [2021/07/11 Theorem setup and configuration]
+ [2021/07/12 Theorem setup and configuration]
%</PJLthm>
%
%<*PJLtoolkit>
\ProvidesPackage{PJLtoolkit}
- [2021/07/11 Collective interface of ProjLib Toolkit]
+ [2021/07/12 Collective interface of ProjLib Toolkit]
%</PJLtoolkit>
%
%# 下面两行引入宏包的代码是所有文件共用的。
diff --git a/macros/luatex/latex/pyluatex/README.md b/macros/luatex/latex/pyluatex/README.md
new file mode 100644
index 0000000000..f9e727fabf
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/README.md
@@ -0,0 +1,56 @@
+# PyLuaTeX
+**Execute Python code on the fly in your LaTeX documents**
+
+PyLuaTeX allows you to execute Python code and to include the resulting output in your LaTeX documents in a *single compilation run*.
+LaTeX documents must be compiled with LuaLaTeX for this to work.
+
+
+## Example
+1\. LaTeX document `example.tex`
+```latex
+\documentclass{article}
+
+\usepackage{pyluatex}
+
+\begin{python}
+import math
+import random
+
+random.seed(0)
+
+greeting = 'Hello PyLuaTeX!'
+\end{python}
+
+\newcommand{\randint}[2]{\py{random.randint(#1, #2)}}
+
+\begin{document}
+\py{greeting}
+
+$\sqrt{371} = \py{math.sqrt(371)}$
+
+\randint{2}{5}
+\end{document}
+```
+2\. Compile using LuaLaTeX (shell escape is required)
+```
+lualatex -shell-escape example.tex
+```
+
+**Note:** Running LaTeX with the shell escape option enabled allows arbitrary code to be
+executed. For this reason, it is recommended to compile trusted documents only.
+
+## Requirements
+* LuaLaTeX
+* Python 3
+* Linux, macOS or Windows
+
+Our automated tests currently use TeX Live 2021 and Python 3.7+ on
+Ubuntu 20.04, macOS Catalina 10.15 and Windows Server 2019.
+
+## License
+[LPPL 1.3c](http://www.latex-project.org/lppl.txt) for LaTeX code and
+[MIT license](https://opensource.org/licenses/MIT) for Python and Lua code.
+
+We use the great [json.lua](https://github.com/rxi/json.lua) library under the terms
+of the [MIT license](https://opensource.org/licenses/MIT).
+
diff --git a/macros/luatex/latex/pyluatex/interpreter.py b/macros/luatex/latex/pyluatex/interpreter.py
new file mode 100644
index 0000000000..4a17b5f5b0
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/interpreter.py
@@ -0,0 +1,71 @@
+"""
+MIT License
+
+Copyright (c) 2021 Tobias Enderle
+
+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.
+"""
+
+from code import InteractiveInterpreter, compile_command
+import traceback
+from io import StringIO
+from contextlib import redirect_stdout, redirect_stderr
+import socketserver
+import json
+import textwrap
+from collections import defaultdict
+
+class Interpreter(InteractiveInterpreter):
+ def execute(self, code):
+ with StringIO() as out, redirect_stdout(out), redirect_stderr(out):
+ self.success = True
+ try:
+ code_obj = compile_command(code, symbol='exec')
+ if code_obj is None:
+ print('Incomplete Python code:\n' + code)
+ self.success = False
+ else:
+ self.runcode(code_obj)
+ except:
+ traceback.print_exc()
+ self.success = False
+ return self.success, out.getvalue()
+
+ def showtraceback(self):
+ super().showtraceback()
+ self.success = False
+
+class Handler(socketserver.StreamRequestHandler):
+ def handle(self):
+ interpreters = defaultdict(Interpreter)
+ while True:
+ data = self.rfile.readline().decode('utf-8')
+ if len(data) == 0:
+ return
+
+ data = json.loads(data)
+ interpreter = interpreters[data['session']]
+ success, output = interpreter.execute(textwrap.dedent(data['code']))
+ response = { 'success': success, 'output': output }
+ self.wfile.write((json.dumps(response) + '\n').encode('utf-8'))
+
+if __name__ == '__main__':
+ with socketserver.TCPServer(('localhost', 0), Handler) as server:
+ print(server.server_address[1], end='\n', flush=True) # publish port
+ server.handle_request()
diff --git a/macros/luatex/latex/pyluatex/json.lua b/macros/luatex/latex/pyluatex/json.lua
new file mode 100644
index 0000000000..711ef78619
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/json.lua
@@ -0,0 +1,388 @@
+--
+-- json.lua
+--
+-- Copyright (c) 2020 rxi
+--
+-- 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.
+--
+
+local json = { _version = "0.1.2" }
+
+-------------------------------------------------------------------------------
+-- Encode
+-------------------------------------------------------------------------------
+
+local encode
+
+local escape_char_map = {
+ [ "\\" ] = "\\",
+ [ "\"" ] = "\"",
+ [ "\b" ] = "b",
+ [ "\f" ] = "f",
+ [ "\n" ] = "n",
+ [ "\r" ] = "r",
+ [ "\t" ] = "t",
+}
+
+local escape_char_map_inv = { [ "/" ] = "/" }
+for k, v in pairs(escape_char_map) do
+ escape_char_map_inv[v] = k
+end
+
+
+local function escape_char(c)
+ return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
+end
+
+
+local function encode_nil(val)
+ return "null"
+end
+
+
+local function encode_table(val, stack)
+ local res = {}
+ stack = stack or {}
+
+ -- Circular reference?
+ if stack[val] then error("circular reference") end
+
+ stack[val] = true
+
+ if rawget(val, 1) ~= nil or next(val) == nil then
+ -- Treat as array -- check keys are valid and it is not sparse
+ local n = 0
+ for k in pairs(val) do
+ if type(k) ~= "number" then
+ error("invalid table: mixed or invalid key types")
+ end
+ n = n + 1
+ end
+ if n ~= #val then
+ error("invalid table: sparse array")
+ end
+ -- Encode
+ for i, v in ipairs(val) do
+ table.insert(res, encode(v, stack))
+ end
+ stack[val] = nil
+ return "[" .. table.concat(res, ",") .. "]"
+
+ else
+ -- Treat as an object
+ for k, v in pairs(val) do
+ if type(k) ~= "string" then
+ error("invalid table: mixed or invalid key types")
+ end
+ table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
+ end
+ stack[val] = nil
+ return "{" .. table.concat(res, ",") .. "}"
+ end
+end
+
+
+local function encode_string(val)
+ return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
+end
+
+
+local function encode_number(val)
+ -- Check for NaN, -inf and inf
+ if val ~= val or val <= -math.huge or val >= math.huge then
+ error("unexpected number value '" .. tostring(val) .. "'")
+ end
+ return string.format("%.14g", val)
+end
+
+
+local type_func_map = {
+ [ "nil" ] = encode_nil,
+ [ "table" ] = encode_table,
+ [ "string" ] = encode_string,
+ [ "number" ] = encode_number,
+ [ "boolean" ] = tostring,
+}
+
+
+encode = function(val, stack)
+ local t = type(val)
+ local f = type_func_map[t]
+ if f then
+ return f(val, stack)
+ end
+ error("unexpected type '" .. t .. "'")
+end
+
+
+function json.encode(val)
+ return ( encode(val) )
+end
+
+
+-------------------------------------------------------------------------------
+-- Decode
+-------------------------------------------------------------------------------
+
+local parse
+
+local function create_set(...)
+ local res = {}
+ for i = 1, select("#", ...) do
+ res[ select(i, ...) ] = true
+ end
+ return res
+end
+
+local space_chars = create_set(" ", "\t", "\r", "\n")
+local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
+local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
+local literals = create_set("true", "false", "null")
+
+local literal_map = {
+ [ "true" ] = true,
+ [ "false" ] = false,
+ [ "null" ] = nil,
+}
+
+
+local function next_char(str, idx, set, negate)
+ for i = idx, #str do
+ if set[str:sub(i, i)] ~= negate then
+ return i
+ end
+ end
+ return #str + 1
+end
+
+
+local function decode_error(str, idx, msg)
+ local line_count = 1
+ local col_count = 1
+ for i = 1, idx - 1 do
+ col_count = col_count + 1
+ if str:sub(i, i) == "\n" then
+ line_count = line_count + 1
+ col_count = 1
+ end
+ end
+ error( string.format("%s at line %d col %d", msg, line_count, col_count) )
+end
+
+
+local function codepoint_to_utf8(n)
+ -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
+ local f = math.floor
+ if n <= 0x7f then
+ return string.char(n)
+ elseif n <= 0x7ff then
+ return string.char(f(n / 64) + 192, n % 64 + 128)
+ elseif n <= 0xffff then
+ return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
+ elseif n <= 0x10ffff then
+ return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
+ f(n % 4096 / 64) + 128, n % 64 + 128)
+ end
+ error( string.format("invalid unicode codepoint '%x'", n) )
+end
+
+
+local function parse_unicode_escape(s)
+ local n1 = tonumber( s:sub(1, 4), 16 )
+ local n2 = tonumber( s:sub(7, 10), 16 )
+ -- Surrogate pair?
+ if n2 then
+ return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
+ else
+ return codepoint_to_utf8(n1)
+ end
+end
+
+
+local function parse_string(str, i)
+ local res = ""
+ local j = i + 1
+ local k = j
+
+ while j <= #str do
+ local x = str:byte(j)
+
+ if x < 32 then
+ decode_error(str, j, "control character in string")
+
+ elseif x == 92 then -- `\`: Escape
+ res = res .. str:sub(k, j - 1)
+ j = j + 1
+ local c = str:sub(j, j)
+ if c == "u" then
+ local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
+ or str:match("^%x%x%x%x", j + 1)
+ or decode_error(str, j - 1, "invalid unicode escape in string")
+ res = res .. parse_unicode_escape(hex)
+ j = j + #hex
+ else
+ if not escape_chars[c] then
+ decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
+ end
+ res = res .. escape_char_map_inv[c]
+ end
+ k = j + 1
+
+ elseif x == 34 then -- `"`: End of string
+ res = res .. str:sub(k, j - 1)
+ return res, j + 1
+ end
+
+ j = j + 1
+ end
+
+ decode_error(str, i, "expected closing quote for string")
+end
+
+
+local function parse_number(str, i)
+ local x = next_char(str, i, delim_chars)
+ local s = str:sub(i, x - 1)
+ local n = tonumber(s)
+ if not n then
+ decode_error(str, i, "invalid number '" .. s .. "'")
+ end
+ return n, x
+end
+
+
+local function parse_literal(str, i)
+ local x = next_char(str, i, delim_chars)
+ local word = str:sub(i, x - 1)
+ if not literals[word] then
+ decode_error(str, i, "invalid literal '" .. word .. "'")
+ end
+ return literal_map[word], x
+end
+
+
+local function parse_array(str, i)
+ local res = {}
+ local n = 1
+ i = i + 1
+ while 1 do
+ local x
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of array?
+ if str:sub(i, i) == "]" then
+ i = i + 1
+ break
+ end
+ -- Read token
+ x, i = parse(str, i)
+ res[n] = x
+ n = n + 1
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "]" then break end
+ if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
+ end
+ return res, i
+end
+
+
+local function parse_object(str, i)
+ local res = {}
+ i = i + 1
+ while 1 do
+ local key, val
+ i = next_char(str, i, space_chars, true)
+ -- Empty / end of object?
+ if str:sub(i, i) == "}" then
+ i = i + 1
+ break
+ end
+ -- Read key
+ if str:sub(i, i) ~= '"' then
+ decode_error(str, i, "expected string for key")
+ end
+ key, i = parse(str, i)
+ -- Read ':' delimiter
+ i = next_char(str, i, space_chars, true)
+ if str:sub(i, i) ~= ":" then
+ decode_error(str, i, "expected ':' after key")
+ end
+ i = next_char(str, i + 1, space_chars, true)
+ -- Read value
+ val, i = parse(str, i)
+ -- Set
+ res[key] = val
+ -- Next token
+ i = next_char(str, i, space_chars, true)
+ local chr = str:sub(i, i)
+ i = i + 1
+ if chr == "}" then break end
+ if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
+ end
+ return res, i
+end
+
+
+local char_func_map = {
+ [ '"' ] = parse_string,
+ [ "0" ] = parse_number,
+ [ "1" ] = parse_number,
+ [ "2" ] = parse_number,
+ [ "3" ] = parse_number,
+ [ "4" ] = parse_number,
+ [ "5" ] = parse_number,
+ [ "6" ] = parse_number,
+ [ "7" ] = parse_number,
+ [ "8" ] = parse_number,
+ [ "9" ] = parse_number,
+ [ "-" ] = parse_number,
+ [ "t" ] = parse_literal,
+ [ "f" ] = parse_literal,
+ [ "n" ] = parse_literal,
+ [ "[" ] = parse_array,
+ [ "{" ] = parse_object,
+}
+
+
+parse = function(str, idx)
+ local chr = str:sub(idx, idx)
+ local f = char_func_map[chr]
+ if f then
+ return f(str, idx)
+ end
+ decode_error(str, idx, "unexpected character '" .. chr .. "'")
+end
+
+
+function json.decode(str)
+ if type(str) ~= "string" then
+ error("expected argument of type string, got " .. type(str))
+ end
+ local res, idx = parse(str, next_char(str, 1, space_chars, true))
+ idx = next_char(str, idx, space_chars, true)
+ if idx <= #str then
+ decode_error(str, idx, "trailing garbage")
+ end
+ return res
+end
+
+
+return json
diff --git a/macros/luatex/latex/pyluatex/pyluatex.lua b/macros/luatex/latex/pyluatex/pyluatex.lua
new file mode 100644
index 0000000000..01a06f548e
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/pyluatex.lua
@@ -0,0 +1,137 @@
+--[[
+MIT License
+
+Copyright (c) 2021 Tobias Enderle
+
+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.
+--]]
+
+local json = require("json")
+local socket = require("socket")
+
+pyluatex = pyluatex or {
+ verbose = false,
+ session = "default"
+}
+
+-- status.filename: path to pyluatex.sty
+local folder = file.pathpart(file.collapsepath(status.filename, true))
+local script = file.join(folder, "interpreter.py")
+local tcp = nil
+
+local python_lines = {}
+
+local env_end = "\\end{python}"
+
+local function err_cmd(message)
+ return "\\PackageError{PyLuaTeX}{" .. message .. "}{}"
+end
+
+function pyluatex.start(executable)
+ local is_windows = package.config:sub(1,1) ~= "/"
+ local cmd
+ if is_windows then
+ cmd = "start /B " .. executable .. " \"" .. script .. "\""
+ else
+ cmd = executable .. " \"" .. script .. "\" &"
+ end
+ local f = io.popen(cmd, "r")
+ local port = f:read("*l"):gsub("\r", ""):gsub("\n", "")
+ f:close()
+
+ if port then
+ tcp = socket.tcp()
+ tcp:connect("127.0.0.1", port)
+ else
+ tex.sprint(err_cmd("Python backend (executable: " .. executable ..
+ ") could not be started"))
+ end
+end
+
+local function request(data)
+ tcp:send(json.encode(data) .. "\n")
+ local output = tcp:receive("*l")
+ local response = json.decode(output)
+ return response.success, response.output
+end
+
+local function print_input(code)
+ texio.write_nl("PyLuaTeX input for session \"" .. pyluatex.session .. "\": " .. code)
+end
+
+local function print_output(code)
+ texio.write_nl("PyLuaTeX output: " .. code)
+end
+
+function pyluatex.execute(code, write)
+ if pyluatex.verbose then print_input(code) end
+
+ local success, output = request({ session = pyluatex.session, code = code })
+ if success then
+ if pyluatex.verbose then print_output(output) end
+ if write then
+ tex.sprint(output)
+ else
+ return output
+ end
+ else
+ if not pyluatex.verbose then print_input(code) end
+ print_output(output)
+ if write then
+ tex.sprint(err_cmd("Python error (see above)"))
+ end
+ end
+ return nil
+end
+
+local function record_line(line)
+ local s, e = line:find(env_end)
+ if s ~= nil then
+ luatexbase.remove_from_callback("process_input_buffer", "pyluatex_record_line")
+ table.insert(python_lines, line:sub(1, s - 1))
+ local code = table.concat(python_lines, "\n")
+ local output = pyluatex.execute(code, false)
+ if output ~= nil then
+ return output .. line:sub(s)
+ else
+ return env_end .. err_cmd("Python error (see above)") .. line:sub(e + 1)
+ end
+ else
+ table.insert(python_lines, line)
+ return ""
+ end
+end
+
+function pyluatex.record_env()
+ python_lines = {}
+ luatexbase.add_to_callback("process_input_buffer", record_line, "pyluatex_record_line")
+end
+
+function pyluatex.run_file(path)
+ local f = io.open(path, "r")
+ if f then
+ local code = f:read("*a")
+ f:close()
+ pyluatex.execute(code, true)
+ else
+ tex.sprint(err_cmd("File not found: " .. path))
+ end
+end
+
+return pyluatex
diff --git a/macros/luatex/latex/pyluatex/pyluatex.pdf b/macros/luatex/latex/pyluatex/pyluatex.pdf
new file mode 100644
index 0000000000..bfb1a27576
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/pyluatex.pdf
Binary files differ
diff --git a/macros/luatex/latex/pyluatex/pyluatex.sty b/macros/luatex/latex/pyluatex/pyluatex.sty
new file mode 100644
index 0000000000..b5c8298bca
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/pyluatex.sty
@@ -0,0 +1,45 @@
+%% Copyright 2021 Tobias Enderle
+%%
+%% 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.
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{pyluatex}[2021/07/12 v0.1.1 Execute Python code on the fly]
+
+\RequirePackage{expl3}
+\ExplSyntaxOn
+\sys_if_engine_luatex:TF{}{%
+\PackageError{PyLuaTeX}{LuaTeX~is~required}{}%
+}
+\sys_if_shell_unrestricted:TF{}{%
+\PackageError{PyLuaTeX}{Shell~escape~required~(add~-shell-escape~option)}{}%
+}
+\ExplSyntaxOff
+
+\directlua{require("pyluatex")}
+
+\RequirePackage{kvoptions}
+\DeclareStringOption[python3]{executable}
+\DeclareVoidOption{verbose}{\directlua{pyluatex.verbose = true}}
+\ProcessKeyvalOptions*
+
+\directlua{pyluatex.start([==[\pyluatex@executable]==])}
+
+\newenvironment{python}{\directlua{pyluatex.record_env()}}{}
+
+\newcommand*{\py}[1]{%
+\directlua{pyluatex.execute([==[print(str(#1), end='')]==], true)}%
+}
+
+\newcommand*{\pyc}[1]{\directlua{pyluatex.execute([==[#1]==], true)}}
+
+\newcommand*{\pysession}[1]{\directlua{pyluatex.session = [==[#1]==]}}
+
+\newcommand*{\pyfile}[1]{\directlua{pyluatex.run_file([==[#1]==])}}
+
+\endinput
diff --git a/macros/luatex/latex/pyluatex/pyluatex.tex b/macros/luatex/latex/pyluatex/pyluatex.tex
new file mode 100644
index 0000000000..4552698539
--- /dev/null
+++ b/macros/luatex/latex/pyluatex/pyluatex.tex
@@ -0,0 +1,168 @@
+\documentclass{article}
+\usepackage{helvet}
+\usepackage{courier}
+\renewcommand{\familydefault}{\sfdefault}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{parskip}
+\linespread{1.2}
+\usepackage{tabularx}
+\usepackage{xcolor}
+\usepackage[listings,breakable,xparse]{tcolorbox}
+\tcbset{breakable,listing only,size=fbox,colframe=black!10,boxrule=3pt,colback=black!10}
+\NewTotalTCBox{\inlcode}{ v }{
+ on line,boxsep=0pt,left=0.5ex,right=0.5ex,top=0pt,bottom=0pt,
+ boxrule=0pt}{\lstinline[style=tcblatex]|#1|\rule[-.3\baselineskip]{0pt}{0.9\baselineskip}}
+\usepackage{url}
+\title{The \emph{pyluatex} package}
+\author{Tobias Enderle\\\url{https://github.com/tndrle/PyLuaTeX}}
+\date{v0.1.1 (2021/07/12)}
+\begin{document}
+\maketitle
+\raggedright
+
+\textbf{Execute Python code on the fly in your \LaTeX{} documents}
+
+PyLuaTeX allows you to execute Python code and to include the resulting output in your \LaTeX{} documents in a \textit{single compilation run}.
+\LaTeX{} documents must be compiled with Lua\LaTeX{} for this to work.
+
+
+\section{Example}
+\begin{enumerate}
+\item \LaTeX{} document \inlcode|example.tex|
+\begin{tcblisting}{breakable,listing only,
+ size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
+\documentclass{article}
+
+\usepackage{pyluatex}
+
+\begin{python}
+import math
+import random
+
+random.seed(0)
+
+greeting = 'Hello PyLuaTeX!'
+\end{python}
+
+\newcommand{\randint}[2]{\py{random.randint(#1, #2)}}
+
+\begin{document}
+\py{greeting}
+
+$\sqrt{371} = \py{math.sqrt(371)}$
+
+\randint{2}{5}
+\end{document}
+\end{tcblisting}
+\item Compile using Lua\LaTeX{} (shell escape is required)
+\begin{tcblisting}{breakable,listing only,
+ size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
+lualatex -shell-escape example.tex
+\end{tcblisting}
+\end{enumerate}
+\textbf{Note:} Running \LaTeX{} with the shell escape option enabled allows arbitrary code to be
+executed. For this reason, it is recommended to compile trusted documents only.
+
+\subsection{Further Examples}
+The folder \inlcode|example| contains additional example documents:
+\begin{itemize}
+\item \inlcode|readme-example.tex|\\[0.5ex]
+ The example above
+\item \inlcode|sessions.tex|\\[0.5ex]
+ Demonstrates the use of different Python sessions in a document
+\item \inlcode|data-visualization.tex|\\[0.5ex]
+ Demonstrates the visualization of data using \textit{pgfplots} and \textit{pandas}
+\end{itemize}
+For more intricate use cases have a look at our tests in the folder \inlcode|test|.
+
+\section{Installation}
+PyLuaTeX is not yet available through package managers or CTAN\footnote{\url{https://ctan.org}}.
+
+To install PyLuaTeX, do the following steps:
+\begin{enumerate}
+\item Locate your local \textit{TEXMF} folder\\[0.5ex]
+The location of this folder may vary. Typical defaults for TeX Live are \inlcode|~/texmf| for Linux,
+\inlcode|~/Library/texmf| for macOS, and \inlcode|C:\Users\<user name>\texmf| for Windows.
+If you are lucky, the command \inlcode|kpsewhich -var-value=TEXMFHOME| tells you the location.
+For MiKTeX, the folder can be found and configured in the \textit{MiKTeX Console}.
+\item Download the latest release\footnote{\url{https://github.com/tndrle/PyLuaTeX/releases/latest}} of PyLuaTeX
+\item Put the downloaded files in the folder \inlcode|TEXMF/tex/latex/pyluatex| (where \inlcode|TEXMF| is the folder located in 1.)\\[0.5ex]
+The final folder structure must be
+\begin{tcblisting}{breakable,listing only,
+ size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
+TEXMF/tex/latex/pyluatex/
+|-- interpreter.py
+|-- json.lua
+|-- pyluatex.lua
+|-- pyluatex.sty
+|-- ...
+\end{tcblisting}
+\end{enumerate}
+\section{Reference}
+PyLuaTeX offers a simple set of options, macros and environments.
+
+\subsection{Package Options}
+\begin{itemize}
+\item \inlcode|verbose|\\[0.5ex]
+ If this option is enabled, Python input and output is written to the log file.\\[0.5ex]
+ \textit{Example:} \inlcode|\usepackage[verbose]{pyluatex}|
+\item \inlcode|executable|\\[0.5ex]
+ Specifies the path to the Python executable. (default: \inlcode|python3|)\\[0.5ex]
+ \textit{Example:} \inlcode|\usepackage[executable=/usr/local/bin/python3]{pyluatex}|
+\end{itemize}
+\subsection{Macros}
+\begin{itemize}
+\item \inlcode|\py{code}|\\[0.5ex]
+ Executes \inlcode|code| and writes the output to the document.\\[0.5ex]
+ \textit{Example:} \inlcode|\py{3 + 7}|
+\item \inlcode|\pyc{code}|\\[0.5ex]
+ Executes \inlcode|code|\\[0.5ex]
+ \textit{Example:} \inlcode|\pyc{x = 5}|
+\item \inlcode|\pyfile{path}|\\[0.5ex]
+ Executes the Python file specified by \inlcode|path|.\\[0.5ex]
+ \textit{Example:} \inlcode|\pyfile{main.py}|
+\item \inlcode|\pysession{session}|\\[0.5ex]
+ Selects \inlcode|session| as Python session for subsequent Python code.\\[0.5ex]
+ The session that is active at the beginning is \inlcode|default|.\\[0.5ex]
+ \textit{Example:} \inlcode|\pysession{main}|
+\end{itemize}
+\subsection{Environments}
+\begin{itemize}
+\item \inlcode|python|\\[0.5ex]
+ Executes the provided block of Python code.\\[0.5ex]
+ The environment handles characters like \inlcode|_|, \inlcode|#|, \inlcode|%|, \inlcode|\|, etc.\\[0.5ex]
+ Code on the same line as \inlcode|\begin{python}| is ignored, i.e., code must start on the next line.\\[0.5ex]
+ If leading spaces are present they are gobbled automatically up to the first level of indentation.\\[0.5ex]
+ \textit{Example:}
+ \begin{tcblisting}{breakable,listing only,
+ size=fbox,colframe=black!8,boxrule=3pt,colback=black!8}
+\begin{python}
+ x = 'Hello PyLuaTeX'
+ print(x)
+\end{python}
+\end{tcblisting}
+\end{itemize}
+\section{Requirements}
+\begin{itemize}
+\item Lua\LaTeX{}
+\item Python 3
+\item Linux, macOS or Windows
+\end{itemize}
+Our automated tests currently use TeX Live 2021 and Python 3.7+ on
+Ubuntu 20.04, macOS Catalina 10.15 and Windows Server 2019.
+
+\section{How It Works}
+PyLuaTeX runs a Python \inlcode|InteractiveInterpreter|\footnote{\url{https://docs.python.org/3/library/code.html#code.InteractiveInterpreter}} (actually several if you use different sessions) in the background for on the fly code execution.
+Python code from your \LaTeX{} file is sent to the background interpreter through a TCP socket.
+This approach allows your Python code to be executed and the output to be integrated in your \LaTeX{} file in a single compilation run.
+No additional processing steps are needed.
+No intermediate files have to be written.
+No placeholders have to be inserted.
+
+\section{License}
+LPPL 1.3c\footnote{\url{http://www.latex-project.org/lppl.txt}} for \LaTeX{} code and
+MIT license\footnote{\url{https://opensource.org/licenses/MIT}} for Python and Lua code.
+
+We use the great json.lua\footnote{\url{https://github.com/rxi/json.lua}} library under the terms
+of the MIT license\footnote{\url{https://opensource.org/licenses/MIT}}.
+\end{document}