summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx105
1 files changed, 85 insertions, 20 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
index b44b307bbf1..e4dba1753ff 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3unicode.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-06-16}
+% \date{Released 2023-06-30}
%
% \maketitle
%
@@ -106,6 +106,22 @@
% category code $10$.
% \end{function}
%
+% \begin{function}[added = 2023-06-19, EXP]{\codepoint_to_category:n}
+% \begin{syntax}
+% \cs{codepoint_to_category:n} \Arg{codepoint}
+% \end{syntax}
+% Expands to the Unicode general category identifier of the \meta{codepoint}.
+% The general category identifier is a string made up of two letter
+% characters, the first uppercase and the second lowercase. The uppercase
+% letters divide codepoints into broader groups, which are then refined
+% by the lowercase letter. For example, codepoints representing letters
+% all have identifiers starting \texttt{L}, for example \texttt{Lu}
+% (uppercase letter), \texttt{Lt} (titlecase letter), \emph{etc.}
+% Full details are available in the documentation provided by the Unicode
+% Consortium: see
+% \url{https://www.unicode.org/reports/tr44/#General_Category_Values}
+% \end{function}
+%
% \begin{function}[added = 2022-10-09, EXP]{\codepoint_to_nfd:n}
% \begin{syntax}
% \cs{codepoint_to_nfd:n} \Arg{codepoint}
@@ -347,6 +363,21 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}[EXP]{\codepoint_to_category:n}
+% Get the value and convert back to the string.
+% \begin{macrocode}
+\cs_new:Npn \codepoint_to_category:n #1
+ {
+ \cs:w
+ c_@@_category_
+ \tex_romannumeral:D
+ \__kernel_codepoint_data:nn { category } {#1}
+ _str
+ \cs_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]{\codepoint_to_nfd:n, \@@_to_nfd:n}
% \begin{macro}[EXP]{\@@_to_nfd:nn}
% \begin{macro}[EXP]{\@@_to_nfd:nnn}
@@ -461,7 +492,7 @@
% \begin{macrocode}
\group_begin:
\clist_map_inline:nn
- { uppercase , lowercase }
+ { category , uppercase , lowercase }
{
\cs_set_nopar:cpn { l_@@_ #1 _block_clist } { }
\cs_set_nopar:cpn { l_@@_ #1 _block_tl } { 1 }
@@ -477,6 +508,29 @@
\cs_set_nopar:Npn \l_@@_next_codepoint_fint_tl { 0 }
\cs_set_nopar:Npn \l_@@_matched_block_tl { 0 }
% \end{macrocode}
+% For Unicode general category, there needs to be numerical representation of
+% each possible value. As we need to go from string to number here, but the
+% other way elsewhere, we set up fast mappings both ways, but one set local
+% and the other as constants.
+% \begin{macrocode}
+ \cs_set_protected:Npn \@@_data_auxi:w #1#2
+ {
+ \quark_if_recursion_tail_stop:n {#2}
+ \cs_set_nopar:cpn { l_@@_category_ #2 _tl } {#1}
+ \str_const:cn { c_@@_category_ \tex_romannumeral:D #1 _str } {#2}
+ \exp_args:Ne \@@_data_auxi:w { \int_eval:n { #1 + 1 } }
+ }
+ \@@_data_auxi:w { 1 }
+ { Lu } { Ll } { Lt } { Lm } { Lo }
+ { Mn } { Me } { Mc }
+ { Nd } { Nl } { No }
+ { Zs } { Zl } { Zp }
+ { Cc } { Cf } { Co } { Cs } { Cn }
+ { Pd } { Ps } { Pe } { Pc } { Po } { Pi } { Pf }
+ { Sm } { Sc } { Sk } { So }
+ \q_recursion_tail
+ \q_recursion_stop
+% \end{macrocode}
% Parse the main Unicode data file and pull out the NFD and case changing
% data. The NFD data is stored on using the hash table approach and can yield
% a predictable number of codepoints: one or two. We also need the case data,
@@ -491,7 +545,7 @@
\tl_if_head_eq_charcode:nNF {#6} < % >
{ \@@_data_auxii:w #1 ; #6 ~ \q_stop }
}
- \@@_data_auxiii:w #1 ; #2 ;
+ \@@_data_auxiii:w #1 ; #2 ; #3 ;
}
\cs_set_protected:Npn \@@_data_auxii:w #1 ; #2 ~ #3 \q_stop
{
@@ -503,22 +557,27 @@
}
}
% \end{macrocode}
+% The category data needs to be converted from a string to the numerical
+% equivalent: a simple operation.
% The case data is going to be stored as an offset from the parent character,
% rather than an absolute value. We therefore deal with that plus the situation
-% where a codepoint has no mapping data in oen shot.
+% where a codepoint has no mapping data in one shot.
% \begin{macrocode}
\cs_set_protected:Npn \@@_data_auxiii:w
- #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ~ \q_stop
+ #1 ; #2 ; #3 ; #4 ; #5 ; #6 ; #7 ; #8 ; #9 ~ \q_stop
{
\use:e
{
\@@_data_auxiv:w
#1 ; #2 ;
- \@@_data_offset:nn {#1} {#6} ;
+ \@@_data_category:n {#3} ;
\@@_data_offset:nn {#1} {#7} ;
- #8;
+ \@@_data_offset:nn {#1} {#8} ;
+ #9;
}
}
+ \cs_set:Npn \@@_data_category:n #1
+ { \use:c { l_@@_category_ #1 _tl } }
\cs_set:Npn \@@_data_offset:nn #1#2
{
\tl_if_blank:nTF {#2}
@@ -536,20 +595,21 @@
% case exceptions are all stored as codepoints, with a fixed number of
% balanced text as we know that there are never more than three.
% \begin{macrocode}
- \cs_set_protected:Npn \@@_data_auxiv:w #1 ; #2 ; #3 ; #4 ; #5 ;
+ \cs_set_protected:Npn \@@_data_auxiv:w #1 ; #2 ; #3 ; #4 ; #5 ; #6 ;
{
\int_compare:nNnT {"#1} > \l_@@_next_codepoint_fint_tl
{
- \@@_data_auxvi:nnnw {#1} {#3} {#4}
+ \@@_data_auxv:nnnnw {#1} {#3} {#4} {#5}
#2 Last> \q_stop
}
- \@@_add:nn { uppercase } {#3}
- \@@_add:nn { lowercase } {#4}
- \int_compare:nNnF {#3} = { \@@_data_offset:nn {#1} {#5} }
+ \@@_add:nn { category } {#3}
+ \@@_add:nn { uppercase } {#4}
+ \@@_add:nn { lowercase } {#5}
+ \int_compare:nNnF {#4} = { \@@_data_offset:nn {#1} {#6} }
{
\tl_const:cx
{ c_@@_titlecase_ \codepoint_str_generate:n {"#1} _tl }
- { {"#5} { } { } }
+ { {"#6} { } { } }
}
\tl_set:Nx \l_@@_next_codepoint_fint_tl
{ \int_eval:n { "#1 + 1 } }
@@ -563,17 +623,22 @@
}
% \end{macrocode}
% Distinguish between a range and a gap, and pass on the appropriate value(s).
+% The general category for unassigned characters is \texttt{Cn}, so we
+% find the correct value once and then use that.
% \begin{macrocode}
- \cs_set_protected:Npn \@@_data_auxvi:nnnw #1#2#3#4 Last> #5 \q_stop
+ \cs_set_protected:Npx \@@_data_auxv:nnnnw #1#2#3#4#5 Last> #6 \q_stop
{
- \tl_if_blank:nTF {#5}
+ \exp_not:N \tl_if_blank:nTF {#6}
{
- \@@_range:nnn {#1} { uppercase } { 0 }
- \@@_range:nnn {#1} { lowercase } { 0 }
+ \exp_not:N \@@_range:nnn {#1} { category }
+ { \exp_not:V \l_@@_category_Cn_tl }
+ \exp_not:N \@@_range:nnn {#1} { uppercase } { 0 }
+ \exp_not:N \@@_range:nnn {#1} { lowercase } { 0 }
}
{
- \@@_range:nnn {#1} { uppercase } {#2}
- \@@_range:nnn {#1} { lowercase } {#3}
+ \exp_not:N \@@_range:nnn {#1} { category } {#2}
+ \exp_not:N \@@_range:nnn {#1} { uppercase } {#3}
+ \exp_not:N \@@_range:nnn {#1} { lowercase } {#4}
}
}
% \end{macrocode}
@@ -672,7 +737,7 @@
% \begin{macrocode}
\cs_set_protected:Npn \@@_finalise_blocks:
{
- \clist_map_inline:nn { uppercase , lowercase }
+ \clist_map_inline:nn { category , uppercase , lowercase }
{
\@@_range:nnn { 110000 } {##1} { 0 }
\@@_finalise_blocks:n {##1}