diff options
author | Karl Berry <karl@freefriends.org> | 2023-02-28 20:58:46 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-02-28 20:58:46 +0000 |
commit | d81371e938b8b6a457f8d18dba05988cb76aea14 (patch) | |
tree | 2f2150f0414f5c349be3ee28a0047682488db548 /Master/texmf-dist/source/latex/fistrum/fistrum.dtx | |
parent | 5bb5421117595253f49df10c66cabffa61f8c4f2 (diff) |
fistrum (28feb23)
git-svn-id: svn://tug.org/texlive/trunk@66258 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/fistrum/fistrum.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/fistrum/fistrum.dtx | 1484 |
1 files changed, 1484 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/fistrum/fistrum.dtx b/Master/texmf-dist/source/latex/fistrum/fistrum.dtx new file mode 100644 index 00000000000..189bb3c6362 --- /dev/null +++ b/Master/texmf-dist/source/latex/fistrum/fistrum.dtx @@ -0,0 +1,1484 @@ +% \iffalse meta-comment +% +% This file is part of the package fistrum for use with LaTeX2e. +% +% Function: Access to 150 paragraphs of the well known Lorem Ipsum dummy text. +% +% This program may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% Please send error reports and suggestions for improvements to +% https://github.com/daviddavo/fistrum +% +\def\fistrumversion{0.1} +\def\fistrumdate{2023-02-28} +%<*driver> +\ProvidesFile{fistrum.dtx}% + [\fistrumdate\space v\fistrumversion\space + Por la gloria de mi madre, ese pedazo de texto de ejemplo.] +\documentclass{l3doc} +\usepackage{xcolor} +\usepackage{booktabs} +\usepackage{tabularx} +\usepackage{enumitem} +\usepackage{tikz} +\usetikzlibrary{positioning} +\usepackage[a4paper, + top=2cm, left=8.8cm, right=2cm, bottom=3cm, + marginparwidth=6.3cm, marginparsep=.5cm, +]{geometry} +\newlength\fullmargin +\setlength\fullmargin\marginparwidth +\addtolength\fullmargin\marginparsep +\usepackage{mdframed} +\mdfdefinestyle{expl}{% + backgroundcolor=black!5!white, + linewidth=0pt, + middlelinewidth=0pt +} +\newmdenv[style=expl]{explbox} + +\usepackage{fistrum,multicol} +\usepackage{multirow} +\usepackage[latin, spanish, es-noshorthands]{babel} +\usepackage[useregional]{datetime2} +\makeatletter +\newcommand\@subtitle{} +\newcommand\subtitle[1]{% + \renewcommand\@subtitle{#1}} + \renewcommand\maketitle[1]{% + \noindent + \hspace{-\fullmargin}% + \begin{minipage}{\textwidth+\fullmargin} + \renewcommand\thefootnote{\fnsymbol{footnote}} + \let\thanks\footnote + { + \centering + {\LARGE \@title}\\[.8\baselineskip] + {\LARGE \@subtitle}\\[2\baselineskip] + {\Large \@author}\\[\baselineskip] + {\Large \@date}\\[\baselineskip] + } + \ifx\\#1\\\else + \begin{multicols}{2}[% + \subsection*{\hfill\abstractname\hfill\null}] + \setlength{\columnsep}{.5cm}% + #1 + \end{multicols} + \fi + \end{minipage}} +\makeatother +\newenvironment{wide} + {\hspace{-.75\fullmargin}% + \begin{minipage}{\textwidth+.75\fullmargin}} + {\end{minipage}} +\newcommand\opt[1]{\textsf{#1}} % l3doc does not have some markup for package options... +\newcommand\fist{\emph{Lorem fistrum\ldots}} +\renewcommand\topfraction{.85} +\renewcommand\textfraction{.15} +\renewcommand\floatpagefraction{.85} +\emergencystretch 2em +\newcommand\secref[1]{(see section~\ref{#1})} +\usepackage{hyperref} +\def\ghissue#1{% + \texttt{\##1}\footnote{% + \url{https://github.com/daviddavo/fistrum/issues/#1}}} +\begin{document} + \DocInput{fistrum.dtx} +\end{document} +%</driver> +%<*package> +\NeedsTeXFormat{LaTeX2e} +\RequirePackage{l3keys2e} +\@ifundefined{NewDocumentCommand} + {\RequirePackage{xparse}}{} +\ProvidesExplPackage {fistrum} {\fistrumdate} {\fistrumversion} + {150 paragraphs of Lorem Fistrum dummy text} +%</package> +% \fi +% +% \title{\pkg{fistrum}} +% \subtitle{Access to 150 paragraphs of Lorem Fistrum very dummy +% text\thanks{Version: \fistrumversion}^^A +% \thanks{Basado en \href{https://chiquitoipsum.com}{Chiquito Ipsum} de +% Isabel Nieto, Carlos A. Hernández y Gauss Multimedia}. +% } +% \author{David Davó\thanks{david@ddavo.me}} +% \date{\DTMdate{2023-02-28}} +% \RecordChanges +% \changes{v0.1}{Feb 2023}{First release} +% \maketitle{\pkg{fistrum} es un paquete de \LaTeX{} derivado de \pkg{lipsum} que produce texto de ejemplo +% para usarlo en documentos y ejemplos. Los párrafos se han tomado con permiso de +% \url{https://www.chiquitoipsum.com/}. +% +% Por favor, si encuentras un bug, alguna errata o tienes alguna sugerencia +% abre un \textit{issue} en +% \url{https://github.com/daviddavo/fistrum}.} +% +% \begin{documentation} +% +% \section{Al ataquerl} +% +% \textbf{Nota: La documentación es una copia de la de lipsum, pueden haber quedado erratas} +% +% To load the package, write +% \begin{verbatim} +% \usepackage{fistrum} +% \end{verbatim} +% in the preamble of your document. Probably the most important macro +% provided by this package is \DescribeMacro{\fistrum}\cs{fistrum}, which +% typesets the \emph{Lorem fistrum} paragraphs. The first optional +% argument allows to specify the range of the paragraphs. For example, +% \verb|\fistrum[4-57]| typesets the paragraphs 4 to 57 and accordingly, +% \verb|\fistrum[23]| typesets the 23\textsuperscript{rd} paragraph. +% Using \cs{fistrum} without its optional argument typesets the +% paragraphs 1--7 of \fist +% +% As of version 2.0, \cs{fistrum} has a second optional argument which allows +% selecting a range of sentences from the paragraphs. To get the sentences +% four to eight from paragraphs three to nine, use |\fistrum[3-9][4-8]|. +% The sentences are counted from the first sentence of the first selected +% paragraph. In the previous example, sentence number~1 is the first +% sentence of paragraph number~3. +% +% \section{Usage} +% +% \pkg{fistrum} was intended to quickly provide a way to fill a page or two to +% analyze the page +% layout\footnote{\url{https://groups.google.com/d/topic/de.comp.text.tex/oPeLOjkrLfk}}. +% While it has grown in the meanwhile and now provides some more advanced +% features, it still is only intended to quickly provide text. If you want more +% features, look at the \pkg{blindtext}-package. +% +% \subsection{Package Options} +% \label{sec:pkg-opt} +% +% \pkg{fistrum} outputs a range of paragraphs taken from the \fist\ dummy +% text. The package options control mainly the behaviour of the +% \cs{fistrum} and \cs{unpackfistrum} commands, and can be set at +% load-time with \cs{usepackage}|[|\meta{option}|]{fistrum}|, or later in +% the document by using \cs{setfistrum}|{|\meta{option}|}|. +% +% \begingroup +% \RenewDocumentCommand \item { r[] e= d() } +% {\par\medskip\noindent\llap +% {\smash{\begin{tabular}{@{}l@{}}\toprule +% \opt{#1}\\\bottomrule\end{tabular}}~~}%^^A +% \IfValueT{#2}{=~~\!\meta{#2}\hfill +% \IfValueT{#3}{\quad(default: \texttt{#3})}\null +% \newline}\ignorespaces} +% +% \item[nopar]={boolean}(false) +% Changes the initial default separator between each paragraph of +% \cs{fistrum} from \cs{par} to \cs{space}, and the other way around +% for \cs{fistrum*}. +% \item[text]={name}(fistrum-es) +% Selects the dummy text \meta{name} that is used by \cs{fistrum} and +% \cs{unpackfistrum} \secref{sec:other-texts}. +% \item[language]={lang}(latin) +% Sets the language to be used by \cs{fistrum} to typeset the currently +% active dummy text \secref{sec:hyphenation}. Changing the dummy text +% with the \opt{text} option will also change the current +% \opt{language}. +% \item[auto-lang]={boolean}(true) +% Turns on/off automatic language switching. This changed since +% version 2.3, in which this option (didn't exist thus) was |false| by +% default. See section~\ref{sec:hyphenation} for more details. +% \item[default-range]={p_i\texttt{-}p_f}(1-7) +% Sets the default range of paragraphs produced by \cs{fistrum} when no +% optional argument is provided. The value to \opt{default-range} +% obeys the \meta{range} syntax described in +% section~\ref{sec:range-syntax}. If no value is given to +% \opt{default-range} (that is, \cs{setfistrum}|{default-range}|), then +% the default is reset to |1-7|. +% +% \endgroup +% +% \medskip +% +% Besides these options, there are still ones that can be passed to the +% package to influence the paragraph and sentence separators and other +% such things. These options are detailed in +% section~\ref{sec:separators}. +% +%^^A Besides the listed options, there are still options that can be +%^^A passed to the package to influence the paragraph and sentence +%^^A separators and other things like that. The options for paragraphs +%^^A are: +%^^A \AddToHookNext{env/multicols/before} +%^^A {\setlength{\multicolsep}{0.5\multicolsep}} +%^^A \begin{multicols}{2} +%^^A \ttfamily \setlist{nosep} +%^^A \begin{itemize} +%^^A \item par-before +%^^A \item par-begin +%^^A \item par-sep +%^^A \item par-end +%^^A \item par-after +%^^A \end{itemize} +%^^A \begin{itemize} +%^^A \item par-before* +%^^A \item par-begin* +%^^A \item par-sep* +%^^A \item par-end* +%^^A \item par-after* +%^^A \end{itemize} +%^^A \end{multicols} +%^^A and for sentences, the same group with |sentence| instead of |par| +%^^A in their name. These options are detailed in +%^^A section~\ref{sec:separators}. +% +% \subsection{User Commands} +% +% \begin{function}{\fistrum} +% \begin{syntax} +% \cs{fistrum}\meta{*}\oarg{par range}\oarg{sentence range} +% \end{syntax} +% \cs{fistrum} outputs the \meta{par range} from the +% currently active dummy text. If \meta{par range} is not given +% or is empty, the \opt{default-range} (initially |1-7|) is output. +% ^^A +% If a \meta{sentence range} is given, the selected paragraphs are +% split into sentences, numbered starting from~1, and the specified +% range of sentences is taken out from those paragraphs. +% ^^A +% If the \meta{*} version is used, a different set of separators is +% inserted around the paragraphs or sentences. +% +% \cs{fistrum} changes the active language to that of the dummy text +% for typesetting, so the proper hyphenation patterns are used. +% See section~\ref{sec:hyphenation}. +% ^^A +% Section~\ref{sec:range-syntax} explains the syntax of ranges, and +% section~\ref{sec:separators} explains the separators added around +% the pieces of text. +% \end{function} +% +% \begin{function}{\unpackfistrum,\fistrumexp} +% \begin{syntax} +% \cs{unpackfistrum}\meta{*}\oarg{par range}\oarg{sentence range} +% \ldots +% \cs{fistrumexp} +% \end{syntax} +% \cs{unpackfistrum} selects the paragraphs and/or sentences exactly as +% described for \cs{fistrum}, but instead of outputting them, it saves +% the selected text in the \cs{fistrumexp} macro. Additionally, +% \cs{unpackfistrum} \ldots\cs{fistrumexp} is not completely equivalent +% to \cs{fistrum} because it doesn't change languages as \cs{fistrum} +% does. +% \end{function} +% +% \begin{function}{\setfistrum} +% \begin{syntax} +% \cs{setfistrum}\Arg{key-val list} +% \end{syntax} +% Applies the \meta{key-val list} of options to the package. The +% options are described in section~\ref{sec:pkg-opt} and in +% section~\ref{sec:separators}. +% \end{function} +% +% \subsection{Other commands} +% +% These commands exist for necessity or backwards comatibility, and +% should normally not be needed in user documents. +% +% \begin{function}{\SetFistrumText} +% \begin{syntax} +% \cs{SetFistrumDefault}\Arg{name} +% \end{syntax} +% Loads the dummy text \meta{name} \secref{sec:other-texts}. +% This command does the same as option \opt{text}, but it is +% kept for backwards compatibility. +% \end{function} +% +% \begin{function}{\SetFistrumDefault} +% \begin{syntax} +% \cs{SetFistrumDefault}\Arg{range} +% \end{syntax} +% Sets the default range for \cs{fistrum} and \cs{unpackfistrum}. +% This command does the same as option \opt{default-range}, but it is +% kept for backwards compatibility. +% \end{function} +% +% \section{General remarks on behaviour} +% +% Here are some topics that are general considerations about the +% behaviour of \pkg{fistrum} and its commands. These are technicalities +% that most end users don't care too much about, unless you are trying +% to do something beyond the usual ``print me some dummy text''. +% +% \subsection{Syntax of paragraph and sentence ranges} +% \label{sec:range-syntax} +% +% A \meta{range} argument can either be blank, a single integer, or a +% proper integer range. If the \meta{range} argument is blank, the +% commands behave as if the argument was not given at all. For example, +% |\fistrum[]| behaves exaclty like |\fistrum| and outputs the default +% paragraph range. Note that |\fistrum[][2-5]| does \textbf{not} behave +% as |\fistrum[2-5]|, but behaves as |\fistrum[1-7][2-5]| (assuming +% |default=range=1-7|), because the default value is then taken for the +% first argument. If the \meta{range} argument is an integer, then only +% a single paragraph/sentence is selected. +% +% If the argument contains a |-| (\textsc{ascii}~45), it is interpreted +% as a \emph{proper} range \meta{n_i}|-|\meta{n_f}. In a proper range, +% if \meta{n_i} is blank, it is taken to be the start of the possible +% range, and in the same way, if \meta{n_f} is empty it is taken to be +% the end of the possible range. That is, |\fistrum[-9]| is the same as +% |\fistrum[1-9]|, and |\fistrum[5-]| is the same (assuming the standard +% 150-paragraph dummy text) as |\fistrum[5-150]|, and similarly, +% |\fistrum[-]| is the same as |\fistrum[1-150]|. +% +% Only one |-| is allowed in a range, so if more than one |-| is given, +% an error is raised and no paragraphs/sentences are output. No +% paragraphs or sentences will be output also in case one of the ranges +% is reversed, so |\fistrum[2-1]| returns no paragraphs, as does +% |\fistrum[][2-1]| output no sentences, for example. Note that +% ``returning no paragraphs/sentences'' is not ``the output is empty'': +% that is mostly true, except that the |-before| and |-after| separators +% are still output \secref{sec:separators}. +% +% Finally, if a range spans more paragraphs or sentences than what the +% dummy text actually provides, the range is truncated so that it fits +% the available text. If the range in the argument does not intersect +% with the range provided by the dummy text, no paragraphs or sentences +% are output. +% +% \subsection{Hyphenation patterns} +% \label{sec:hyphenation} +% +% Since version~2.4, the command \cs{fistrum} automatically changes the +% hyphenation patterns when typesetting a dummy text, so that +% line-breaking looks better \secref{sec:foreword2.4}. This feature is +% on by default, so if you need the old behaviour you have to explicitly +% disable automatic language switching with +% |\setfistrum{auto-lang=false}|. +% +% The language is defined individually for each dummy text +% \secref{sec:other-texts}, but you may change it for the current dummy +% text by using |\setfistrum{language=|\meta{lang}|}|. If you load +% another dummy text (for example with the \opt{text} option), then the +% option \opt{language} is also changed according to the dummy text +% loaded \secref{sec:other-texts}. +% +% \subsection{Paragraph and sentence separators} +% \label{sec:separators} +% +% As may be clear by now, \pkg{fistrum} has two modes of operation: +% sentence output, and paragraph output, selected by providing or not +% providing the second optional argument to \cs{fistrum}. In each mode, +% the dummy text is separated into chunks (paragraphs or sentences), +% which are counted, and then output accordingly. +% +% When \cs{fistrum} (or \cs{unpackfistrum}) is used with a single (or no) +% optional argument, then a range of paragraphs is output, along with +% some ``separators'' (in the lack of a better name) between paragraphs, +% around each paragraph, and before and after the whole output. +% A schematic (very colorful, because I couldn't find a better visual) +% representation of the output is: +% +% \begin{function}{ +% par-before, +% par-begin, +% par-sep, +% par-end, +% par-after, +% sentence-before, +% sentence-begin, +% sentence-sep, +% sentence-end, +% sentence-after, +% } +% \noindent +% \begin{tikzpicture}[x=0.703cm, +% item/.style={ +% draw, +% rounded corners=2mm, +% minimum width=2.2cm, +% execute at begin node=\strut, +% rotate=54, +% font=\footnotesize, +% }, +% ] +% \def\sep#1{\texttt{par-\textbf{#1}}\null} +% \node [item,fill=red!40 ] at (0 ,0) {\sep{before}}; +% \node [item,fill=red!20 ] at (1 ,0) {\sep{begin }}; +% \node [item,fill=red!20 ] at (2 ,0) {\meta{paragraph}}; +% \node [item,fill=red!20 ] at (3 ,0) {\sep{end \ }}; +% \node [item,shading=axis,left color=red!30,right color=green!30, +% shading angle=54] at (4 ,0) {\sep{sep \ }}; +% \node [item,fill=green!20] at (5 ,0) {\sep{begin }}; +% \node [item,fill=green!20] at (6 ,0) {\meta{paragraph}}; +% \node [item,fill=green!20] at (7 ,0) {\sep{end \ }}; +% \node [item,shading=axis,left color=green!30,right color=blue!30, +% shading angle=54] at (8 ,0) {\sep{sep \ }}; +% \node [item,fill=blue!20 ] at (9 ,0) {\sep{begin }}; +% \node [item,fill=blue!20 ] at (10,0) {\meta{paragraph}}; +% \node [item,fill=blue!20 ] at (11,0) {\sep{end \ }}; +% \node [item,fill=blue!40 ] at (12,0) {\sep{after\ }}; +% \end{tikzpicture} +% +% When \cs{fistrum} is called, the first thing it outputs is the +% \opt{par-before} tokens. These tokens are output unconditionally, +% regardless of how many (if any) paragraph is output. +% +% Then, before each paragraph in the range, \cs{fistrum} outputs the +% \opt{par-begin} tokens, and then the actual text of the +% \meta{paragraph}, and then the \opt{par-end} tokens. These tokens are +% output conditionally, if the paragraph text is output. If more than +% one paragraph is output, then the \opt{par-sep} tokens are inserted +% between the \opt{par-end} of one paragraph and the \opt{par-begin} of +% the paragraph that follows. +% +% \end{function} +% +% Finally, at the end, the \opt{par-after} tokens are inserted +% unconditionally at the end, same as for \opt{par-before}. +% +% As mentioned before, in case of an error parsing the range, the output +% will be no paragraphs, but the \opt{par-before} and \opt{par-after} +% tokens are still output. +% +% The explanation above is equally valid for the starred variants. If +% \cs{fistrum}|*| is used, the \opt{par-before*} tokens are +% inserted, and so on. It is also true for sentences (starred or +% otherwise), replacing |par| in the option names by |sentence|, so when +% you use, for example, |\fistrum[][1-9]|, the \opt{sentence-before} +% tokens will be unconditionally inserted, and so on. +% +% Note that, when \cs{fistrum} is used in sentence-mode (for example, +% with |\fistrum[1-3][1-9]|), only the |sentence-...| tokens are inserted +% in the output, regardless of how many paragraphs those sentences were +% collected from. In the same way, if paragraph-mode is being used, only +% |par-...| tokens are inserted. +% +% \subsubsection{Deprecated command-based syntax} +% +% Older versions of \pkg{fistrum} (from 2.0 to 2.3) provided~10 CamelCase +% commands for changing the separators, but the syntax was rather +% cumbersome to use, so the keyval syntax presented thus far was +% introduced in the hopes of making things a bit easier. The old +% commands will still exist for some time in the package, but with a +% deprecation warning. Changing to the keyval syntax is advised, so +% here is a correspondence table between the old and new syntaxes: +% +% \begin{center} +% \ttfamily \makeatletter +% \definecolor{a}{HTML}{E0211A}\colorlet{a}{a!60!black} +% \definecolor{b}{HTML}{5970D5}\colorlet{b}{b!60!black} +% \protected@edef\x#1#2{\string\SetFistrum +% {\color{a}#1}List{\color{b}#2}}% +% \def\y#1#2{{\color{a}#1}-{\color{b}#2}} +% \begin{tabular}{@{}ll@{}} +% \toprule +% \textrm{Old command} & \textrm{New key name} \\ +% \midrule +% \x{Par}{Start} & \y{par}{before} \\ +% \x{Par}{ItemStart} & \y{par}{begin} \\ +% \x{Par}{ItemSeparator} & \y{par}{sep} \\ +% \x{Par}{ItemEnd} & \y{par}{end} \\ +% \x{Par}{End} & \y{par}{after} \\ +% \x{Sentence}{Start} & \y{sentence}{before} \\ +% \x{Sentence}{ItemStart} & \y{sentence}{begin} \\ +% \x{Sentence}{ItemSeparator} & \y{sentence}{sep} \\ +% \x{Sentence}{ItemEnd} & \y{sentence}{end} \\ +% \x{Sentence}{End} & \y{sentence}{after} \\ +% \bottomrule +% \end{tabular} +% \end{center} +% +% Additionally, the command-based interface provided shortcuts +% |\SetFistrum|\meta{Thing}|List|(|Item|)|Surrounders|, which are +% equivalent to just using the commands +% |\SetFistrum|\meta{Thing}|List|(|Item|)|Start| then |\...End|. These +% don't provide any functionality, other than requiring a little less +% typing, so no key-val alternative was implemented. +% The |\...|\meta{Thing}|...Surrounders| commands should be replaced by +% \meta{thing}|-before| and \meta{thing}|-after|, and the +% |\...|\meta{Thing}|...ItemSurrounders| commands should be replaced by +% \meta{thing}|-begin| and \meta{thing}|-end|, as in the correspondence +% table below: +% +% \begin{center} +% \ttfamily \makeatletter +% \definecolor{a}{HTML}{E0211A}\colorlet{a}{a!60!black} +% \definecolor{b}{HTML}{5970D5}\colorlet{b}{b!60!black} +% \protected@edef\x#1#2{\string\SetFistrum +% {\color{a}#1}List{\color{b}#2}Surrounders%^^A +% \kern .5\tabcolsep \xleaders\hbox{\vrule +% width 2pt height \dimexpr .5ex+.4pt\relax depth -.5ex +% \kern 2pt}% +% \hskip 0pt plus 1filll \kern -.5\tabcolsep +% \raise.5ex\rlap{\kern.5\tabcolsep +% \vrule width \tabcolsep height 0.4pt depth 0pt +% \kern-0.5\tabcolsep +% \smash{\vrule depth \normalbaselineskip width 0.4pt +% \raise-\normalbaselineskip +% \hbox{\vrule width .5\tabcolsep height 0.4pt depth 0pt}}}}% +% \def\y#1#2{{\color{a}#1}-{\color{b}#2}} +% \begin{tabular}{@{}ll@{}} +% \toprule +% \textrm{Old command} & \textrm{New key names} \\ +% \midrule +% \x{Par}{} & \y{par}{}before \\ +% & \y{par}{}after \\ +% \x{Par}{Item} & \y{par}{begin} \\ +% & \y{par}{end} \\ +% \x{Sentence}{} & \y{sentence}{}before \\ +% & \y{sentence}{}after \\ +% \x{Sentence}{Item} & \y{sentence}{begin} \\ +% & \y{sentence}{end} \\ +% \bottomrule +% \end{tabular} +% \end{center} +% +% \section{Loading and defining dummy texts} +% \label{sec:other-texts} +% +% Starting with \pkg{fistrum} v2.2, a simple interface is provided to +% define and load other texts for the output of \cs{fistrum} and friends. +% This interface can, for example, be used to implement dummy texts in +% different languages without re-coding the logic implemented by +% \pkg{fistrum}. +% +% \begin{function}{\NewFistrumPar} +% \begin{syntax} +% \cs{NewFistrumPar}\Arg{paragraph} +% \end{syntax} +% In order to provide a new text that will be used by \pkg{fistrum}, +% define the text by using a set of \cs{NewFistrumPar}\Arg{paragraph} +% commands in a file with the ending |.ftd.tex| (|ftd| means +% \emph{fistrum text definition}\footnotemark{}) to a location where +% your \TeX{} system will find it. The \meta{paragraph}-argument is a +% single paragraph of the new text. Thus, the first occurence of +% \cs{NewFistrumPar} defines the first paragraph, the second occurence +% the second paragraph and so on. +% \end{function} +% \footnotetext{To avoid name clashes with files using general languages +% as names, I chose to introduce the |.ftd.tex| file ending. I did not +% find a file with this ending in my |texmf|-tree, so I guess it is +% safe.} +% +% \begin{function}{\SetFistrumLanguage} +% \begin{syntax} +% \cs{SetFistrumLanguage}\Arg{lang} +% \end{syntax} +% Additionally, tell \pkg{fistrum} the language of the dummy text using +% \cs{SetFistrumLanguage}\Arg{lang} somewhere in the |.ftd.tex| file. +% \end{function} +% +% \medskip +% +% To specify the new text as output for \cs{fistrum} and friends, use +% \cs{setfistrum}|{|\opt{text}|=|\meta{name}|}|, where \meta{name} is the +% name of the file without the ending |.ftd.tex|, as given in the table +% below. When a new dummy text is loaded, the previous one is cleared, +% and the language is changed as well, according to the table. +% +% \begin{table}[ht] +% \begin{wide} +% \begin{tabularx}{\textwidth}{lllX} +% \toprule +% File (\texttt{.ftd.tex}) & Language & Source & Description \\ +% \midrule +% \texttt{fistrum-la} & Latin +% & Chiquito +% & Contiene el texto \emph{Lorem fistrum} tras seleccionar la opción +% latín en \url{https://www.chiquitoipsum.com/}. \\ +% \texttt{fistrum-es} & Spanish +% & Chiquito +% & Contiene el texto \emph{Lorem fistrum} tras seleccionar la opción +% fistrum en \url{https://www.chiquitoipsum.com/}. \\ +% \bottomrule +% \end{tabularx} +% \end{wide} +% \end{table} +% +% \subsection{Guidelines on providing new dummy texts} +% +% \cs{SetFistrumText} more or less just uses an \cs{input} or, to be more +% precise, the \LaTeX3-variant \cs{file_input:n}, to load the |.ftd.tex| +% file. This means, that the file is not necessarily loaded in the +% preamble of the document and thus the contents of the file underlie +% the respective restrictions. +% +% Should you want a new dummy text, create an issue in the GitHub +% repository\footnote{\url{https://github.com/daviddavo/fistrum}} +% with the source for the dummy text. +% +% Should you prefer to distribute the dummy text as a separate package, +% make sure that the text follows the layout of \pkg{fistrum}'s dummy +% texts, so that everything works correctly. The dummy text definition +% file should contain a line with \cs{SetFistrumLanguage}, and then as +% many \cs{NewFistrumPar} entries as there are paragraphs in the dummy +% text. Make sure that the file has the |.ftd.tex| extension, and +% everything should work smoothly. +% +% \end{documentation} +% +% \clearpage +% \newgeometry{left=5cm,right=2cm} +% +% \begin{implementation} +% +% \section{\pkg{fistrum} Implementation} +% +% \begin{macrocode} +%<*package> +%<@@=fistrum> +% \end{macrocode} +% +% \subsection{Variables} +% +% \begin{variable}{\g_@@_par_int} +% Stores the number of paragraphs in the current text. +% \begin{macrocode} +\int_new:N \g_@@_par_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_language_tl} +% Stores the language of the dummy text for hyphenation patterns. +% \begin{macrocode} +\tl_new:N \g_@@_language_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}[int]{\g_fistrum_default_range_tl} +% The default range for fistrum paragraphs. +% \begin{macrocode} +\tl_new:N \g_fistrum_default_range_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_output_tl} +% This variables is used to store the token list containing the +% selected output. +% \begin{macrocode} +\tl_new:N \l_@@_output_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_text_str} +% Holds the current text loaded for the output of \cs{fistrum} and +% friends. Used to avoid loading the same text definition if it is +% already used. +% \begin{macrocode} +\str_new:N \g_@@_text_str +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_sep_set_str} +% Holds the name of the active separator token set. By default it is +% empty to use the default separator set (empty). +% \begin{macrocode} +\str_new:N \l_@@_sep_set_str +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_autolang_bool} +% Boolean whether to change hyphenation patterns according to the +% dummy text language. +% \begin{macrocode} +\bool_new:N \l_@@_autolang_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\q_@@_mark,\s_@@} +% Quark and scan mark used throughout the package. +% \begin{macrocode} +\quark_new:N \q_@@_mark +\scan_new:N \s_@@ +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_tmpa_str,\l_@@_a_int,\l_@@_b_int} +% Scratch variables. +% \begin{macrocode} +\str_new:N \l_@@_tmpa_str +\int_new:N \l_@@_a_int +\int_new:N \l_@@_b_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_tmp:w} +% Scratch macro. +% \begin{macrocode} +\cs_new_eq:NN \@@_tmp:w ? +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\l_@@_<thing>_<place>_<version>_tl} +% \csname @gobble\endcsname{ +% \l_@@_par_end_nostar_tl, +% \l_@@_par_end_star_tl, +% \l_@@_par_end__tl, +% \l_@@_par_itemend_nostar_tl, +% \l_@@_par_itemend_star_tl, +% \l_@@_par_itemend__tl, +% \l_@@_par_itemseparator_nostar_tl, +% \l_@@_par_itemseparator_star_tl, +% \l_@@_par_itemseparator__tl, +% \l_@@_par_itemstart_nostar_tl, +% \l_@@_par_itemstart_star_tl, +% \l_@@_par_itemstart__tl, +% \l_@@_par_start_nostar_tl, +% \l_@@_par_start_star_tl, +% \l_@@_par_start__tl, +% \l_@@_sentence_end_nostar_tl, +% \l_@@_sentence_end_star_tl, +% \l_@@_sentence_end__tl, +% \l_@@_sentence_itemend_nostar_tl, +% \l_@@_sentence_itemend_star_tl, +% \l_@@_sentence_itemend__tl, +% \l_@@_sentence_itemseparator_nostar_tl, +% \l_@@_sentence_itemseparator_star_tl, +% \l_@@_sentence_itemseparator__tl, +% \l_@@_sentence_itemstart_nostar_tl, +% \l_@@_sentence_itemstart_star_tl, +% \l_@@_sentence_itemstart__tl, +% \l_@@_sentence_start_nostar_tl, +% \l_@@_sentence_start_star_tl, +% \l_@@_sentence_start__tl, +% } +% These variables store the separators and delimiters added around the +% paragraphs and sentences, in the starred or nonstarred variants, as +% well as the generic version for runtime usage. +% \begin{macrocode} +\clist_map_inline:nn { start, itemstart, itemseparator, itemend, end } + { + \clist_map_inline:nn { par, sentence } + { + \clist_map_inline:nn { { }, star, nostar } + { \tl_new:c { l_@@_##1_#1_####1_tl } } + } + \tl_new:c { l_@@_par_#1_parsepar_tl } + } +\tl_set:Nn \l_@@_par_itemseparator_parsepar_tl { ~ } +% \end{macrocode} +% \end{variable} +% +% \subsection{Developer interface} +% +% \begin{macro}{\@@_parse_par_range:nNN,\@@_parse_par_range:eNN} +% \begin{macro}{\@@_parse_sentence_range:nNN,\@@_parse_sentence_range:eNN} +% \begin{macro}{\@@_parse_range_arg:nNNn,\@@_parse_range_arg:wnNNn} +% \begin{macro}{\@@_int_set:Nnn} +% Parses an argument that may be a single integer or an integer range +% separated by a |-|, and stores them into the integer registers |#2| +% and |#3|. If a number is blank, zero is used. If only a single +% number is given, |#3| is set equal to |#2|. +% \begin{macrocode} +\cs_new_protected:Npn \@@_parse_par_range:nNN #1 #2 #3 + { + \tl_if_blank:nTF {#1} + { \exp_args:NV \@@_parse_range_arg:nNNn \g_fistrum_default_range_tl } + { \@@_parse_range_arg:nNNn {#1} } + #2 #3 { \g_@@_par_int } + } +\cs_new_protected:Npn \@@_parse_sentence_range:nNN #1 #2 #3 + { \@@_parse_range_arg:nNNn {#1} #2 #3 { \c_max_int } } +\cs_new_protected:Npn \@@_parse_range_arg:nNNn #1 + { + \exp_last_unbraced:No \@@_parse_range_arg:wnNNn + \tl_to_str:n { #1 - - } \s_@@ {#1} + } +\cs_new_protected:Npn \@@_parse_range_arg:wnNNn + #1 - #2 - #3 \s_@@ #4 #5#6 #7 + { + \str_if_eq:nnTF {#3} { - } + { + \@@_int_set:Nnn #5 {#1} { 1 } + \@@_int_set:Nnn #6 {#2} {#7} + } + { + \tl_if_empty:nTF {#3} + { + \@@_int_set:Nnn #5 {#1} { \ERROR } + \int_set_eq:NN #6 #5 + } + { + \msg_error:nnn { fistrum } { invalid-range } {#4} + \@@_parse_range_arg:nNNn { 2 - 1 } #5 #6 {#7} + } + } + } +\cs_new_protected:Npn \@@_int_set:Nnn #1 #2 #3 + { \int_set:Nn #1 { \tl_if_blank:nT {#2} {#3} #2 } } +\cs_generate_variant:Nn \@@_parse_par_range:nNN { e } +\cs_generate_variant:Nn \@@_parse_sentence_range:nNN { e } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_sep_item:nn} +% A shorthand to leave an (\cs{undexpanded}) token list. +% \begin{macrocode} +\cs_new:Npn \@@_sep_item:nn #1 #2 + { \exp_not:v { l_@@_#1_#2_ \l_@@_sep_set_str _tl } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\fistrum_get_range:nn} +% \begin{macro}{ +% \@@_build_list:nn, +% \@@_build_list_aux:n, +% \@@_get_paragraph:ww, +% \@@_get_paragraph_end:w, +% } +% Expands to the paragraphs between \meta{number_1} and +% \meta{number_2} with the proper delimiters added. Text is returned +% in \cs{exp_not:n}, so this macro can be safely used in an \cs{edef}. +% \begin{macrocode} +\cs_new:Npn \fistrum_get_range:nn #1 #2 + { + \@@_sep_item:nn { par } { start } + \use:e + { + \exp_not:N \@@_get_paragraph:ww + \@@_build_list:nn {#1} {#2} + \exp_not:N \q_@@_mark ; + \exp_not:N \q_@@_mark ; \s_@@ + } + \@@_sep_item:nn { par } { end } + } +\cs_new:Npn \@@_build_list:nn #1 #2 + { + \int_step_function:nnN + { \int_max:nn {#1} { 1 } } + { \int_min:nn {#2} { \g_@@_par_int } } + \@@_build_list_aux:n + } +\cs_new:Npn \@@_build_list_aux:n #1 { #1 ; } +\cs_new:Npn \@@_get_paragraph:ww #1 ; #2 ; + { + \if_meaning:w \q_@@_mark #2 + \if_meaning:w \q_@@_mark #1 + \@@_get_paragraph_end:w + \else: + \fistrum_get_paragraph:n {#1} + \fi: + \else: + \fistrum_get_paragraph:n {#1} + \@@_sep_item:nn { par } { itemseparator } + \fi: + \@@_get_paragraph:ww #2 ; + } +\cs_new:Npn \@@_get_paragraph_end:w #1 \s_@@ { \fi: \fi: } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\fistrum_get_paragraph:n} +% Expands to the paragraph \meta{number} with the proper delimiters +% added. Text is returned in \cs{exp_not:n}, so this macro can be +% safely used in an \cs{edef}. +% \begin{macrocode} +\cs_new:Npn \fistrum_get_paragraph:n #1 + { + \@@_sep_item:nn { par } { itemstart } + \@@_unexpanded_par:n {#1} + \@@_sep_item:nn { par } { itemend } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_unexpanded_par:n} +% Expands to the paragraph \meta{number} wrapped in \cs{exp_not:n}. +% If \meta{number} is out of range, it expands to nothing. +% \begin{macrocode} +\cs_new:Npn \@@_unexpanded_par:n #1 + { + \bool_lazy_and:nnT + { \int_compare_p:nNn { 0 } < {#1} } + { \int_compare_p:nNn {#1} < { \g_@@_par_int + 1 } } + { \exp_not:v { g_@@_par_#1_tl } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\fistrum_get_sentences:nnn,\fistrum_get_sentences:nnV} +% \begin{macro}{\@@_get_sentences:nnnw,\@@_get_sentences_end:w} +% Expands to the sentences numbered between \meta{number_1} and +% \meta{number_2}, inclusive, contained in the \meta{text}, and adding +% the proper separators. +% \begin{macrocode} +\cs_new:Npn \fistrum_get_sentences:nnn #1 #2 #3 + { + \@@_sep_item:nn { sentence } { start } + \exp_args:Ne \use_ii_i:nn { { \int_max:nn {#1} { 1 } } } + { \@@_get_sentences:nnnw { 1 } } {#2} + #3 ~ \q_@@_mark .~ \s_@@ + \@@_sep_item:nn { sentence } { end } + } +\cs_new:Npn \@@_get_sentences:nnnw #1 #2 #3 #4 .~ + { + \int_compare:nNnT {#1} > {#3} { \@@_get_sentences_end:w } + \use:nn { \if_meaning:w \q_@@_mark } #4 + \exp_after:wN \@@_get_sentences_end:w + \else: + \int_compare:nNnF {#1} < {#2} + { + \int_compare:nNnF {#1} = {#2} + { \@@_sep_item:nn { sentence } { itemseparator } } + \@@_sep_item:nn { sentence } { itemstart } + \exp_not:n { #4 . } + \@@_sep_item:nn { sentence } { itemend } + } + \fi: + \exp_args:Nf \@@_get_sentences:nnnw { \int_eval:n { #1 + 1 } } + {#2} {#3} + } +\cs_new:Npn \@@_get_sentences_end:w #1 \s_@@ { } +\cs_generate_variant:Nn \fistrum_get_sentences:nnn { nnV } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{User- and developer-level commands} +% +% \begin{macro}[int]{\fistrumPar} +% Macro to typeset a single paragraph of \fist\ Was not officially +% available in version prior to 2.0. +% \begin{arguments} +% \item Number of the paragraph to typeset. +% \end{arguments} +% Implemented as follows: +% \begin{macrocode} +\NewDocumentCommand \fistrumPar { m } + { + \@@_deprecated:n { FistrumPar } + \@@_unexpanded_par:n {#1} \par + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Tokens surrounding the \fist\ content} +% +% \begin{macro}{\@@_element_set:nnn} +% A general macro for setting starred/non-starred versions of several +% elements used between chunks of dummy text. Arguments are: +% \begin{arguments} +% \item Element name; +% \item Boolean true or false if the |*| variant was used; +% \item Value to set the element to. +% \end{arguments} +% \begin{macrocode} +\cs_new_protected:Npn \@@_element_set:nnn #1 #2 #3 + { \tl_set:cn { l_@@_ #1 _ \IfBooleanF {#2} { no } star _tl } {#3} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_deprecated:n} +% Warns about deprecated commands and destroys itself. +% \begin{macrocode} +\cs_new_protected:Npn \@@_deprecated:n #1 + { + \msg_warning:nnn { fistrum } { cmd-deprecated } {#1} + \cs_gset_eq:NN \@@_deprecated:n \use_none:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{ +% \SetFistrumParListStart, +% \SetFistrumParListEnd, +% \SetFistrumParListSurrounders, +% \SetFistrumParListItemSeparator, +% \SetFistrumParListItemStart, +% \SetFistrumParListItemEnd, +% \SetFistrumParListItemSurrounders, +% \SetFistrumSentenceListStart, +% \SetFistrumSentenceListEnd, +% \SetFistrumSentenceListSurrounders, +% \SetFistrumSentenceListItemSeparator, +% \SetFistrumSentenceListItemStart, +% \SetFistrumSentenceListItemEnd, +% \SetFistrumSentenceListItemSurrounders, +% } +% A dirty loop to quickly define the old command-based user-interface. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 #4 + { + \str_set:Nx \l_@@_tmpa_str + { #2 \tl_if_empty:nTF {#4} {#3} { start } } + \use:e + { + \NewDocumentCommand \exp_not:c { SetFistrum #1 List #2 #3 } + { s +m \tl_if_empty:nF {#4} { +m } } + { + \@@_deprecated:n { SetFistrum #1 List #2 #3 } + \@@_element_set:nnn + { \exp_args:Ne \str_lowercase:n { #1_\l_@@_tmpa_str } } + {##1} {##2} + \tl_if_empty:nT {#4} { \use_none:nnnn } + \@@_element_set:nnn { \str_lowercase:n { #1_#2 #4 } } + {##1} {##3} + } + } + } +\clist_map_inline:nn { Par, Sentence } + { + \clist_map_inline:nn + { { Start } { }, { End } { }, { Surrounders } { end } } + { \@@_tmp:w {#1} { Item } ##1 \@@_tmp:w {#1} { } ##1 } + \@@_tmp:w {#1} { Item } { Separator } { } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SetFistrumDefault} +% Command to change the default range used by \cs{fistrum} and friends. +% \begin{arguments} +% \item[\meta{range}] Range to be used as default. +% \end{arguments} +% Implemented as: +% \begin{macrocode} +\NewDocumentCommand \SetFistrumDefault { m } + { + \@@_parse_par_range:eNN {#1} \l_@@_a_int \l_@@_b_int + \tl_gset:Nx \g_fistrum_default_range_tl + { \int_use:N \l_@@_a_int - \int_use:N \l_@@_b_int } + } +% \end{macrocode} +% \end{macro} +% +% The following macros are considered to be user-level commands and thus +% all lower-case. +% +% \begin{macro}{\fistrum} +% \begin{arguments} +% \item Range-like string that specifies the number of the +% paragraphs taken from \fist\ If omitted, the value set by +% \cs{SetFistrumDefault} is used, which defaults to |1-7|. +% \item Sentences to be typeset from the range selected by +% \meta{paragraph range}. If sentences outside the number of +% sentences in \meta{paragraph range} are specified, only existing +% sentences are typeset. +% \end{arguments} +% The difference between \cs{fistrum} and \cs{fistrum*} is the token(s) +% that are inserted after each paragraph (only if called without the +% second optional argument). +% +% \cs{fistrum} and \cs{unpackfistrum} have the same interface and do +% almost the same thing, so both are implemented using a common macro +% \cs{@@_do:nnnn} that does the heavy-lifting, and at the end +% executes the code in |#4|. +% \begin{macrocode} +\NewDocumentCommand \fistrum { s O { \g_fistrum_default_range_tl } o } + { + \@@_do:nnnn {#1} {#2} {#3} + { + \@@_set_hyphens: + \tl_use:N ##1 + \@@_restore_hyphens: + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\unpackfistrum,\fistrumexp} +% This command does the same as \cs{fistrum}, but instead of +% typesetting the paragraphs or sentences, it stores the expanded +% content in the \cs{fistrumexp} token list. The tokens between items +% of the list, set, for example, by using the package option +% \opt{space} or by using the \cs{SetFistrum...List} commands, are +% |x|-expanded. +% \begin{macrocode} +\NewDocumentCommand \unpackfistrum { s O { \g_fistrum_default_range_tl } o } + { \@@_do:nnnn {#1} {#2} {#3} { \tl_gset_eq:NN \fistrumexp ##1 } } +\cs_new_eq:NN \fistrumexp \prg_do_nothing: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_do:nnnn} +% \begin{macro}{\@@_do:N} +% This is the main macro for \cs{fistrum} and \cs{unpackfistrum}. +% It parses the paragraph range, sets the sentence/paragraph +% separators, then acts accordingly if a sentence range was provided. +% \begin{macrocode} +\cs_new_protected:Npn \@@_do:nnnn #1 #2 #3 #4 + { + \cs_set_protected:Npn \@@_do:N ##1 {#4} + \@@_parse_par_range:eNN {#2} \l_@@_a_int \l_@@_b_int + \str_set_eq:NN \l_@@_tmpa_str \l_@@_sep_set_str + \str_set:Nx \l_@@_sep_set_str { \IfBooleanF {#1} { no } star } + \bool_lazy_or:nnTF + { \tl_if_novalue_p:n {#3} } + { \tl_if_blank_p:n {#3} } + { + \tl_set:Nx \l_@@_output_tl + { \fistrum_get_range:nn { \l_@@_a_int } { \l_@@_b_int } } + } + { + \str_set:Nn \l_@@_sep_set_str { parsepar } + \tl_set:Nx \l_@@_output_tl + { \fistrum_get_range:nn { \l_@@_a_int } { \l_@@_b_int } } + \str_set:Nx \l_@@_sep_set_str { \IfBooleanF {#1} { no } star } + \@@_parse_sentence_range:eNN {#3} \l_@@_a_int \l_@@_b_int + \tl_set:Nx \l_@@_output_tl + { + \fistrum_get_sentences:nnV { \l_@@_a_int } { \l_@@_b_int } + \l_@@_output_tl + } + } + \str_set_eq:NN \l_@@_sep_set_str \l_@@_tmpa_str + \@@_do:N \l_@@_output_tl + } +\cs_new_eq:NN \@@_do:N ? +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_set_hyphens:,\@@_restore_hyphens:} +% Selects the hyphenation patterns for the language of the dummy text, +% using \cs{hyphenrules} if that's defined. If \cs{hyphenrules} +% doesn't exist try setting hyphenation with \cs{@@_set_hyphens_raw:}. +% Each \cs[no-index]{@@_set_hyphens_\meta{method}:} function +% appropriately redefines \cs{@@_restore_hypehens:} to reset the +% hyphenation patterns. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_hyphens: + { + \bool_if:NTF \l_@@_autolang_bool + { \use:n } { \use_none:n } + { + \cs_if_exist:NTF \hyphenrules + { + \cs_if_exist:cTF { ver@polyglossia.sty } + { \@@_set_hyphens_polyglossia: } + { \@@_set_hyphens_babel: } + } + { \@@_set_hyphens_raw: } + } + } +\cs_new_protected:Npn \@@_restore_hyphens: + { \prg_do_nothing: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_set_hyphens_babel:} +% \pkg{babel} makes things pretty simple. We just check if +% \cs[no-index]{l@\meta{lang}} is defined, and if so, use +% \cs{hyphenrules} to set it, and once more to reset in +% \cs{@@_restore_hyphens:}. \cs{hyphenrules} is actually an +% environment, but in \pkg{babel} its \cs[no-index]{end} part does +% nothing, and its effect can be undone by just using another +% \cs{hyphenrules} on top of it. +% +% If the language is not defined, the language either doesn't exist at +% all, or we are using Lua\TeX. Both cases are handled by +% \cs{@@_lang_not_available:}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_hyphens_babel: + { + \cs_if_exist:cTF { l@ \g_@@_language_tl } + { + \exp_args:NV \hyphenrules \g_@@_language_tl + \cs_set_protected:Npx \@@_restore_hyphens: + { \exp_not:N \hyphenrules { \languagename } } + } + { \@@_lang_not_available: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_set_hyphens_polyglossia:} +% \pkg{polyglossia} less friendly. We also check if the language is +% loaded (looking at \cs[no-index]{\meta{lang}@loaded}), and if it +% is, load it with the \env{hyphenrules} environment. Here we can't +% use the command form, as the \cs[no-index]{end} part is not a no-op. +% This also means that an extra group is added around the dummy text, +% which causes issue \ghissue{1} when used with \pkg{wrapfig}, for +% example. But not too much we can do about that for now. +% +% In case the language is not loaded, fall back to +% \cs{@@_set_hyphens_raw:} for a final attempt before giving up. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_hyphens_polyglossia: + { + \cs_if_exist:cTF { \g_@@_language_tl @loaded } + { + \exp_args:NnV \begin{hyphenrules} \g_@@_language_tl + \cs_set_protected:Npn \@@_restore_hyphens: + { \end{hyphenrules} } + } + { \@@_set_hyphens_raw: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_set_hyphens_raw:} +% If nothing else is available, try setting the language using +% \cs{language}\meta{number}. This is always available, +% except with Lua\TeX, which loads languages on-the-fly. +% \begin{macrocode} +\cs_new_protected:Npn \@@_set_hyphens_raw: + { + \cs_if_exist:cTF { l@ \g_@@_language_tl } + { + \use:x + { + \language \use:c { l@ \g_@@_language_tl } + \cs_set_protected:Npn \@@_restore_hyphens: + { \language \int_eval:n { \language } \scan_stop: } + } + } + { \@@_lang_not_available: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_lang_not_available:} +% If the requested language is for some reason unavailable, warn the +% user, then fall back to the current language. If the requested +% language and \cs{languagename} are the same, we are probably running +% into this warning again because we have no languages loaded (e.g., +% testing environments). In that case, shut up because there's not +% much that can be done (and a warning that says ``language "english" +% is not available; using "english" instead'' is of little use). +% \begin{macrocode} +\cs_new_protected:Npn \@@_lang_not_available: + { + \str_if_eq:VVF \g__fistrum_language_tl \languagename + { + \msg_warning:nnx { fistrum } { missing-language } + { \g_@@_language_tl } + \tl_gset_eq:NN \g_@@_language_tl \languagename + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NewFistrumPar} +% Developer-Level macro to add a paragraph to the dummy text used by +% \cs{fistrum} and related commands. To specify a new dummy text, see +% section~\ref{sec:other-texts}. +% \begin{macrocode} +\cs_new_protected:Npn \NewFistrumPar #1 + { + \int_gincr:N \g_@@_par_int + \tl_gclear_new:c { g_@@_par_ \int_use:N \g_@@_par_int _tl } + \tl_gset:cn { g_@@_par_ \int_use:N \g_@@_par_int _tl } {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SetFistrumText} +% Used to select and load the text output by \cs{fistrum} and friends. +% See the section on loading and defining new outputs for \cs{fistrum} +% (section~\ref{sec:other-texts}). It first checks whether the +% requested text is already loaded, and if not, it loads the +% corresponding fistrum text definition file, and clears remaining +% paragraphs from the previous text, in case their lengths differ. +% \begin{macrocode} +\NewDocumentCommand \SetFistrumText { m } + { + \str_if_eq:VnF \g_@@_text_str {#1} + { + \tl_gset:Nn \g_@@_language_tl { english } + \int_gzero:N \g_@@_par_int + \file_input:n { #1.ftd } + \str_gset:Nn \g_@@_text_str {#1} + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SetFistrumLanguage} +% This macro sets the language for hyphenation patterns of the dummy +% text. When a new fistrum text is read, this is reset. +% \begin{macrocode} +\NewDocumentCommand \SetFistrumLanguage { m } + { \tl_gset:Nn \g_@@_language_tl {#1} } +% \end{macrocode} +% \end{macro} +% +% \subsection{Package options and defaults} +% +% \begin{macro}[int]{ +% \fistrumRestoreParList, +% \fistrumRestoreSentenceList, +% \fistrumRestoreAll, +% } +% \begin{macro}{\@@_delim_restore:nnn} +% \begin{macro}{\@@_restore_par_list:,\@@_restore_sentence_list:} +% These are some auxiliaries for the package options and for setting +% up the default behaviour. +% \begin{macrocode} +\cs_new_protected:Npn \@@_delim_restore:nnn #1 #2 #3 + { + \keys_set:nn { fistrum } + { + #1-before = , #1-begin = , #1-end = , #1-after = , + #1-before* = , #1-begin* = , #1-end* = , #1-after* = , + #1-sep = {#2}, #1-sep* = {#3} + } + } +\cs_new_protected:Nn \@@_restore_sentence_list: + { \@@_delim_restore:nnn { sentence } { ~ } { ~ } } +\cs_new_eq:NN \@@_restore_par_list: ? +\cs_new_protected:Npn \fistrumRestoreParList + { + \@@_deprecated:n { FistrumRestoreParList } + \@@_restore_par_list: + } +\cs_new_protected:Npn \fistrumRestoreSentenceList + { + \@@_deprecated:n { FistrumRestoreSentenceList } + \@@_restore_sentence_list: + } +\cs_new_protected:Npn \fistrumRestoreAll + { + \@@_deprecated:n { FistrumRestoreAll } + \@@_restore_par_list: \@@_restore_sentence_list: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\setfistrum} +% Here are the options available at load-time and to \cs{setfistrum}. +% \begin{macrocode} +\NewDocumentCommand \setfistrum { +m } + { \keys_set:nn { fistrum } {#1} } +\keys_define:nn { fistrum } + { +% \end{macrocode} +% \opt{nopar} is implemented as a choice key instead of a boolean so +% we can update the separators using \cs{@@_delim_restore:nnn}. +% It's initially false, and the default is |true| so that +% |\usepackage[nopar]{fistrum}| works as it always did. +% \begin{macrocode} + nopar .choice: , + nopar / true .code:n = + { + \cs_gset_protected:Npn \@@_restore_par_list: + { \@@_delim_restore:nnn { par } { ~ } { \par } } + } , + nopar / false .code:n = + { + \cs_gset_protected:Nn \@@_restore_par_list: + { \@@_delim_restore:nnn { par } { \par } { ~ } } + } , + nopar .initial:n = false , + nopar .default:n = true , +% \end{macrocode} +% \opt{auto-lang} sets \cs{l_@@_autolang_bool}. It is initially +% |true|, changing the default behaviour from previous versions. +% \begin{macrocode} + auto-lang .bool_set:N = \l_@@_autolang_bool , + auto-lang .initial:n = true , + auto-lang .default:n = true , +% \end{macrocode} +% \opt{text} just does \cs{SetFistrumText}. The |initial| value is not +% set here because this chunk of code is executed in \pkg{expl3} +% syntax, then thetextloadswithoutspaces, so |\setfistrum{text=fistrum-la}| +% is used later. +% \begin{macrocode} + text .code:n = \SetFistrumText{#1} , + text .value_required:n = true , +% \end{macrocode} +% \opt{language} sets the language to be used when typesetting. +% \begin{macrocode} + language .tl_gset:N = \g_@@_language_tl , + language .value_required:n = true , +% \end{macrocode} +% \opt{default-range} does \cs{SetFistrumDefault}, initially |1-7|, as +% documented. It's default is also |1-7| so that the key has two +% meanings: \cs{setfistrum}|{default-range=|\meta{range}|}| sets the +% range to the given value, while \cs{setfistrum}|{default-range}| sets +% the range to the ``default default range''. Pretty neat :) +% \begin{macrocode} + default-range .code:n = \SetFistrumDefault{#1} , + default-range .initial:n = 1-7 , + default-range .default:n = 1-7 , + } +% \end{macrocode} +% This chunk defines the keys \meta{thing}-\meta{place}[*], where +% \meta{thing} is |par| or |sentence|, \meta{place} is |before|, +% |begin|, |sep|, |end|, and |after|, which totals~10 keys, and +% another~10 with the |*| in the name. Each sets a token list called +% \cs[no-index]{l_@@_\meta{thing}_\meta{place}_[no]star_tl}. +% \begin{macrocode} +\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 + { + \keys_define:nn { fistrum } + { + #1-before #2 .tl_set:c = l_@@_#1_start _#3star_tl , + #1-begin #2 .tl_set:c = l_@@_#1_itemstart _#3star_tl , + #1-sep #2 .tl_set:c = l_@@_#1_itemseparator _#3star_tl , + #1-end #2 .tl_set:c = l_@@_#1_itemend _#3star_tl , + #1-after #2 .tl_set:c = l_@@_#1_end _#3star_tl , + } + } +\@@_tmp:w { par } { } { no } \@@_tmp:w { sentence } { } { no } +\@@_tmp:w { par } * { } \@@_tmp:w { sentence } * { } +% \end{macrocode} +% \end{macro} +% +% Now turn \cs{ExplSyntaxOff} for a while, and load the default \fist{} +% text, then process the package options, and finally turn +% \cs{ExplSyntaxOn} again. Finally, call \cs{@@_restore_par_list:} and +% \cs{@@_restore_sentence_list:} to set the defaults +% (\cs{@@_restore_par_list:} may have been redefined by \opt{nopar}). +% \begin{macrocode} +\ExplSyntaxOff +\setfistrum{text=fistrum-es} +\ProcessKeysOptions{fistrum} +\ExplSyntaxOn +\@@_restore_par_list: +\@@_restore_sentence_list: +% \end{macrocode} +% +% \subsection{Messages} +% +% Now define the messages used throughout the package. +% \begin{macrocode} +\msg_new:nnn { fistrum } { invalid-range } + { Invalid~number~or~range~'#1'. } +\msg_new:nnn { fistrum } { cmd-deprecated } + { + Command~'\iow_char:N\\#1'~deprecated. \\ + See~the~fistrum~documentation~for~help. + } +\msg_new:nnn { fistrum } { missing-language } + { + Unknown~language~'#1'.~Hyphenation~patterns~for~ + '\languagename'~will~be~used~instead. + \sys_if_engine_luatex:T + { + \\ \\ + \cs_if_exist:cTF { ver@polyglossia.sty } + { + With~polyglossia,~you~have~to~explicitly~load~languages~ + with~\iow_char:N\\setotherlanguage{#1}~or~similar. + } + { + With~LuaTeX,~fistrum~requires~babel~to~get~proper~ + hyphenation~(you~can~use~ + \iow_char:N\\usepackage[base]{babel}). + } + } + } +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: |