diff options
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3text.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3text.dtx | 178 |
1 files changed, 177 insertions, 1 deletions
diff --git a/macros/latex/contrib/l3kernel/l3text.dtx b/macros/latex/contrib/l3kernel/l3text.dtx index df4f2fcde5..3e89563a5e 100644 --- a/macros/latex/contrib/l3kernel/l3text.dtx +++ b/macros/latex/contrib/l3kernel/l3text.dtx @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2022-08-23} +% \date{Released 2022-08-30} % % \maketitle % @@ -184,6 +184,8 @@ % combining dot is removed when uppercasing in these cases. Note that % \emph{only} the accents used in Lithuanian are covered: the behaviour % of other accents are not modified. +% \item Medieval Latin (\texttt{la-xmedieval}). +% The characters |u| and |V| are interchanged on case changing. % \item Dutch (\texttt{nl}). % Capitalisation of \texttt{ij} at the beginning of titlecased % input produces \texttt{IJ} rather than \texttt{Ij}. The output @@ -299,6 +301,62 @@ % \texttt{true}. % \end{variable} % +% \section{Mapping to graphemes} +% +% Grapheme splitting is implemented using the algorithm described in Unicode +% Standard Annex \#29. This includes support for extended grapheme clusters. +% Text starting with a line feed or carriage return character will drop this +% due to standard \TeX{} processing. At present extended pictograms are +% not supported: these may be added in a future release. +% +% \begin{function}[rEXP, added = 2022-08-04]{\text_map_function:nN} +% \begin{syntax} +% \cs{text_map_function:nN} \meta{text} \Arg{function} +% \end{syntax} +% Takes user input \meta{text} and expands as described for +% \cs{text_expand:n}, then maps over the \emph{graphemes} within the +% result, passing each grapheme to the \meta{function}. +% Broadly a grapheme is a \enquote{user perceived character}: +% the Unicode Consortium describe the decomposition of input to +% graphemes in depth, and the approach used here implements that +% algorithm. The \meta{function} should accept one argument as \meta{balanced +% text}: this may be comprise codepoints or may be a control sequence. +% With $8$-bit engines, the codepoint(s) themselves may of course be +% made up of multiple bytes: the mapping will pass the correct codepoints +% independent of the engine in use. +% See also \cs{text_map_inline:nn}. +% \end{function} +% +% \begin{function}[added = 2022-08-04]{\text_map_inline:nn} +% \begin{syntax} +% \cs{text_map_inline:nn} \meta{text} \Arg{inline function} +% \end{syntax} +% Takes user input \meta{text} and expands as described for +% \cs{text_expand:n}, then maps over the \emph{graphemes} within the +% result, passing each grapheme to the \meta{inline function}. +% Broadly a grapheme is a \enquote{user perceived character}: +% the Unicode Consortium describe the decomposition of input to +% graphemes in depth, and the approach used here implements that +% algorithm. The \meta{inline function} should consist of code which +% receives the grapheme as \meta{balanced +% text}: this may be comprise codepoints or may be a control sequence. +% With $8$-bit engines, the codepoint(s) themselves may of course be +% made up of multiple bytes: the mapping will pass the correct codepoints +% independent of the engine in use. +% See also \cs{text_map_function:nN}. +% \end{function} +% +% \begin{function}[rEXP, added = 2022-08-04] +% {\text_map_break:, \text_map_break:n} +% \begin{syntax} +% \cs{text_map_break:} +% \cs{text_map_break:n} \Arg{code} +% \end{syntax} +% Used to terminate a \cs[no-index]{text_map_\ldots} function before all +% entries in the \meta{text} have been processed. This +% normally takes place within a conditional statement. +% \end{function} +% % \end{documentation} % % \begin{implementation} @@ -357,11 +415,14 @@ % \end{macro} % % \begin{macro}[EXP]{\@@_if_q_recursion_tail_stop_do:Nn} +% \begin{macro}[EXP]{\@@_if_q_recursion_tail_stop_do:nn} % Functions to query recursion quarks. % \begin{macrocode} \__kernel_quark_new_test:N \@@_if_q_recursion_tail_stop_do:Nn +\__kernel_quark_new_test:N \@@_if_q_recursion_tail_stop_do:nn % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{variable}{\s_@@_recursion_tail,\s_@@_recursion_stop} % Internal scan marks quarks. @@ -581,6 +642,121 @@ % \end{macrocode} % \end{macro} % +% \subsection{Codepoint utilities} +% +% For working with codepoints in an engine-neutral way. +% +% \begin{macro}[EXP]{\@@_codepoint_process:nN} +% \begin{macro}[EXP]{\@@_codepoint_process:nNN} +% \begin{macro}[EXP]{\@@_codepoint_process:nNNN} +% \begin{macro}[EXP]{\@@_codepoint_process:nNNNN} +% Grab a codepoint and apply some code to it: here |#1| should expect one +% following \emph{balanced text}. +% \begin{macrocode} +\bool_lazy_or:nnTF + { \sys_if_engine_luatex_p: } + { \sys_if_engine_xetex_p: } + { + \cs_new:Npn \@@_codepoint_process:nN #1#2 { #1 {#2} } + } + { + \cs_new:Npn \@@_codepoint_process:nN #1#2 + { + \int_compare:nNnTF { `#2 } > { "80 } + { + \int_compare:nNnTF { `#2 } < { "E0 } + { \@@_codepoint_process:nNN } + { + \int_compare:nNnTF { `#2 } < { "F0 } + { \@@_codepoint_process:nNNN } + { \@@_codepoint_process:nNNNN } + } + } + { \use:n } + {#1} #2 + } + \cs_new:Npn \@@_codepoint_process:nNN #1#2#3 + { #1 {#2#3} } + \cs_new:Npn \@@_codepoint_process:nNNN #1#2#3#4 + { #1 {#2#3#4} } + \cs_new:Npn \@@_codepoint_process:nNNNN #1#2#3#4#5 + { #1 {#2#3#4#5} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[EXP, pTF]{\@@_codepoint_compare:nNn} +% \begin{macro}[EXP]{\@@_codepoint_compare:N, \@@_codepoint_compare_aux:N} +% \begin{macro}[EXP]{\@@_codepoint_compare:NN} +% \begin{macro}[EXP]{\@@_codepoint_compare:NNN} +% \begin{macro}[EXP]{\@@_codepoint_compare:NNNN} +% Allows comparison for all engines using a first \enquote{character} followed +% by a codepoint. +% \begin{macrocode} +\bool_lazy_or:nnTF + { \sys_if_engine_luatex_p: } + { \sys_if_engine_xetex_p: } + { + \prg_new_conditional:Npnn + \@@_codepoint_compare:nNn #1#2#3 { TF , p } + { + \int_compare:nNnTF { `#1 } #2 {#3} + \prg_return_true: \prg_return_false: + } + } + { + \prg_new_conditional:Npnn + \@@_codepoint_compare:nNn #1#2#3 { TF , p } + { + \int_compare:nNnTF { \@@_codepoint_compare:N #1 } + #2 {#3} + \prg_return_true: \prg_return_false: + } + \cs_new:Npn \@@_codepoint_compare:N #1 + { + \if_int_compare:w `#1 > "80 \exp_stop_f: + \if_int_compare:w `#1 < "E0 \exp_stop_f: + \exp_after:wN \exp_after:wN \exp_after:wN + \@@_codepoint_compare:NN + \else: + \if_int_compare:w `#1 < "F0 \exp_stop_f: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \@@_codepoint_compare:NNN + \else: + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \exp_after:wN \exp_after:wN + \exp_after:wN \@@_codepoint_compare:NNNN + \fi: + \fi: + \else: + \exp_after:wN \@@_codepoint_compare_aux:N + \fi: + #1 + } + \cs_new:Npn \@@_codepoint_compare_aux:N #1 { `#1 } + \cs_new:Npn \@@_codepoint_compare:NN #1#2 + { (`#1 - "C0) * "40 + `#2 - "80 } + \cs_new:Npn \@@_codepoint_compare:NNN #1#2#3 + { (`#1 - "E0) * "1000 + (`#2 - "80) * "40 + `#3 - "80 } + \cs_new:Npn \@@_codepoint_compare:NNNN #1#2#3#4 + { + (`#1 - "F0) * "40000 + + (`#2 - "80) * "1000 + + (`#3 - "80) * "40 + + `#4 - "80 + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Configuration variables} % % \begin{variable}{\l_text_accents_tl, \l_text_letterlike_tl} |