diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/xetex/latex/interchar |
Initial commit
Diffstat (limited to 'macros/xetex/latex/interchar')
-rw-r--r-- | macros/xetex/latex/interchar/README | 15 | ||||
-rw-r--r-- | macros/xetex/latex/interchar/interchar.pdf | bin | 0 -> 67551 bytes | |||
-rw-r--r-- | macros/xetex/latex/interchar/interchar.sty | 641 | ||||
-rw-r--r-- | macros/xetex/latex/interchar/interchar.tex | 178 |
4 files changed, 834 insertions, 0 deletions
diff --git a/macros/xetex/latex/interchar/README b/macros/xetex/latex/interchar/README new file mode 100644 index 0000000000..0de6815b56 --- /dev/null +++ b/macros/xetex/latex/interchar/README @@ -0,0 +1,15 @@ + +Package interchar: managing character class schemes of XeTeX +Copyright (C) 2015 Zou Hu <zohooo@yeah.net> + +The package requires LaTeX3 support as provided in the l3kernel and +l3packages bundles. + +Please report bugs, problems, and suggestions via + https://github.com/zohooo/interchar + +The package 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 diff --git a/macros/xetex/latex/interchar/interchar.pdf b/macros/xetex/latex/interchar/interchar.pdf Binary files differnew file mode 100644 index 0000000000..5ffe0337d7 --- /dev/null +++ b/macros/xetex/latex/interchar/interchar.pdf diff --git a/macros/xetex/latex/interchar/interchar.sty b/macros/xetex/latex/interchar/interchar.sty new file mode 100644 index 0000000000..d3c347e4e0 --- /dev/null +++ b/macros/xetex/latex/interchar/interchar.sty @@ -0,0 +1,641 @@ +% % -*- coding: utf-8 -*- +% % Package interchar: managing character class schemes of XeTeX +% % Copyright (C) 2015 Zou Hu <zohooo@yeah.net> +% % +% % Please report bugs, problems, and suggestions via +% % https://github.com/zohooo/interchar +% % +% % This file 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 +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{interchar}[2015/02/17 v0.2 + managing character class schemes of XeTeX] +\RequirePackage{expl3}[2014/05/20] +\RequirePackage{xparse} + +\ExplSyntaxOn + +% Some more scratch variables. +\tl_new:N \l__interchar_a_tl +\tl_new:N \l__interchar_b_tl +\tl_new:N \l__interchar_x_tl +\tl_new:N \l__interchar_y_tl +\tl_new:N \l__interchar_ab_tl +\tl_new:N \l__interchar_xy_tl + +% Generate variants for some functions. +\cs_generate_variant:Nn \clist_concat:NNN { c } +\cs_generate_variant:Nn \int_to_hexadecimal:n { V } +\cs_generate_variant:Nn \prop_get:NnN { cx } +\cs_generate_variant:Nn \prop_item:cn { cx } +\cs_generate_variant:Nn \prop_put:Nnn { cx } +\cs_generate_variant:Nn \tl_if_eq:nnT { Vo } + +% Rename some primitive commands of XeTeX. +\cs_new_eq:NN \xetex_intercharstate:D \XeTeXinterchartokenstate +\cs_new_eq:NN \xetex_newcharclass:D \newXeTeXintercharclass +\cs_new_eq:NN \xetex_charclass:D \XeTeXcharclass +\cs_new_eq:NN \xetex_interchartoks:D \XeTeXinterchartoks + +% Need to update them according to `unicode-letters.tex'. +\clist_new:N \g_interchar_default_classes_clist +\clist_gset:Nn \g_interchar_default_classes_clist { 1, 2, 3, 256 } +\int_new:N \g_interchar_default_newclass_int +\int_gset:Nn \g_interchar_default_newclass_int { 4 } +\clist_new:c { l_interchar_default_chars_0_clist } +\clist_set:cn { l_interchar_default_chars_0_clist } + { + 1-2319, 231C-2328, 232B-23EF, 23F4-25FF, 2604-2613, 2616-2617, 2619, + 2620-2638, 263C-2667, 2669-267E, 2680-26BC, 26C9-26CC, 26CE, 26D2, + 26D5-26D7, 26DA-26DB, 26DD-26DE, 26E2-26E9, 26EB-26F0, 26F6, 26FB-26FC, + 2705-2707, 270E-2E7F, 2E9A, 2EF4-2EFF, 2FD6-2FEF, 2FFC-3000, 3040-3041, + 3043, 3045, 3047, 3049, 3063, 3083, 3085, 3087, 308E, 3095-3098, 30A1, 30A3, + 30A5, 30A7, 30A9, 30C3, 30E3, 30E5, 30E7, 30EE, 30F5-30F6, 30FC, 3100-3104, + 312E-3130, 318F, 31BB-31BF, 31E4-31FF, 321F, 3248-324F, 32FF, 4DC0-4DFF, + A48D-A48F, A4C7-F8FF, FB00-FE0F, FE19-FE2F, FE53, FE67, FE69-FE6A, + FE6C-FF00, FF04-FF05, FF66-FF9D, FFA0-FFE1, FFE5-FFFD + } +\clist_new:c { l_interchar_default_chars_1_clist } +\clist_set:cn { l_interchar_default_chars_1_clist } + { + 231A-231B, 23F0-23F3, 2600-2603, 2614-2615, 2618, 261A-261F, 2639-263B, + 2668, 267F, 26BD-26C8, 26CD, 26CF-26D1, 26D3-26D4, 26D8-26D9, 26DC, + 26DF-26E1, 26EA, 26F1-26F5, 26F7-26FA, 26FD-2704, 2708-270D, 2E80-2E99, + 2E9B-2EF3, 2F00-2FD5, 2FF0-2FFB, 3003-3004, 3006-3007, 3012-3013, 3020-3029, + 3030-3034, 3036-303A, 303D-303F, 3042, 3044, 3046, 3048, 304A-3062, + 3064-3082, 3084, 3086, 3088-308D, 308F-3094, 309F, 30A2, 30A4, 30A6, 30A8, + 30AA-30C2, 30C4-30E2, 30E4, 30E6, 30E8-30ED, 30EF-30F4, 30F7-30FA, 30FF, + 3105-312D, 3131-318E, 3190-31BA, 31C0-31E3, 3200-321E, 3220-3247, 3250-32FE, + 3300-4DBF, 4E00-A014, A016-A48C, A490-A4C6, F900-FAFF, FE30-FE34, FE45-FE46, + FE49-FE4F, FE51, FE58, FE5F-FE66, FE68, FE6B, FF02-FF03, FF06-FF07, + FF0A-FF0B, FF0D, FF0F-FF19, FF1C-FF1E, FF20-FF3A, FF3C, FF3E-FF5A, FF5C, + FF5E, FFE2-FFE4, 1B000-1B001, 1F000-1F02B, 1F030-1F093, 1F0A0-1F0AE, + 1F0B1-1F0BF, 1F0C1-1F0CF, 1F0D1-1F0F5, 1F200-1F202, 1F210-1F23A, + 1F240-1F248, 1F250-1F251, 1F300-1F32C, 1F330-1F37D, 1F380-1F39B, + 1F39E-1F3B4, 1F3B7-1F3BB, 1F3BD-1F3CE, 1F3D4-1F3F7, 1F400-1F49F, 1F4A1, + 1F4A3, 1F4A5-1F4AE, 1F4B0, 1F4B3-1F4FE, 1F507-1F516, 1F525-1F531, 1F54A, + 1F550-1F579, 1F57B-1F5A3, 1F5A5-1F5D3, 1F5DC-1F5F3, 1F5FA-1F642, + 1F645-1F64F, 1F680-1F6CF, 1F6E0-1F6EC, 1F6F0-1F6F3, + } +\clist_new:c { l_interchar_default_chars_2_clist } +\clist_set:cn { l_interchar_default_chars_2_clist } + { + 2329, 3008, 300A, 300C, 300E, 3010, 3014, 3016, 3018, 301A, 301D, FE17, + FE35, FE37, FE39, FE3B, FE3D, FE3F, FE41, FE43, FE47, FE59, FE5B, FE5D, + FF08, FF3B, FF5B, FF5F, FF62 + } +\clist_new:c { l_interchar_default_chars_3_clist } +\clist_set:cn { l_interchar_default_chars_3_clist } + { + 232A, 3001-3002, 3005, 3009, 300B, 300D, 300F, 3011, 3015, 3017, 3019, + 301B-301C, 301E-301F, 303B-303C, 309B-309E, 30A0, 30FB, 30FD-30FE, A015, + FE10-FE16, FE18, FE36, FE38, FE3A, FE3C, FE3E, FE40, FE42, FE44, FE48, FE50, + FE52, FE54-FE57, FE5A, FE5C, FE5E, FF01, FF09, FF0C, FF0E, FF1A-FF1B, FF1F, + FF3D, FF5D, FF60-FF61, FF63-FF65, FF9E-FF9F + } +\clist_set:cn { l_interchar_default_chars_256_clist } + { + 302A-302F, 3035, 3099-309A + } +\prop_new:N \l_interchar_default_toks_prop +\prop_put:Nnn \l_interchar_default_toks_prop {0~1} {\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {0~2} {\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {0~3} {\nobreak\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {1~0} {\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {2~0} {\nobreak\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {3~0} {\xtxHanSpace} +\prop_put:Nnn \l_interchar_default_toks_prop {1~1} {\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {1~2} {\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {1~3} {\nobreak\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {2~1} {\nobreak\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {2~2} {\nobreak\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {2~3} {\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {3~1} {\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {3~2} {\xtxHanGlue} +\prop_put:Nnn \l_interchar_default_toks_prop {3~3} {\nobreak\xtxHanGlue} + +% Create a new interchar scheme for each package. +\msg_new:nnn { interchar } { Empty-Argument } + { + The~argument~should~not~be~empty! + } + +\tl_new:N \l_interchar_current_scheme_tl +\tl_set:Nn \l_interchar_current_scheme_tl {default} + +\NewDocumentCommand \newintercharscheme { m } + { + \tl_if_empty:nT {#1} { \msg_critical:nn { interchar } { Empty-Argument } } + \clist_new:c { g_interchar_#1_classes_clist } + \clist_gset:cn { g_interchar_#1_classes_clist } { 1, 2, 3 } + \int_new:c { g_interchar_#1_newclass_int } + \int_gset:cn { g_interchar_#1_newclass_int } { 4 } + \clist_new:c { l_interchar_#1_chars_1_clist } + \clist_new:c { l_interchar_#1_chars_2_clist } + \clist_new:c { l_interchar_#1_chars_3_clist } + \prop_new:c { l_interchar_#1_toks_prop } + % Used for migrating from XeTeX's primitive commands + \interchar@migration { #1 } + } + +% High level |\intercharstate| command. +% #1: scheme name; #2: state code. +\NewDocumentCommand \intercharstate { O{default} m } + { + \interchar_state:nn {#1} {#2} + } +\cs_new_protected_nopar:Npn \interchar_state:nn #1#2 + { + \__interchar_clear_toks:V \l_interchar_current_scheme_tl + \clist_map_inline:Nn \g_interchar_default_classes_clist + { \__interchar_apply_class:nn {default} {##1} } + \__interchar_apply_class:nn {default} {0} + \__interchar_apply_toks:n {default} + \int_compare:nTF { #2 > 0 } + { + \clist_map_inline:cn { g_interchar_#1_classes_clist } + { \__interchar_apply_class:nn {#1} {##1} } + \__interchar_apply_toks:n {#1} + % Use \tl_set:Nx rathar than \tl_set:Nn here + \tl_set:Nx \l_interchar_current_scheme_tl {#1} + } + { \tl_set:Nn \l_interchar_current_scheme_tl {default} } + } +\cs_generate_variant:Nn \interchar_state:nn { VV } + +% #1: scheme name; #2: class number. +\cs_new_protected_nopar:Npn \__interchar_apply_class:nn #1#2 + { + \clist_map_inline:cn + { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } + { + \__interchar_class_split_range:nNN {##1} \l_tmpa_tl \l_tmpb_tl + \int_set:Nn \l_tmpa_int { "\l_tmpa_tl } + \int_set:Nn \l_tmpb_int { "\l_tmpb_tl } + \int_while_do:nn { \l_tmpa_int <= \l_tmpb_int } + { + \xetex_charclass:D \l_tmpa_int = #2 + \int_incr:N \l_tmpa_int + } + } + } + +% #1: scheme name. +\cs_new_protected_nopar:Npn \__interchar_apply_toks:n #1 + { + \prop_map_inline:cn { l_interchar_#1_toks_prop } + { \xetex_interchartoks:D ##1 = {##2} } + } + +% #1: scheme name. +\cs_new_protected_nopar:Npn \__interchar_clear_toks:n #1 + { + \prop_map_inline:cn { l_interchar_#1_toks_prop } + { \xetex_interchartoks:D ##1 = {} } + } +\cs_generate_variant:Nn \__interchar_clear_toks:n { V } + +% High level |\getintercharstate| command. +% #1: scheme name; #2 result control sequence. +\DeclareDocumentCommand \getintercharstate { O{default} m } + { + \interchar_get_state:nN {#1} {#2} + } +\cs_new_protected_nopar:Npn \interchar_get_state:nN #1#2 + { + \tl_set:Nx #2 { \interchar_get_state:n {#1} } + } + +% #1: scheme name. This function is fully expandable. +\cs_new_nopar:Npn \interchar_get_state:n #1 + { + \str_if_eq:VnTF \l_interchar_current_scheme_tl { #1 } { 1 } { 0 } + } + +% High level |\intercharnewclass| command. +% #1: scheme name; #2: control sequence for class number. +\NewDocumentCommand \newintercharclass { O{default} m} + { + \interchar_newclass:nn { #1 } { #2 } + } +\cs_new_protected_nopar:Npn \interchar_newclass:nn #1#2 + { + \int_set:Nn \l_tmpa_int { \int_use:N \use:c {g_interchar_#1_newclass_int} } + \int_new:N #2 + \int_set_eq:NN #2 \l_tmpa_int + \clist_put_right:co {g_interchar_#1_classes_clist} {\int_use:N \l_tmpa_int} + \clist_new:c { l_interchar_#1_chars_ \int_use:N\l_tmpa_int _clist } + \int_incr:c { g_interchar_#1_newclass_int } + } + +% High level |\intercharclass| command. +% #1: scheme name; #2: char range; #3: class number. +\NewDocumentCommand \intercharclass { O{default} m m } + { + \interchar_class:nnn {#1} {#2} {#3} + } +\bool_new:N \g__interchar_class_delete_char_bool +\cs_new_protected_nopar:Npn \interchar_class:nnn #1#2#3 + { + \int_compare:nT { #3 > 0 } + { + \int_set:Nn \l_tmpa_int {#3} + \clist_if_in:coF {g_interchar_#1_classes_clist} + { \int_use:N \l_tmpa_int } + { + \clist_put_right:co { g_interchar_#1_classes_clist } + { \int_use:N\l_tmpa_int } + \clist_new:c + { l_interchar_#1_chars_ \int_use:N\l_tmpa_int _clist } + } + \__interchar_class_insert_char:nnn {#1} {#3} {#2} + } + \bool_set_false:N \g__interchar_class_delete_char_bool + \clist_map_inline:cn {g_interchar_#1_classes_clist} + { + \int_compare:nT { #3 != ##1 } + { + \bool_if:NTF \g__interchar_class_delete_char_bool + { \clist_map_break: } + { \__interchar_class_delete_char:nnn {#1} {##1} {#2} } + } + } + } +\cs_generate_variant:Nn \interchar_class:nnn { VVV } + +% High level |\getintercharclass| command. +% #1: scheme name; #2: char code; #3: result control sequence. +\DeclareDocumentCommand \getintercharclass { O{default} m m } + { + \interchar_get_class:nnN {#1} {#2} {#3} + } +\cs_new_protected_nopar:Npn \interchar_get_class:nnN #1#2#3 + { + \tl_set:Nx #3 { \interchar_get_class:nn {#1} {#2} } + } + +% #1: scheme name; #2: char code. +% This function is fully expandable. +\cs_new_nopar:Npn \interchar_get_class:nn #1#2 + { + \__interchar_get_class_aux:vNnn { g_interchar_#1_classes_clist } + \__interchar_class_find_char:nnn {#1} {#2} + } +\cs_generate_variant:Nn \interchar_get_class:nn { VV } +\cs_new_nopar:Npn \__interchar_get_class_aux:nNnn #1#2#3#4 + { + \__interchar_get_class_loop:Nnnw #2 {#3} {#4} + #1 , \q_recursion_tail , \q_recursion_stop + } +\cs_generate_variant:Nn \__interchar_get_class_aux:nNnn { v } +\cs_new_nopar:Npn \__interchar_get_class_loop:Nnnw #1#2#3#4 , + { + \quark_if_recursion_tail_stop:n {#4} + #1 {#2} {#4} {#3} + \__interchar_get_class_loop:Nnnw #1 {#2} {#3} + } + +% #1: scheme name; #2: class number; #3: char code. +\cs_new_nopar:Npn \__interchar_class_find_char:nnn #1#2#3 + { + \__interchar_class_find_char_aux:vnn {l_interchar_#1_chars_#2_clist} {#2} {#3} + } +\cs_new_nopar:Npn \__interchar_class_find_char_aux:nnn #1#2#3 + { + \__interchar_class_find_char_loop:nnw {#2} {#3} + #1 , \q_recursion_tail , \q_recursion_stop + } +\cs_generate_variant:Nn \__interchar_class_find_char_aux:nnn { v } +\cs_new_nopar:Npn \__interchar_class_find_char_loop:nnw #1#2#3 , + { + \quark_if_recursion_tail_stop:n {#3} + \int_case:nn { \__interchar_class_compare_char:nn {#2} {#3} } + { + { -1 } { \use_none_delimit_by_q_recursion_stop:w } + { 0 } { #1 % found the char in class #1, stop two level loops + \use_i_delimit_by_q_recursion_stop:nw + { \use_none_delimit_by_q_recursion_stop:w } + } + } + \__interchar_class_find_char_loop:nnw {#1} {#2} + } + +% #1: char code; #2 char code or char range in Hex form. +% result: -1 if #1 before #2; 1 if #1 after #2; 0 otherwise. +\cs_new_nopar:Npn \__interchar_class_compare_char:nn #1#2 + { + \__interchar_class_compare_char_aux:www #1 - #2 - - \q_stop + } +\cs_new_nopar:Npn \__interchar_class_compare_char_aux:www #1 - #2 - #3 - + { + \tl_if_empty:nTF { #3 } + { + \int_compare:nTF { #1 = "#2 } + { 0 } { \int_compare:nTF { #1 < "#2 } { -1 } { 1 } } + } + { + \int_compare:nTF { "#2 <= #1 <= "#3 } + { 0 } { \int_compare:nTF { #1 < "#2 } { -1 } { 1 } } + } + \__interchar_class_compare_char_stop:w + } +\cs_new_nopar:Npn \__interchar_class_compare_char_stop:w #1 \q_stop {} + +% #1: scheme name; #2: class number; #3 char range. +\cs_new_protected_nopar:Npn \__interchar_class_insert_char:nnn #1#2#3 + { + % store all char ranges before #3 + \clist_clear:N \l_tmpa_clist + % store all char ranges after #3 + \clist_set_eq:Nc + \l_tmpb_clist { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } + \__interchar_class_split_range:nNN {#3} \l__interchar_a_tl \l__interchar_b_tl + \tl_set:Nx \l_tmpa_tl { \int_to_hexadecimal:V \l__interchar_a_tl } + \tl_set:Nx \l_tmpb_tl { \int_to_hexadecimal:V \l__interchar_b_tl } + % if correct position found + \bool_set_false:N \l_tmpa_bool + \bool_do_until:Nn \l_tmpa_bool + { + \tl_if_empty:NTF \l_tmpb_clist + { \bool_set_true:N \l_tmpa_bool } + { + \clist_pop:NN \l_tmpb_clist \l__interchar_xy_tl + \exp_args:NV \__interchar_class_split_range:nNN + { \l__interchar_xy_tl } \l__interchar_x_tl \l__interchar_y_tl + \int_compare:nTF { "\l__interchar_y_tl < "\l_tmpa_tl - 1 } + { + % left + \clist_put_right:NV \l_tmpa_clist \l__interchar_xy_tl + } + { + \int_compare:nTF { "\l__interchar_x_tl > "\l_tmpb_tl + 1} + { + % right + \clist_put_left:NV \l_tmpb_clist \l__interchar_xy_tl + \bool_set_true:N \l_tmpa_bool + } + { + % middle + \int_compare:nT { "\l__interchar_x_tl < "\l_tmpa_tl } + { \tl_set_eq:NN \l_tmpa_tl \l__interchar_x_tl } + \int_compare:nT { "\l__interchar_y_tl > "\l_tmpb_tl } + { \tl_set_eq:NN \l_tmpb_tl \l__interchar_y_tl } + } + } + } + } + \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl + { \tl_set_eq:NN \l__interchar_ab_tl \l_tmpa_tl } + { \tl_set:Nx \l__interchar_ab_tl { \l_tmpa_tl - \l_tmpb_tl } } + \clist_put_right:NV \l_tmpa_clist \l__interchar_ab_tl + \clist_concat:cNN { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } + \l_tmpa_clist \l_tmpb_clist + } + +% #1: scheme name; #2: class number; #3: char range. +\cs_new_protected_nopar:Npn \__interchar_class_delete_char:nnn #1#2#3 + { + % store all char ranges before #3 + \clist_clear:N \l_tmpa_clist + % store all char ranges after #3 + \clist_set_eq:Nc + \l_tmpb_clist { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } + \__interchar_class_split_range:nNN {#3} \l__interchar_a_tl \l__interchar_b_tl + \tl_set:Nx \l_tmpa_tl { \int_to_hexadecimal:V \l__interchar_a_tl } + \tl_set:Nx \l_tmpb_tl { \int_to_hexadecimal:V \l__interchar_b_tl } + % if correct position found + \bool_set_false:N \l_tmpa_bool + \bool_do_until:Nn \l_tmpa_bool + { + \tl_if_empty:NTF \l_tmpb_clist + { \bool_set_true:N \l_tmpa_bool } + { + \clist_pop:NN \l_tmpb_clist \l__interchar_xy_tl + \exp_args:NV \__interchar_class_split_range:nNN + { \l__interchar_xy_tl } \l__interchar_x_tl \l__interchar_y_tl + \int_compare:nTF { "\l__interchar_y_tl < "\l_tmpa_tl} + { + % left + \clist_put_right:NV \l_tmpa_clist \l__interchar_xy_tl + } + { + \int_compare:nTF { "\l__interchar_x_tl > "\l_tmpb_tl} + { + % right + \clist_put_left:NV \l_tmpb_clist \l__interchar_xy_tl + \bool_set_true:N \l_tmpa_bool + } + { + % middle: put [x,a-1] and [b+1,y] into clist + \int_compare:nTF { "\l_tmpa_tl - "\l__interchar_x_tl = 1 } + { + \clist_put_right:NV \l_tmpa_clist \l__interchar_x_tl + } + { + \int_compare:nT { "\l_tmpa_tl - "\l__interchar_x_tl > 1 } + { + \tl_set:Nx \l__interchar_z_tl + { \int_to_hexadecimal:n { "\l_tmpa_tl - 1 } } + \clist_put_right:Nx \l_tmpa_clist + { \l__interchar_x_tl - \l__interchar_z_tl } + } + } + \int_compare:nTF { "\l__interchar_y_tl - "\l_tmpb_tl = 1 } + { + \clist_put_right:NV \l_tmpa_clist \l__interchar_y_tl + } + { + \int_compare:nT { "\l__interchar_y_tl - "\l_tmpb_tl > 1 } + { + \tl_set:Nx \l__interchar_z_tl + { \int_to_hexadecimal:n { "\l_tmpb_tl + 1 } } + \clist_put_right:Nx \l_tmpa_clist + { \l__interchar_z_tl - \l__interchar_y_tl } + } + } + \tl_if_eq:NNT \l_tmpa_tl \l_tmpb_tl + { \bool_set_true:N \g__interchar_class_delete_char_bool } + } + } + } + } + \clist_concat:cNN { l_interchar_#1_chars_ \int_to_arabic:n{#2} _clist } + \l_tmpa_clist \l_tmpb_clist + } + +% Split #1 with - and put the results into #2 and #3. +\NewDocumentCommand \__interchar_class_split_range:nNN + { > { \SplitArgument { 1 } { - } } m m m} + { + \tl_set:No #2 { \use_i:nn #1} + \tl_set:No #3 { \use_ii:nn #1} + \exp_args:No \IfNoValueT {#3} { \tl_set_eq:NN #3 #2 } + } + +% High level |\interchartoks| command. +% #1: scheme name; #2 and #3: class numbers; #4: tokens. +\NewDocumentCommand \interchartoks { O{default} m m +m } + { + \interchar_toks:nnnn {#1} {#2} {#3} {#4} + } +\cs_new_protected_nopar:Npn \interchar_toks:nnnn #1#2#3#4 + { + \int_set:Nn \l_tmpa_int {#2} + \int_set:Nn \l_tmpb_int {#3} + \prop_put:cxn { l_interchar_#1_toks_prop } + { \int_use:N \l_tmpa_int \c_space_tl \int_use:N \l_tmpb_int } + { #4 } + \tl_if_eq:VoT \l_interchar_current_scheme_tl { #1 } + { + \xetex_interchartoks:D \l_tmpa_int \l_tmpb_int = { #4 } + } + } +\cs_generate_variant:Nn \interchar_toks:nnnn { VVVV } + +% #1: scheme name; #2 and #3: class numbers; #4: result control sequence. +\DeclareDocumentCommand \getinterchartoks { O{default} m m m } + { + \interchar_get_toks:nnnN {#1} {#2} {#3} {#4} + } +\cs_new_protected_nopar:Npn \interchar_get_toks:nnnN #1#2#3#4 + { + \int_set:Nn \l_tmpa_int {#2} + \int_set:Nn \l_tmpb_int {#3} + \prop_get:cxN { l_interchar_#1_toks_prop } + { \int_use:N \l_tmpa_int \c_space_tl \int_use:N \l_tmpb_int } #4 + \quark_if_no_value:NT #4 { \tl_clear:N #4 } + } + +% #1: scheme name; #2 and #3: class numbers. +% This function is fully expandable. +% If #2 or #3 is a control sequence generated from `\newintercharclass', +% use the following function variants instead. +\cs_new_nopar:Npn \interchar_get_toks:nnn #1#2#3 + { + \prop_item:cn { l_interchar_#1_toks_prop } { #2 ~ #3 } + } +\cs_generate_variant:Nn \interchar_get_toks:nnn { nVn, nnV, nVV, VVV } + +\xetex_intercharstate:D = 1 + +\ExplSyntaxOff + +% We need to call LaTeX3 functions. +\catcode `\_ = 11 \catcode `\: = 11 + +% From now on, we use `\newcommand' for commands, `\def' for variables. + +% First we define some variables. +\def\interchar@scheme@name@tl{} +\def\interchar@c@tl{} +\def\interchar@tmpa@int{} +\def\interchar@tmpb@int{} +\def\interchar@tmpa@tl{} + +% Switch between getting and setting values. +\newif\ifinterchar@get + +% Used for migrating from XeTeX's primitive commands. +\let \NewIntercharScheme = \newintercharscheme + +% #1: scheme name. +\newcommand\interchar@migration[1]{% + \expandafter\def\expandafter\interchar@c@tl\expandafter{\tl_upper_case:n #1}% + \expandafter\newcommand\csname\interchar@c@tl IntercharState\endcsname{% + \def\interchar@scheme@name@tl{#1}% + \interchar@state@auxi + }% + \expandafter\newcommand\csname Get\interchar@c@tl IntercharState\endcsname{% + \interchar_get_state:n{#1}% + }% + \expandafter\newcommand\csname New\interchar@c@tl IntercharClass\endcsname[1]{% + \interchar_newclass:nn {#1} {##1}% + }% + \expandafter\newcommand\csname\interchar@c@tl IntercharClass\endcsname{% + \def\interchar@scheme@name@tl{#1}% + \interchar@class@auxi + }% + \expandafter\newcommand\csname Get\interchar@c@tl IntercharClass\endcsname{% + \def\interchar@scheme@name@tl{#1}% + \interchar@gettrue + \interchar@class@auxi + }% + \expandafter\newcommand\csname\interchar@c@tl IntercharToks\endcsname{% + \def\interchar@scheme@name@tl{#1}% + \interchar@toks@auxi + }% + \expandafter\newcommand\csname Get\interchar@c@tl IntercharToks\endcsname{% + \def\interchar@scheme@name@tl{#1}% + \interchar@gettrue + \interchar@toks@auxi + }% +} + +% Commands for scanning number or toks arguments. +\newcommand\interchar@scan@number[1]{% + \afterassignment#1\count255 % +} +\newcommand\interchar@scan@number@x[1]{% + \afterassignment#1\count255=% +} +\newcommand\interchar@scan@toks[1]{% + \afterassignment#1\toks0 % +} + +% Scanning arguments of `\FOOinterchartokenstate' command. +\newcommand\interchar@state@auxi{% + \interchar@scan@number \interchar@state@auxii +} +\newcommand\interchar@state@auxii{% + \edef\interchar@tmpa@int{\the\count255}% + \interchar_state:VV \interchar@scheme@name@tl \interchar@tmpa@int +} + +% Scanning arguments of `\FOOcharclass' command. +\newcommand\interchar@class@auxi{% + \interchar@scan@number@x \interchar@class@auxii +} +\newcommand\interchar@class@auxii{% + \edef\interchar@tmpa@int{\the\count255}% + \ifinterchar@get + \interchar@getfalse + \interchar_get_class:VV \interchar@scheme@name@tl \interchar@tmpa@int + \else + \interchar@scan@number \interchar@class@auxiii + \fi +} +\newcommand\interchar@class@auxiii{% + \edef\interchar@tmpb@int{\the\count255}% + \interchar_class:VVV \interchar@scheme@name@tl + \interchar@tmpa@int \interchar@tmpb@int +} + +% Scanning arguments of `\FOOinterchartoks' and `\getFOOinterchartoks' command. +\newcommand\interchar@toks@auxi{% + \interchar@scan@number@x \interchar@toks@auxii +} +\newcommand\interchar@toks@auxii{% + \edef\interchar@tmpa@int{\the\count255}% + \interchar@scan@number@x \interchar@toks@auxiii +} +\newcommand\interchar@toks@auxiii{% + \edef\interchar@tmpb@int{\the\count255}% + \ifinterchar@get + \interchar@getfalse + \interchar_get_toks:VVV \interchar@scheme@name@tl + \interchar@tmpa@int \interchar@tmpb@int + \else + \interchar@scan@toks \interchar@toks@auxiv + \fi +} +\newcommand\interchar@toks@auxiv{% + \edef\interchar@tmpa@tl{\the\toks0}% + \interchar_toks:VVVV \interchar@scheme@name@tl + \interchar@tmpa@int \interchar@tmpb@int \interchar@tmpa@tl +} + +% Recover catcode changes. +\catcode `\_ = 8 \catcode `\: = 12 diff --git a/macros/xetex/latex/interchar/interchar.tex b/macros/xetex/latex/interchar/interchar.tex new file mode 100644 index 0000000000..641d9f0c60 --- /dev/null +++ b/macros/xetex/latex/interchar/interchar.tex @@ -0,0 +1,178 @@ +% -*- coding: utf-8 -*- +% Package interchar: managing character class schemes of XeTeX +% Copyright (C) 2015 Zou Hu <zohooo@yeah.net> +% +% Please report bugs, problems, and suggestions via +% https://github.com/zohooo/interchar +% +% This file 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 +\documentclass{article} +\usepackage[b5paper,margin=17mm]{geometry} +\usepackage{xcolor,hyperref,float,makedoc,niceverb,interchar} +\hypersetup{ + colorlinks, + citecolor = teal, + linkcolor = blue, + urlcolor = purple, + pdfstartview = {FitH}, + bookmarksnumbered +} +\begin{document} + +\title{Documentation for package \texttt{interchar} +\footnote{Version 0.2. Please report bugs via \url{https://github.com/zohooo/interchar}.}} +\author{Zou Hu (zohooo@yeah.net)} +\maketitle +\tableofcontents + +\section{Introduction} + +With XeTeX\rq s character class mechanism, we could put characters into different classes, +and insert some tokens to the input stream between characters in one class and those in +another class. This mechanism is originally used for switching fonts and adjusting spaces. +But it has many other useful applications. + +By default, all characters are of class 0, except CJK ideographs are of class 1, CJK left +punctuation of class 2, CJK right punctuation of class 3, text boundaries (glues, kerns, +maths, boxes, etc.) of class 255, and several characters of class 256 (this class is ignored). + +\MakeNormal\` +\newintercharclass{\myclass} +\intercharclass{`\o}{\myclass} +\interchartoks{0}{\myclass}{\bgroup\color{red}} +\interchartoks{255}{\myclass}{\bgroup\color{red}} +\interchartoks{\myclass}{0}{\egroup} +\interchartoks{\myclass}{255}{\egroup} +\intercharstate{1} +\MakeActive\` +Package 'interchar' is written for making character class mechanism more easy to use. For example, +after loading the package with `\usepackage{interchar}', you may change the color of every +occurrences of character \texttt{o}: +\intercharstate[foo]{0} +\begin{verbatim} +\newintercharclass{\myclass} +\intercharclass{`\o}{\myclass} +\interchartoks{0}{\myclass}{\bgroup\color{red}} +\interchartoks{255}{\myclass}{\bgroup\color{red}} +\interchartoks{\myclass}{0}{\egroup} +\interchartoks{\myclass}{255}{\egroup} +\intercharstate{1} +\end{verbatim} + +There are some existing packages using this mechanism, such as 'polyglossia', 'xeCJK' and +'xesearch'. But since one character could only be put into one single class, when loading two +or more of these packages simultaneously, it would be very likely that some conflicts occur. + +Package 'interchar' also provides some migration commands for these packages. With minor changes +these packages should be compatible with 'interchar', and users could switch between different +character class schemes when loading these packages at the same time. + +\section{Commands for normal users} + +\begin{itemize} + \item |\newintercharscheme{<scheme>}| creates a new char class scheme. For example, + \begin{verbatim}\newintercharscheme{foo}\end{verbatim} + There is a prebuilt `default' scheme which you need not to create it. + The first argument of the other commands in this section is optional; + its default value is `default'. + \item |\intercharstate[<scheme>]{<state-code>}| changes current scheme. + If '<state-code>' is positive, changes current scheme to `<scheme>'; + otherwise, changes current scheme to `default'. For example, + \begin{verbatim}\intercharstate[foo]{1}\end{verbatim} + \item |\getintercharstate[<scheme>]{\cs}| gets current state of the specified scheme + and store the state code in `\cs'. For example, + \begin{verbatim}\getintercharstate[foo]{\mystate}\end{verbatim} + \item |\newintercharclass[<scheme>]{\cs}| creates a new char class in the specified scheme + and stores the class number in `\cs'. For example, + \begin{verbatim}\newintercharclass[foo]{\myclass}\end{verbatim} + \item |\intercharclass[<scheme>]{<char-range>}{<char-class>}| moves all characters within + `<char-range>' to the class `<char-class>' in the specified scheme. For example, +\begin{verbatim} +\intercharclass[foo]{`\@}{255} +\intercharclass[foo]{`\a-`\z}{\myclass} +\end{verbatim} + \item |\getintercharclass[<scheme>]{<char-code>}{\cs}| gets the class number of the specified + character in the specified scheme, and stores the result in `\cs'. For example, + \begin{verbatim}\getintercharclass[foo]{`\@}{\result}\end{verbatim} + \item |\interchartoks[<scheme>]{<char-class-1>}{<char-class-2>}{<tokens>}| defines tokens to be + inserted between `<char-class-1>' and `<char-class-2>' (in that order) in the specified + scheme. For example, +\begin{verbatim} +\interchartoks[foo]{0}{\myclass}{\bgroup\color{red}} +\interchartoks[foo]{\myclass}{0}{\egroup} +\end{verbatim} + \item |\getinterchartoks[<scheme>]{<char-class-1>}{<char-class-2>}{\cs}| gets the tokens to be + inserted between `<char-class-1>' and `<char-class-2>' in the specified scheme, and stores + the result in `\cs'. For example, + \begin{verbatim}\getinterchartoks[foo]{0}{\myclass}{\mytoks}\end{verbatim} +\end{itemize} + +\section{Commands for macro writers} + +For macro writers, we provide |\NewIntercharScheme| command which is an alias of user command `\newintercharscheme'. When you write `\NewIntercharScheme{foo}', 'interchar' package also +creates the following migration commands for you: + +\begin{table}[H] +\MakeNormal\& \MakeNormal\` \MakeNormal\| \catcode`\?=13 \let?=| \MakeActive\` \MakeActive\| +\renewcommand{\arraystretch}{1.4} +\begin{tabular}{?l?l?} + \hline + \textbf{Migration Command} & \textbf{Analogous to Commands} \\ \hline + |\FooIntercharState = <state-code>| & `\XeTeXinterchartokenstate' \\ + |\GetFooIntercharState| & `\the\XeTeXinterchartokenstate' \\ + |\NewFooIntercharClass <control-sequence>| & `\newXeTeXintercharclass' \\ + |\FooIntercharClass <char-code> = <char-class>| & `\XeTeXcharclass' \\ + |\GetFooIntercharClass <char-code>| & `\the\XeTeXcharclass'. \\ + |\FooIntercharToks <class1> <class2> = {<toks>}| & `\XeTeXinterchartoks' \\ + |\GetFooIntercharToks <class1> <class2>| & `\the\XeTeXinterchartoks' \\ + \hline +\end{tabular} +\end{table} + +Within the command specifications in the above table, all of the equal signs `=' +and most of the spaces are optional. + +If you are the author of package 'foo' which use XeTeX\rq s char class mechanism, +with some minor changes you could make your package compatible with other packages. + +\begin{enumerate} + \item Add the following lines to the beginning of your package file: +\begin{verbatim} +\ifdefined\NewIntercharScheme + \NewIntercharScheme{foo}% +\else + \let \FooIntercharState = \XeTeXinterchartokenstate + \def \GetFooIntercharState {\the\XeTeXinterchartokenstate}% + \let \NewFooIntercharClass = \newXeTeXintercharclass + \let \FooIntercharClass = \XeTeXcharclass + \def \GetFooIntercharClass {\the\XeTeXcharclass}% + \let \FooIntercharToks = \XeTeXinterchartoks + \def \GetFooIntercharToks {\the\XeTeXinterchartoks}% +\fi +\end{verbatim} + \item Rename every occurrence of XeTeX\rq s commands in your package file with the new name + according to the above table. +\end{enumerate} + +After these modifications, when users doesn\rq t load 'interchar', your package should +behave as before, but when users load 'interchar' package \textbf{before} your package, +'interchar' will takes over XeTeX\rq s char class mechanism, therefore users could switch +among different char class schemes at will. + +Note that `\GetFooIntercharState' is \textbf{fully expandable}, which means you could write +the following conditional test: +\begin{verbatim}\ifnum \GetFooIntercharState > 0 doA \else doB \fi\end{verbatim} +However `\GetFooIntercharClass' and `\GetFooIntercharToks' are +\textbf{not fully expandable} for the time being. + +\section{Implementation} + +%\AutoCmdSyntaxVerb +\NoEmptyCodeLines +\MakeInputJobDoc[sty][ltx]{0}{\ProcessInputWith{PScomment}} + +\end{document} |