summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx299
1 files changed, 220 insertions, 79 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
index a69a695f493..f761831a6b7 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2023-06-05}
+% \date{Released 2023-06-16}
%
% \maketitle
%
@@ -935,6 +935,14 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}[EXP]{\@@_change_case_generate:n}
+% A utility.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_generate:n #1
+ { \codepoint_generate:nn {#1} { \char_value_catcode:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]
% {\@@_change_case_upper_de-x-eszett:nnnn, \@@_change_case_upper_de-alt:nnnn}
% A simple alternative version for German.
@@ -979,25 +987,22 @@
% \begin{macro}[EXP]
% {
% \@@_change_case_upper_el_ypogegrammeni:n ,
-% \@@_change_case_upper_el-x-iota_ypogegrammeni:n ,
-% \@@_change_case_upper_el_ypogegrammeni_aux:n
+% \@@_change_case_upper_el-x-iota_ypogegrammeni:n
% }
+% \begin{macro}[EXP]{\@@_change_case_upper_el_stress:nn}
% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnw}
% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnN}
% \begin{macro}[EXP]{\@@_change_case_upper_el_gobble:nnn}
-% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek:n}
-% \begin{macro}[EXP]{\@@_change_case_if_greek:n}
-% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek:n}
-% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek_spacing_diacritic:n}
-% \begin{macro}[EXP]{\@@_change_case_if_greek_spacing_diacritic:n}
-% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek_accent:n}
-% \begin{macro}[EXP]{\@@_change_case_if_greek_accent:n}
-% \begin{macro}[EXP,pTF]{\@@_change_case_if_greek_diacritic:n}
-% \begin{macro}[EXP]{\@@_change_case_if_greek_diacritic:n}
-% \begin{macro}[EXP,TF]{\@@_change_case_if_takes_dialytika:n}
-% \begin{macro}[EXP]{\@@_change_case_if_takes_dialytika:n}
-% \begin{macro}[EXP,TF]{\@@_change_case_if_takes_ypogegrammeni:n}
-% \begin{macro}[EXP]{\@@_change_case_if_takes_ypogegrammeni:n}
+% \begin{macro}[EXP,noTF]
+% {
+% \@@_change_case_if_greek:n ,
+% \@@_change_case_if_greek_spacing_diacritic:n ,
+% \@@_change_case_if_greek_accent:n ,
+% \@@_change_case_if_greek_breathing:n ,
+% \@@_change_case_if_greek_stress:n ,
+% \@@_change_case_if_takes_dialytika:n ,
+% \@@_change_case_if_takes_ypogegrammeni:n
+% }
% For Greek uppercasing, we need to know if characters \emph{in the Greek
% range} have accents. That means doing a \textsc{nfd} conversion first, then
% starting a search. As described by the Unicode \textsc{cldr}, Greek accents
@@ -1131,7 +1136,7 @@
{
\bool_lazy_or:nnTF
{ \@@_change_case_if_greek_accent_p:n {#6} }
- { \@@_change_case_if_greek_diacritic_p:n {#6} }
+ { \@@_change_case_if_greek_breathing_p:n {#6} }
{
\@@_change_case_upper_el_ypogegrammeni:nnnnnw
{#1} {#2} {#3} {#4#6} {#5}
@@ -1152,7 +1157,7 @@
\@@_change_case_if_greek_accent:nTF {#4}
{ \@@_change_case_upper_el_hiatus:nnnw {#2} {#3} {#1} }
{
- \@@_change_case_if_greek_diacritic:nTF {#4}
+ \@@_change_case_if_greek_breathing:nTF {#4}
{ \@@_change_case_upper_el:nnn {#1} {#2} {#3} }
{
\@@_codepoint_compare:nNnTF {#4} = { "0345 }
@@ -1162,15 +1167,24 @@
\@@_change_case_loop:nnw {#2} {#3}
}
{
- \@@_change_case_store:e
- { \@@_change_case_codepoint:nn { upper } {#1} }
- \@@_change_case_loop:nnw {#2} {#3} #4
+ \@@_change_case_if_greek_stress:nTF {#4}
+ {
+ \@@_change_case_store:e
+ { \@@_change_case_upper_el_stress:nn {#1} {#4} }
+ \@@_change_case_loop:nnw {#2} {#3}
+
+ }
+ {
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#1} }
+ \@@_change_case_loop:nnw {#2} {#3} #4
+ }
}
}
}
}
}
-% \end{macrocode}
+% \end{macrocode}
% We handle \emph{dialytika} in parts as it's also needed for the hiatus.
% We know only two letters take it, so we can shortcut here on the second
% part of the tests.
@@ -1247,20 +1261,20 @@
% \begin{macrocode}
\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni:n #1
{
- \int_case:nnF
- { \@@_codepoint_from_chars:Nw #1 }
+ \exp_args:Ne \@@_change_case_generate:n
{
- { "0391 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FBC } }
- { "03B1 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FBC } }
- { "0397 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FCC } }
- { "03B7 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FCC } }
- { "03A9 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FFC } }
- { "03C9 } { \@@_change_case_upper_el_ypogegrammeni_aux:n { "1FFC } }
+ \int_case:nn
+ { \@@_codepoint_from_chars:Nw #1 }
+ {
+ { "0391 } { "1FBC }
+ { "03B1 } { "1FBC }
+ { "0397 } { "1FCC }
+ { "03B7 } { "1FCC }
+ { "03A9 } { "1FFC }
+ { "03C9 } { "1FFC }
+ }
}
- { \@@_change_case_upper_el_ypogegrammeni:n {#1} }
}
-\cs_new:Npn \@@_change_case_upper_el_ypogegrammeni_aux:n #1
- { \codepoint_generate:nn {#1} { \char_value_catcode:n {#1} } }
\cs_new:cpn { @@_change_case_upper_el-x-iota_ypogegrammeni:n } #1
{
\@@_change_case_codepoint:nn { upper } {#1}
@@ -1268,6 +1282,44 @@
{ \char_value_catcode:n { "0399 } }
}
% \end{macrocode}
+% We choose to retain stress diacritics, but we also need to recombine
+% them for pdf\TeX{}. That is handled here.
+% \begin{macrocode}
+\cs_new:Npn \_@@_change_case_upper_el_stress:nn #1#2
+ {
+ \exp_args:Ne \@@_change_case_generate:n
+ {
+ \int_case:nn
+ { \@@_codepoint_from_chars:Nw #2 }
+ {
+ { "0304 }
+ {
+ \int_case:nn { \@@_codepoint_from_chars:Nw #1 }
+ {
+ { "0391 } { "1FB9 }
+ { "03B1 } { "1FB9 }
+ { "0399 } { "1FD9 }
+ { "03B9 } { "1FD9 }
+ { "03A5 } { "1FE9 }
+ { "03C5 } { "1FE9 }
+ }
+ }
+ { "0306 }
+ {
+ \int_case:nn { \@@_codepoint_from_chars:Nw #1 }
+ {
+ { "0391 } { "1FB8 }
+ { "03B1 } { "1FB8 }
+ { "0399 } { "1FD8 }
+ { "03B9 } { "1FD8 }
+ { "03A5 } { "1FE8 }
+ { "03C5 } { "1FE8 }
+ }
+ }
+ }
+ }
+ }
+% \end{macrocode}
% For clearing out trailing combining marks after we have dealt with
% the first one.
% \begin{macrocode}
@@ -1293,7 +1345,7 @@
{
\bool_lazy_or:nnTF
{ \@@_change_case_if_greek_accent_p:n {#3} }
- { \@@_change_case_if_greek_diacritic_p:n {#3} }
+ { \@@_change_case_if_greek_breathing_p:n {#3} }
{ \@@_change_case_upper_el_gobble:nnw {#1} {#2} }
{ \@@_change_case_loop:nnw {#1} {#2} #3 }
}
@@ -1443,13 +1495,31 @@
\fi:
\fi:
}
-\prg_new_conditional:Npnn \@@_change_case_if_greek_diacritic:n
+\prg_new_conditional:Npnn \@@_change_case_if_greek_breathing:n
#1 { TF , p }
{
- \exp_args:Nf \@@_change_case_if_greek_diacritic:n
+ \exp_args:Nf \@@_change_case_if_greek_breathing:n
{ \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
}
-\cs_new:Npn \@@_change_case_if_greek_diacritic:n #1
+\cs_new:Npn \@@_change_case_if_greek_breathing:n #1
+ {
+ \if_int_compare:w #1 = "0313 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \if_int_compare:w #1 = "0314 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\prg_new_conditional:Npnn \@@_change_case_if_greek_stress:n
+ #1 { TF , p }
+ {
+ \exp_args:Nf \@@_change_case_if_greek_stress:n
+ { \int_eval:n { \@@_codepoint_from_chars:Nw #1 } }
+ }
+\cs_new:Npn \@@_change_case_if_greek_stress:n #1
{
\if_int_compare:w #1 = "0304 \exp_stop_f:
\prg_return_true:
@@ -1457,15 +1527,7 @@
\if_int_compare:w #1 = "0306 \exp_stop_f:
\prg_return_true:
\else:
- \if_int_compare:w #1 = "0313 \exp_stop_f:
- \prg_return_true:
- \else:
- \if_int_compare:w #1 = "0314 \exp_stop_f:
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- \fi:
+ \prg_return_false:
\fi:
\fi:
}
@@ -1534,26 +1596,15 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
% \begin{macro}[EXP]
% {\@@_change_case_boundary_upper_el:Nnnw, \@@_change_case_boundary_upper_el-x-iota:Nnnw}
% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnN}
% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnn}
% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnw}
-% \begin{macro}[EXP]{\@@_change_case_boundary_upper_el:nnnN}
-% There is one special case in Greek that needs to be picked up based on
-% being an isolated letter. We do that using a test similar to final sigma,
-% but it has to fire off from the space grabber.
+% There is one things that need special treatment at start start of
+% words in Greek. For an isolated accent \emph{eta},
+% which is handled by seeing if we have exactly one of the affected
+% codepoints followed by a space or brace group.
% \begin{macrocode}
\cs_new:Npn \@@_change_case_boundary_upper_el:Nnnw
#1#2#3#4 \q_@@_recursion_stop
@@ -1585,43 +1636,133 @@
{ \@@_codepoint_compare_p:nNn {#3} = { "1F2A } }
}
{ \@@_change_case_boundary_upper_el:nnnw {#1} {#2} {#3} }
- { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ { \@@_change_case_breathing:nnn {#1} {#2} {#3} }
}
\cs_new:Npn \@@_change_case_boundary_upper_el:nnnw
#1#2#3#4 \q_@@_recursion_stop
{
\tl_if_head_is_N_type:nTF {#4}
- { \@@_change_case_boundary_upper_el:nnnN {#3} }
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
{
\@@_change_case_store:e
{
\codepoint_generate:nn { "0389 }
{ \@@_change_case_catcode:nn {#3} { "0389 } }
}
- \@@_change_case_loop:nnw
+ \@@_change_case_loop:nnw {#1} {#2}
}
- {#1} {#2} #4 \q_@@_recursion_stop
+ #4 \q_@@_recursion_stop
}
-\cs_new:Npn \@@_change_case_boundary_upper_el:nnnN #1#2#3#4
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnn}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnnn}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing:nnnnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnnn}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnnw}
+% \begin{macro}[EXP]{\@@_change_case_breathing_aux:nnN}
+% \begin{macro}[EXP]{\@@_change_case_breathing_dialytika:nnn}
+% In Greek, breathing diacritics are normally dropped when uppercasing:
+% see the code for the general case. However, for the first character
+% of a word, if there is a breather \emph{and} the next character takes
+% a \emph{dialytika}, it needs to be added. We start by checking if
+% the current codepoint is in the Greek range, then decomposing.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_breathing:nnn #1#2#3
{
- \bool_lazy_or:nnTF
- { \token_if_letter_p:N #4 }
- {
- \bool_lazy_and_p:nn
- { \token_if_active_p:N #4 }
- { ! \int_compare_p:nNn {`#4} < { "80 } }
- }
- { \@@_change_case_loop:nnw {#2} {#3} #1#4 }
+ \@@_change_case_if_greek:nTF {#3}
{
- \@@_change_case_store:e
+ \exp_args:Ne \@@_change_case_breathing:nnnn
{
- \codepoint_generate:nn { "0389 }
- { \@@_change_case_catcode:nn {#1} { "0389 } }
+ \codepoint_to_nfd:n
+ { \@@_codepoint_from_chars:Nw #3 }
}
- \@@_change_case_loop:nnw {#2} {#3} #4
+ {#1} {#2} {#3}
}
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ }
+\cs_new:Npn \@@_change_case_breathing:nnnn #1#2#3#4
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_breathing:nnnnw {#2} {#3} {#4} }
+ #1 \q_mark
}
% \end{macrocode}
+% Normal form decomposition will always give between one and three
+% codepoints. Luckily, the two breathing marks (\emph{psili} and
+% \emph{dasia}) will be in a predictable position: last. So we can
+% quickly establish first that there was a change on decomposition,
+% and second if the final resulting codepoint is one of the two we
+% care about.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_breathing:nnnnw #1#2#3#4#5 \q_mark
+ {
+ \tl_if_blank:nTF {#5}
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_breathing:nnnnnw {#1} {#2} {#3} {#4} }
+ #5 \q_mark
+ }
+ }
+\cs_new:Npn \@@_change_case_breathing:nnnnnw #1#2#3#4#5#6 \q_mark
+ {
+ \tl_if_blank:nTF {#6}
+ {
+ \@@_change_case_breathing_aux:nnnnn
+ {#1} {#2} {#3} {#4} {#5}
+ }
+ {
+ \@@_change_case_breathing_aux:nnnnn
+ {#1} {#2} {#3} {#4} {#6}
+ }
+ }
+\cs_new:Npn \@@_change_case_breathing_aux:nnnnn #1#2#3#4#5
+ {
+ \bool_lazy_or:nnTF
+ { \@@_codepoint_compare_p:nNn {#5} = { "0313 } }
+ { \@@_codepoint_compare_p:nNn {#5} = { "0314 } }
+ { \@@_change_case_breathing_aux:nnnw {#1} {#2} {#4} }
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ }
+% \end{macrocode}
+% Now the lookahead can be fired: check the next codepoint and assess
+% whether it takes a \emph{dialytika}. Drop the
+% breathing mark or generate the \emph{dialytika}: the
+% latter is code shared with the general mechanism.
+% \begin{macrocode}
+\cs_new:Npn \@@_change_case_breathing_aux:nnnw #1#2#3#4
+ \q_@@_recursion_stop
+ {
+ \@@_change_case_store:e
+ { \@@_change_case_codepoint:nn { upper } {#3} }
+ \tl_if_head_is_N_type:nTF {#4}
+ { \@@_change_case_breathing_aux:nnN }
+ { \@@_change_case_loop:nnw }
+ {#1} {#2} #4 \q_@@_recursion_stop
+ }
+\cs_new:Npn \@@_change_case_breathing_aux:nnN #1#2#3
+ {
+ \@@_codepoint_process:nN
+ { \@@_change_case_breathing_dialytika:nnn {#1} {#2} } #3
+ }
+\cs_new:Npn \@@_change_case_breathing_dialytika:nnn #1#2#3
+ {
+ \@@_change_case_if_takes_dialytika:nTF {#3}
+ {
+ \@@_change_case_upper_el_dialytika:n {#3}
+ \@@_change_case_loop:nnw {#1} {#2}
+ }
+ { \@@_change_case_loop:nnw {#1} {#2} #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
@@ -1744,7 +1885,7 @@
% \end{macrocode}
% If there was a hit, output the result with the dot-above and move on.
% Otherwise, look for one of the three letters that can take a combining
-% accent: I, J and I-ogonek.
+% accent: I, J nd I-ogonek.
% \begin{macrocode}
\cs_new:Npn \@@_change_case_lower_lt_auxi:nnnn #1#2#3#4
{