diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3text-case.dtx | 299 |
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 { |