diff options
author | Norbert Preining <norbert@preining.info> | 2022-07-07 03:01:45 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-07-07 03:01:45 +0000 |
commit | c925207bc17a56bf94a6e3d156db27042965136d (patch) | |
tree | b5dc80f7f6791eba6121e1a44c1c2b9a4b46dbb2 /macros | |
parent | 9f9a07ef2eb0c1f25ce9afc7bb94928956c036ea (diff) |
CTAN sync 202207070301
Diffstat (limited to 'macros')
21 files changed, 2200 insertions, 700 deletions
diff --git a/macros/latex/contrib/inlinelabel/README.md b/macros/latex/contrib/inlinelabel/README.md index e7acb7ca7e..14e2879a9f 100644 --- a/macros/latex/contrib/inlinelabel/README.md +++ b/macros/latex/contrib/inlinelabel/README.md @@ -1,27 +1,26 @@ -# Inlinelabel Package +# inlinelabel This package can assign equation numbers to inline equations. When Japanese is supported, you can switch to circled equation numbers. -## System Requirements +## Documents -+ TeX format: LaTeX -+ Prerequisite package: amsmath and refcount -+ Prerequisite package with [circled] option: japanese-otf - - -## Installation - -Move inlinelabel.sty file to $TEXMF/tex/latex/hideanswer. +Documents for this pacakge are available in English and Japanese. ## License This package released under [the MIT license](https://ctan.org/license/mit). +(C) 2022 Yukoh KUSAKABE + ## Revision History ++ Version 1.1 2022-07-07 + + Rewrite README. + + Add the document (inlinelabel.pdf). + + Add the [luacircled] option. + Version 1.0 2022-06-28 + The first public version. diff --git a/macros/latex/contrib/inlinelabel/inlinelabel-en.md b/macros/latex/contrib/inlinelabel/inlinelabel-en.md deleted file mode 100644 index dd726d5533..0000000000 --- a/macros/latex/contrib/inlinelabel/inlinelabel-en.md +++ /dev/null @@ -1,55 +0,0 @@ -# Inlinelabel Package - -This package can assign equation numbers to inline equations. When Japanese is supported, you can switch to circled equation numbers. - - -## System Requirements - -+ TeX format: LaTeX -+ Prerequisite package: amsmath and refcount -+ Prerequisite package with [circled] option: japanese-otf - - -## Installation - -Move inlinelabel.sty file to $TEXMF/tex/latex/hideanswer. - - -## Usage - -### \inlinelabel{<label>} - -Put the inline equation number. Place it outside of the equation (outside of the $--$). Take the name of the label as an argument. Take a small margin before and after the text to make it look natural. If you don't want margins, use \inlinelabel*{<label>}. - - -### Option [circled] - -Assuming you are using a Japanese environment. Switch to circled equation numbers. All equation numbers are rewritten, not just the inline equation numbers. - - -### \circledref{<label>} - -Only valid when [circled] option is loaded. -Refer to the circled equation number. - - -### \equationref{<label>} - -Only valid when [circled] option is loaded. -This macro is the same as \circledref{<label>}. - - -## License - -This package released under [the MIT license](https://ctan.org/license/mit). - - -## Revision History - -+ Version 1.0 2022-06-28 - + The first public version. - - ---- - -[Yukoh KUSAKABE](https://twitter.com/metaphysicainfo) (screen-name) at [metaphysica.info](https://www.metaphysica.info/)
\ No newline at end of file diff --git a/macros/latex/contrib/inlinelabel/inlinelabel-ja.md b/macros/latex/contrib/inlinelabel/inlinelabel-ja.md deleted file mode 100644 index a0e14fe403..0000000000 --- a/macros/latex/contrib/inlinelabel/inlinelabel-ja.md +++ /dev/null @@ -1,55 +0,0 @@ -# Inlinelabel パッケージ - -このパッケージは,インライン数式に数式番号を振ることができます。また,日本語を扱えるときには,丸で囲まれた数式番号に切り替えることができます。 - - -## 前提条件 - -+ TeX format: LaTeX -+ Prerequisite package: amsmath and refcount -+ Prerequisite package with [circled] option: japanese-otf - - -## インストール - -inlinelabel.sty を $TEXMF/tex/latex/hideanswer (TeXが見つけられる場所)に置いてください。 - - -## 使用方法 - -### \inlinelabel{<label>} - -インラインの数式番号を置きます。数式の外($--$の外)に置いてください。引数にラベルの名前を取ります。文章を自然に見せるために,前後に少しの余白を取ります。余白がいらないときは,\inlinelabel*{<label>} を使ってください。 - - -### Option [circled] - -あなたが日本語の環境を使用していることを前提とします。丸で囲まれた数式番号に切り替えます。インラインの数式番号だけでなく,すべての数式番号が書き換えられます。 - - -### \circledref{<label>} - -[circled] オプションを読み込んでいるときにのみ有効です。 -丸で囲まれた数式番号を参照します。 - - -### \equationref{<label>} - -[circled] オプションを読み込んでいるときにのみ有効です。 -\circledref{<label>} と同じです。 - - -## ライセンス - -このパッケージは[MITライセンス](https://ctan.org/license/mit)のもとで配布しています。 - - -## 更新履歴 - -+ Version 1.0 2022-06-28 - + The first public version. - - ---- - -[Yukoh KUSAKABE](https://twitter.com/metaphysicainfo) (screen-name) at [metaphysica.info](https://www.metaphysica.info/)
\ No newline at end of file diff --git a/macros/latex/contrib/inlinelabel/inlinelabel.pdf b/macros/latex/contrib/inlinelabel/inlinelabel.pdf Binary files differnew file mode 100644 index 0000000000..67544ad66c --- /dev/null +++ b/macros/latex/contrib/inlinelabel/inlinelabel.pdf diff --git a/macros/latex/contrib/inlinelabel/inlinelabel.sty b/macros/latex/contrib/inlinelabel/inlinelabel.sty index 93c4822c83..54f35259ff 100644 --- a/macros/latex/contrib/inlinelabel/inlinelabel.sty +++ b/macros/latex/contrib/inlinelabel/inlinelabel.sty @@ -10,11 +10,18 @@ %% % \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{inlinelabel}[2022/06/28 v1.0] +\ProvidesPackage{inlinelabel}[2022/07/07 v1.1] % % When you meet ''Package pxufont Error: You must load this package % after 'otf'.'', move \usepackage{otf} to a forward row. % +%% \if@inlinelabel@nospace +\newif\if@inlinelabel@nospace +\@inlinelabel@nospacefalse +% +%% [nospace] +\DeclareOption{nospace}{\@inlinelabel@nospacetrue} +% %% \if@inlinelabel@circled \newif\if@inlinelabel@circled \@inlinelabel@circledfalse @@ -22,6 +29,14 @@ %% [circled] \DeclareOption{circled}{\@inlinelabel@circledtrue} % +%% \if@inlinelabel@luacircled +\newif\if@inlinelabel@luacircled +\@inlinelabel@luacircledfalse +% +%% [luacircled] +\DeclareOption{luacircled}{\@inlinelabel@luacircledtrue} +% +% \ExecuteOptions{} \ProcessOptions\relax % @@ -47,9 +62,38 @@ \fi %% % +%% When [luacircled] +\if@inlinelabel@luacircled +% +% for \ajMaru +\RequirePackage{luatexja-otf} +% for \getrefnumber +\RequirePackage{refcount} +% +% renew tagform +\def\tagform@#1{\maketag@@@{$\ldots\hspace*{-0.075em}$\ignorespaces\ajMaru{#1}\unskip\@@italiccorr}}% +% +%% \circledref{<label>} +%% \equationref{<label>} +\DeclareRobustCommand{\circledref}[1]{\mbox{\ajMaru{\getrefnumber{#1}}}} +\DeclareRobustCommand{\equationref}[1]{\mbox{\ajMaru{\getrefnumber{#1}}}} +% +\fi +% +\if@inlinelabel@nospace +% +%% [nospace]\inlinelabel{<label>} +\DeclareRobustCommand{\inlinelabel}{\@ifstar{\@inlinelabelstar}{\@inlinelabelnostar}} +\DeclareRobustCommand{\@inlinelabelnostar}[1]{\refstepcounter{equation}\tagform@\theequation\expandafter\label{#1}} +\DeclareRobustCommand{\@inlinelabelstar}[1]{\hspace{0.5em}\refstepcounter{equation}\tagform@\theequation\expandafter\label{#1}\hspace{0.5em}} +% +\else +% %% \inlinelabel{<label>} \DeclareRobustCommand{\inlinelabel}{\@ifstar{\@inlinelabelstar}{\@inlinelabelnostar}} \DeclareRobustCommand{\@inlinelabelstar}[1]{\refstepcounter{equation}\tagform@\theequation\expandafter\label{#1}} \DeclareRobustCommand{\@inlinelabelnostar}[1]{\hspace{0.5em}\refstepcounter{equation}\tagform@\theequation\expandafter\label{#1}\hspace{0.5em}} % +\fi +% %% EOF
\ No newline at end of file diff --git a/macros/latex/contrib/inlinelabel/inlinelabel_example.tex b/macros/latex/contrib/inlinelabel/inlinelabel_example.tex deleted file mode 100644 index bf70bcaf82..0000000000 --- a/macros/latex/contrib/inlinelabel/inlinelabel_example.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentclass[uplatex]{article} -\usepackage{inlinelabel} -\begin{document} -$1=2$\inlinelabel{a} - -$1=2$\inlinelabel*{b} - -\ref{a} - -\ref{b} -\end{document}
\ No newline at end of file diff --git a/macros/latex/contrib/postnotes/CHANGELOG.md b/macros/latex/contrib/postnotes/CHANGELOG.md index 384af1bb2e..42e0f5f7f7 100644 --- a/macros/latex/contrib/postnotes/CHANGELOG.md +++ b/macros/latex/contrib/postnotes/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## [Unreleased](https://github.com/gusbrs/postnotes/compare/v0.1.3...HEAD) +## [Unreleased](https://github.com/gusbrs/postnotes/compare/v0.1.4...HEAD) + +## [v0.1.4](https://github.com/gusbrs/postnotes/compare/v0.1.3...v0.1.4) (2022-07-06) + +### Added +- `zref-check` support. ## [v0.1.3](https://github.com/gusbrs/postnotes/compare/v0.1.2...v0.1.3) (2022-05-28) diff --git a/macros/latex/contrib/postnotes/postnotes-code.pdf b/macros/latex/contrib/postnotes/postnotes-code.pdf Binary files differindex b1af0cc1e0..c364f3c9b7 100644 --- a/macros/latex/contrib/postnotes/postnotes-code.pdf +++ b/macros/latex/contrib/postnotes/postnotes-code.pdf diff --git a/macros/latex/contrib/postnotes/postnotes.dtx b/macros/latex/contrib/postnotes/postnotes.dtx index 7124ed7d70..489c40bf5d 100644 --- a/macros/latex/contrib/postnotes/postnotes.dtx +++ b/macros/latex/contrib/postnotes/postnotes.dtx @@ -147,7 +147,7 @@ % % % \begin{macrocode} -\ProvidesExplPackage {postnotes} {2022-05-28} {0.1.3} +\ProvidesExplPackage {postnotes} {2022-07-06} {0.1.4} {Endnotes for LaTeX} % \end{macrocode} % @@ -1338,7 +1338,7 @@ { content } \l_@@_print_content_tl \cs_set:Npn \@currentcounter { postnotetext } \int_set:Nn \c@postnotetext - { \int_eval:n { \l_@@_print_counter_tl } } + { \l_@@_print_counter_tl } \cs_set:Npx \@currentlabel { \p@postnote \l_@@_print_mark_tl } \@@_hyperref_make_currentHref:n @@ -1940,6 +1940,12 @@ % % \section{Compatibility} % +% A dedicated temp variable for restoring data. +% +% \begin{macrocode} +\tl_new:N \l_@@_restore_tmp_tl +% \end{macrocode} +% % \subsection*{\cs{caption}} % % For \cs{caption}'s possible two passes. This catches more than just @@ -2055,21 +2061,20 @@ % \end{macrocode} % Restore \pkg{biblatex} variables for each note. % \begin{macrocode} - \tl_new:N \l_@@_biblatex_restore_tl \AddToHook { postnotes/print/eachnote } [ postnotes ] { \@@_prop_get:nnN { \l_@@_print_note_id_tl } - { biblatex@refsection } \l_@@_biblatex_restore_tl - \int_set:Nn \c@refsection { \l_@@_biblatex_restore_tl } + { biblatex@refsection } \l_@@_restore_tmp_tl + \int_set:Nn \c@refsection { \l_@@_restore_tmp_tl } \@@_prop_get:nnN { \l_@@_print_note_id_tl } - { biblatex@refsegment } \l_@@_biblatex_restore_tl - \int_set:Nn \c@refsegment { \l_@@_biblatex_restore_tl } + { biblatex@refsegment } \l_@@_restore_tmp_tl + \int_set:Nn \c@refsegment { \l_@@_restore_tmp_tl } \@@_prop_get:nnN { \l_@@_print_note_id_tl } - { biblatex@refcontextbool } \l_@@_biblatex_restore_tl - \use:c { toggle \l_@@_biblatex_restore_tl } { blx@refcontext } + { biblatex@refcontextbool } \l_@@_restore_tmp_tl + \use:c { toggle \l_@@_restore_tmp_tl } { blx@refcontext } \@@_prop_get:nnN { \l_@@_print_note_id_tl } - { biblatex@refcontext } \l_@@_biblatex_restore_tl - \blx@edef@refcontext { \l_@@_biblatex_restore_tl } + { biblatex@refcontext } \l_@@_restore_tmp_tl + \blx@edef@refcontext { \l_@@_restore_tmp_tl } } % \end{macrocode} % Make \pkg{biblatex}'s \cs{mkbibendnote} use \cs{postnote}. This is very @@ -2204,15 +2209,15 @@ \AddToHook { postnotes/print/eachnote } [ postnotes ] { \@@_prop_get:nnN { \l_@@_print_note_id_tl } - { biblatex@refsection } \l_@@_biblatex_restore_tl + { biblatex@refsection } \l_@@_restore_tmp_tl \tl_if_eq:NNF - \l_@@_biblatex_restore_tl + \l_@@_restore_tmp_tl \g_@@_biblatex_prev_refsection_tl { \int_set:Nn \c@blx@maxsection - { \l_@@_biblatex_restore_tl - 1 } + { \l_@@_restore_tmp_tl - 1 } \tl_gset_eq:NN \g_@@_biblatex_prev_refsection_tl - \l_@@_biblatex_restore_tl + \l_@@_restore_tmp_tl \group_begin: \cs_set_eq:NN \label \use_none:n \cs_set_eq:NN \blx@info \use_none:n @@ -2308,6 +2313,35 @@ % \end{macrocode} % % +% \subsection*{\pkg{zref-check}} +% +% \begin{macrocode} +\AddToHook { package/zref-check/after } + { + \IfPackageAtLeastTF { zref-check } { 2022-07-05 } + { + \AddToHook { postnotes/store/note } [ postnotes ] + { + \prop_gput:cnx { \@@_data_name:e { \l_@@_note_id_tl } } + { zref-check@abschap } { \int_use:N \c@zc@abschap } + \prop_gput:cnx { \@@_data_name:e { \l_@@_note_id_tl } } + { zref-check@abssec } { \int_use:N \c@zc@abssec } + } + \AddToHook { postnotes/print/eachnote } [ postnotes ] + { + \@@_prop_get:nnN { \l_@@_print_note_id_tl } + { zref-check@abschap } \l_@@_restore_tmp_tl + \int_set:Nn \c@zc@abschap { \l_@@_restore_tmp_tl } + \@@_prop_get:nnN { \l_@@_print_note_id_tl } + { zref-check@abssec } \l_@@_restore_tmp_tl + \int_set:Nn \c@zc@abssec { \l_@@_restore_tmp_tl } + } + } + { } + } +% \end{macrocode} +% +% % \subsection*{\pkg{amsmath}} % % \begin{macrocode} diff --git a/macros/latex/contrib/postnotes/postnotes.pdf b/macros/latex/contrib/postnotes/postnotes.pdf Binary files differindex af17232cc1..6059ea2438 100644 --- a/macros/latex/contrib/postnotes/postnotes.pdf +++ b/macros/latex/contrib/postnotes/postnotes.pdf diff --git a/macros/latex/contrib/profcollege/doc/ProfCollege-doc.pdf b/macros/latex/contrib/profcollege/doc/ProfCollege-doc.pdf Binary files differindex 75069775ec..f2aa966d0e 100644 --- a/macros/latex/contrib/profcollege/doc/ProfCollege-doc.pdf +++ b/macros/latex/contrib/profcollege/doc/ProfCollege-doc.pdf diff --git a/macros/latex/contrib/profcollege/latex/ProfCollege.sty b/macros/latex/contrib/profcollege/latex/ProfCollege.sty index 45e407cf36..5221eebaa9 100644 --- a/macros/latex/contrib/profcollege/latex/ProfCollege.sty +++ b/macros/latex/contrib/profcollege/latex/ProfCollege.sty @@ -1,9 +1,8 @@ % Author : Christophe Poulain % licence : Released under the LaTeX Project Public License v1.3c % or later, see http://www.latex-project.org/lppl.txtf - \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{ProfCollege}[2022/06/01 v0.99-p Aide pour l'utilisation de LaTeX au college] +\ProvidesPackage{ProfCollege}[2022/07/01 v0.99-r Aide pour utiliser LaTeX au college] \RequirePackage{verbatim} @@ -190,9 +189,11 @@ }% \newcommand\Lignespointilles[1]{% - \xintFor* ##1 in {\xintSeq {1}{#1}}\do{% - \pointilles\par% - }% + \xintifboolexpr{#1>1}{% + \xintFor* ##1 in {\xintSeq {1}{#1}}\do{% + \pointilles\par% + }% + }{}% }% \newcommand\MultiCol[2]{% @@ -337,6 +338,717 @@ } %%% +% Représenter un entier +%%% +\setKVdefault[ClesREntier]{Echelle=1,Unite=false,Compact=false,Impression=false,ListeCouleurs={Tomato,LightSteelBlue,LightGreen,Cornsilk}}% + +\newcommand\RepresenterEntier[2][]{% + \useKVdefault[ClesREntier]% + \setKV[ClesREntier]{#1}% + \ifboolKV[ClesREntier]{Unite}{% + \begin{Geometrie}[TypeTrace="Espace",CoinBG={u*(-10,-10)}] + Echelle=\useKV[ClesREntier]{Echelle}; + Initialisation(5,30,15,50*Echelle); + color A,B,C,D,E,F,G,H; + pointilles:="non"; + trace Pave(A,B,C,D,E,F,G,H)(0.1,0.1,0.1); + \end{Geometrie} + }{% + % On décompose le nombre + \StrLen{#2}[\LongueurNombreEntier]% + \xdef\FooListeEntier{} + \xintFor* ##1 in{\xintSeq{1}{\LongueurNombreEntier}}\do{% + \StrChar{#2}{##1}[\ChiffreAAjouter] + \xdef\FooListeEntier{\FooListeEntier \ChiffreAAjouter,} + } + \setsepchar{,}\ignoreemptyitems + \readlist*\ListeDesChiffres{\FooListeEntier}% + \xdef\ListeAvantCouleurs{\useKV[ClesREntier]{ListeCouleurs}}% + \readlist*\ListeCouleurEntier{\ListeAvantCouleurs}% + \xintifboolexpr{\LongueurNombreEntier==4}{% + \xdef\NombreMilliers{\ListeDesChiffres[1]}% + \xdef\NombreCentaines{\ListeDesChiffres[2]}% + \xdef\NombreDizaines{\ListeDesChiffres[3]}% + \xdef\NombreUnites{\ListeDesChiffres[4]}% + }{% + \xintifboolexpr{\LongueurNombreEntier==3}{% + \xdef\NombreMilliers{0}% + \xdef\NombreCentaines{\ListeDesChiffres[1]}% + \xdef\NombreDizaines{\ListeDesChiffres[2]}% + \xdef\NombreUnites{\ListeDesChiffres[3]}% + }{% + \xintifboolexpr{\LongueurNombreEntier==2}{% + \xdef\NombreMilliers{0}% + \xdef\NombreCentaines{0}% + \xdef\NombreDizaines{\ListeDesChiffres[1]}% + \xdef\NombreUnites{\ListeDesChiffres[2]}% + }{% + \xdef\NombreMilliers{0}% + \xdef\NombreCentaines{0}% + \xdef\NombreDizaines{0}% + \xdef\NombreUnites{\ListeDesChiffres[1]}% + }% + }% + }% + \begin{Geometrie}[TypeTrace="Espace",CoinBG={u*(-10,-10)},CoinHD={u*(20,20)}] + Echelle=\useKV[ClesREntier]{Echelle}; + NM=\NombreMilliers; + NC=\NombreCentaines; + ND=\NombreDizaines; + NU=\NombreUnites; + color ColorEntier[]; + ColorEntier1=\ListeCouleurEntier[1]; + ColorEntier2=\ListeCouleurEntier[2]; + ColorEntier3=\ListeCouleurEntier[3]; + ColorEntier4=\ListeCouleurEntier[4]; + boolean Compact,Print; + Compact=\useKV[ClesREntier]{Compact}; + Print=\useKV[ClesREntier]{Impression}; + Initialisation(5,30,15,50*Echelle); + color A,B,C,D,E,F,G,H; + picture TypePave[]; + TypePave0=image( + trace Pave(A,B,C,D,E,F,G,H)(1,1,1); + currentpicture:=nullpicture; + remplis polygone(A,B,C,H,E,F) withcolor if Print : blanc else: ColorEntier1 fi; + for k=0 upto 10: + trace chemin((k/10)[A,B],(k/10)[F,G],(k/10)[E,H]); + endfor; + for k=0 upto 10: + trace chemin((k/10)[B,C],(k/10)[G,H],(k/10)[F,E]); + endfor; + for k=0 upto 10: + trace chemin((k/10)[A,F],(k/10)[B,G],(k/10)[C,H]); + endfor; + %if Compact: + %trace chemin(B,B+(0,0,-0.2)) dashed evenly withpen pencircle scaled 1.25; + %fi; + ); + color A,B,C,D,E,F,G,H; + TypePave1=image( + trace Pave(A,B,C,D,E,F,G,H)(0.1,1,1); + currentpicture:=nullpicture; + remplis polygone(A,B,C,H,E,F) withcolor if Print : blanc else: ColorEntier2 fi; + trace chemin(C,H,E); + for k=0 upto 10: + trace chemin((k/10)[A,B],(k/10)[F,G],(k/10)[E,H]); + endfor; + for k=0 upto 10: + trace chemin((k/10)[A,F],(k/10)[B,G],(k/10)[C,H]); + endfor; + %if Compact: + %trace chemin(B,B+(0,0,-0.2)) dashed evenly withpen pencircle scaled 1.25; + %fi; + ); + color A,B,C,D,E,F,G,H; + TypePave2=image( + trace Pave(A,B,C,D,E,F,G,H)(0.1,0.1,1); + currentpicture:=nullpicture; + remplis polygone(A,B,C,H,E,F) withcolor if Print : blanc else: ColorEntier3 fi; + trace chemin(C,H,E); + trace chemin(A,F,E); + trace chemin(B,G,F); + for k=0 upto 10: + trace chemin((k/10)[A,F],(k/10)[B,G],(k/10)[C,H]); + endfor; + %if Compact: + %trace chemin(B,B+(0,0,-0.2)) dashed evenly withpen pencircle scaled 1.25; + %fi; + ); + color A,B,C,D,E,F,G,H; + TypePave3=image( + trace Pave(A,B,C,D,E,F,G,H)(0.1,0.1,0.1); + currentpicture:=nullpicture; + remplis polygone(A,B,C,H,E,F) withcolor if Print : blanc else: ColorEntier4 fi; + trace chemin(C,H,E); + trace chemin(A,F,E); + trace chemin(A,B,C); + trace chemin(F,G,H); + trace chemin(B,G); + ); + if Compact: + for k=0 upto (\NombreMilliers-1): + trace TypePave0 shifted ((Projette((k,0,0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreCentaines-1): + trace TypePave1 shifted ((Projette((0.1*k,1.5,0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreDizaines-1): + trace TypePave2 shifted ((Projette((0.1*k,3,0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreUnites-1): + trace TypePave3 shifted ((Projette((0,3.6,0.1*k))-Projette((0,0,0)))); + endfor; + else: + for k=0 upto (\NombreMilliers-1): + trace TypePave0 shifted ((Projette((0,1.1*(k-1),0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreCentaines-1): + trace TypePave1 shifted ((Projette((0,1.1*\NombreMilliers+1.1*(k-1),0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreDizaines-1): + trace TypePave2 shifted ((Projette((0,1.1*\NombreMilliers+1.1*(\NombreCentaines-1)+0.2+0.2*(k-1),0))-Projette((0,0,0)))); + endfor; + for k=0 upto (\NombreUnites-1): + trace TypePave3 shifted ((Projette((0,1.1*\NombreMilliers+1.1*(\NombreCentaines-1)+0.2+0.2*(\NombreDizaines-1),0.2*(k)))-Projette((0,0,0)))); + endfor; + fi; + \end{Geometrie} + } +} + +% Gestion de l'aléatoire (pour la CAN) +\newcommand\ChoixAlea[4][]{% + \ifx\bla#1\bla% + \xdef#4{\fpeval{randint(#2,#3)}}% + \else% + \xdef#4{\fpeval{round(randint(#2,#3)+rand(),#1)}}% + \fi% +}% + +\def\VariableAlea#1#2{% + \xdef#1{\fpeval{#2}}% +}% + +% On bloque la graine de fabrication des nombres aléatoires. +\ExplSyntaxOn +\cs_new_eq:NN \PfCGraineAlea \sys_gset_rand_seed:n +\ExplSyntaxOff + +%%% +% Course aux nombres +%%% +\RequirePackage{longtable} +% https://tex.stackexchange.com/questions/642775/when-displaying-a-datatool-database-with-dtldisplaylongdb-how-to-obtain-a-hor +% Patch éventuel à ajouter +%\makeatletter +%\expandafter\patchcmd\expandafter{\csname\string\DTLdisplaylongdb\endcsname}% +% {\@dtl@resetdoamp\dtldisplaystarttab}% +% {\dtldisplaystarttab\@dtl@resetdoamp}% +% {\message{Patching succeeded.}}% +% {\message{Patching failed.}}% +%\makeatother + +\setKVdefault[ClesMathAlea]{NbQ=5,ChoixTables=2-9,ValeurMax=20,Classique,Trou=false,Melange=false,Multiple=2,Theme=false}% +\defKV[ClesMathAlea]{Trous=\setKV[ClesMathAlea]{Classique=false}\setKV[ClesMathAlea]{Trou}}% +\defKV[ClesMathAlea]{Melanges=\setKV[ClesMathAlea]{Classique=false}\setKV[ClesMathAlea]{Melange}}% + +\newcommand\MathAlea[2][]{% + \useKVdefault[ClesMathAlea]% + \setKV[ClesMathAlea]{#1}% + \input{#2}% +}% + +\newcommand\CourseNombreTotalQuestions[1]{% + \setKV[ClesCN]{TotalQ=#1}% + \xdef\CNfoo{}% + \xintFor* ##1 in{\xintSeq{1}{#1}}\do{% + \xdef\CNfoo{\CNfoo ##1,}% + }% +}% + +\setKVdefault[ClesCN]{% + Stretch=2.5,%Elasticité du tableau + NbQ=5,%Nb de questions à poser + RAZ=false,%Pour remettre à zéro le compteur des questions + Ordre=false,%Pour mettre toutes les questions dans l'ordre des numéros + Exercice=false,%Pour utiliser l'aléatoire des questions mais sans habillage particulier, autre que des \item + Perso=false,%Pour que utiliser un choix personnel des questions + Lecture=false,%Pour différencier avec une lecture automatisée sur les numéros de fichiers + Maitre=false,%Pour indiquer qu'on prend en compte ou pas les sous-dossiers + Nom=false,%Pour afficher le nom des fichiers utilisés. + Theme=false,%Pour afficher le theme travaillé dans les fichiers utilisés. + AMC=false,% + Multi=false% +}% +\defKV[ClesCN]{Liste=\setKV[ClesCN]{Perso=true}\setKV[ClesCN]{Lecture}}% +\defKV[ClesCN]{Dossier=\setKV[ClesCN]{Lecture}}% +\defKV[ClesCN]{Debut=\setKV[ClesCN]{RAZ}}% +\setsepchar[*]{,*/}% +\readlist*\ListeMotsCAN{La moitié de /2,Le double de /1,Le triple de /1, Le tiers de /3,Le nombre dix fois plus grand que /1,Le nombre cent fois plus grand que /1,Le nombre mille fois plus grand que /1,Le nombre dix fois plus petit que /10,Le nombre cent fois plus petit que /100,Le nombre mille fois plus petit que /1000}% +\readlist*\ListeMulAstucieuxCAN{50/2,25/4,20/5}% +\readlist*\ListeLieuxObjetsCAN{boulangerie/pains au chocolat/un pain au chocolat,boulangerie/cookies/un cookie,boulangerie/brioches/une brioche,piscine/entrées/une entrée,boucherie/saucisses/une saucisse,boucherie/cuisses de poulet/une cuisse de poulet}% +\readlist*\ListeNomsCAN{Aude/Elle,Bernard/Il,Céline/Elle,Daniel/Il,Elise/Elle,Fabien/Il,Gérard/Il,Hélène/Elle,Ilies/Il,Jasmine/Elle,Kylian/Il,Laurent/Il,Mathilde/Elle,Nina/Elle,Octave/Il,Philippe/Il,Joachim/Il,Thérèse/Elle,Nawel/Elle,Alexandre/Il,Maxence/Il,Sophie/Elle,Christophe/Il,Myriam/Elle}% +\readlist*\ListeComposantStatCAN{voitures/un garage/Cross-over/Utilitaires/Berlines,fruits/une corbeille/Pommes/Oranges/Bananes,vêtements/une armoire/Pulls/T-shirts/Chemises,couverts/un tiroir/Fourchettes/Couteaux/Cuillères}% +\readlist*\ListeObjetsSymbolesCAN{fleurs/96,ciseaux/36,crayons/47,enveloppes/41}%uniquement avec pifont +\setsepchar{,}% +\readlist*\ListeObjetsCAN{bonbons,billes,jouets,fruits,biscuits,gâteaux,pommes,poires} +\readlist*\ListeFruitsCAN{pommes,poires,abricots,cerises,fraises,framboises,noix,pêches,nectarines,myrtilles} +\readlist*\ListeSommetsCAN{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} + +\newcommand\ExtraitSymboles[1]{% + \xdef\CANSGFoo{}% + \foreachitem\compteur\in\ListeObjetsSymbolesCAN{% + \xdef\CANSGFoo{\CANSGFoo \ListeObjetsSymbolesCAN[\compteurcnt],}% + }% + \MelangeListe{\CANSGFoo}{#1}% + \setsepchar[*]{,*/}% + \readlist*\SymbolesMelanges{\faa}% + \setsepchar{,}% +}% + +\newcommand\ExtraitSommet[1]{% + \xdef\CANSGFoo{}% + \foreachitem\compteur\in\ListeSommetsCAN{% + \xdef\CANSGFoo{\CANSGFoo \ListeSommetsCAN[\compteurcnt],}% + }% + \MelangeListe{\CANSGFoo}{#1}% + \readlist*\SommetsMelanges{\faa}% +}% + +\newcommand\ExtraitFruit[1]{% + \xdef\CANSGFoo{}% + \foreachitem\compteur\in\ListeFruitsCAN{% + \xdef\CANSGFoo{\CANSGFoo \ListeFruitsCAN[\compteurcnt],}% + }% + \MelangeListe{\CANSGFoo}{#1}% + \readlist*\FruitsMelanges{\faa}% +}% + +\newcommand\ExtraitNom[1]{% + \xdef\CANSGFoo{}% + \foreachitem\compteur\in\ListeNomsCAN{% + \xdef\CANSGFoo{\CANSGFoo \ListeNomsCAN[\compteurcnt],}% + }% + \MelangeListe{\CANSGFoo}{#1}% + \setsepchar[*]{,*/}% + \readlist*\NomsMelanges{\faa}% + \setsepchar{,}% +}% + +\newcommand\ExtraitElements[1]{% + \xdef\CANSGFoo{}% + \foreachitem\compteur\in\ListeComposantStatCAN{% + \xdef\CANSGFoo{\CANSGFoo \ListeComposantStatCAN[\compteurcnt],}% + }% + \MelangeListe{\CANSGFoo}{#1}% + \setsepchar[*]{,*/}% + \readlist*\ElementsMelanges{\faa}% + \setsepchar{,}% +}% + +\newcounter{CNNumQ}% +\setcounter{CNNumQ}{1}% + +\newcommand\CANNew{% + \textcolor{Crimson}{\faCopy}% +}% + +\newread\RecupNbFichiers +\newread\RecupSSDossiers +\newread\zzz +\def\zzpar{\par}% + +\makeatletter +\def\app@exe{\write18} +% Recuperer les sous-dossiers +\def\RecupererSousDossiers#1{%#1 est le dossier contenant les fichiers can classés en sous-dossier + \app@exe{rm -f RecapSSDossier.tmp ; ls -1 -I "*.tex" #1 > RecapSSDossier.tmp}% + \immediate\openin\zzz=RecapSSDossier.tmp + \loop% + \read\zzz to \tmp% + \ifx\tmp\zzpar\else% + \xdef\CNFOOSSDossiers{\CNFOOSSDossiers \expandafter\detokenize\expandafter{\tmp},}% + \fi% + \ifeof\zzz\else% + \repeat% + \setsepchar{,}\ignoreemptyitems + \readlist*\ListeSSDossiers{\CNFOOSSDossiers} +} + +\def\RecupererFichierTeXSSDossier#1#2{% + \openin\zzz="|ls #1/#2/*.tex"% + \loop% + \read\zzz to \tmp% + \ifx\tmp\zzpar\else% + \xdef\CNFOO{\CNFOO \expandafter\detokenize\expandafter{\tmp},}% + \fi% + \ifeof\zzz\else% + \repeat% +} + +\def\RecupererFichierTeXDossier#1{% + \xdef\CNFOO{}% + \openin\zzz="|ls #1/*.tex" + \loop% + \read\zzz to \tmp% + \ifx\tmp\zzpar\else% + \xdef\CNFOO{\CNFOO \expandafter\detokenize\expandafter{\tmp},}% + \fi% + \ifeof\zzz\else% + \repeat% +} + +\def\DefinirListeFichiers{% + \setsepchar{,}\ignoreemptyitems% + \readlist*\ListeFichiers{\CNFOO}% +} + +\def\RecupererFichierTeXAllSSDossier#1{% + \RecupererSousDossiers{#1}% + \foreachitem\compteur\in\ListeSSDossiers{\RecupererFichierTeXSSDossier{#1}{\ListeSSDossiers[\compteurcnt]}}% + \DefinirListeFichiers% +} + +\def\RecupererFichierTeXAllDossier#1{% + \RecupererFichierTeXDossier{#1}% + \DefinirListeFichiers% +} + +\def\RecupererFichierTeXComplet#1{% + \RecupererFichierTeXDossier{#1}% + \RecupererSousDossiers{#1}% + \foreachitem\compteur\in\ListeSSDossiers{\RecupererFichierTeXSSDossier{#1}{\ListeSSDossiers[\compteurcnt]}}% + \DefinirListeFichiers% +} + +\def\RecupererFichierTeXSSDossierPerso#1{% + \openin\zzz="|ls #1/*.tex" + \loop% + \read\zzz to \tmp% + \ifx\tmp\zzpar\else% + \xdef\CNFOO{\CNFOO \expandafter\detokenize\expandafter{\tmp},}% + \fi% + \ifeof\zzz\else% + \repeat% +} + +\makeatother + +\newcommand\CNTheme[1]{}% + +\NewDocumentCommand\CourseNombre{o m}{% + \setKV[ClesMathAlea]{NbQ=1}% + \useKVdefault[ClesCN]% + \setKV[ClesCN]{#1}% + \ifboolKV[ClesCN]{Theme}{\renewcommand\CNTheme[1]{{\ttfamily Thème : ##1}\par}}{}% + \ifboolKV[ClesCN]{RAZ}{%\setcounter{CNNumQ}{1}}{}% + \setcounter{CNNumQ}{\useKV[ClesCN]{Debut}}% + }{}% + \setKV[ClesMathAlea]{NbQ=1}% + \xdef\CNFOOSSDossiers{}% + \xdef\CNFOO{}% + \ifboolKV[ClesCN]{Lecture}{% + \ifboolKV[ClesCN]{Perso}{% + % % Ici \useKV[ClesCN]{Liste} + \xdef\CNFOOListePerso{\useKV[ClesCN]{Liste}}% + % % OK -> Là, normalement, c'est la liste des dossiers choisis par l'utilisateur : \CNFOOListePerso + \setsepchar{,}% + \readlist*\ListeDesSSDossiersPerso{\CNFOOListePerso}% + % % \par OK -> Là, normalement, c'est la liste des dossiers perso sous forme de liste : \showitems\ListeDesSSDossiersPerso[]% + \foreachitem\compteur\in\ListeDesSSDossiersPerso{\RecupererFichierTeXSSDossierPerso{\ListeDesSSDossiersPerso[\compteurcnt]}}% + \DefinirListeFichiers% + % % \par OK -> Là, enfin, normalement, c'est la liste des fichiers contenus dans les dossiers perso : + % % \showitems\ListeFichiers[] + }{% + \ifboolKV[ClesCN]{Maitre}{% + % % On récupère tous les fichiers can dans les sous-dossiers + % % et on construit une liste \ListeFichiers contenant les chemins des fichiers considérés. + \RecupererFichierTeXComplet{\useKV[ClesCN]{Dossier}}% + }{% + % % Là + % % On récupère seulement les fichiers can de ce dossier + % % et on consruit une liste \ListeFichiers contenant les chemins des fichiers considérés. + \RecupererFichierTeXAllDossier{\useKV[ClesCN]{Dossier}}% + }% + }% + % % On crée la liste du nombre total de questions + \xdef\CNfooListe{}% + \xintFor* ##1 in{\xintSeq{1}{\ListeFichierslen}}\do{% + \xdef\CNfooListe{\CNfooListe ##1,}% + }% + % % \par OK -> normalement, on a la liste du nombre de questions : \CNfooListe + % % On affiche les questions : + \ifboolKV[ClesCN]{Ordre}{% + % % soit dans un exercice + \ifboolKV[ClesCN]{Exercice}{% + % % Attention le style de l'environnement est à choisir par l'utilisateur + \xintFor* ##1 in {\xintSeq{1}{\ListeFichierslen}}\do{% + \item\input{\ListeFichiers[##1]}% + }% + }{% Soit toutes les questions au format course + \renewcommand{\arraystretch}{\useKV[ClesCN]{Stretch}}% + \begin{longtable}{|c|p{0.7\linewidth}|p{0.1\linewidth}|p{0.05\linewidth}|}% + \hhline{~---}% + \multicolumn{1}{c|}{}&\cellcolor{gray!15}\centering\'Enoncé&\cellcolor{gray!15}\centering Réponse&\cellcolor{gray!15}\centering\arraybackslash Jury\\% + \hline% + \endhead% + \xintFor* ##1 in {\xintSeq{1}{\ListeFichierslen}}\do{% + \ttfamily{\theCNNumQ}\stepcounter{CNNumQ}&\input{\ListeFichiers[##1]}\ifboolKV[ClesCN]{Nom}{\par\hfill\footnotesize\ttfamily\ListeFichiers[##1]}{}&&\\% + \hline% + }% + \end{longtable}% + \renewcommand{\arraystretch}{1}% + }% + }{% + % On prévient l'utilisateur si le nb de questions est inférieur à NbQ + \xintifboolexpr{\ListeFichierslen<\useKV[ClesCN]{NbQ}}{% + \faExclamationCircle~Le nombre maximal de questions est inférieur au nombre de questions à afficher. Modifier la clé {\ttfamily NbQ} ou ajouter des questions dans le(s) répertoire(s).% + }{%%On choisit NbQ questions parmi la liste de fichiers + \MelangeListe{\CNfooListe}{\useKV[ClesCN]{NbQ}}% + \setsepchar{,}\ignoreemptyitems% + \readlist*\ListeCNQuestions{\faa} + \ifboolKV[ClesCN]{Exercice}{% + \xintFor* ##1 in {\xintSeq{1}{\useKV[ClesCN]{NbQ}}}\do{% + \item\xdef\Numerodelaquestionaposer{\ListeCNQuestions[##1]}\input{\ListeFichiers[\Numerodelaquestionaposer]}% + }% + }{% On les affiche + \renewcommand{\arraystretch}{\useKV[ClesCN]{Stretch}}% + \begin{longtable}{|c|p{0.7\linewidth}|p{0.1\linewidth}|p{0.05\linewidth}|}% + \hhline{~---}% + \multicolumn{1}{c|}{}&\cellcolor{gray!15}\centering\'Enoncé&\cellcolor{gray!15}\centering Réponse&\cellcolor{gray!15}\centering\arraybackslash Jury\\% + \hline% + \endhead% + \xintFor* ##1 in {\xintSeq{1}{\useKV[ClesCN]{NbQ}}}\do{% + \ttfamily{\theCNNumQ}\stepcounter{CNNumQ}&\xdef\Numerodelaquestionaposer{\ListeCNQuestions[##1]}\input{\ListeFichiers[\Numerodelaquestionaposer]}\ifboolKV[ClesCN]{Nom}{\par\hfill\footnotesize\ttfamily\ListeFichiers[##1]}{}&&\\ + \hline + }% + \end{longtable}% + \renewcommand{\arraystretch}{1}% + }% + }% + }% + }{% + \input{#2} + }% +}% +% fin course aux nombres + +%%% +% Frise temporelle +%%% +\setKVdefault[ClesFrise]{Longueur=8cm,Fleches=false,Ecart=5mm,Sup=false}% + +\newtoks\toklistefrise% +\def\UpdatetoksFrise#1/#2/#3\nil{\addtotok\toklistefrise{"#1","#2","#3",}}% + +\newcommand\Frise[2][]{% + \useKVdefault[ClesFrise]% + \setKV[ClesFrise]{#1}% + \setsepchar[*]{,*/}\ignoreemptyitems% + \readlist*\ListeTempo{#2}% + \toklistefrise{}% + \foreachitem\compteur\in\ListeTempo{\expandafter\UpdatetoksFrise\compteur\nil} + \MPDessineFrise{\the\toklistefrise}% +} + +\newcommand\MPDessineFrise[1]{% + \ifluatex + \mplibforcehmode + \begin{mplibcode} + Longueur:=\useKV[ClesFrise]{Longueur}; + Ecart:=\useKV[ClesFrise]{Ecart}; + boolean Fleches; + Fleches=\useKV[ClesFrise]{Fleches}; + boolean Sup; + Sup=\useKV[ClesFrise]{Sup}; + pair A[],B; + A0=(0,0); + B-A0=(Longueur,0); + n=0; + for p_=#1: + n:=n+1; + endfor; + for k=1 upto ((n div 3)-2): + A[k]=(k/((n div 3)-1))[A0,B]; + endfor; + A[(n div 3)-1]=B; + if Sup: + for k=0 upto ((n div 3)-1): + trace (u*(0,-0.1)--u*(0,0.1)) shifted A[k]; + endfor; + % on définit les points milieu des fleches + path Fleche[]; + pair C[]; + for k=0 upto ((n div 3)-3): + Fleche[k]=(A[k]{dir-30}..{dir30}A[k+1]) shifted((0,-Ecart)); + C[k]=point (0.5*length Fleche[k]) of Fleche[k]; + endfor; + Fleche[(n div 3)-2]=%(A[(n div 3)-3]{dir-30}..{dir30}A[(n div 3)-1]) shifted((0,-Ecart)); + chemin(A[(n div 3)-3]+(0,-Ecart),A[(n div 3)-3]+(0,-4*Ecart),A[(n div 3)-1]+(0,-4*Ecart),A[(n div 3)-1]+(0,-Ecart)); + C[(n div 3)-1]=point (0.5*length Fleche[(n div 3)-2]) of Fleche[(n div 3)-2]; + Fleche[(n div 3)-1]=(A[(n div 3)-1]{dir-150}..{dir150}A[(n div 3)-2]) shifted((0,-Ecart)); + C[(n div 3)-2]=point (0.5*length Fleche[(n div 3)-1]) of Fleche[(n div 3)-1]; + % + maxx:=n; + trace segment(A0,A[(n div 3)-2]); + trace segment(A[(n div 3)-2],A[(n div 3)-1]) dashed evenly; + n:=0; + labeloffset:=labeloffset*2; + for p_=#1: + n:=n+1; + if n<maxx+1: + if (n mod 3)=1: + label.top(TEX(""&p_&""),A[n div 3]); + elseif (n mod 3)=2: + label.top(TEX(""&p_&""),C[n div 3]);% + elseif (n mod 3)=0: + label.bot(TEX(""&p_&""),C[(n div 3)-1]); + fi; + fi; + endfor; + drawoptions(); + labeloffset:=labeloffset/2; + if Fleches: + for k=0 upto ((n div 3)-4): + drawarrow Fleche[k]; + endfor; + drawarrow Fleche[(n div 3)-1]; + drawarrow Fleche[(n div 3)-2]; + drawarrow (A[(n div 3)-1]{dir-150}..{dir150}A[(n div 3)-2]) shifted((0,-Ecart)); + for k=0 upto ((n div 3)-2): + draw segment(A[k],A[k]+(0,-Ecart)) dashed evenly; + endfor; + draw segment(A[(n div 3)-1],A[(n div 3)-1]+(0,-Ecart)) dashed evenly; + fi; + %fin Sup + else: + for k=0 upto ((n div 3)-1): + trace (u*(0,-0.1)--u*(0,0.1)) shifted A[k]; + endfor; + % on définit les points milieu des fleches + path Fleche[]; + pair C[]; + for k=0 upto ((n div 3)-2): + Fleche[k]=(A[k]{dir-30}..{dir30}A[k+1]) shifted((0,-Ecart)); + C[k]=point (0.5*length Fleche[k]) of Fleche[k]; + endfor; + maxx:=n; + trace segment(A0,A[(n div 3)-1]); + n:=0; + labeloffset:=labeloffset*2; + for p_=#1: + n:=n+1; + if n<maxx: + if (n mod 3)=1: + label.top(TEX(""&p_&""),A[n div 3]); + elseif (n mod 3)=2: + if (n div 3)<((maxx div 3)-1):label.top(TEX(""&p_&""),C[n div 3]);fi; + elseif (n mod 3)=0: + label.bot(TEX(""&p_&""),C[(n div 3)-1]); + fi; + fi; + endfor; + labeloffset:=labeloffset/2; + if Fleches: + for k=0 upto ((n div 3)-2): + draw segment(A[k],A[k]+(0,-Ecart)) dashed evenly; + drawarrow Fleche[k]; + endfor; + draw segment(A[(n div 3)-1],A[(n div 3)-1]+(0,-Ecart)) dashed evenly; + fi; + fi; + \end{mplibcode} + \else + \begin{mpost}[mpsettings={% + Longueur:=\useKV[ClesFrise]{Longueur}; + Ecart:=\useKV[ClesFrise]{Ecart}; + boolean Fleches; + Fleches=\useKV[ClesFrise]{Fleches}; + boolean Sup; + Sup=\useKV[ClesFrise]{Sup}; + }] + pair A[],B; + A0=(0,0); + B-A0=(Longueur,0); + n=0; + for p_=#1: + n:=n+1; + endfor; + for k=1 upto ((n div 3)-2): + A[k]=(k/((n div 3)-1))[A0,B]; + endfor; + A[(n div 3)-1]=B; + if Sup: + for k=0 upto ((n div 3)-1): + trace (u*(0,-0.1)--u*(0,0.1)) shifted A[k]; + endfor; + % on définit les points milieu des fleches + path Fleche[]; + pair C[]; + for k=0 upto ((n div 3)-3): + Fleche[k]=(A[k]{dir-30}..{dir30}A[k+1]) shifted((0,-Ecart)); + C[k]=point (0.5*length Fleche[k]) of Fleche[k]; + endfor; + Fleche[(n div 3)-2]=%(A[(n div 3)-3]{dir-30}..{dir30}A[(n div 3)-1]) shifted((0,-Ecart)); + chemin(A[(n div 3)-3]+(0,-Ecart),A[(n div 3)-3]+(0,-4*Ecart),A[(n div 3)-1]+(0,-4*Ecart),A[(n div 3)-1]+(0,-Ecart)); + C[(n div 3)-1]=point (0.5*length Fleche[(n div 3)-2]) of Fleche[(n div 3)-2]; + Fleche[(n div 3)-1]=(A[(n div 3)-1]{dir-150}..{dir150}A[(n div 3)-2]) shifted((0,-Ecart)); + C[(n div 3)-2]=point (0.5*length Fleche[(n div 3)-1]) of Fleche[(n div 3)-1]; + % + maxx:=n; + trace segment(A0,A[(n div 3)-2]); + trace segment(A[(n div 3)-2],A[(n div 3)-1]) dashed evenly; + n:=0; + labeloffset:=labeloffset*2; + for p_=#1: + n:=n+1; + if n<maxx+1: + if (n mod 3)=1: + label.top(LATEX(""&p_&""),A[n div 3]); + elseif (n mod 3)=2: + label.top(LATEX(""&p_&""),C[n div 3]);% + elseif (n mod 3)=0: + label.bot(LATEX(""&p_&""),C[(n div 3)-1]); + fi; + fi; + endfor; + drawoptions(); + labeloffset:=labeloffset/2; + if Fleches: + for k=0 upto ((n div 3)-4): + drawarrow Fleche[k]; + endfor; + drawarrow Fleche[(n div 3)-1]; + drawarrow Fleche[(n div 3)-2]; + drawarrow (A[(n div 3)-1]{dir-150}..{dir150}A[(n div 3)-2]) shifted((0,-Ecart)); + for k=0 upto ((n div 3)-2): + draw segment(A[k],A[k]+(0,-Ecart)) dashed evenly; + endfor; + draw segment(A[(n div 3)-1],A[(n div 3)-1]+(0,-Ecart)) dashed evenly; + fi; + %fin Sup + else: + for k=0 upto ((n div 3)-1): + trace (u*(0,-0.1)--u*(0,0.1)) shifted A[k]; + endfor; + % on définit les points milieu des fleches + path Fleche[]; + pair C[]; + for k=0 upto ((n div 3)-2): + Fleche[k]=(A[k]{dir-30}..{dir30}A[k+1]) shifted((0,-Ecart)); + C[k]=point (0.5*length Fleche[k]) of Fleche[k]; + endfor; + maxx:=n; + trace segment(A0,A[(n div 3)-1]); + n:=0; + labeloffset:=labeloffset*2; + for p_=#1: + n:=n+1; + if n<maxx: + if (n mod 3)=1: + label.top(LATEX(""&p_&""),A[n div 3]); + elseif (n mod 3)=2: + if (n div 3)<((maxx div 3)-1):label.top(LATEX(""&p_&""),C[n div 3]);fi; + elseif (n mod 3)=0: + label.bot(LATEX(""&p_&""),C[(n div 3)-1]); + fi; + fi; + endfor; + labeloffset:=labeloffset/2; + if Fleches: + for k=0 upto ((n div 3)-2): + draw segment(A[k],A[k]+(0,-Ecart)) dashed evenly; + drawarrow Fleche[k]; + endfor; + draw segment(A[(n div 3)-1],A[(n div 3)-1]+(0,-Ecart)) dashed evenly; + fi; + fi; + \end{mpost} + \fi +} + +%%% % Geometrie %%% \setKVdefault[Geometrie]{CoinBG={(0,0)},CoinHD={(10u,10u)},TypeTrace="Instruments"}% @@ -404,7 +1116,7 @@ %%https://tex.stackexchange.com/questions/3695/smileys-in-latex/227226 \tikzset{face/.style={shape=circle,minimum size=4ex,shading=radial,outer sep=0pt, inner color=white!50!yellow,outer color= yellow!70!orange}} -\newcommand{\emoticon}[2][]{% +\newcommand\emoticon[2][]{% \scalebox{.5}{\begin{tikzpicture} \node[face,#1,draw,thick] (emoticon) {}; %% The eyes are fixed. @@ -413,7 +1125,7 @@ \end{tikzpicture}}% } -\newcommand{\pupils}{ +\newcommand\pupils{ %% standard pupils \fill[shift={(0.5ex,0.5ex)},rotate=80] (0,0) ellipse (0.3ex and 0.15ex); \fill[shift={(-0.5ex,0.5ex)},rotate=100] (0,0) ellipse (0.3ex and 0.15ex);} @@ -614,8 +1326,8 @@ \newcommand\MelangeListe[2]{% % #1 Liste à mélanger % #2 Nombre d'éléments à conserver - \setsepchar{,}\ignoreemptyitems - \readlist*\ListeInter{#1} + \setsepchar{,}\ignoreemptyitems% + \readlist*\ListeInter{#1}% \xdef\faa{}% Liste construite \xdef\fii{}% Liste détruite % on crée les #2 premieres solutions. @@ -1112,7 +1824,7 @@ \xdef\CountcolDeux{0}% \useKVdefault[ClesFicheMemo]% \setKV[ClesFicheMemo]{#1}% - \setsepchar[*]{§*/}% + \setsepchar[*]{§*/}\reademptyitems% \readlist*\ListeQuestionColonneUn{#2}% \readlist*\ListeQuestionColonneDeux{#3}% \renewcommand{\arraystretch}{1.35}% @@ -1123,35 +1835,36 @@ \tikz\draw[dashed,gray!50](2-|4.5) to (last-|4.5);% \Body% \Block{1-1}{\bfseries\useKV[ClesFicheMemo]{TexteReponses}}&&&\Block{1-1}{\bfseries\useKV[ClesFicheMemo]{TexteReponses}}\\ - \xintFor* ##4 in {\xintSeq {1}{\ListeQuestionColonneUnlen}}\do{% - \xintifboolexpr{\listlen\ListeQuestionColonneUn[##4]==2}{% + \xintFor* ##1 in {\xintSeq {1}{\ListeQuestionColonneUnlen}}\do{% + \xintifboolexpr{\listlen\ListeQuestionColonneUn[##1]==2}{% \uppercase{&}}{% - \Block[l]{\fpeval{\ListeQuestionColonneUn[##4,1]}-1}{\ifboolKV[ClesFicheMemo]{Solution}{\ListeQuestionColonneUn[##4,3]}{}}\uppercase{&}\xdef\CountcolUn{\fpeval{\CountcolUn+1}}\Block[l]{\fpeval{\ListeQuestionColonneUn[##4,1]}-1}{\ListeQuestionColonneUn[##4,2]}% + \Block[l]{\fpeval{\ListeQuestionColonneUn[##1,1]}-1}{\ifboolKV[ClesFicheMemo]{Solution}{\ListeQuestionColonneUn[##1,3]}{}}% + \uppercase{&}\xdef\CountcolUn{\fpeval{\CountcolUn+1}}\Block[l]{\fpeval{\ListeQuestionColonneUn[##1,1]}-1}{\ListeQuestionColonneUn[##1,2]}% }% &% - \xintifboolexpr{\listlen\ListeQuestionColonneDeux[##4]==2}{% + \xintifboolexpr{\listlen\ListeQuestionColonneDeux[##1]==2}{% \uppercase{&}% }{% - \xdef\CountcolDeux{\fpeval{\CountcolDeux+1}}\Block[l]{\fpeval{\ListeQuestionColonneDeux[##4,1]}-1}{\ListeQuestionColonneDeux[##4,2]}\uppercase{&}\Block[l]{\fpeval{\ListeQuestionColonneDeux[##4,1]}-1}{\ifboolKV[ClesFicheMemo]{Solution}{\ListeQuestionColonneDeux[##4,3]}{}}% + \xdef\CountcolDeux{\fpeval{\CountcolDeux+1}}\Block[l]{\fpeval{\ListeQuestionColonneDeux[##1,1]}-1}{\ListeQuestionColonneDeux[##1,2]}\uppercase{&}\Block[l]{\fpeval{\ListeQuestionColonneDeux[##1,1]}-1}{\ifboolKV[ClesFicheMemo]{Solution}{\ListeQuestionColonneDeux[##1,3]}{}}% }% \\% }% \CodeAfter% \tikz\node[xshift=0.5em] at (2-|1) {\scriptsize\faCut};% \xdef\PfCCountCutUn{2}% - \xintFor* ##4 in {\xintSeq {1}{\ListeQuestionColonneUnlen}}\do{% - \xintifboolexpr{\listlen\ListeQuestionColonneUn[##4]==2}{% + \xintFor* ##1 in {\xintSeq {1}{\ListeQuestionColonneUnlen}}\do{% + \xintifboolexpr{\listlen\ListeQuestionColonneUn[##1]==2}{% }{% - \xdef\PfCCountCutUn{\fpeval{\PfCCountCutUn+\ListeQuestionColonneUn[##4,1]}}% + \xdef\PfCCountCutUn{\fpeval{\PfCCountCutUn+\ListeQuestionColonneUn[##1,1]}}% \tikz\node[xshift=0.5em] at (\fpeval{\PfCCountCutUn}-|1) {\scriptsize\faCut};% }% }% \tikz\node[xshift=-0.5em] at (2-|last) {\scriptsize\rotatebox{180}{\faCut}};% \xdef\PfCCountCutDeux{2}% - \xintFor* ##4 in {\xintSeq {1}{\ListeQuestionColonneDeuxlen}}\do{% - \xintifboolexpr{\listlen\ListeQuestionColonneDeux[##4]==2}{% + \xintFor* ##1 in {\xintSeq {1}{\ListeQuestionColonneDeuxlen}}\do{% + \xintifboolexpr{\listlen\ListeQuestionColonneDeux[##1]==2}{% }{% - \xdef\PfCCountCutDeux{\fpeval{\PfCCountCutDeux+\ListeQuestionColonneDeux[##4,1]}}% + \xdef\PfCCountCutDeux{\fpeval{\PfCCountCutDeux+\ListeQuestionColonneDeux[##1,1]}}% \tikz\node[xshift=-0.5em] at (\fpeval{\PfCCountCutDeux}-|last) {\scriptsize\rotatebox{180}{\faCut}};% }% }% @@ -1163,6 +1876,7 @@ \tikz\node at (1.5-|3.5) {\bfseries\useKV[ClesFicheMemo]{TexteQuestions} \num{\fpeval{\CountcolUn+1}} à \num{\fpeval{\CountcolUn+\CountcolDeux}}};% \end{NiceTabular}% \renewcommand{\arraystretch}{1}% + \setsepchar{,}% }% %%% @@ -1170,9 +1884,9 @@ %%% %% D'après https://tex.stackexchange.com/questions/277246/drawing-a-circle-around-the-numbers-in-xlop-package -\newcommand{\PfCchiffre}[2]{\tikz[remember picture] \node[inner sep=0pt](#1){#2};} +\newcommand\PfCchiffre[2]{\tikz[remember picture] \node[inner sep=0pt](#1){#2};} -\newcommand{\PfCentoure}[2]{\tikz[remember picture,overlay] \node[preaction={draw={\useKV[ClesOperations]{CouleurCadre}},ultra thick,opacity=1, +\newcommand\PfCentoure[2]{\tikz[remember picture,overlay] \node[preaction={draw={\useKV[ClesOperations]{CouleurCadre}},ultra thick,opacity=1, transform canvas={xshift=0em,yshift=0em}},rectangle,rounded corners,ultra thick,inner sep=.55em,fit=(#1.center)(#2.center)]{} ;} \newcounter{divxlop}% @@ -2097,6 +2811,7 @@ transform canvas={xshift=0em,yshift=0em}},rectangle,rounded corners,ultra thick, \dtlexpandnewvalue% \DTLgnewdb{mtnumedb}% +\DTLgnewdb{mtRGTdb}% Pb de doublon avec mtdb de Mediane \newcommand\Rangement[2][]{% \useKVdefault[ClesRgt]% @@ -2111,48 +2826,48 @@ transform canvas={xshift=0em,yshift=0em}},rectangle,rounded corners,ultra thick, }% % On cr\'ee la liste des rangements. \DTLcleardb{mtnumedb}% - % on les trie pour les ranger par ordre croissant +% % on les trie pour les ranger par ordre croissant \foreachitem\x\in\ListeRgt{% \DTLnewrow{mtnumedb}% \xdef\toto{\fpeval{\ListeRgt[\xcnt,1]*\the\ppcm/\ListeRgt[\xcnt,2]}}% \DTLnewdbentry{mtnumedb}{numeric}{\toto}% }% - % On trie +% % On trie \ifboolKV[ClesRgt]{Decroissant}{% - % On trie la liste +% % On trie la liste \dtlsort{numeric=descending}{mtnumedb}{\dtlicompare}% \ifboolKV[ClesRgt]{Details}{\ensuremath{\DTLforeach{mtnumedb}{\numeroDonnee=numeric}{\frac{\num{\numeroDonnee}}{\num{\the\ppcm}}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{>}{\geqslant}}}}}{% \ensuremath{\DTLforeach{mtnumedb}{\numeroDonnee=numeric}{\Simplification{\numeroDonnee}{\ppcm}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{>}{\geqslant}}}}% } }{% - % On trie la liste +% % On trie la liste \dtlsort{numeric}{mtnumedb}{\dtlicompare}% \ifboolKV[ClesRgt]{Details}{% \ensuremath{\DTLforeach{mtnumedb}{\numeroDonnee=numeric}{\frac{\num{\numeroDonnee}}{\num{\the\ppcm}}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{<}{\leqslant}}}}% }{% \ensuremath{\DTLforeach{mtnumedb}{\numeroDonnee=numeric}{\Simplification{\numeroDonnee}{\ppcm}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{<}{\leqslant}}}}% - } + }% }% }{% \setsepchar{,}\ignoreemptyitems% \readlist*\ListeRgt{#2}% % on cr\'ee la base de donn\'ees des valeurs - \DTLcleardb{mtdb}% - % on les trie pour les ranger par ordre croissant + \DTLcleardb{mtRGTdb}% +% % on les trie pour les ranger par ordre croissant \foreachitem\x\in\ListeRgt{% - \DTLnewrow{mtdb}% + \DTLnewrow{mtRGTdb}% \itemtomacro\ListeRgt[\xcnt]\y% - \DTLnewdbentry{mtdb}{numeric}{\y}% + \DTLnewdbentry{mtRGTdb}{numeric}{\y}% }% - % +% % \ifboolKV[ClesRgt]{Decroissant}{% % On trie la liste - \dtlsort{numeric=descending}{mtdb}{\dtlicompare}% - \ensuremath{\DTLforeach{mtdb}{\numeroDonnee=numeric}{\num{\numeroDonnee}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{>}{\geqslant}}}}% + \dtlsort{numeric=descending}{mtRGTdb}{\dtlicompare}% + \ensuremath{\DTLforeach{mtRGTdb}{\numeroDonnee=numeric}{\num{\numeroDonnee}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{>}{\geqslant}}}}% }{% - % On trie la liste - \dtlsort{numeric}{mtdb}{\dtlicompare}% - \ensuremath{\DTLforeach{mtdb}{\numeroDonnee=numeric}{\num{\numeroDonnee}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{<}{\leqslant}}}}% +% % On trie la liste + \dtlsort{numeric}{mtRGTdb}{\dtlicompare}% + \ensuremath{\DTLforeach{mtRGTdb}{\numeroDonnee=numeric}{\num{\numeroDonnee}\DTLiflastrow{}{\ifboolKV[ClesRgt]{Strict}{<}{\leqslant}}}}% }% }% }% @@ -3771,7 +4486,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. \foreach \i in {1,...,3}{% \coordinate[xshift=\i*0.25*\paperwidth] (A\i) at (current page.north west);% \coordinate[xshift=\i*0.25*\paperwidth] (B\i) at (current page.south west);% - } + }% \foreach \i in{1,...,4}{% \coordinate[yshift=-\i*0.25*\paperheight] (C\i) at (current page.north west);% \coordinate[yshift=-\i*0.25*\paperheight] (F\i) at (current page.north east);% @@ -3894,10 +4609,10 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(V3)!0.5!(V4)$) {\ListeAutoEn[2,1]};% \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(V5)!0.5!(V6)$) {\ListeAutoEn[3,1]};% \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(V7)!0.5!(V8)$) {\ListeAutoEn[4,1]};% - \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R1)!0.5!(R2)$) {\ListeAutoQ[1,2]};% - \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R3)!0.5!(R4)$) {\ListeAutoQ[2,2]};% - \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R5)!0.5!(R6)$) {\ListeAutoQ[3,2]};% - \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R7)!0.5!(R8)$) {\ListeAutoQ[4,2]};% + \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R1)!0.5!(R2)$) {\ListeAutoQ[1,2]};%% + \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R3)!0.5!(R4)$) {\ListeAutoQ[2,2]};%% + \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R5)!0.5!(R6)$) {\ListeAutoQ[3,2]};%% + \node[align=justify,anchor=center,text width=0.9*0.25\textwidth] at ($(R7)!0.5!(R8)$) {\ListeAutoQ[4,2]};%% }{% \foreach \i in {1,...,8}{% \node[text width=0.9*0.25\paperwidth] at (V\i) {\ListeAutoQ[\i,2]};% @@ -5982,7 +6697,16 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. cc=fullcircle scaled 1u; % on marque les angles picture MAngle; - MAngle=image( + MAngle=image(% + if #6=0:%Pour l'isocèle + path cd; pair M[]; + cd=B--(A+B+C)/3; + M1=cd intersectionpoint (cc shifted B); + trace 9/10[B,M1]--11/10[B,M1]; + cd:=C--(A+B+C)/3; + M1:=cd intersectionpoint (cc shifted C); + trace 9/10[C,M1]--11/10[C,M1]; + fi; draw (cc shifted A); draw (cc shifted B); draw (cc shifted C); @@ -6490,9 +7214,11 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. \xintifboolexpr{#3<#4 || #3==#4}{ \xdef\PetitCote{#3}% \xdef\MoyenCote{#4}% + \xdef\GrandCote{}% }{% \xdef\GrandCote{#3}% \xdef\MoyenCote{#4}% + \xdef\PetitCote{}% Pour la personnalisation } % On retient les noms des sommets \StrMid{#2}{1}{1}[\NomA]% @@ -6613,13 +7339,13 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. % Distributivit\'e %%% % https://tex.stackexchange.com/questions/168972/draw-arrows-to-show-multiplication-pattern-distributive-property/169278?noredirect=1 -\newcommand{\Tikzmark}[1]{% +\newcommand\Tikzmark[1]{% \tikz[remember picture,baseline,inner sep=0pt]{% \node[name=Distri-\theNbDistri,anchor=base] {${#1}$};}% \stepcounter{NbDistri}% }% -\newcommand{\DrawArrow}{% +\newcommand\DrawArrow{% \begin{tikzpicture}[overlay,remember picture] \draw[-stealth,out=50,in=140,DCFlechesh,transform canvas={yshift=2pt}] (Distri-0.north) to (Distri-2.north); \draw[-stealth,out=50,in=140,DCFlechesh!50,transform canvas={yshift=2pt}] (Distri-0.north) to (Distri-3.north); @@ -7016,7 +7742,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. \xdef\SommeB{0}% \xdef\SommeC{0}% -\newcommand{\Distri}[5][]{% +\newcommand\Distri[5][]{% \useKVdefault[ClesDistributivite]%obligatoire car la macro n'est pas dans un groupe. \setKV[ClesDistributivite]{#1}%On lit les arguments optionnels \ifboolKV[ClesDistributivite]{RAZ}{\xdef\SommeA{0}\xdef\SommeB{0}\xdef\SommeC{0}% @@ -7292,7 +8018,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. }% }% -\newcommand{\DistriEchange}[5][]{% +\newcommand\DistriEchange[5][]{% \ensuremath{% \useKVdefault[ClesDistributivite]%obligatoire car la macro n'est pas dans un groupe. \setKV[ClesDistributivite]{#1}%On lit les arguments optionnels @@ -8529,7 +9255,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. } -\newcommand{\SSimpli}[2]{% +\newcommand\SSimpli[2]{% % D\'ecomposition d'une simplification de #1/#2 \newcount\numerateur\newcount\denominateur\newcount\valabsnum\newcount\valabsdeno% \numerateur=\number#1 @@ -9092,7 +9818,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. \newcommand\EcritureQuotients{}% %%% -\newcommand{\TTThales}[6][]{% +\newcommand\TTThales[6][]{% \useKVdefault[ClesThales]% \setKV[ClesThales]{#1}% \ifboolKV[ClesThales]{Perso}{\RedactionThales}{% @@ -9121,7 +9847,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. }% }% -\newcommand{\TThalesCalculsD}[8][]{% +\newcommand\TThalesCalculsD[8][]{% \setKV[ClesThales]{#1}% \newcount\zzz\newcount\yyy\newcount\xxx%Pour se rappeller des calculs \`a faire et combien en faire% \def\Nomx{}% @@ -9359,7 +10085,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. }{} } -\newcommand{\TThalesCalculsE}[8][]{% +\newcommand\TThalesCalculsE[8][]{% \setKV[ClesThales]{#1}% \newcount\zzz\newcount\yyy\newcount\xxx%Pour se rappeller des calculs \`a faire et combien en faire% \newcount\valx\newcount\Valx% @@ -9682,7 +10408,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. }{}% } -\newcommand{\TThales}[8][]{% +\newcommand\TThales[8][]{% \setKV[ClesThales]{#1}% \StrMid{#2}{1}{1}[\NomA]\StrMid{#2}{2}{2}[\NomB]\StrMid{#2}{3}{3}[\NomC]\StrMid{#2}{4}{4}[\NomM]\StrMid{#2}{5}{5}[\NomN]% \ifboolKV[ClesThales]{FigureSeule}{% @@ -9733,7 +10459,7 @@ couleur indiquée, le nombre de cases donné par le résultat du calcul. } } -\newcommand{\ReciThalesCalculs}[8][]{% +\newcommand\ReciThalesCalculs[8][]{% \StrMid{#2}{1}{1}[\NomA]% \StrMid{#2}{2}{2}[\NomB]% \StrMid{#2}{3}{3}[\NomC]% @@ -10587,7 +11313,7 @@ Rayon=3cm,AffichageAngle=false,AffichageDonnee=false,ListeCouleurs={white},Hachu %Pour les représentations Representation=false,% %Pour les barres horizontales -Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% +Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false,EcartBarre=0%Grille est dispo } %compl\'ements \defKV[ClesStat]{AngleRotationAbscisse=\setKV[ClesStat]{AbscisseRotation}}% @@ -10705,8 +11431,8 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% \xdef\PfCfooStat{\PfCfooStat \ListeComplete[##1,2],}% }% \xdef\DivMax{\fpeval{max(\PfCfooStat)}}% - \xdef\DivMax{\fpeval{round(ln(\DivMax)/ln(10))}}% - \xdef\DivMax{\fpeval{10**\DivMax}}% + \xdef\ExposantDivMax{\fpeval{round(ln(\DivMax)/ln(10))}}% + \xdef\DivMax{\fpeval{10**\ExposantDivMax}}% \xdef\PfCfooStat{}% \xintFor* ##1 in {\xintSeq {1}{\ListeCompletelen}}\do{% \xdef\PfCfooStat{\PfCfooStat \ListeComplete[##1,1]/\ListeComplete[##1,2]/\fpeval{\ListeComplete[##1,2]/\DivMax},}% @@ -10799,17 +11525,25 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% % #2 Liste des valeurs associées % #3 Liste des valeurs à afficher (si pb calcul MP) % #4 Liste des couleurs - \ifluatex + \ifluatex% \mplibforcehmode% \begin{mplibcode}% Longueur:=\useKV[ClesStat]{Longueur}; Hauteur:=\useKV[ClesStat]{Hauteur}; + Ecart:=\useKV[ClesStat]{EcartBarre}; + ExposantDivMax:=\ExposantDivMax; ecarthachures=\useKV[ClesStat]{EcartHachures}; epaisseurhachures=\useKV[ClesStat]{EpaisseurHachures}; boolean Hachures; Hachures=\useKV[ClesStat]{Hachures}; boolean Bicolore; Bicolore=\useKV[ClesStat]{Bicolore}; + boolean Grille; + Grille=\useKV[ClesStat]{Grille}; + boolean AffichageDonnee; + AffichageDonnee=\useKV[ClesStat]{AffichageDonnee}; + boolean LegendeVide; + LegendeVide=\useKV[ClesStat]{LegendeVide}; vardef CalculNombreDonneesEtDonneeMax(text t)= nbdon:=0;%nombre de données DonneeMax:=0;%donnée DonneeMaximale @@ -10836,10 +11570,40 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% endfor; enddef; vardef TraceDiag= + if Grille: + pair Zz[];%Pour déterminer "le dernier point" + Zz0=(0,-(nbdon-1)*(Hauteur+Ecart)-Ecart); + Zz2=(0,(Hauteur+Ecart)); + Zz1=((1/DonneeMax)*Longueur,-(nbdon-1)*(Hauteur+Ecart)-Ecart); + Zz3=if ExposantDivMax=0 : (DonneeMax+1)[Zz0,Zz1] else: ((floor(DonneeMax*10+2))/10)[Zz0,Zz1];fi; + if ExposantDivMax=0: + for k=1 upto DonneeMax+1: + trace (Zz0--Zz2) shifted (k*(Zz1-Zz0)) dashed evenly withcolor 0.5white; + endfor; + else: + for k=1 upto (floor(DonneeMax*10+2)): + trace (Zz0--Zz2) shifted ((k/10)*(Zz1-Zz0)) dashed evenly withcolor 0.5white; + endfor; + fi; + if ExposantDivMax=0: + for k=1 upto (DonneeMax+1): + label.bot(TEX("\num{"&decimal(k)&"}"),Zz0+k*(Zz1-Zz0)); + endfor; + else: + if ExposantDivMax<5: + for k=1 upto (floor(DonneeMax*10+2)): + label.bot(TEX("\num{\fpeval{"&decimal(k)&"*(10**"&decimal(ExposantDivMax-1)&")}}"),Zz0+(k/10)*(Zz1-Zz0)); + endfor; + else: + dotlabel.bot(TEX("\num{\fpeval{10**"&decimal(ExposantDivMax)&"}}"),Zz1); + fi; + fi; + fi; for k=0 upto nbdon-1: path RectangleDonnee; - RectangleDonnee=(unitsquare xscaled ((Donnees[k+1]/DonneeMax)*Longueur) yscaled Hauteur) shifted(0,-k*Hauteur); + RectangleDonnee=(unitsquare xscaled ((Donnees[k+1]/DonneeMax)*Longueur) yscaled Hauteur) shifted(0,-k*(Hauteur+Ecart)); if Hachures: + fill RectangleDonnee withcolor white; trace Hachurage(RectangleDonnee,60 if (k mod 2)=0: +90 fi,ecarthachures,if (k mod 2)=0 : 0 else: 1 fi) withpen pencircle scaled epaisseurhachures; @@ -10848,18 +11612,22 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% fi; trace RectangleDonnee; endfor; + if Grille: + drawarrow (0,-(nbdon-1)*(Hauteur+Ecart)-Ecart)--(0,(Hauteur+Ecart)) withpen pencircle scaled 1.5; + drawarrow (0,-(nbdon-1)*(Hauteur+Ecart)-Ecart)--(Zz3+u*(0.25,0)) withpen pencircle scaled 1.5; + fi; enddef; vardef AffichageNom(text t)= k:=0; for p_=t: - label.lft(TEX(p_),0.5[(0,0),(0,Hauteur)] shifted (0,-k*Hauteur)); + label.lft(TEX(p_),0.5[(0,0),(0,Hauteur)] shifted (0,-k*(Hauteur+Ecart))); k:=k+1; endfor; enddef; vardef AffichageDonnees(text t)= k:=0; for p_=t: - label.rt(TEX("\num{"&p_&"}"),0.5[(0,0),(0,Hauteur)] shifted (((Donnees[k+1]/DonneeMax)*Longueur),-k*Hauteur)); + label.rt(TEX("\num{"&p_&"}"),0.5[(0,0),(0,Hauteur)] shifted (((Donnees[k+1]/DonneeMax)*Longueur),-k*(Hauteur+Ecart))); k:=k+1; endfor; enddef; @@ -10867,21 +11635,33 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% ListeDonnees(#2); RecuperationCouleurs(#4); TraceDiag; + if LegendeVide=false: AffichageNom(#1); + fi; + if AffichageDonnee: AffichageDonnees(#3); + fi; \end{mplibcode} - \else + \else% \begin{mpost}[mpsettings={% - Longueur:=\useKV[ClesStat]{Longueur}; - Hauteur:=\useKV[ClesStat]{Hauteur}; - ecarthachures=\useKV[ClesStat]{EcartHachures}; - epaisseurhachures=\useKV[ClesStat]{EpaisseurHachures}; - boolean Hachures; - Hachures=\useKV[ClesStat]{Hachures}; - boolean Bicolore; - Bicolore=\useKV[ClesStat]{Bicolore}; - }] - vardef CalculNombreDonneesEtDonneeMax(text t)= + Longueur:=\useKV[ClesStat]{Longueur}; + Hauteur:=\useKV[ClesStat]{Hauteur}; + Ecart:=\useKV[ClesStat]{EcartBarre}; + ExposantDivMax:=\ExposantDivMax; + ecarthachures=\useKV[ClesStat]{EcartHachures}; + epaisseurhachures=\useKV[ClesStat]{EpaisseurHachures}; + boolean Hachures; + Hachures=\useKV[ClesStat]{Hachures}; + boolean Bicolore; + Bicolore=\useKV[ClesStat]{Bicolore}; + boolean Grille; + Grille=\useKV[ClesStat]{Grille}; + boolean AffichageDonnee; + AffichageDonnee=\useKV[ClesStat]{AffichageDonnee}; + boolean LegendeVide; + LegendeVide=\useKV[ClesStat]{LegendeVide}; + }] + vardef CalculNombreDonneesEtDonneeMax(text t)= nbdon:=0;%nombre de données DonneeMax:=0;%donnée DonneeMaximale for p_=t: @@ -10907,10 +11687,40 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% endfor; enddef; vardef TraceDiag= + if Grille: + pair Zz[];%Pour déterminer "le dernier point" + Zz0=(0,-(nbdon-1)*(Hauteur+Ecart)-Ecart); + Zz2=(0,(Hauteur+Ecart)); + Zz1=((1/DonneeMax)*Longueur,-(nbdon-1)*(Hauteur+Ecart)-Ecart); + Zz3=if ExposantDivMax=0 : (DonneeMax+1)[Zz0,Zz1] else: ((floor(DonneeMax*10+2))/10)[Zz0,Zz1];fi; + if ExposantDivMax=0: + for k=1 upto DonneeMax+1: + trace (Zz0--Zz2) shifted (k*(Zz1-Zz0)) dashed evenly withcolor 0.5white; + endfor; + else: + for k=1 upto (floor(DonneeMax*10+2)): + trace (Zz0--Zz2) shifted ((k/10)*(Zz1-Zz0)) dashed evenly withcolor 0.5white; + endfor; + fi; + if ExposantDivMax=0: + for k=1 upto (DonneeMax+1): + label.bot(TEX("\num{"&decimal(k)&"}"),Zz0+k*(Zz1-Zz0)); + endfor; + else: + if ExposantDivMax<5: + for k=1 upto (floor(DonneeMax*10+2)): + label.bot(TEX("\num{\noexpand\fpeval{"&decimal(k)&"*(10**"&decimal(ExposantDivMax-1)&")}}"),Zz0+(k/10)*(Zz1-Zz0)); + endfor; + else: + dotlabel.bot(TEX("\num{\noexpand\fpeval{10**"&decimal(ExposantDivMax)&"}}"),Zz1); + fi; + fi; + fi; for k=0 upto nbdon-1: path RectangleDonnee; - RectangleDonnee=(unitsquare xscaled ((Donnees[k+1]/DonneeMax)*Longueur) yscaled Hauteur) shifted(0,-k*Hauteur); + RectangleDonnee=(unitsquare xscaled ((Donnees[k+1]/DonneeMax)*Longueur) yscaled Hauteur) shifted(0,-k*(Hauteur+Ecart)); if Hachures: + fill RectangleDonnee withcolor white; trace Hachurage(RectangleDonnee,60 if (k mod 2)=0: +90 fi,ecarthachures,if (k mod 2)=0 : 0 else: 1 fi) withpen pencircle scaled epaisseurhachures; @@ -10919,18 +11729,22 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% fi; trace RectangleDonnee; endfor; + if Grille: + drawarrow (0,-(nbdon-1)*(Hauteur+Ecart)-Ecart)--(0,(Hauteur+Ecart)) withpen pencircle scaled 1.5; + drawarrow (0,-(nbdon-1)*(Hauteur+Ecart)-Ecart)--(Zz3+u*(0.25,0)) withpen pencircle scaled 1.5; + fi; enddef; vardef AffichageNom(text t)= k:=0; for p_=t: - label.lft(LATEX(p_),0.5[(0,0),(0,Hauteur)] shifted (0,-k*Hauteur)); + label.lft(TEX(p_),0.5[(0,0),(0,Hauteur)] shifted (0,-k*(Hauteur+Ecart))); k:=k+1; endfor; enddef; vardef AffichageDonnees(text t)= k:=0; for p_=t: - label.rt(LATEX("\num{"&p_&"}"),0.5[(0,0),(0,Hauteur)] shifted (((Donnees[k+1]/DonneeMax)*Longueur),-k*Hauteur)); + label.rt(TEX("\num{"&p_&"}"),0.5[(0,0),(0,Hauteur)] shifted (((Donnees[k+1]/DonneeMax)*Longueur),-k*(Hauteur+Ecart))); k:=k+1; endfor; enddef; @@ -10938,10 +11752,14 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% ListeDonnees(#2); RecuperationCouleurs(#4); TraceDiag; + if LegendeVide=false: AffichageNom(#1); + fi; + if AffichageDonnee: AffichageDonnees(#3); + fi; \end{mpost} - \fi + \fi% }% % la construction du graphique en bâtons pour quantitatif @@ -12446,7 +13264,7 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% %Une simplification de a/b est possible ou non ? \newboolean{Simplification} -\newcommand{\SSimpliTest}[2]{% +\newcommand\SSimpliTest[2]{% % Test d'une simplification possible ou pas de #1/#2 \newcount\numerateur\newcount\denominateur\newcount\valabsnum\newcount\valabsdeno% \numerateur=\number#1 @@ -13258,13 +14076,13 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% \end{tabular}% }% -\newcommand{\TikzRH}{% +\newcommand\TikzRH{% \tikz[remember picture,overlay]{% \coordinate[name=ProporH-\theNbPropor,yshift=\getstrut\ht*\arraystretch];}% \stepcounter{NbPropor}% }% - \newcommand{\TikzRB}{% + \newcommand\TikzRB{% \tikz[remember picture, overlay]{% \coordinate[name=ProporB-\theNbPropor,yshift=-\getstrut\dp*\arraystretch];}% \stepcounter{NbPropor}% @@ -13490,7 +14308,7 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% \def\MPFigureDroite#1#2{% \ifluatex - \mplibcodeinherit{enable} + %\mplibcodeinherit{enable} \mplibforcehmode \begin{mplibcode} pair A,B,C,D,E,F,G,H,I,J,K; @@ -13574,7 +14392,7 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% reste:=reste rotatedabout(u*(3,3),-90+uniformdeviate(180)); draw reste; \end{mplibcode} - \mplibcodeinherit{disable} + %\mplibcodeinherit{disable} \else \begin{mpost} pair A,B,C,D,E,F,G,H,I,J,K; @@ -17687,7 +18505,7 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% if p_<>"": drawarrow (unitp*(valeur[n],-1))--(unitp*(valeur[n],-0.3)); label.bot(btex \hbox to2em{\dotfill} etex,(unitp*(valeur[n],-1))); - pointe(unitp*(valeur[n]-ValeurOrigine,0)); + pointe(unitp*(valeur[n],0)); fi; endfor; elseif AffichageCoord=2: @@ -17700,7 +18518,7 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% else: label.bot(TEX("\footnotesize\num{\fpeval{"&decimal(ValeurUnitex)&"*"&decimal(valeur[n])&"/"&decimal(pasx)&"}}"),unitp*(valeur[n],0)); fi; - pointe(unitp*(valeur[n]-ValeurOrigine,0)); + pointe(unitp*(valeur[n],0)); fi; endfor; elseif AffichageCoord=1: @@ -18218,58 +19036,59 @@ Barre=false,Longueur=10cm,Hauteur=5mm,Bicolore=false% %D'apres https://tex.stackexchange.com/questions/38905/time-of-the-day-or-time-period-using-the-package-siunitx \ExplSyntaxOn \NewDocumentCommand \Temps { o > { \SplitArgument { 5 } { ; } } m } -{ - \group_begin: - \IfNoValueF {#1} +{% + \group_begin:% + \IfNoValueF{#1} { \keys_set:nn { siunitx } {#1} } \siunitx_hms_output:nnn #2 \group_end: } \cs_new_protected:Npn \siunitx_hms_output:nnn #1#2#3#4#5#6 -{ - \IfNoValueF {#1} - { - \tl_if_blank:nF {#1} - { - \SI {#1} { \annee\xintifboolexpr{#1>1}{s}{} } - \IfNoValueF {#2} { ~ } - } - } - \IfNoValueF {#2} - { - \tl_if_blank:nF {#2} - { - \SI {#2} { \mois } - \IfNoValueF {#3} { ~ } - } - } - \IfNoValueF {#3} - { - \tl_if_blank:nF {#3} - { - \SI {#3} { \jour } - \IfNoValueF {#4} { ~ } - } - } - \IfNoValueF {#4} - { - \tl_if_blank:nF {#4} - { - \SI {#4} { \hour } - \IfNoValueF {#5} { ~ } - } - } - \IfNoValueF {#5} - { - \tl_if_blank:nF {#5} - { - \SI {#5} { \minute } - \IfNoValueF {#6} { ~ } - } - } - \IfNoValueF {#6} - { \tl_if_blank:nF {#6} { \SI {#6} { \second } } } -} +{% + \IfNoValueF {#1}% + {% + \tl_if_blank:nF {#1}% + {% + \SI{#1}{\annee\xintifboolexpr{#1>1}{s}{}}% + \IfNoValueF {#2}{~}% + }% + }% + \IfNoValueF {#2}% + {% + \tl_if_blank:nF {#2}% + {% + \SI{#2}{\mois}% + \IfNoValueF{#3}{~}% + }% + }% + \IfNoValueF {#3}% + {% + \tl_if_blank:nF {#3}% + {% + \SI{#3}{\jour}% + \IfNoValueF{#4}{~}% + }% + }% + \IfNoValueF {#4}% + {% + \tl_if_blank:nF {#4}% + {% + \SI{#4}{\hour}% + \IfNoValueF{#5}{~}% + }% + }% + \IfNoValueF {#5}% + {% + \tl_if_blank:nF {#5}% + {% + \SI[minimum-integer-digits=2]{#5}{\minute}% + \IfNoValueF{#6}{~}% + }% + }% + \IfNoValueF {#6}% + {% + \tl_if_blank:nF {#6} {\SI{#6}{\second}}}% +}% \ExplSyntaxOff \newcommand\Temp[2][]{% diff --git a/macros/latex/contrib/profcollege/metapost/PfCGeometrie.mp b/macros/latex/contrib/profcollege/metapost/PfCGeometrie.mp index 3386a78680..02a3f66ce2 100644 --- a/macros/latex/contrib/profcollege/metapost/PfCGeometrie.mp +++ b/macros/latex/contrib/profcollege/metapost/PfCGeometrie.mp @@ -1276,4 +1276,240 @@ vardef Tetraedrer(text t)= tetrar enddef; +%Outils +numeric echelleequerre; +echelleequerre=2; +vardef equerre(expr dte,drte,perpe,sens)= + save picequerre; + picture picequerre; + pair ww,t[]; + path intermede; + pair perpen,ptt,pttt; + perpen:=projection(perpe,dte,drte); + %if sens=1 : + ptt:=longueurequerre*(drte-dte) rotated 90 shifted perpen; + %else : +% ptt:=longueurequerre*(drte-dte) rotated (-90) shifted perpen; + %fi; + ww=unitvector(drte-dte); + intermede=ptt--(10[ptt,(perpen rotatedabout(ptt,if sens=1: 30 else:-30 fi))]); + pttt=intermede intersectionpoint (10[dte,drte]--10[drte,dte]); + picequerre=image( + draw perpen--ptt--pttt--cycle; + draw codeperp(ptt,perpen,pttt,5); + ); + picequerre +enddef; + + vardef regle(expr depart,arrivee,rr)= + save picregle; + picture picregle,grad[],gradu[],final; + pair t[]; + path reduit; + t1000=depart shifted (5*unitvector(depart-arrivee)); + t1003=arrivee shifted (20*unitvector(arrivee-depart)); + t1004=(unitvector(arrivee-depart) rotated (-90)) shifted t1000; + t1001=t1000 shifted (50*(t1004-t1000)); + t1002=t1001 shifted (t1003-t1000); + reduit=t1000--t1001--t1002..(t1002 shifted(5*unitvector(t1001-t1002)+1/4(t1003-t1002)))..(t1002 shifted(5*unitvector(t1002-t1001)+2/4(t1003-t1002)))..(t1002 shifted(5*unitvector(t1001-t1002)+3/4(t1003-t1002)))..t1003--cycle; + gradu1=image( + for k=0 upto 59: + for j=1 upto 4: + t[5*k+j]=depart shifted (1mm*(5*k+j)*unitvector(arrivee-depart)); + t[400+5*k+j]=t[5*k+j] shifted (2*(t1004-t1000)); + draw t[5*k+j]--t[400+5*k+j]; + endfor; + endfor + ); + gradu2=image( + for k=0 upto 29: + t[5*(2*k+1)]=depart shifted (1mm*5*(2*k+1)*unitvector(arrivee-depart)); + t[400+5*(2*k+1)]=t[5*(2*k+1)] shifted (5*(t1004-t1000)); + draw t[5*(2*k+1)]--t[400+5*(2*k+1)]; + endfor + ); + gradu3=image( + for k=0 upto 30: + t[10*k]=depart shifted(1mm*10*k*unitvector(arrivee-depart)); + t[400+10*k]=t[10*k] shifted (10*(t1004-t1000)); + draw t[10*k]--t[400+10*k]; + endfor + ); + for j=0 upto 30: + grad[j]=image( + label.bot(TEX(""&decimal(j)&""),t[400+10*j]); + %affixe[j](t[400+10*j])s; + currentpicture:=currentpicture rotatedabout(t[400+10*j],90+angle(t[400+10*j]-t[10*j])); + ); + endfor + final=image( + for k=0 upto 30: + draw grad[k]; + endfor + for k=1 upto 3: + draw gradu[k]; + endfor + clip currentpicture to reduit; + draw reduit; + ); + if rr=-1: + picregle=image( + draw final rotatedabout(1/2[depart,arrivee],180); + ); + else: + picregle=image( + draw final; + ); + fi + picregle +enddef; + +vardef crayon(expr depart,arrive,ptplace,nbechelle)= + save piccray; + picture piccray,crayolat; + pair w[]; + w0=(0,0); + w1=(1,2)*u/2; + w2=(-1,2)*u/2; + w3=(0,2)*u/2; + w4=(0,7)*u/2; + path ccc,ccd; + ccc=cercles(w0,abs(w3-w2)); + ccd=ccc yscaled 0.25 shifted w3; + crayolat=image( + draw subpath((length ccd)/2,length ccd) of ccd; + draw ccd shifted (w4-w3); + draw w2--w0--w1; + draw w1--((1,7)*u/2); + draw w2--((-1,7)*u/2); + ); + crayolat:=crayolat scaled nbechelle; + piccray=(crayolat rotated(angle(arrive-depart)-30)) shifted ptplace; + piccray +enddef; + +boolean Simple; +Simple=false; + +vardef rapporteur(expr centre,segment,rr)= + save raps; + picture raps; + raps=image( + Simple:=true; + trace rapporteurdouble(centre,segment,rr); + Simple:=false; + ); + raps +enddef; + +vardef rapporteurdouble(expr centre,segment,rr)= + save rap,cc,cd,v,w,t,ww,vv; + picture rap; + path cc,cd; + pair a[],b[],v,w,t,ww,vv,rap[],rapp[]; + cc=cercle(centre,0.75*abs(centre-segment)); + t=cc intersectionpoint (centre--segment); + w=t-2*unitvector(segment-centre);v=symetrie(w,t); + ww=t-5*unitvector(segment-centre);vv=symetrie(ww,t); + a0=(ww-centre) shifted centre; + b0=(vv-centre) shifted centre; + for i=0 upto 35 : + for j=1 upto 4 : + a[5*i+j]=(w-centre) rotated (rr*(5*i+j)) shifted centre; + b[5*i+j]=(v-centre) rotated (rr*(5*i+j)) shifted centre; + endfor; + a[5*(i+1)]=(ww-centre) rotated (rr*(5*(i+1))) shifted centre; + b[5*(i+1)]=(vv-centre) rotated (rr*(5*(i+1))) shifted centre; + endfor + picture nomb[],nombre[]; + if rr=1: + for j=0 upto 18: + nombre[10*j]=image( + label.bot(TEX("\fontsize{4}{4}\selectfont"&decimal(10*j)&""),a[10*j]); + currentpicture:=currentpicture rotatedabout(a[10*j],angle(a[10*j]-centre)-90); + ); + endfor + for j=0 upto 18: + nombre[10*j+1]=image( + % affixe.[180-10*j](b[10*j])n; + label.top(TEX("\fontsize{4}{4}\selectfont"&decimal(180-10*j)&""),b[10*j]); + currentpicture:=currentpicture rotatedabout(b[10*j],angle(b[10*j]-centre)-90); + ); + endfor + else: + for j=0 upto 18: + nombre[10*j]=image( + label.bot(TEX("\fontsize{4}{4}\selectfont"&decimal(180-10*j)&""),a[10*j]); + currentpicture:=currentpicture rotatedabout(a[10*j],angle(a[10*j]-centre)-90); + ); + endfor + for j=18 downto 0: + nombre[10*j+1]=image( + % affixe.[10*j](b[10*j])n; + label.top(TEX("\fontsize{4}{4}\selectfont"&decimal(10*j)&""),b[10*j]); + currentpicture:=currentpicture rotatedabout(b[10*j],angle(b[10*j]-centre)-90); + ); + endfor + fi + rap=image( + for i=0 upto 18 : + draw nombre[10*i+1]; + if Simple=false: + draw nombre[10*i]; + fi; + endfor; + path cerc; + cerc=subpath((angle(segment-centre)*(length cc))/360,((length cc)/2)+(angle(segment-centre)*(length cc))/360) of cc; + if rr=-1: + draw cerc reflectedabout(segment,centre); + else: + draw cerc; + fi + draw a0--b0 withpen pencircle scaled 1.25bp; + for i=0 upto 35 : + for j=1 upto 4 : + draw a[5*i+j]--b[5*i+j]; + endfor; + endfor; + for i=1 step 2 until 35: + draw a[5*i]--b[5*i]; + endfor; + for i=1 upto 18: + draw a[10*i]--b[10i] withpen pencircle scaled 1.25; + endfor; + draw a0--a180; + path cent; + cent=cercle(centre,0.05*u); + fill cent withcolor if unknown fillrap: 0.9white else: fillrap fi; + ); + rap +enddef; + +vardef compas(expr centre,extre,n)= + save piccompas; + picture piccompas; + pair r,s,t,a,b,c,d,e,f; + if (abs(centre-extre)<10*u): + r=((extre-1/2[centre,extre]) rotated (n*90)) shifted (1/2[centre,extre]); + else: + r=0.25[1/2[centre,extre],((extre-1/2[centre,extre]) rotated (n*90)) shifted (1/2[centre,extre])]; + fi + s=(1+50/abs(centre-extre))[1/2[centre,extre],r]; + t=10*unitvector(extre-centre) rotated (n*90); + a=centre shifted t; + b=s shifted (5*unitvector(centre-extre)+10*unitvector(s-r)); + c=b shifted (30*unitvector(s-r)); + d=c reflectedabout(r,s); + e=b reflectedabout(r,s); + f=a reflectedabout(r,s); + path comp; + comp=a--b--c--d--e--f--s--a--cycle; + piccompas=image( + fill comp withcolor black; + draw centre--a withpen pencircle scaled 1.5bp; + draw f--extre withpen pencircle scaled 1.5bp withcolor 0.25[red,blue]; + ); + piccompas +enddef; + endinput; diff --git a/macros/latex/contrib/profcollege/metapost/PfCScratch.mp b/macros/latex/contrib/profcollege/metapost/PfCScratch.mp index c3a41e3eb4..d8b2a0a851 100644 --- a/macros/latex/contrib/profcollege/metapost/PfCScratch.mp +++ b/macros/latex/contrib/profcollege/metapost/PfCScratch.mp @@ -122,7 +122,7 @@ vardef OvalVar(expr ar)= save Ovar; picture Ovar; save TAvar; path TAvar; string TTv; - TTv=ar&"\barre"; + TTv="\barre\bfseries "&ar;% TAvar=OvalBox(TTv); Ovar=image( fill TAvar if print=false : withcolor OrangeTrois else : withcolor white fi; diff --git a/macros/luatex/generic/luakeys/README.md b/macros/luatex/generic/luakeys/README.md index ca73100b64..2bff44088b 100644 --- a/macros/luatex/generic/luakeys/README.md +++ b/macros/luatex/generic/luakeys/README.md @@ -144,6 +144,18 @@ local opts = { local result = luakeys.parse('one,two,three', opts) ``` +## Development + +`luakeys` is developed using the +[Lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) +extension in Visual Studio Code. This extension understands the [EmmyLua +annotations](https://github.com/sumneko/lua-language-server/wiki/EmmyLua-Annotations). +The Lua source code documentation is generated with +[LDoc](https://stevedonovan.github.io/ldoc/manual/doc.md.html). + +The Lua code is automatically formatted with the help of the +[LuaFormatter](https://github.com/Koihik/LuaFormatter). + ## Tasks ### Installing @@ -154,6 +166,9 @@ make install ### Testing +The framework [busted](https://github.com/Olivine-Labs/busted) is used +for the tests. + ``` luarocks install busted busted --exclude-tags=skip test/lua/*.lua @@ -167,11 +182,14 @@ make test ### Release a new version +This project uses [semantic versioning](https://semver.org). + Update version in: * luakeys-doc.tex * luakeys-debug.sty * luakeys.sty +* luakeys.lua Update copyright in: @@ -185,4 +203,4 @@ Update copyright in: Summarize the changes in the luakeys-doc.tex as changes. -Create a new git tag `git tag -sa v0.3`. Prefix the version with “v”. +Create a new git tag `git tag -sa 0.7.0`. diff --git a/macros/luatex/generic/luakeys/luakeys-debug.sty b/macros/luatex/generic/luakeys/luakeys-debug.sty index 7fcb483741..1a26a66450 100644 --- a/macros/luatex/generic/luakeys/luakeys-debug.sty +++ b/macros/luatex/generic/luakeys/luakeys-debug.sty @@ -17,6 +17,6 @@ % luakeys-debug.sty and luakeys-debug.tex. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{luakeys-debug}[2022/06/09 v0.6 Debug package for luakeys.] +\ProvidesPackage{luakeys-debug}[2022/07/06 0.7.0 Debug package for luakeys.] \input luakeys-debug.tex diff --git a/macros/luatex/generic/luakeys/luakeys-debug.tex b/macros/luatex/generic/luakeys/luakeys-debug.tex index e7758cce0a..b78951779b 100644 --- a/macros/luatex/generic/luakeys/luakeys-debug.tex +++ b/macros/luatex/generic/luakeys/luakeys-debug.tex @@ -16,50 +16,29 @@ % This work consists of the files luakeys.lua, luakeys.sty, luakeys.tex % luakeys-debug.sty and luakeys-debug.tex. -\directlua{ +\directlua +{ luakeys = require('luakeys') } -% https://tex.stackexchange.com/a/418401/42311 -\catcode`\@=11 -\long\def\LuaKeysIfNextChar#1#2#3{% - \let\@tmpa=#1% - \def\@tmpb{#2}% - \def\@tmpc{#3}% - \futurelet\@future\LuaKeysIfNextChar@i% -}% -\def\LuaKeysIfNextChar@i{% - \ifx\@tmpa\@future% - \expandafter\@tmpb - \else - \expandafter\@tmpc - \fi -}% -\def\luakeysdebug@parse@options#1{ - \directlua{ - luakeys.save( - 'debug_options', - luakeys.parse('#1', { format_keys = { 'snake', 'lower' } }) - ) - } -}% -\def\luakeysdebug@output#1{ +\def\luakeysdebug% +{% + \directlua% { - \tt - \parindent=0pt - \directlua{ - local result = luakeys.parse('\luaescapestring{\unexpanded{#1}}', luakeys.get('debug_options')) - tex.print(luakeys.stringify(result, true)) - luakeys.debug(result) - } - } -}% -\def\luakeysdebug@oarg[#1]#2{% - \luakeysdebug@parse@options{#1}% - \luakeysdebug@output{#2}% -}% -\def\luakeysdebug@marg#1{% - \luakeysdebug@output{#1}% -}% -\def\luakeysdebug{\LuaKeysIfNextChar[{\luakeysdebug@oarg}{\luakeysdebug@marg}}% -\catcode`\@=12 + local oarg = luakeys.utils.scan_oarg() + local marg = token.scan_argument(false) + local opts + if oarg then + opts = luakeys.parse(oarg, { format_keys = { 'snake', 'lower' } }) + end + local result = luakeys.parse(marg, opts) + luakeys.debug(result) + tex.print( + '{' .. + '\string\\tt' .. + '\string\\parindent=0pt' .. + luakeys.stringify(result, true) .. + '}' + ) + }% +} diff --git a/macros/luatex/generic/luakeys/luakeys-doc.pdf b/macros/luatex/generic/luakeys/luakeys-doc.pdf Binary files differindex 6fe42295c4..ee0f3411f6 100644 --- a/macros/luatex/generic/luakeys/luakeys-doc.pdf +++ b/macros/luatex/generic/luakeys/luakeys-doc.pdf diff --git a/macros/luatex/generic/luakeys/luakeys-doc.tex b/macros/luatex/generic/luakeys/luakeys-doc.tex index bc9a55f632..dd6fcc0973 100644 --- a/macros/luatex/generic/luakeys/luakeys-doc.tex +++ b/macros/luatex/generic/luakeys/luakeys-doc.tex @@ -1,12 +1,12 @@ \documentclass{ltxdoc} -\usepackage[hidelinks]{hyperref} \EnableCrossrefs \CodelineIndex \RecordChanges \usepackage{mdframed} \usepackage{minted} +\usepackage{luakeys} \usepackage{luakeys-debug} \usepackage{multicol} \usepackage{luacode} @@ -22,19 +22,30 @@ \def\lua#1{\mintinline{lua}|#1|} \def\latex#1{\mintinline{latex}|#1|} -\NewDocumentCommand { \InputLatexExample } { O{} m } { +\NewDocumentCommand { \InputLatex } { O{} m } { \begin{mdframed} \inputminted[linenos=false,#1]{latex}{examples/#2} \end{mdframed} } -\NewDocumentCommand { \InputLuaExample } { O{} m } { +\NewDocumentCommand { \InputLua } { O{} m } { \begin{mdframed} \inputminted[linenos=false,#1]{lua}{examples/#2} \end{mdframed} } \catcode`_=12 +\def\DefaultOpt#1{% + \texttt{\directlua{ + tex.print(luakeys.print_default('opts', '#1')) + }}% +} + +\def\DefaultOptDescription#1{ +\noindent +The default value of the option “\texttt{#1}” is: +\DefaultOpt{#1}. +} \begin{document} @@ -44,15 +55,16 @@ \author{% Josef Friedrich\\% \url{josef@friedrich.rocks}\\% - \href{https://github.com/Josef-Friedrich/luakeys}{github.com/Josef-Friedrich/luakeys}% + \href{https://github.com/Josef-Friedrich/luakeys} + {github.com/Josef-Friedrich/luakeys}% } -\date{v0.6 from 2022/06/09} +\date{0.7.0 from 2022/07/06} \maketitle \vfill -\InputLuaExample[firstline=4,lastline=7]{first-page.lua} +\InputLua[firstline=4,lastline=7]{first-page.lua} \noindent Result: @@ -83,6 +95,7 @@ Result: \newpage +% \section{Einführung} \section{Introduction} \noindent @@ -112,20 +125,62 @@ Since |luakeys| uses \href{http://www.inf.puc-rio.br/~roberto/lpeg/}{LPeg}, the parsing mechanism should be pretty robust. +% Der Artikel TUGboat +% \href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf} +% {“Implementing key–value input: An introduction” (Volume 30 (2009), No. +% 1)} von \emph{Joseph Wright} und \emph{Christian Feuersänger} gibt einen +% einen guten Überblick über die verfügbaren Key-Value-Pakete. The TUGboat article \href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf} -{“Implementing key–value input: An introduction” (Volume 30 (2009), No. 1)} -by \emph{Joseph Wright} and \emph{Christian Feuersänger} gives a good -overview of the available key-value packages. - +{“Implementing key–value input: An introduction” (Volume 30 (2009), No. +1)} by \emph{Joseph Wright} and \emph{Christian Feuersänger} gives a +good overview of the available key-value packages. + +% Dieses Paket wäre ohne den Artikel +% \href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf} +% {"Parsing complex data formats in LuaTEX with LPEG" (Volume 40 (2019), +% No. 2)} nicht möglich gewesen. This package would not be possible without the article \href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf} -{“Parsing complex data formats in LuaTEX with LPEG” (Volume 40 (2019), No. 2)}. +{“Parsing complex data formats in LuaTEX with LPEG” (Volume 40 (2019), +No. 2)}. + +\subsection{Pros of \texttt{luakeys}} + +\begin{itemize} +% \item Schlüssel-Wert-Paare können unabhängig vom Makro-Paket (latex or +% context) analysiert werden. +\item Key-value pairs can be parsed independently of the macro +collection (\LaTeX{} or Con\TeX{}t). + +% \item Sogar in Plain LuaTex können Schlüssel analysiert werden +\item Even in plain Lua\TeX{} keys can be parsed. + +% \item |luakeys| kann mit ineinander verschachtelten listen an +% Schlüssel-Wert-Paaren umgehen, d. h. es kann mit einer rekursiven +% Datenstruktur an Schlüssel umgehen. +\item |luakeys| can handle nested lists of key-value pairs, i.e. it can +handle a recursive data structure of keys. + +% \item Schlüssel müssen nicht, aber können definiert werden. +\item Keys do not have to be defined, but can they can be defined. +\end{itemize} + +\subsection{Cons of \texttt{luakeys}} + +\begin{itemize} +% \item Das Packet funktioniert nur in der Verbindung mit Lua\TeX. +\item The package works only in combination with Lua\TeX. + +% \item Du musst zwei Sprachen beherrschen: \TeX{} und Lua. +\item You need to know two languages: \TeX{} and Lua. +\end{itemize} %----------------------------------------------------------------------- % %----------------------------------------------------------------------- +% \section{Wie das Paket geladen wird} \section{How the package is loaded} %% @@ -142,7 +197,7 @@ The core functionality of this package is realized in Lua. So you can use |luakeys| even without using the wrapper files |luakeys.sty| and |luakeys.tex|. -\InputLatexExample{loading/lua.tex} +\InputLatex{loading/lua.tex} %% % @@ -155,8 +210,8 @@ So you can use |luakeys| even without using the wrapper files For example, the MiK\TeX{} package manager downloads packages only when needed. % -% Es wurde berichtet, dass dieser automatische Download nur mit Hilfe der -% Hüll-Dateien funktioniert. +% Es wurde berichtet, dass dieser automatische Download nur mit Hilfe +% der Hüll-Dateien funktioniert. It has been reported that this automatic download only works with this wrapper files. % @@ -164,7 +219,7 @@ wrapper files. % “\latex{\usepackage{luakeys}} ”Ausschau. Probably MiK\TeX{} is searching for an occurrence of the \LaTeX{} macro “\latex{\usepackage{luakeys}}”. - +% % Die mitgelieferte Lua\LaTeX{}-Datei ist recht klein: The supplied Lua\LaTeX{} file is quite small: @@ -175,38 +230,62 @@ The supplied Lua\LaTeX{} file is quite small: \end{minted} \noindent +% Es lädt das Lua-Modul in die globale Variable \texttt{luakeys}. It loads the Lua module into the global variable \texttt{luakeys}. -\InputLatexExample{loading/latex.tex} +\InputLatex{loading/tex-latex.tex} %% % %% +% \subsection{Verwendung des Plain-Lua\TeX{}-Hüllpakets +% \texttt{luakeys.tex}} \subsection{Using the plain Lua\TeX{} wrapper \texttt{luakeys.tex}} -Even smaller is the file \texttt{luakeys.tex}. It consists of only one -line: +% Noch kleiner ist die Datei \texttt{luakeys.tex}. +Even smaller is the file \texttt{luakeys.tex}. +% +% Sie besteht aus nur einer Zeile: +It consists of only one line: \begin{minted}{latex} \directlua{luakeys = require('luakeys')} \end{minted} \noindent +% Es macht dasselbe wie das Lua\LaTeX{}-Hüllpacket und lädt das +% Lua-Modul \texttt{luakeys.lua} in die globale Variable +% \texttt{luakeys}. It does the same as the Lua\LaTeX{} wrapper and loads the Lua module \texttt{luakeys.lua} into the global variable \texttt{luakeys}. -\InputLatexExample{loading/tex.tex} +\InputLatex{loading/tex-plain.tex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \section{Lua interface / API} -To learn more about the individual functions (local functions), please +% Das Lua-Modul exportiert diese Funktionen und Tabellen: +The Lua module exports this functions and tables: + +\InputLua[firstline=3,lastline=13]{export.lua} + +% Diese Dokumentation stellt nur die öffentlichen Funktionen und +% Tabellen vor. +This documentation presents only the public functions and tables. +% +% Um mehr über die privaten, nicht exportierten Funktionen zu erfahren, +% lesen Sie bitte die +% \href{https://josef-friedrich.github.io/luakeys/}{Quellcode +% Dokumentation}, die mit +% \href{http://stevedonovan.github.io/ldoc/}{LDoc} erstellt wurde. +To learn more about the private, not exported functions, please read the \href{https://josef-friedrich.github.io/luakeys/}{source code documentation}, which was created with -\href{http://stevedonovan.github.io/ldoc/}{LDoc}. The Lua module exports -this functions and tables: - -\InputLuaExample[firstline=3,lastline=12]{export.lua} +\href{http://stevedonovan.github.io/ldoc/}{LDoc}. \subsection{Lua indentifier names} @@ -219,7 +298,8 @@ hopefully unambiguous and familiar to external readers. \begin{tabular}{lll} Abbreviation & spelled out & Example \\\hline \lua{kv_string} & Key-value string & \lua{'key=value'} \\ -\lua{opts} & Options (for the parse function) & \lua{ { no_error = false } } \\ +\lua{opts} & Options (for the parse function) & +\lua{ { no_error = false } } \\ \lua{defs} & Definitions \\ \lua{def} & Definition \\ \lua{attr} & Attributes (of a definition) \\ @@ -233,7 +313,8 @@ These unabbreviated variable names are commonly used. \begin{tabular}{ll} \lua{result} & -% Das Endergebnis aller einzelnen Übersetzungs- und Normalisierungsschritte +% Das Endergebnis aller einzelnen Übersetzungs- und +% Normalisierungsschritte The final result of all individual parsing and normalization steps. \\ \lua{unknown} & @@ -250,54 +331,41 @@ The raw result of the Lpeg grammar parser. \\ % %% -\subsection{Function \texttt{parse(kv_string, opts): result, unknown, raw}} +\subsection{Function “\texttt{parse(kv_string, opts): result, unknown, +raw}”} \label{parse} % Die Function parse ist die wichtigste Funktion des Pakets. The function \lua{parse(kv_string, opts)} is the most important function of the package. +% +% % Sie konvertiert eine Schlüssel-Wert-Zeichenkette in eine Lua Tabelle. It converts a key-value string into a Lua table. -\begin{minted}{latex} -\newcommand{\mykeyvalcmd}[2][]{ - \directlua{ - result = luakeys.parse('#1') - luakeys.debug(result) - } - #2 -} -\mykeyvalcmd[one=1]{test} -\end{minted} +\InputLatex{functions/parse/tex-latex.tex} \noindent In plain \TeX: -\begin{minted}{latex} -\def\mykeyvalcommand#1{ - \directlua{ - result = luakeys.parse('#1') - luakeys.debug(result) - } -} -\mykeyvalcmd{one=1} -\end{minted} +\InputLatex{functions/parse/tex-plain.tex} \subsection{Options to configure the \texttt{parse} function} \noindent The \lua{parse} function can be called with an options table. This -options are supported: +options are supported: \catcode`_=12 +\directlua{luakeys.print_names('opts')} -\InputLuaExample[firstline=5,lastline=69]{opts/all-opts.lua} +\InputLua[firstline=5,lastline=69]{opts/all-opts.lua} \noindent The options can also be set globally using the exported table |opts|: -\InputLuaExample[firstline=4,lastline=4]{opts/exported-default-opts.lua} +\InputLua[firstline=4,lastline=4]{opts/exported-default-opts.lua} -\InputLuaExample[firstline=10,lastline=11]{opts/exported-default-opts.lua} +\InputLua[firstline=10,lastline=11]{opts/exported-default-opts.lua} %% % @@ -305,45 +373,49 @@ The options can also be set globally using the exported table \subsubsection{Option “\texttt{convert_dimensions}”} +% Wenn Sie die Option \lua{convert_dimensions} auf \lua{true} setzen, +% erkennt |luakeys| die \TeX{}-Dimensionen und konvertiert sie mit Hilfe +% der die Funktion \lua{tex.sp(dim)} in scaled points. If you set the option \lua{convert_dimensions} to \lua{true}, |luakeys| detects the \TeX{} dimensions and converts them into scaled points using the function \lua{tex.sp(dim)}. -\InputLuaExample[firstline=4,lastline=7]{opts/convert-dimensions.lua} +\InputLua[firstline=4,lastline=7]{opts/convert-dimensions/true.lua} \noindent +% Standardmäßig werden die Dimensionen nicht in skalierte Punkte +% umgewandelt. By default the dimensions are not converted into scaled points. -\InputLuaExample[firstline=13,lastline=18]{opts/convert-dimensions.lua} +\InputLua[firstline=4,lastline=9]{opts/convert-dimensions/false.lua} \noindent -If you want to convert a scale point into a unit string you can use the module -\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua}{lualibs-util-dim.lua}. +% Wenn Sie eine skalierte Punktzahl in einen Dimensionszeichenketten +% umwandeln möchten, können Sie das Modul +If you want to convert a scaled points number into a dimension string +you can use the module +\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua} +{lualibs-util-dim.lua}. \begin{minted}{lua} require('lualibs') tex.print(number.todimen(tex.sp('1cm'), 'cm', '%0.0F%s')) \end{minted} +\DefaultOptDescription{convert_dimensions} + %% % %% \subsubsection{Option “\texttt{debug}”} -If the option “debug” is set to ture, the result table is printed to the -console. +% Wenn die Option \lua{debug} auf true gesetzt ist, wird die +% Ergebnistabelle in der Konsole ausgegeben. +If the option \lua{debug} is set to ture, the result table is printed to +the console. -\begin{minted}{latex} -\documentclass{article} -\usepackage{luakeys} -\begin{document} -\directlua{ - luakeys.parse('one,two,three', { debug = true }) -} -debug -\end{document} -\end{minted} +\InputLatex{opts/debug-latex.tex} \begin{verbatim} This is LuaHBTeX, Version 1.15.0 (TeX Live 2022) @@ -361,6 +433,8 @@ local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./debug.aux) Transcript written on debug.log. \end{verbatim} +\DefaultOptDescription{debug} + %% % %% @@ -375,13 +449,15 @@ The option \lua{default} can be used to specify which value naked keys (keys without a value) get. This option has no influence on keys with values. -\InputLuaExample[firstline=4,lastline=5]{opts/default.lua} +\InputLua[firstline=4,lastline=5]{opts/default.lua} \noindent % Standardmäßig erhalten nackte Schlüssel den Wert \lua{true}. By default, naked keys get the value \lua{true}. -\InputLuaExample[firstline=11,lastline=12]{opts/default.lua} +\InputLua[firstline=11,lastline=12]{opts/default.lua} + +\DefaultOptDescription{default} %% % @@ -402,7 +478,9 @@ The result table is merged into the defaults table. Values in the defaults table are overwritten by values in the result table. -\InputLuaExample[firstline=4,lastline=7]{opts/defaults.lua} +\InputLua[firstline=4,lastline=7]{opts/defaults.lua} + +\DefaultOptDescription{defaults} %% % @@ -421,13 +499,15 @@ If you use the \lua{defs} option, you don't need to call the % Anstatt Instead of ... -\InputLuaExample[firstline=4,lastline=5]{opts/defs.lua} +\InputLua[firstline=4,lastline=5]{opts/defs.lua} \noindent % können wir schreiben .. we can write ... -\InputLuaExample[firstline=11,lastline=13]{opts/defs.lua} +\InputLua[firstline=11,lastline=13]{opts/defs.lua} + +\DefaultOptDescription{defs} %% % @@ -438,17 +518,19 @@ we can write ... \begin{description} \item[lower] \strut -\InputLuaExample[firstline=4,lastline=5]{opts/format-keys.lua} +\InputLua[firstline=4,lastline=5]{opts/format-keys.lua} \item[snake] \strut -\InputLuaExample[firstline=11,lastline=12]{opts/format-keys.lua} +\InputLua[firstline=11,lastline=12]{opts/format-keys.lua} \item[upper] \strut -\InputLuaExample[firstline=18,lastline=19]{opts/format-keys.lua} +\InputLua[firstline=18,lastline=19]{opts/format-keys.lua} \end{description} +\DefaultOptDescription{format_keys} + %% % %% @@ -463,8 +545,8 @@ processing of the \lua{parse} function. % Die Funktionen sind in der Verarbeitungsreihenfolge aufgelistet. The functions are listed in processing order. % -% \lua{*_before_opts} bedeutet, dass die Hooks nach der LPeg Syntaxanalyse -% und vor dem Anwenden der Optionen ausgeführt +% \lua{*_before_opts} bedeutet, dass die Hooks nach der LPeg +% Syntaxanalyse und vor dem Anwenden der Optionen ausgeführt \lua{*_before_opts} means that the hooks are executed after the LPeg syntax analysis and before the options are applied. % @@ -504,7 +586,7 @@ definitions. The \lua{kv_string} hook is called as the first of the hook functions before the LPeg syntax parser is executed. -\InputLuaExample[firstline=4,lastline=11]{hooks/kv-string.lua} +\InputLua[firstline=4,lastline=11]{hooks/kv-string.lua} \paragraph{\texttt{keys_*}} @@ -515,12 +597,12 @@ result table. % Die Hook-Funktion muss zwei Werte zurückgeben: \lua{key, value} The hook function must return two values: \lua{key, value}. % -% Das folgende Beispiel gibt \lua{key} und \lua{value} unverändert zurück, -% sodass die Ergebnistabelle nicht verändert wird. +% Das folgende Beispiel gibt \lua{key} und \lua{value} unverändert +% zurück, sodass die Ergebnistabelle nicht verändert wird. The following example returns \lua{key} and \lua{value} unchanged, so the result table is not changed. -\InputLuaExample[firstline=4,lastline=11]{hooks/keys-unchanged.lua} +\InputLua[firstline=4,lastline=11]{hooks/keys-unchanged.lua} \noindent % Das nächste Beispiel demonstriert den dritten Parameter \lua{depth} @@ -528,7 +610,7 @@ the result table is not changed. The next example demonstrates the third parameter \lua{depth} of the hook function. -\InputLuaExample[firstline=4,lastline=16]{hooks/keys-depth.lua} +\InputLua[firstline=4,lastline=16]{hooks/keys-depth.lua} \paragraph{\texttt{result_*}} @@ -549,12 +631,14 @@ as a parameter. With the help of the option \lua{naked_as_value}, naked keys are not given a default value, but are stored as values in a Lua table. -\InputLuaExample[firstline=4,lastline=5]{opts/naked-as-value.lua} +\InputLua[firstline=4,lastline=5]{opts/naked-as-value.lua} \noindent If we set the option \lua{naked_as_value} to \lua{true}: -\InputLuaExample[firstline=11,lastline=14]{opts/naked-as-value.lua} +\InputLua[firstline=11,lastline=14]{opts/naked-as-value.lua} + +\DefaultOptDescription{naked_as_value} %% % @@ -568,12 +652,14 @@ By default the parse function throws an error if there are unknown keys. % Mit Hilfe der Option \lua{no_error} kann dies unterbunden werden. This can be prevented with the help of the \lua{no_error} option. -\InputLuaExample[firstline=5,lastline=6]{opts/no-error.lua} +\InputLua[firstline=5,lastline=6]{opts/no-error.lua} \noindent If we set the option \lua{no_error} to \lua{true}: -\InputLuaExample[firstline=9,lastline=10]{opts/no-error.lua} +\InputLua[firstline=9,lastline=10]{opts/no-error.lua} + +\DefaultOptDescription{no_error} %% % @@ -587,15 +673,17 @@ If we set the option \lua{no_error} to \lua{true}: With the help of the option \lua{unpack}, all tables that consist of only one a single naked key or a single standalone value are unpacked. -\InputLuaExample[firstline=4,lastline=5]{opts/unpack.lua} +\InputLua[firstline=4,lastline=5]{opts/unpack.lua} + +\InputLua[firstline=11,lastline=12]{opts/unpack.lua} -\InputLuaExample[firstline=11,lastline=12]{opts/unpack.lua} +\DefaultOptDescription{unpack} %% % %% -\subsection{Function \texttt{define(defs, opts): parse}} +\subsection{Function “\texttt{define(defs, opts): parse}”} \label{define} The \lua{define} function returns a \lua{parse} function (see @@ -609,13 +697,13 @@ key-value pair is then stored under this key. \item by the “name” attribute. \end{enumerate} -\InputLuaExample[firstline=4,lastline=16]{functions/define.lua} +\InputLua[firstline=4,lastline=16]{functions/define.lua} \noindent For nested definitions, only the last two ways of specifying the key names can be used. -\InputLuaExample[firstline=26,lastline=33]{functions/define.lua} +\InputLua[firstline=26,lastline=33]{functions/define.lua} %----------------------------------------------------------------------- % @@ -636,12 +724,16 @@ The name \emph{“attribute”} for an option, a key, a property ... (to list just a few naming possibilities) to define keys, was deliberately chosen to distinguish them from the options of the \lua{parse} function. % +% Diese Attribute sind erlaubt. +These attributes are allowed: +\directlua{luakeys.print_names('attrs')}. +% % Das folgende Codebeispiel listet alle Attribute auf, die verwendet % werden können, um Schlüssel-Wert-Paare zu definieren. The code example below lists all the attributes that can be used to define key-value pairs. -\InputLuaExample[firstline=5,lastline=41]{defs/all-attrs.lua} +\InputLua[firstline=5,lastline=46]{defs/all-attrs.lua} %% % @@ -653,12 +745,12 @@ With the help of the \lua{alias} attribute, other key names can be used. The value is always stored under the original key name. A single alias name can be specified by a string ... -\InputLuaExample[firstline=4,lastline=7]{defs/attrs/alias.lua} +\InputLua[firstline=4,lastline=7]{defs/attrs/alias.lua} \noindent multiple aliases by a list of strings. -\InputLuaExample[firstline=13,lastline=16]{defs/attrs/alias.lua} +\InputLua[firstline=13,lastline=16]{defs/attrs/alias.lua} %% % @@ -669,7 +761,7 @@ multiple aliases by a list of strings. % Die Option \lua{default} wird nur bei nackten Schlüsseln verwendet. The \lua{default} attribute is used only for naked keys. -\InputLuaExample[firstline=4,lastline=5]{defs/attrs/always-present.lua} +\InputLua[firstline=4,lastline=5]{defs/attrs/always-present.lua} \noindent % Wird die Option \lua{always_present} auf wahr gesetzt, wird der @@ -678,7 +770,7 @@ If the attribute \lua{always_present} is set to true, the key is always included in the result. If no default value is definied, true is taken as the value. -\InputLuaExample[firstline=11,lastline=12]{defs/attrs/always-present.lua} +\InputLua[firstline=11,lastline=12]{defs/attrs/always-present.lua} %% % @@ -690,14 +782,14 @@ as the value. Some key values should be selected from a restricted set of choices. These can be handled by passing an array table containing choices. -\InputLuaExample[firstline=4,lastline=5]{defs/attrs/choices.lua} +\InputLua[firstline=4,lastline=5]{defs/attrs/choices.lua} \noindent When the key-value pair is parsed, values will be checked, and an error message will be displayed if the value was not one of the acceptable choices: -\InputLuaExample[firstline=13,lastline=15]{defs/attrs/choices.lua} +\InputLua[firstline=13,lastline=15]{defs/attrs/choices.lua} %% % @@ -727,8 +819,8 @@ A type conversion can fail with the three data types % Dann wird eine Fehlermeldung ausgegeben. Then an error message is displayed. -\InputLuaExample[firstline=4,lastline=8]{defs/attrs/data-type.lua} -\InputLuaExample[firstline=11,lastline=15]{defs/attrs/data-type.lua} +\InputLua[firstline=4,lastline=8]{defs/attrs/data-type.lua} +\InputLua[firstline=11,lastline=15]{defs/attrs/data-type.lua} %% % @@ -746,7 +838,7 @@ key individually. With the global \lua{default} attribute (\ref{option-default}) a default value can be specified for all naked keys. -\InputLuaExample[firstline=4,lastline=9]{defs/attrs/default.lua} +\InputLua[firstline=4,lastline=9]{defs/attrs/default.lua} %% % @@ -766,14 +858,15 @@ Only one key from this group is allowed. % Wert verwendet werden. Any value can be used as a name for this exclusive group. -\InputLuaExample[firstline=4,lastline=9]{defs/attrs/exclusive-group.lua} +\InputLua[firstline=4,lastline=9]{defs/attrs/exclusive-group.lua} +\noindent % Werden mehrer Schlüssel der Gruppe angegeben, so wird eine % Fehlermeldung geworfen. If more than one key of the group is specified, an error message is thrown. -\InputLuaExample[firstline=21,lastline=23]{defs/attrs/exclusive-group.lua} +\InputLua[firstline=21,lastline=23]{defs/attrs/exclusive-group.lua} %% % @@ -809,13 +902,13 @@ opposite key pair. If the key \lua{show} is parsed by the \lua{parse} function, then the target key \lua{visibility} receives the value \lua{true}. -\InputLuaExample[firstline=4,lastline=7]{defs/attrs/opposite-keys.lua} +\InputLua[firstline=4,lastline=7]{defs/attrs/opposite-keys.lua} % Wird der Schlüssel \lua{hide} gelesen, dann \lua{falsch}. \noindent If the key \lua{hide} is parsed, then \lua{false}. -\InputLuaExample[firstline=13,lastline=13]{defs/attrs/opposite-keys.lua} +\InputLua[firstline=13,lastline=13]{defs/attrs/opposite-keys.lua} %% % @@ -844,21 +937,31 @@ parse('key=value') \subsubsection{Attribute “\texttt{match}”} -% Der Wert des Schlüssel wird der Lua Funktion übergeben -The value of the key is passed to the Lua function -\lua{string.match(value, match)} ((\url{http://www.lua.org/manual/5.3/manual.html#pdf-string.match})). +% Der Wert des Schlüssel wird zuerst der Lua Funktion +% \lua{string.match(value, match)} übergeben, bevor er dem Schlüssel +% zugewiesen wird. +The value of the key is first passed to the Lua function +\lua{string.match(value, match)} +(\url{http://www.lua.org/manual/5.3/manual.html#pdf-string.match}) +before being assigned to the key. +% +% Du kannst das Attribut \lua{match} deshalb mit einer Pattern-Matching- +% Zeichenkette konfigurieren, wie sie in Lua zu Einsatz kommt. +You can therefore configure the \lua{match} attribute with a pattern +matching string used in Lua. +% % Werfe einen Blick in das Lua-Handbuch, wie man Patterns schreibt. Take a look at the Lua manual on how to write patterns -(\url{http://www.lua.org/manual/5.3/manual.html#6.4.1}) +(\url{http://www.lua.org/manual/5.3/manual.html#6.4.1}). -\InputLuaExample[firstline=4,lastline=6]{defs/attrs/match.lua} +\InputLua[firstline=4,lastline=7]{defs/attrs/match/birthday.lua} \noindent % Kann das Pattern im Wert nicht gefunden werden, wird eine % Fehlermeldung ausgegeben. If the pattern cannot be found in the value, an error message is issued. -\InputLuaExample[firstline=14,lastline=17]{defs/attrs/match.lua} +\InputLua[firstline=15,lastline=18]{defs/attrs/match/birthday.lua} \noindent % Der Schlüssel erhält das Ergebnis der Funktion \lua{string.match(value, @@ -867,8 +970,11 @@ If the pattern cannot be found in the value, an error message is issued. The key receives the result of the function \lua{string.match(value, match)}, which means that the original value may not be stored completely in the key. +% +% Im nächsten Beispiel wird der gesamte Eingabewert akzeptiert: +In the next example, the entire input value is accepted: -\InputLuaExample[firstline=22,lastline=23]{defs/attrs/match.lua} +\InputLua[firstline=4,lastline=5]{defs/attrs/match/year.lua} \noindent % Das Präfix “waste ” und das Suffix “ rubbisch” der Zeichenketten wird @@ -876,7 +982,7 @@ completely in the key. The prefix “waste ” and the suffix “ rubbisch” of the string are discarded. -\InputLuaExample[firstline=29,lastline=29]{defs/attrs/match.lua} +\InputLua[firstline=11,lastline=11]{defs/attrs/match/year.lua} \noindent % Da Funktion \lua{string.match(value, match)} immer eine Zeichenkette @@ -897,13 +1003,61 @@ The \lua{name} attribute allows an alternative notation of key names. % Anstatt ... Instead of ... -\InputLuaExample[firstline=4,lastline=5]{defs/attrs/name.lua} +\InputLua[firstline=4,lastline=8]{defs/attrs/name/as-key.lua} \noindent % ... können wir schreiben: ... we can write: -\InputLuaExample[firstline=11,lastline=15]{defs/attrs/name.lua} +\InputLua[firstline=4,lastline=8]{defs/attrs/name/name-attr.lua} + +%% +% +%% + +\subsubsection{Attribute “\texttt{pick}”} + +% Das Attribut \lua{pick} sucht nach einem Wert, der keinem Schlüssel +% zugeordnet ist. +The attribute \lua{pick} searches for a value not assigned to a key. +% Der zuerst gefundene Wert, d. h. der weiter links stehende Wert, wird +% einem Schlüssel zugewiesen. +The first value found, i.e. the one further to the left, is assigned to +a key. + +\InputLua[firstline=4,lastline=6]{defs/attrs/pick/dimension.lua} + +\noindent +% Es wird nur in der aktuellen Ergebnistabelle gesucht und nicht auf +% anderen Ebenen in der rekursiven Datenstruktur. +Only the current result table is searched, not other levels in the +recursive data structure. + +\InputLua[firstline=4,lastline=11]{defs/attrs/pick/different-levels.lua} + +\noindent +% Die Suche nach Werte wird aktiviert, wenn das Attribut \lua{pick} auf +% \lua{true} gesetzt wird. +The search for values is activated when the attribute \lua{pick} is set +to \lua{true}. +% Die Suche kann eingeschränkt werden, indem ein Datentype angegeben +% wird. +The search can be limited by specifying a data type. +% Nach diesen Datentypen kann gesucht werden: +These data types can be searched for: +\directlua{ + local types = {} + for t, fn in pairs(luakeys.is) do + table.insert(types, t) + end + tex.print(table.concat(types, ', ')) +}. + +% Wird einem Schlüssel bereits bei der Eingabe ein Wert zugewiesen, dann +% wird nicht weiter nach Werten gesucht. +If a value is already assigned to a key when it is entered, then no +further search for values is performed. +\InputLua[firstline=4,lastline=8]{defs/attrs/pick/value-set.lua} %% % @@ -912,19 +1066,24 @@ Instead of ... \subsubsection{Attribute “\texttt{process}”} \label{attr-process} -The \lua{process} attribute can be used to define a function whose return -value is passed to the key. Four parameters are passed when the -function is called: +% Das Attribut \lua{process} kann dazu verwendet werden, um eine Funktion +% zu definieren, deren Rückgabewert an den Schlüssel übergeben wird. +The \lua{process} attribute can be used to define a function whose +return value is passed to the key. +% +% Beim Aufruf der Funktion werden vier Parameter übergeben: +Four parameters are passed when the function is called: \begin{enumerate} \item \lua{value}: -% Der zum schlüssel gehörende aktuelle Wert. +% Der zum Schlüssel gehörende aktuelle Wert. The current value asssociated with the key. \item \lua{input}: % Die Ergebnis-Tabelle, die vor dem Zeitpunkt geklont wurde, als mit dem % Anwenden der Definitionen begonnen wurde. -The result table cloned before the time the definitions started to be applied. +The result table cloned before the time the definitions started to be +applied. \item \lua{result}: The table in which the final result will be saved. @@ -932,26 +1091,29 @@ The result table cloned before the time the definitions started to be applied. are stored. \end{enumerate} -% Das folgende Beispiel demonstriert den Parameter \lua{value}. \noindent +% Das folgende Beispiel demonstriert den Parameter \lua{value}: The following example demonstrates the \lua{value} parameter: -\InputLuaExample[firstline=4,lastline=14]{defs/attrs/process.lua} +\InputLua[firstline=4,lastline=14]{defs/attrs/process/parameter-value.lua} \noindent +% Das folgende Beispiel demonstriert den Parameter \lua{input}: The following example demonstrates the \lua{input} parameter: -\InputLuaExample[firstline=22,lastline=34]{defs/attrs/process.lua} +\InputLua[firstline=4,lastline=16]{defs/attrs/process/parameter-input.lua} \noindent +% Das folgende Beispiel demonstriert den Parameter \lua{result}: The following example demonstrates the \lua{result} parameter: -\InputLuaExample[firstline=42,lastline=50]{defs/attrs/process.lua} +\InputLua[firstline=4,lastline=12]{defs/attrs/process/parameter-result.lua} \noindent +% Das folgende Beispiel demonstriert den Parameter \lua{unknown}: The following example demonstrates the \lua{unknown} parameter: -\InputLuaExample[firstline=58,lastline=65]{defs/attrs/process.lua} -\InputLuaExample[firstline=69,lastline=69]{defs/attrs/process.lua} +\InputLua[firstline=4,lastline=11]{defs/attrs/process/parameter-unknown.lua} +\InputLua[firstline=15,lastline=15]{defs/attrs/process/parameter-unknown.lua} %% % @@ -959,16 +1121,41 @@ The following example demonstrates the \lua{unknown} parameter: \subsubsection{Attribute “\texttt{required}”} -\InputLuaExample[firstline=4,lastline=5]{defs/attrs/required.lua} +% Durch das Attribut \lua{required} kann erzwungen werden, dass ein +% bestimmter Schlüssel angegeben werden muss. +The \lua{required} attribute can be used to enforce that a specific key +must be specified. +% +% Im untenstehenden Beispiel wird der Schlüssel \lua{important} als +% zwingend notwendig definiert. +In the example below, the key \lua{important} is defined as mandatory. -\InputLuaExample[firstline=13,lastline=14]{defs/attrs/required.lua} +\InputLua[firstline=4,lastline=5]{defs/attrs/required.lua} + +\noindent +% Fehlt der Schlüssel \lua{important} in der Eingabe, so tritt eine +% Fehlermeldung auf. +If the key \lua{important} is missing in the input, an error message +occurs. + +\InputLua[firstline=13,lastline=14]{defs/attrs/required.lua} \noindent A recursive example: -\InputLuaExample[firstline=18,lastline=23]{defs/attrs/required.lua} -\InputLuaExample[firstline=29,lastline=30]{defs/attrs/required.lua} -\InputLuaExample[firstline=38,lastline=39]{defs/attrs/required.lua} +\InputLua[firstline=18,lastline=23]{defs/attrs/required.lua} + +\noindent +% Der Schlüssel \lua{important2} auf der Ebene 2 fehlt. +The \lua{important2} key on level 2 is missing. + +\InputLua[firstline=29,lastline=30]{defs/attrs/required.lua} + +\noindent +% Der Schlüssel \lua{important1} auf der untersten Schlüssel-Ebene fehlt. +The \lua{important1} key at the lowest key level is missing. + +\InputLua[firstline=38,lastline=39]{defs/attrs/required.lua} %% % @@ -981,39 +1168,39 @@ A recursive example: The \lua{sub_keys} attribute can be used to build nested key-value pair definitions. -\InputLuaExample[firstline=4,lastline=16]{defs/attrs/sub-keys.lua} +\InputLua[firstline=4,lastline=16]{defs/attrs/sub-keys.lua} %----------------------------------------------------------------------- % %----------------------------------------------------------------------- -\subsection{Function \texttt{render(result): string}} +\subsection{Function “\texttt{render(result): string}”} The function \lua{render(result)} reverses the function \lua{parse(kv_string)}. It takes a Lua table and converts this table into a key-value string. The resulting string usually has a different order as the input table. -\InputLuaExample[firstline=4,lastline=10]{functions/render.lua} +\InputLua[firstline=4,lastline=10]{functions/render.lua} \noindent In Lua only tables with 1-based consecutive integer keys (a.k.a. array tables) can be parsed in order. -\InputLuaExample[firstline=16,lastline=17]{functions/render.lua} +\InputLua[firstline=16,lastline=17]{functions/render.lua} %% % %% -\subsection{Function \texttt{debug(result): void}} +\subsection{Function “\texttt{debug(result): void}”} The function \lua{debug(result)} pretty prints a Lua table to standard output (stdout). It is a utility function that can be used to debug and inspect the resulting Lua table of the function \lua{parse}. You have to compile your \TeX{} document in a console to see the terminal output. -\InputLuaExample[firstline=4,lastline=5]{functions/debug.lua} +\InputLua[firstline=4,lastline=5]{functions/debug.lua} \noindent The output should look like this: @@ -1032,7 +1219,7 @@ The output should look like this: % %% -\subsection{Function \texttt{save(identifier, result): void}} +\subsection{Function “\texttt{save(identifier, result): void}”} The function \lua{save(identifier, result)} saves a result (a table from a previous run of \lua{parse}) under an identifier. @@ -1043,7 +1230,7 @@ store results for the later usage. % %% -\subsection{Function \texttt{get(identifier): result}} +\subsection{Function “\texttt{get(identifier): result}”} The function \lua{get(identifier)} retrieves a saved result from the result store. @@ -1052,22 +1239,105 @@ result store. % %% -\subsection{Table \texttt{is}} +\subsection{Table “\texttt{is}”} + +% In der Tabelle \lua{is} werden einige Funktionen zusammengefasst, die +% überprüft ob eine Eingabe einem bestimmen Datentyp entspricht. +In the table \lua{is} some functions are summarized, which check whether +an input corresponds to a certain data type. +% +% Alle Funktionen akzeptieren nicht nur die entsprechenden Lua-Datentypen, +% sondern auch Eingaben als Zeichenketten. +All functions accept not only the corresponding Lua data types, but also +input as strings. +% +% Beispielsweise wird die Zeichenkette \lua{'true'} von der +% \lua{is.boolean()}-Funktion als Wahrheitswert erkannt. +For example, the string \lua{'true'} is recognized by the +\lua{is.boolean()} function as a boolean value. + +\subsubsection{Function “\texttt{is.boolean(value): boolean}”} +\InputLua[firstline=6,lastline=23]{functions/is/boolean.lua} + +\subsubsection{Function “\texttt{is.dimension(value): boolean}”} +\InputLua[firstline=6,lastline=16]{functions/is/dimension.lua} + +\subsubsection{Function “\texttt{is.integer(value): boolean}”} +\InputLua[firstline=6,lastline=11]{functions/is/integer.lua} + +\subsubsection{Function “\texttt{is.number(value): boolean}”} +\InputLua[firstline=6,lastline=13]{functions/is/number.lua} + +\subsubsection{Function “\texttt{is.string(value): boolean}”} +\InputLua[firstline=6,lastline=12]{functions/is/string.lua} + +%% +% +%% + +\subsection{Table “\texttt{utils}”} + +\subsubsection{Function “\texttt{utils.scan_oarg(initial_delimiter?, end_delimiter?): string}”} -\subsubsection{Function \texttt{is.boolean(value): boolean}} -\InputLuaExample[firstline=7,lastline=23]{is-table.lua} +% Plain \TeX{} kennt keine optionalen Argumente (oarg). +Plain \TeX{} does not know optional arguments (oarg). +% +% Die Funktion ermöglicht es nicht nur in \LaTeX{}, sondern auch in +% Plain \TeX{} nach optionalen Argumenten zu suchen. +The function \\ \lua{utils.scan_oarg(initial_delimiter?, +end_delimiter?): string} allows to search for optional arguments not only +in \LaTeX{} but also in Plain \TeX. +% +% Die Funktion basiert auf der Token-Bibliothek. +The function uses the token library built into Lua\TeX{}. +% +% Die beiden Parameter \lua{initial_delimiter} und \lua{end_delimiter} +% können weggelassen werden. +The two parameters \lua{initial_delimiter} and \lua{end_delimiter} can +be omitted. +% +% Dann werden eckige Klammern als Begrenzungszeichen angenommen. +Then square brackets are assumed to be delimiters. +% +% Dieser Lua-Code \lua{utils.scan_oarg('(', ')')} sucht beispielsweise +% nach an einem optionalen Argument in runden Klammern. +For example, this Lua code \lua{utils.scan_oarg('(', ')')} searches for +an optional argument in round brackets +% +% Die Funktion gibt die Zeichenkette zwischen den Begrenzungszeichen +% zurück, oder nil wenn Begrenzungszeichen gefunden werden konnten. +The function returns the string between the delimiters or \lua{nil} if +no delimiters could be found. +% +% Die Begrenzungszeichen sind im Ergebnis nicht enthalten. +The delimiters themselves are not included in the result. +% +% Nach dem \latex{\directlua{}} darf das Makro, indem +% \lua{utils.scan_oarg} eingesetzt wird, zu keinen Zeichen expandieren. +After the \latex{\directlua{}}, the macro using \lua{utils.scan_oarg} +must not expand to any characters. -\subsubsection{Function \texttt{is.dimension(value): boolean}} -\InputLuaExample[firstline=27,lastline=37]{is-table.lua} +\InputLatex{utils/scan-oarg-plain.tex} -\subsubsection{Function \texttt{is.integer(value): boolean}} -\InputLuaExample[firstline=41,lastline=46]{is-table.lua} +%% +% +%% + +\subsection{Table “version”} -\subsubsection{Function \texttt{is.number(value): boolean}} -\InputLuaExample[firstline=50,lastline=57]{is-table.lua} +% Das luakeys Projekt verwendet semantic versioning +The luakeys project uses semantic versioning. +% Die drei Versionenzahlen des Semantic Versioning Schemas werden in +% einer Tabelle in der Reihenfolge MAJOR, MINOR, PATCH als Ganzzahlen +% abgelegt. +The three version numbers of the semantic versioning scheme are stored +in a table as integers in the order MAJOR, MINOR, PATCH. +% Mit Hilfe dieser Tabelle kann überprüft werden, ob die richtige +% Version installiert ist. +This table can be used to check whether the correct version is +installed. -\subsubsection{Function \texttt{is.string(value): boolean}} -\InputLuaExample[firstline=61,lastline=67]{is-table.lua} +\InputLua[firstline=4,lastline=10]{version.lua} %----------------------------------------------------------------------- % @@ -1128,10 +1398,12 @@ key-value lists (\texttt{level1=\{level2=\{key=value,naked\}\}}). \alt `ex' | `EX' \alt `in' | `IN' \alt `mm' | `MM' + \alt `mu' | `MU' \alt `nc' | `NC' \alt `nd' | `ND' \alt `pc' | `PC' \alt `pt' | `PT' + \alt `px' | `PX' \alt `sp' | `SP' <boolean> ::= <boolean-true> | <boolean-false> @@ -1156,16 +1428,10 @@ into Lua’s boolean type \lua{true}, the strings \texttt{false}, \texttt{FALSE} and \texttt{False} into \lua{false}. \begin{multicols}{2} -\begin{minted}{latex} -\luakeysdebug{ - lower case true = true, - upper case true = TRUE, - title case true = True - lower case false = false, - upper case false = FALSE, - title case false = False, -} -\end{minted} +\InputLatex[firstline=5,lastline=12]{luakeysdebug/boolean-latex.tex} + +\columnbreak + \begin{minted}{lua} { ['lower case true'] = true, @@ -1185,18 +1451,19 @@ into Lua’s boolean type \lua{true}, the strings \texttt{false}, \subsubsection{number} \begin{multicols}{2} -\begin{minted}{latex} -\luakeysdebug{ - num1 = 4, - num2 = -4, - num3 = 0.4 -} -\end{minted} +\InputLatex[firstline=5,lastline=13]{luakeysdebug/number-latex.tex} + +\columnbreak + \begin{minted}{lua} { - ['num1'] = 4, - ['num2'] = -4, - ['num3'] = 0.4 + ['num0'] = 42, + ['num1'] = 42, + ['num2'] = -42, + ['num3'] = 4.2, + ['num4'] = 0.42, + ['num5'] = 0.42, + ['num6'] = '0 . 42', -- string } \end{minted} \end{multicols} @@ -1207,6 +1474,22 @@ into Lua’s boolean type \lua{true}, the strings \texttt{false}, \subsubsection{dimension} +% Luakeys versucht alle Einheiten zu erkennen, die in der TeX-Welt +% verwendet werden. +|luakeys| tries to recognize all units used in the \TeX{} world. +% +% Nach dem Lua\TeX-Quellcode . +According to the Lua\TeX{} source code +(\href{https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625} +{source/texk/web2c/luatexdir/lua/ltexlib.c}) +% +% und nach dem Dimensionen-Modul der lulibs-Bibliothek +and the dimension module of the lualibs library +(\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua} +{lualibs-util-dim.lua}), +% +% müssten alle Einheiten erkannt werden +all units should be recognized. \begin{multicols}{3} \tiny \begin{center} @@ -1221,33 +1504,19 @@ em & horizontal measure of \emph{M} \\ ex & vertical measure of \emph{x} \\ in & inch \\ mm & milimeter \\ +mu & math unit \\ nc & new cicero \\ nd & new didot \\ pc & pica \\ pt & point \\ +px & x height current font \\ sp & scaledpoint \\ \end{tabular} \end{center} \columnbreak -\begin{minted}{latex} -\luakeysdebug{ - bp = 1bp, - cc = 1cc, - cm = 1cm, - dd = 1dd, - em = 1em, - ex = 1ex, - in = 1in, - mm = 1mm, - nc = 1nc, - nd = 1nd, - pc = 1pc, - pt = 1pt, - sp = 1sp, -} -\end{minted} +\InputLatex[firstline=5,lastline=21]{luakeysdebug/dimension/all-latex.tex} \columnbreak @@ -1261,15 +1530,39 @@ sp & scaledpoint \\ ['ex'] = 282460, ['in'] = 4736286, ['mm'] = 186467, + ['mu'] = 65536, ['nc'] = 839105, ['nd'] = 69925, ['pc'] = 786432, ['pt'] = 65536, + ['px'] = 65781, ['sp'] = 1, } \end{minted} \end{multicols} +\noindent +% Im nächsten Beispiel werden die unterschiedlichen Notationsformen der +% Dimensionen illustriert. +The next example illustrates the different notations of the dimensions. + +\begin{multicols}{2} +\InputLatex[firstline=5,lastline=12]{luakeysdebug/dimension/notations-latex.tex} + +\columnbreak + +\begin{minted}{lua} +{ + ['upper'] = 1864679, + ['lower'] = 1864679, + ['space'] = 1864679, + ['plus'] = 1864679, + ['minus'] = -1864679, + ['nodim'] = '1 c m', -- string +} +\end{minted} +\end{multicols} + %% % %% @@ -1287,7 +1580,7 @@ With or without double quotes. If the text have to contain commas, curly braces or equal signs, then double quotes must be used. -\InputLuaExample[firstline=4,lastline=17]{data-types/string.lua} +\InputLua[firstline=4,lastline=17]{data-types/string.lua} \subsubsection{Naked keys} @@ -1303,14 +1596,14 @@ and stored into an array. % Index ist 1). In Lua an array is a table with numeric indexes (The first index is 1). -\InputLatexExample[firstline=5,lastline=12]{luakeysdebug/naked-keys.tex} +\InputLatex[firstline=5,lastline=12]{luakeysdebug/naked-keys-latex.tex} \noindent % VAlle erkannten Datentypen können als eigenständige Werte verwendet % werden. All recognized data types can be used as standalone values. -\InputLatexExample[firstline=14,lastline=19]{luakeysdebug/naked-keys.tex} +\InputLatex[firstline=14,lastline=19]{luakeysdebug/naked-keys-latex.tex} %----------------------------------------------------------------------- % @@ -1320,6 +1613,10 @@ All recognized data types can be used as standalone values. \section{Examples} +%% +% +%% + \subsection{Extend and modify keys of existing macros} Extend the includegraphics macro with a new key named \latex{caption} @@ -1327,17 +1624,34 @@ and change the accepted values of the \latex{width} key. A number between 0 and 1 is allowed and converted into \latex{width=0.5\linewidth} -\InputLuaExample{extend-includegraphics/extend-keys.lua} -\InputLatexExample{extend-includegraphics/extend-keys.tex} +\InputLua{extend-includegraphics/extend-keys.lua} +\InputLatex{extend-includegraphics/extend-keys-latex.tex} + +%% +% +%% \subsection{Process document class options} -\begin{minted}{latex} -\directlua{luakeys.parse('\@classoptionslist')} -\end{minted} +% Auf die Optionen einer \LaTeX{} Dokumentenklasse kann über das Macro +% \latex{\@classoptionslist} zu gegriffen werden. +The options of a \LaTeX{} document class can be accessed via the +\latex{\@classoptionslist} macro. +% +% Die Zeichenkette des Makros \latex{\@classoptionslist} ist bereits +% expandiert und normalisiert. +The string of the macro \latex{\@classoptionslist} is already expanded +and normalized. +% +% Neben Leerzeichen werden auch die geschweiften Klammern entfernt. +In addition to spaces, the curly brackets are also removed. +% Es ist deshalb nicht möglich, in einander geschachtelte hierarische +% Schlüssel-Wert-Paare über die Option zu verarbeiten. +It is therefore not possible to process nested hierarchical key-value +pairs via the option. -\InputLatexExample{class-options/test-class.cls} -\InputLatexExample{class-options/use-test-class.tex} +\InputLatex{class-options/test-class.cls} +\InputLatex{class-options/use-test-class-latex.tex} \begin{minted}{lua} { @@ -1458,30 +1772,30 @@ An example of how to use the command in \LaTeX: \inputminted[linenos=true]{latex}{luakeys-debug.sty} -\changes{v0.1}{2021/01/18}{Inital release} -\changes{v0.2}{2021/09/19}{ +\changes{0.1.0}{2021/01/18}{Inital release} +\changes{0.2.0}{2021/09/19}{ * Allow all recognized data types as keys * Allow TeX macros in the values * New public Lua functions: save(identifier, result), get(identifier) } -\changes{v0.3}{2021/11/05}{ +\changes{0.3.0}{2021/11/05}{ * Add a LuaLaTeX wrapper “luakeys.sty” * Add a plain LuaTeX wrapper “luakeys.tex” * Rename the previous documentation file “luakeys.tex” to luakeys-doc.tex” } -\changes{v0.4}{2021/12/31}{ +\changes{0.4.0}{2021/12/31}{ * Parser: Add support for nested tables (for example {{'a', 'b'}}) * Parser: Allow only strings and numbers as keys * Parser: Remove support from Lua numbers with exponents (for example '5e+20') * Switch the Lua testing framework to busted } -\changes{v0.5}{2022/04/04}{ +\changes{0.5.0}{2022/04/04}{ * Add possibility to change options globally * New option: standalone_as_true * Add a recursive converter callback / hook to process the parse tree * New option: case_insensitive_keys } -\changes{v0.6}{2022/06/09}{ +\changes{0.6.0}{2022/06/09}{ * New feature: keys now can be defined using the function “define(defs, opts)” or “define(kv_string, { defs = { key = { ... } } })” * Rename the global options table from “default_options” to “opts” @@ -1494,6 +1808,14 @@ An example of how to use the command in \LaTeX: produce the previous effect. * The function “print()” is now called “debug()” } +\changes{0.7.0}{2022/07/06}{ +* The project now uses semantic versioning. +* New definition attribute “pick” to pick standalone values and assign + them to a key +* New function “utils.scan_oarg()” to search for an optional argument, + that means scan for tokens that are enclosed in square brackets +* extend and improve documentation +} \pagebreak \PrintChanges \pagebreak diff --git a/macros/luatex/generic/luakeys/luakeys.lua b/macros/luatex/generic/luakeys/luakeys.lua index ae689d02c1..3221fc3efd 100644 --- a/macros/luatex/generic/luakeys/luakeys.lua +++ b/macros/luatex/generic/luakeys/luakeys.lua @@ -36,13 +36,59 @@ if not token then } end +--- Merge two tables in the first specified table. +--- The `merge_tables` function copies all keys from the `source` table +--- to a target table. It returns the modified target table. +--- +---@see https://stackoverflow.com/a/1283608/10193818 +--- +---@param target table +---@param source table +--- +---@return table target The modified target table. +local function merge_tables(target, source) + for key, value in pairs(source) do + if type(value) == 'table' then + if type(target[key] or false) == 'table' then + merge_tables(target[key] or {}, source[key] or {}) + elseif target[key] == nil then + target[key] = value + end + elseif target[key] == nil then + target[key] = value + end + end + return target +end + +---Clone a table. +--- +---@see http://lua-users.org/wiki/CopyTable +--- +---@param orig table +--- +---@return table +local function clone_table(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[clone_table(orig_key)] = clone_table(orig_value) + end + setmetatable(copy, clone_table(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy +end + local utils = { --- Get the size of an array like table `{ 'one', 'two', 'three' }` = 3. - -- - -- @tparam table value A table or any input. - -- - -- @treturn number The size of the array like table. 0 if the input is - -- no table or the table is empty. + --- + ---@param value table # A table or any input. + --- + ---@return number # The size of the array like table. 0 if the input is no table or the table is empty. get_array_size = function(value) local count = 0 if type(value) == 'table' then @@ -53,12 +99,11 @@ local utils = { return count end, - --- Get the size of a table `{ one = 'one', 'two', 'three' }` = 3. - -- - -- @tparam table value A table or any input. - -- - -- @treturn number The size of the array like table. 0 if the input is - -- no table or the table is empty. + ---Get the size of a table `{ one = 'one', 'two', 'three' }` = 3. + --- + ---@param value table|any # A table or any input. + --- + ---@return number # The size of the array like table. 0 if the input is no table or the table is empty. get_table_size = function(value) local count = 0 if type(value) == 'table' then @@ -69,6 +114,10 @@ local utils = { return count end, + merge_tables = merge_tables, + + clone_table = clone_table, + remove_from_array = function(array, element) for index, value in pairs(array) do if element == value then @@ -77,58 +126,95 @@ local utils = { end end end, -} ---- https://stackoverflow.com/a/1283608/10193818 -local function merge_tables(target, t2) - for k, v in pairs(t2) do - if type(v) == 'table' then - if type(target[k] or false) == 'table' then - merge_tables(target[k] or {}, t2[k] or {}) - elseif target[k] == nil then - target[k] = v + ---Scan for an optional argument. + --- + ---@param initial_delimiter? string # The character that marks the beginning of an optional argument (by default `[`). + ---@param end_delimiter? string # The character that marks the end of an optional argument (by default `]`). + --- + ---@return string|nil # The string that was enclosed by the delimiters. The delimiters themselves are not returned. + scan_oarg = function(initial_delimiter, end_delimiter) + if initial_delimiter == nil then + initial_delimiter = '[' + end + + if end_delimiter == nil then + end_delimiter = ']' + end + + local function convert_token(t) + if t.index ~= nil then + return utf8.char(t.index) + else + return '\\' .. t.csname end - elseif target[k] == nil then - target[k] = v end - end - return target -end ---- http://lua-users.org/wiki/CopyTable -local function clone_table(orig) - local orig_type = type(orig) - local copy - if orig_type == 'table' then - copy = {} - for orig_key, orig_value in next, orig, nil do - copy[clone_table(orig_key)] = clone_table(orig_value) + local function get_next_char() + local t = token.get_next() + return convert_token(t), t end - setmetatable(copy, clone_table(getmetatable(orig))) - else -- number, string, boolean, etc - copy = orig - end - return copy -end ---- This table stores all allowed option keys. -local all_options = { - convert_dimensions = false, - debug = false, - default = true, - defaults = false, - defs = false, - format_keys = false, - hooks = {}, - naked_as_value = false, - no_error = false, - postprocess = false, - preprocess = false, - unpack = true, + local char, t = get_next_char() + if char == initial_delimiter then + local oarg = {} + char = get_next_char() + while char ~= end_delimiter do + table.insert(oarg, char) + char = get_next_char() + end + return table.concat(oarg, '') + else + token.put_next(t) + end + end, +} + +local namespace = { + opts = { + convert_dimensions = false, + debug = false, + default = true, + defaults = false, + defs = false, + format_keys = false, + hooks = {}, + naked_as_value = false, + no_error = false, + unpack = true, + }, + + hooks = { + kv_string = true, + keys_before_opts = true, + result_before_opts = true, + keys_before_def = true, + result_before_def = true, + keys = true, + result = true, + }, + + attrs = { + alias = true, + always_present = true, + choices = true, + data_type = true, + default = true, + exclusive_group = true, + l3_tl_set = true, + macro = true, + match = true, + name = true, + opposite_keys = true, + pick = true, + process = true, + required = true, + sub_keys = true, + }, } --- The default options. -local default_options = clone_table(all_options) +local default_options = clone_table(namespace.opts) local function throw_error(message) if type(tex.error) == 'function' then @@ -144,16 +230,15 @@ local l3_code_cctab = 10 -- @section --- The function `render(tbl)` reverses the function --- `parse(kv_string)`. It takes a Lua table and converts this table --- into a key-value string. The resulting string usually has a --- different order as the input table. In Lua only tables with --- 1-based consecutive integer keys (a.k.a. array tables) can be --- parsed in order. --- --- @tparam table result A table to be converted into a key-value string. --- --- @treturn string A key-value string that can be passed to a TeX --- macro. +--- `parse(kv_string)`. It takes a Lua table and converts this table +--- into a key-value string. The resulting string usually has a +--- different order as the input table. In Lua only tables with +--- 1-based consecutive integer keys (a.k.a. array tables) can be +--- parsed in order. +--- +---@param result table # A table to be converted into a key-value string. +--- +---@return string # A key-value string that can be passed to a TeX macro. local function render(result) local function render_inner(result) local output = {} @@ -183,20 +268,19 @@ local function render(result) end --- The function `stringify(tbl, for_tex)` converts a Lua table into a --- printable string. Stringify a table means to convert the table into --- a string. This function is used to realize the `debug` function. --- `stringify(tbl, true)` (`for_tex = true`) generates a string which --- can be embeded into TeX documents. The macro `\luakeysdebug{}` uses --- this option. `stringify(tbl, false)` or `stringify(tbl)` generate a --- string suitable for the terminal. --- --- @tparam table result A table to stringify. --- --- @tparam boolean for_tex Stringify the table into a text string that --- can be embeded inside a TeX document via tex.print(). Curly braces --- and whites spaces are escaped. --- --- https://stackoverflow.com/a/54593224/10193818 +--- printable string. Stringify a table means to convert the table into +--- a string. This function is used to realize the `debug` function. +--- `stringify(tbl, true)` (`for_tex = true`) generates a string which +--- can be embeded into TeX documents. The macro `\luakeysdebug{}` uses +--- this option. `stringify(tbl, false)` or `stringify(tbl)` generate a +--- string suitable for the terminal. +--- +---@see https://stackoverflow.com/a/54593224/10193818 +--- +---@param result table # A table to stringify. +---@param for_tex? boolean # Stringify the table into a text string that can be embeded inside a TeX document via tex.print(). Curly braces and whites spaces are escaped. +--- +---@return string local function stringify(result, for_tex) local line_break, start_bracket, end_bracket, indent @@ -242,7 +326,8 @@ local function stringify(result, for_tex) add(0, stringify_inner(value, depth + 1)) add(depth, end_bracket .. ','); else - add(depth, key .. ' = ' .. start_bracket .. end_bracket .. ',') + add(depth, + key .. ' = ' .. start_bracket .. end_bracket .. ',') end else if (type(value) == 'string') then @@ -259,19 +344,17 @@ local function stringify(result, for_tex) return table.concat(output, line_break) end - return - start_bracket .. line_break .. stringify_inner(result, 1) .. line_break .. - end_bracket + return start_bracket .. line_break .. stringify_inner(result, 1) .. + line_break .. end_bracket end ---- The function `debug(tbl)` pretty prints a Lua table to standard +--- The function `debug(result)` pretty prints a Lua table to standard -- output (stdout). It is a utility function that can be used to -- debug and inspect the resulting Lua table of the function -- `parse`. You have to compile your TeX document in a console to -- see the terminal output. -- --- @tparam table result A table to be printed to standard output for --- debugging purposes. +---@param result table # A table to be printed to standard output for debugging purposes. local function debug(result) print('\n' .. stringify(result, false)) end @@ -280,19 +363,23 @@ end -- @section --- Generate the PEG parser using Lpeg. --- --- Explanations of some LPeg notation forms: --- --- * `patt ^ 0` = `expression *` --- * `patt ^ 1` = `expression +` --- * `patt ^ -1` = `expression ?` --- * `patt1 * patt2` = `expression1 expression2`: Sequence --- * `patt1 + patt2` = `expression1 / expression2`: Ordered choice --- --- * [TUGboat article: Parsing complex data formats in LuaTEX with LPEG](https://tug.org/TUGboat/tb40-2/tb125menke-Patterndf) --- --- @treturn userdata The parser. -local function generate_parser(initial_rule, convert_dimensions) +--- +--- Explanations of some LPeg notation forms: +--- +--- * `patt ^ 0` = `expression *` +--- * `patt ^ 1` = `expression +` +--- * `patt ^ -1` = `expression ?` +--- * `patt1 * patt2` = `expression1 expression2`: Sequence +--- * `patt1 + patt2` = `expression1 / expression2`: Ordered choice +--- +--- * [TUGboat article: Parsing complex data formats in LuaTEX with LPEG](https://tug.or-g/TUGboat/tb40-2/tb125menke-Patterndf) +--- +---@param initial_rule string # The name of the first rule of the grammar table passed to the `lpeg.P(attern)` function (e. g. `list`, `number`). +---@param convert_dimensions? boolean # Whether the dimensions should be converted to scaled points (by default `false`). +--- +---@return userdata # The parser. +local function generate_parser(initial_rule, + convert_dimensions) if convert_dimensions == nil then convert_dimensions = false end @@ -315,7 +402,17 @@ local function generate_parser(initial_rule, convert_dimensions) return white_space ^ 0 * Pattern(match) * white_space ^ 0 end + --- Convert a dimension to an normalized dimension string or an + --- integer in the scaled points format. + --- + ---@param input string + --- + ---@return integer|string # A dimension as an integer or a dimension string. local capture_dimension = function(input) + -- Remove all whitespaces + input = input:gsub('%s+', '') + -- Convert the unit string into lowercase. + input = input:lower() if convert_dimensions then return tex.sp(input) else @@ -325,27 +422,27 @@ local function generate_parser(initial_rule, convert_dimensions) --- Add values to a table in two modes: -- - -- # Key value pair + -- Key-value pair: -- - -- If arg1 and arg2 are not nil, then arg1 is the key and arg2 is the + -- If `arg1` and `arg2` are not nil, then `arg1` is the key and `arg2` is the -- value of a new table entry. -- - -- # Index value + -- Indexed value: -- - -- If arg2 is nil, then arg1 is the value and is added as an indexed + -- If `arg2` is nil, then `arg1` is the value and is added as an indexed -- (by an integer) value. -- - -- @tparam table table - -- @tparam mixed arg1 - -- @tparam mixed arg2 - -- - -- @treturn table - local add_to_table = function(table, arg1, arg2) + ---@param result table # The result table to which an additional key-value pair or value should to be added + ---@param arg1 any # The key or the value. + ---@param arg2? any # Always the value. + --- + ---@return table # The result table to which an additional key-value pair or value has been added. + local add_to_table = function(result, arg1, arg2) if arg2 == nil then - local index = #table + 1 - return rawset(table, index, arg1) + local index = #result + 1 + return rawset(result, index, arg1) else - return rawset(table, arg1, arg2) + return rawset(result, arg1, arg2) end end @@ -438,6 +535,7 @@ local function generate_parser(initial_rule, convert_dimensions) -- 'bp' / 'BP' / 'cc' / etc. -- https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua + -- https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625 unit = Pattern('bp') + Pattern('BP') + Pattern('cc') + Pattern('CC') + @@ -447,10 +545,12 @@ local function generate_parser(initial_rule, convert_dimensions) Pattern('ex') + Pattern('EX') + Pattern('in') + Pattern('IN') + Pattern('mm') + Pattern('MM') + + Pattern('mu') + Pattern('MU') + Pattern('nc') + Pattern('NC') + Pattern('nd') + Pattern('ND') + Pattern('pc') + Pattern('PC') + Pattern('pt') + Pattern('PT') + + Pattern('px') + Pattern('PX') + Pattern('sp') + Pattern('SP'), -- '"' ('\"' / !'"')* '"' @@ -483,7 +583,8 @@ local function visit_tree(tree, callback_func) callback_func) for key, value in pairs(current) do if type(value) == 'table' then - value = visit_tree_recursive(tree, value, {}, depth + 1, callback_func) + value = visit_tree_recursive(tree, value, {}, depth + 1, + callback_func) end key, value = callback_func(key, value, depth, current, tree) @@ -514,7 +615,7 @@ local is = { return true end local parser = generate_parser('boolean_only', false) - local result = parser:match(value) + local result = parser:match(tostring(value)) return result ~= nil end, @@ -523,7 +624,7 @@ local is = { return false end local parser = generate_parser('dimension_only', false) - local result = parser:match(value) + local result = parser:match(tostring(value)) return result ~= nil end, @@ -543,7 +644,7 @@ local is = { return true end local parser = generate_parser('number_only', false) - local result = parser:match(value) + local result = parser:match(tostring(value)) return result ~= nil end, @@ -555,14 +656,13 @@ local is = { --- Apply the key-value-pair definitions (defs) on an input table in a --- recursive fashion. --- ----@param defs table A table containing all definitions. ----@param opts table The parse options table. ----@param input table The current input table. ----@param output table The current output table. ----@param unknown table Always the root unknown table. ----@param key_path table An array of key names leading to the current ----@param input_root table The root input table ---- input and output table. +---@param defs table # A table containing all definitions. +---@param opts table # The parse options table. +---@param input table # The current input table. +---@param output table # The current output table. +---@param unknown table # Always the root unknown table. +---@param key_path table # An array of key names leading to the current +---@param input_root table # The root input table input and output table. local function apply_definitions(defs, opts, input, @@ -583,7 +683,7 @@ local function apply_definitions(defs, return new_key_path end - local function set_default_value(def) + local function get_default_value(def) if def.default ~= nil then return def.default elseif opts ~= nil and opts.default ~= nil then @@ -599,7 +699,7 @@ local function apply_definitions(defs, return value -- naked keys: values with integer keys elseif utils.remove_from_array(input, search_key) ~= nil then - return set_default_value(def) + return get_default_value(def) end end @@ -634,7 +734,7 @@ local function apply_definitions(defs, always_present = function(value, key, def) if value == nil and def.always_present then - return set_default_value(def) + return get_default_value(def) end end, @@ -692,9 +792,10 @@ local function apply_definitions(defs, throw_error('Unknown data type: ' .. def.data_type) end if converted == nil then - throw_error('The value “' .. value .. '” of the key “' .. key .. - '” could not be converted into the data type “' .. - def.data_type .. '”!') + throw_error( + 'The value “' .. value .. '” of the key “' .. key .. + '” could not be converted into the data type “' .. + def.data_type .. '”!') else return converted end @@ -723,7 +824,8 @@ local function apply_definitions(defs, return end if def.l3_tl_set ~= nil then - tex.print(l3_code_cctab, '\\tl_set:Nn \\g_' .. def.l3_tl_set .. '_tl') + tex.print(l3_code_cctab, + '\\tl_set:Nn \\g_' .. def.l3_tl_set .. '_tl') tex.print('{' .. value .. '}') end end, @@ -747,8 +849,9 @@ local function apply_definitions(defs, end local match = string.match(value, def.match) if match == nil then - throw_error('The value “' .. value .. '” of the key “' .. key .. - '” does not match “' .. def.match .. '”!') + throw_error( + 'The value “' .. value .. '” of the key “' .. key .. + '” does not match “' .. def.match .. '”!') else return match end @@ -780,6 +883,41 @@ local function apply_definitions(defs, end end, + pick = function(value, key, def) + if def.pick then + if type(def.pick) == 'string' and is[def.pick] == nil then + throw_error( + 'Wrong setting. Allowed settings for the attribute “def.pick” are: true, boolean, dimension, integer, number, string. Got “' .. + tostring(def.pick) .. '”.') + end + + if value ~= nil then + return value + end + for i, v in pairs(input) do + -- We can not use ipairs here. `ipairs(t)` iterates up to the + -- first absent index. Values are deleted from the `input` + -- table. + if type(i) == 'number' then + local picked_value = nil + -- Pick a value by type: boolean, dimension, integer, number, string + if is[def.pick] ~= nil then + if is[def.pick](v) then + picked_value = v + end + -- Pick every value + elseif v ~= nil then + picked_value = v + end + if picked_value ~= nil then + input[i] = nil + return picked_value + end + end + end + end + end, + required = function(value, key, def) if def.required ~= nil and def.required and value == nil then throw_error(string.format('Missing required key “%s”!', key)) @@ -797,8 +935,8 @@ local function apply_definitions(defs, elseif type(value) == 'table' then v = value end - v = apply_definitions(def.sub_keys, opts, v, output[key], unknown, - add_to_key_path(key_path, key), input_root) + v = apply_definitions(def.sub_keys, opts, v, output[key], + unknown, add_to_key_path(key_path, key), input_root) if utils.get_table_size(v) > 0 then return v end @@ -821,23 +959,33 @@ local function apply_definitions(defs, end for index, def in pairs(defs) do - --- Find key and def + -- Find key and def local key - if type(def) == 'table' and def.name == nil and type(index) == 'string' then + -- `{ key1 = { }, key2 = { } }` + if type(def) == 'table' and def.name == nil and type(index) == + 'string' then key = index + -- `{ { name = 'key1' }, { name = 'key2' } }` elseif type(def) == 'table' and def.name ~= nil then key = def.name + -- Definitions as strings in an array: `{ 'key1', 'key2' }` elseif type(index) == 'number' and type(def) == 'string' then key = def - def = { default = true } + def = { default = get_default_value({}) } end if type(def) ~= 'table' then - throw_error('Key definition must be a table') + throw_error('Key definition must be a table!') + end + + for attr, _ in pairs(def) do + if namespace.attrs[attr] == nil then + throw_error('Unknown definition attribute: ' .. tostring(attr)) + end end if key == nil then - throw_error('key name couldn’t be detected!') + throw_error('Key name couldn’t be detected!') end local value = find_value(key, def) @@ -845,6 +993,7 @@ local function apply_definitions(defs, for _, def_opt in ipairs({ 'alias', 'opposite_keys', + 'pick', 'always_present', 'required', 'data_type', @@ -888,14 +1037,14 @@ end --- Parse a LaTeX/TeX style key-value string into a Lua table. --- ----@param kv_string string A string in the TeX/LaTeX style key-value format as described above. ----@param opts table A table containing the settings: +---@param kv_string string # A string in the TeX/LaTeX style key-value format as described above. +---@param opts table # A table containing the settings: --- `convert_dimensions`, `unpack`, `naked_as_value`, `converter`, --- `debug`, `preprocess`, `postprocess`. -- ----@return table result The final result of all individual parsing and normalization steps. ----@return table unknown A table with unknown, undefinied key-value pairs. ----@return table raw The unprocessed, raw result of the LPeg parser. +---@return table result # The final result of all individual parsing and normalization steps. +---@return table unknown # A table with unknown, undefinied key-value pairs. +---@return table raw # The unprocessed, raw result of the LPeg parser. local function parse(kv_string, opts) if kv_string == nil then return {} @@ -903,21 +1052,21 @@ local function parse(kv_string, opts) --- Normalize the parse options. --- - --- @param opts table Options in a raw format. The table may be empty or some keys are not set. + ---@param opts table # Options in a raw format. The table may be empty or some keys are not set. --- - --- @return table + ---@return table local function normalize_opts(opts) if type(opts) ~= 'table' then opts = {} end for key, _ in pairs(opts) do - if all_options[key] == nil then + if namespace.opts[key] == nil then throw_error('Unknown parse option: ' .. tostring(key) .. '!') end end local old_opts = opts opts = {} - for name, _ in pairs(all_options) do + for name, _ in pairs(namespace.opts) do if old_opts[name] ~= nil then opts[name] = old_opts[name] else @@ -925,18 +1074,8 @@ local function parse(kv_string, opts) end end - local hooks = { - kv_string = true, - keys_before_opts = true, - result_before_opts = true, - keys_before_def = true, - result_before_def = true, - keys = true, - result = true, - } - for hook in pairs(opts.hooks) do - if hooks[hook] == nil then + if namespace.hooks[hook] == nil then throw_error('Unknown hook: ' .. tostring(hook) .. '!') end end @@ -983,8 +1122,8 @@ local function parse(kv_string, opts) -- tasks are performed on the raw input table coming directly from -- the PEG parser: -- - --- @param result table The raw input table coming directly from the PEG parser - --- @param opts table Some options. + ---@param result table # The raw input table coming directly from the PEG parser + ---@param opts table # Some options. local function apply_opts(result, opts) local callbacks = { unpack = function(key, value) @@ -1012,7 +1151,8 @@ local function parse(kv_string, opts) elseif style == 'upper' then key = key:upper() else - throw_error('Unknown style to format keys: ' .. tostring(style) .. + throw_error('Unknown style to format keys: ' .. + tostring(style) .. ' Allowed styles are: lower, snake, upper') end end @@ -1031,8 +1171,9 @@ local function parse(kv_string, opts) if opts.format_keys then if type(opts.format_keys) ~= 'table' then - throw_error('The option “format_keys” has to be a table not ' .. - type(opts.format_keys)) + throw_error( + 'The option “format_keys” has to be a table not ' .. + type(opts.format_keys)) end result = visit_tree(result, callbacks.format_key) end @@ -1045,8 +1186,8 @@ local function parse(kv_string, opts) local unknown = nil if type(opts.defs) == 'table' then apply_hooks('before_defs') - result, unknown = apply_definitions(opts.defs, opts, result, {}, {}, {}, - clone_table(result)) + result, unknown = apply_definitions(opts.defs, opts, result, {}, {}, + {}, clone_table(result)) end apply_hooks() @@ -1077,6 +1218,26 @@ local result_store = {} -- @section local export = { + version = { 0, 7, 0 }, + + namespace = namespace, + + ---This function is used in the documentation. + --- + ---@param from string # A key in the namespace table, either `opts`, `hook` or `attrs`. + print_names = function(from) + local names = {} + for name in pairs(namespace[from]) do + table.insert(names, name) + end + table.sort(names) + tex.print(table.concat(names, ', ')) + end, + + print_default = function(from, name) + tex.print(tostring(namespace[from][name])) + end, + --- @see default_options opts = default_options, @@ -1089,7 +1250,10 @@ local export = { define = function(defs, opts) return function(kv_string, inner_opts) local options - if inner_opts ~= nil then + + if inner_opts ~= nil and opts ~= nil then + options = merge_tables(opts, inner_opts) + elseif inner_opts ~= nil then options = inner_opts elseif opts ~= nil then options = opts @@ -1116,11 +1280,9 @@ local export = { -- Therefore, it is not necessary to pollute the global namespace to -- store results for the later usage. -- - -- @tparam string identifier The identifier under which the result is - -- saved. + ---@param identifier string # The identifier under which the result is saved. -- - -- @tparam table result A result to be stored and that was created by - -- the key-value parser. + ---@param result table # A result to be stored and that was created by the key-value parser. save = function(identifier, result) result_store[identifier] = result end, @@ -1128,8 +1290,9 @@ local export = { --- The function `get(identifier): table` retrieves a saved result -- from the result store. -- - -- @tparam string identifier The identifier under which the result was - -- saved. + ---@param identifier string # The identifier under which the result was saved. + --- + ---@return table get = function(identifier) -- if result_store[identifier] == nil then -- throw_error('No stored result was found for the identifier \'' .. identifier .. '\'') @@ -1138,6 +1301,8 @@ local export = { end, is = is, + + utils = utils, } return export diff --git a/macros/luatex/generic/luakeys/luakeys.sty b/macros/luatex/generic/luakeys/luakeys.sty index 51e2c9bec5..d0917f1d9d 100644 --- a/macros/luatex/generic/luakeys/luakeys.sty +++ b/macros/luatex/generic/luakeys/luakeys.sty @@ -17,5 +17,5 @@ % luakeys-debug.sty and luakeys-debug.tex. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{luakeys}[2022/06/09 v0.6 Parsing key-value options using Lua.] +\ProvidesPackage{luakeys}[2022/07/06 0.7.0 Parsing key-value options using Lua.] \directlua{luakeys = require('luakeys')} |