% % ***************** THE SPBMARK PACKAGE ***************** % % Copyright (C) 2021-2024 by Qu Yi % % This work may be distributed and/or modified under the % conditions of the CC-BY 4.0 License. % The latest version of this license is in % https://creativecommons.org/licenses/by/4.0/legalcode \NeedsTeXFormat{LaTeX2e}[2018/12/31] \RequirePackage{xparse} \ProvidesExplPackage{spbmark}{2024/12/08}{1.46w} {Customize superscripts and subscripts} \cs_generate_variant:Nn \box_set_ht:Nn { cv } \cs_generate_variant:Nn \box_set_dp:Nn { cv } \cs_generate_variant:Nn \dim_max:nn { VV } \cs_generate_variant:Nn \dim_gset:Nn { Nv } \cs_generate_variant:Nn \dim_abs:n { V,v } \cs_generate_variant:Nn \dim_compare:nNnTF { V,v } \cs_generate_variant:Nn \str_case:nn { x } \cs_generate_variant:Nn \tl_if_novalue:nF { V } \cs_generate_variant:Nn \tl_if_blank:nF { v } \providecommand{\AfterPreamble}{\AtBeginDocument} \AtBeginDocument{\cs_set_eq:NN \AfterPreamble \use:n} \cs_set_eq:NN \spb@textsuperscript@save \textsuperscript \cs_set_eq:NN \spb@textsubscript@save \textsubscript \cs_set_eq:NN \spb@math@super@save \sp \cs_set_eq:NN \spb@math@sub@save \sb \cs_set_eq:NN \spb@@makefnmark@save \@makefnmark \cs_new_protected:Npn \spb_define:n { \keys_define:nn { ctex/tools } } \cs_new_protected:Npn \spb_set:n { \keys_set:nn { ctex/tools } } \cs_set_eq:NN \spbset \spb_set:n \cs_new_protected:Npn \spb_mark_core_set_trad:n #1 { \cs_set_eq:cc { spb@text#1script@core } { spb@text#1script@save } \cs_set_eq:cc { spb@math@#1@core } { spb@math@#1@save } } \cs_new_protected:Npn \spb_mark_core_set_none:n #1 { \cs_set_eq:cN { spb@text#1script@core } \use:n \cs_set_eq:cN { spb@math@#1@core } \use:n } \keys_define:nn { spbmark/option } { text .choice:, text/true .code:n = { \cs_set:Npn \textsuperscript { \super[textsp] } \cs_set:Npn \textsubscript { \sub[textsb] } }, text/false .code:n = { \cs_set:Npn \textsuperscript { \spb@textsuperscript@core } \cs_set:Npn \textsubscript { \spb@textsubscript@core } }, text .default:n = true, math .choice:, math/true .code:n = { \cs_set:Npn \sp { \super[mathsp] } \cs_set:Npn \sb { \sub[mathsb] } }, math/false .code:n = { \cs_set:Npn \sp { \spb@math@super@core } \cs_set:Npn \sb { \spb@math@sub@core } }, math .default:n = true, foot .choice:, foot/true .code:n = { \cs_set:Npn \@makefnmark { \hbox:n { \fnmarkfont{\super[fnmark]{\@thefnmark}} } } }, foot/false .code:n = { \cs_set:Npn \@makefnmark { \spb@@makefnmark@save } }, foot .default:n = true, both .meta:n = { text = #1,math = #1 }, both .default:n = true, all .meta:n = { text = #1,math = #1,foot = #1 }, all .default:n = true, spcore .choice:, spcore .value_required:n = true, spcore/trad .code:n = \spb_mark_core_set_trad:n { super }, spcore/none .code:n = \spb_mark_core_set_none:n { super }, spcore .initial:n = trad, sbcore .choice:, sbcore .value_required:n = true, sbcore/trad .code:n = \spb_mark_core_set_trad:n { sub }, sbcore/none .code:n = \spb_mark_core_set_none:n { sub }, sbcore .initial:n = trad } \char_set_catcode_active:N \~ \keys_define:nn { spbmark/option } { math* .choice:, math*/true .code:n = { \AfterPreamble { \group_begin: \char_set_lccode:nn { `\~ } { `\^ } \lowercase{\group_end:\cs_set:Npn ~} { \super[mathsp*] } \group_begin: \char_set_lccode:nn { `\~ } { `\_ } \lowercase{\group_end:\cs_set:Npn ~} { \sub[mathsb*] } \char_set_mathcode:nn { `\^ } { "8000 } \char_set_catcode_other:N \^ \char_set_catcode_other:N \_ } }, math*/false .code:n = { \AfterPreamble { \char_set_catcode_math_superscript:N \^ \char_set_catcode_math_subscript:N \_ \char_set_mathcode:nn { `\^ } { "005E } } }, math* .default:n = true } \char_set_catcode_space:N \~ \tl_if_exist:NTF \ftntm@font { \tl_set_eq:NN \fnmarkfont \ftntm@font } { \tl_set_eq:NN \fnmarkfont \normalfont } \cs_if_exist:NTF \ProcessKeyOptions { \ProcessKeyOptions[spbmark/option] } { \RequirePackage{l3keys2e} \ProcessKeysOptions{spbmark/option} } \tl_new:N \g__spb_mark_case_init_tl \bool_new:N \l__spb_mark_at_local_bool \cs_new_protected:Npn \spb_local_case_init:nnn #1#2#3 { \bool_if:NTF \l__spb_mark_at_local_bool { \str_case:Vn \g__spb_mark_case_init_tl { { super } {#1} { sub } {#2} { supersub } {#3} } } { #1#2#3 } } \NewDocumentCommand{\spb@both@vsep@assign} {>{\SplitArgument{1}{,}}m} {\spb_supersub_both_vsep:nn #1} \cs_new_protected:Npn \spb_supersub_both_vsep:nn #1#2 { \tl_if_novalue:nTF {#2} { \tl_set:Nn \l__spb_super_vsep_ii_tl { #1/2 } \tl_set:Nn \l__spb_sub_vsep_ii_tl { #1/2 } } { \tl_set:Nn \l__spb_super_vsep_ii_tl {#1} \tl_set:Nn \l__spb_sub_vsep_ii_tl {#2} } } \cs_new_protected:Npn \defspbstyle #1#2 { \spb_define:n { style/#1 .undefine:, style/#1 .code:n = \spb_set:n {#2} } } \cs_new_protected:Npn \spbshortkv #1#2 { \spb_define:n { #1 .meta:n = {#2} } } \clist_map_inline:nn { textsp,textsb,mathsp,mathsb,mathsp*,mathsb*,fnmark } { \defspbstyle{#1}{} \spbshortkv{#1}{style = #1} } \spb_define:n { mode .tl_set:N = \l__spb_mode_value_tl, mode .initial:n = match, style .choice:, style .value_required:n = true, vsep .code:n = \spb@both@vsep@assign{#1}, vsep .initial:n = 0.6ex, halign .tl_set:N = \l__spb_supersub_halign_tl, halign .initial:n = l, spvmove .tl_set:N = \l__spb_super_vmove_tl, spvmove .initial:n = 0pt, sphmove .tl_set:N = \l__spb_super_hmove_tl, sphmove .initial:n = 0pt, sbvmove .tl_set:N = \l__spb_sub_vmove_tl, sbvmove .initial:n = 0pt, sbhmove .tl_set:N = \l__spb_sub_hmove_tl, sbhmove .initial:n = 0pt, spbhmove .tl_set:N = \l__spb_supersub_hmove_tl, spbhmove .initial:n = 0pt, vmove .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__spb_super_vmove_tl {#1} } { \tl_set:Nn \l__spb_sub_vmove_tl {#1} } { \spb@both@vsep@assign{#1} } }, hmove .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__spb_super_hmove_tl {#1} } { \tl_set:Nn \l__spb_sub_hmove_tl {#1} } { \tl_set:Nn \l__spb_supersub_hmove_tl {#1} } }, nohmove .meta:n = { sphmove = 0pt,sbhmove = 0pt }, novmove .meta:n = { spvmove = 0pt,sbvmove = 0pt } } \cs_new:Npn \spb_box_super_move_up_i:n #1 { \box_move_up:nn {#1} { \box_use:N \g__super_i_inner_box } } \cs_new:Npn \spb_box_sub_move_down_i:n #1 { \box_move_down:nn {#1} { \box_use:N \g__sub_i_inner_box } } \cs_new:Npn \spb_box_super_move_up_ii:n #1 { \box_move_up:nn {#1} { \box_use:N \g__super_ii_box } } \cs_new:Npn \spb_box_sub_move_down_ii:n #1 { \box_move_down:nn {#1} { \box_use:N \g__sub_ii_box } } \cs_new:Npn \spb_inner_box_vmove_i:nn #1 { \str_case:nn {#1} { { super } { \spb_box_super_move_up_i:n } { sub } { \spb_box_sub_move_down_i:n } } } \cs_generate_variant:Nn \spb_box_super_move_up_ii:n { V } \cs_generate_variant:Nn \spb_box_sub_move_down_ii:n { V } \providecommand{\hbox_overlap_center:n}[1] {\hbox_to_zero:n { \hss #1\hss }} \cs_new:Npn \spb_hbox_overlap_vmove_ii:n #1 { \use:c { hbox_overlap_#1:n } { \spb_box_super_move_up_ii:V \l__spb_super_vsep_ii_tl } \use:c { hbox_overlap_#1:n } { \spb_box_sub_move_down_ii:V \l__spb_sub_vsep_ii_tl } } \tl_new:N \l__spb_super_cmd_ii_tl \tl_new:N \l__spb_sub_cmd_ii_tl \spb_define:n { spcmd .tl_set:N = \l__spb_super_cmd_i_tl, sbcmd .tl_set:N = \l__spb_sub_cmd_i_tl, spbcmd .code:n = \spb@both@cmd@assign{#1}, cmd .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__spb_super_cmd_i_tl {#1} } { \tl_set:Nn \l__spb_sub_cmd_i_tl {#1} } { \spb@both@cmd@assign{#1} } }, spcmd+ .code:n = \tl_put_right:Nn \l__spb_super_cmd_i_tl {#1}, sbcmd+ .code:n = \tl_put_right:Nn \l__spb_sub_cmd_i_tl {#1}, spbcmd+ .code:n = \spb@both@cmd@assign+{#1}, cmd+ .code:n = { \spb_local_case_init:nnn { \tl_put_right:Nn \l__spb_super_cmd_i_tl {#1} } { \tl_put_right:Nn \l__spb_sub_cmd_i_tl {#1} } { \spb@both@cmd@assign+{#1} } } } \NewDocumentCommand{\spb@both@cmd@assign} {t+>{\SplitArgument{1}{,}}m} { \IfBooleanTF{#1} {\spb_supersub_both_addto_cmd:nn #2} {\spb_supersub_both_cmd:nn #2} } \cs_new_protected:Npn \spb_supersub_both_cmd:nn #1#2 { \tl_set:Nn \l__spb_super_cmd_ii_tl {#1} \tl_if_novalue:nTF {#2} { \tl_clear:N \l__spb_sub_cmd_ii_tl } { \tl_set:Nn \l__spb_sub_cmd_ii_tl {#2} } } \cs_new_protected:Npn \spb_supersub_both_addto_cmd:nn #1#2 { \tl_put_right:Nn \l__spb_super_cmd_ii_tl {#1} \tl_if_novalue:nF {#2} { \tl_put_right:Nn \l__spb_sub_cmd_ii_tl {#2} } } \spb_define:n { spheight .tl_set:N = \l__super_height_i_tl, sbheight .tl_set:N = \l__sub_height_i_tl, spbheight .tl_set:N = \l__super_height_ii_tl, height .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__super_height_i_tl {#1} } { \tl_set:Nn \l__sub_height_i_tl {#1} } { \tl_set:Nn \l__super_height_ii_tl {#1} } }, spdepth .tl_set:N = \l__super_depth_i_tl, sbdepth .tl_set:N = \l__sub_depth_i_tl, spbdepth .tl_set:N = \l__sub_depth_ii_tl, depth .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__super_depth_i_tl {#1} } { \tl_set:Nn \l__sub_depth_i_tl {#1} } { \tl_set:Nn \l__sub_depth_ii_tl {#1} } } } \cs_new_protected:Npn \spb_ht_dp_assign:nnnn #1#2#3#4 { \tl_if_blank:vF { l__#1_height_#3_tl } { \box_set_ht:cv { g__#1_#3#4_box } { l__#1_height_#3_tl } } \tl_if_blank:vF { l__#1_depth_i_tl } { \box_set_dp:cv { g__#2_#3#4_box } { l__#2_depth_#3_tl } } } \box_new:N \g__super_i_outer_box \box_new:N \g__super_i_inner_box \box_new:N \g__sub_i_outer_box \box_new:N \g__sub_i_inner_box \box_new:N \g__super_ii_box \box_new:N \g__sub_ii_box \dim_new:N \llastwd \dim_new:N \clastwd \dim_new:N \rlastwd \tl_set:Nn \superwd { \box_wd:N \g__super_ii_box } \tl_set:Nn \subwd { \box_wd:N \g__sub_ii_box } \tl_set:Nn \maxwd { \dim_max:VV \superwd \subwd } \tl_set:Nn \l__spb_box_super_wd_i_tl { \box_wd:N \g__super_i_inner_box } \tl_set:Nn \l__spb_box_sub_wd_i_tl { \box_wd:N \g__sub_i_inner_box } \providecommand{\NewHookWithArguments}[2]{} \providecommand{\UseHookWithArguments}[4]{} \NewHookWithArguments{spb/super/before}{2} \NewHookWithArguments{spb/super/after}{2} \NewHookWithArguments{spb/sub/before}{2} \NewHookWithArguments{spb/sub/after}{2} \NewHookWithArguments{spb/super*/before}{2} \NewHookWithArguments{spb/super*/after}{2} \NewHookWithArguments{spb/sub*/before}{2} \NewHookWithArguments{spb/sub*/after}{2} \NewHookWithArguments{cmd+/super/after}{2} \NewHookWithArguments{cmd+/sub/after}{2} \cs_new:Npn \spb_math_print_store_i:nnnn #1#2#3#4 { \bool_if:NTF \l__spb_nobox_mark_bool { \tl_gset:cn { g__#1_i_nobox_mark_tl } } { \hbox_gset:cn { g__#1_i_inner_box } } { #3{ \UseHookWithArguments{spb/#1/before}{2}{#1}{#2} \use:c {#4} { \tl_use:c { l__spb_#1_cmd_i_tl }{#2} } \UseHookWithArguments{spb/#1/after}{2}{#1}{#2} } } \dim_gset:Nv \rlastwd { l__spb_box_#1_wd_i_tl } } \cs_new:Npn \spb_math_print_store_i:nn #1#2 { \spb_math_print_store_i:nnnn {#1} {#2} { \ensuremath } { spb@math@#1@core } } \cs_new:Npn \spb_text_print_store_i:nn #1#2 { \spb_math_print_store_i:nnnn {#1} {#2} { \use:n } { spb@text#1script@core } } \cs_new:Npn \spb_math_print_store_ii:nnnnn #1#2#3#4#5 { \hbox_gset:Nn \g__super_ii_box { #3{ \UseHookWithArguments{spb/super*/before}{2}{super}{#1} #4{\l__spb_super_cmd_ii_tl{#1}} \UseHookWithArguments{spb/super*/after}{2}{super}{#1} } } \hbox_gset:Nn \g__sub_ii_box { #3{ \UseHookWithArguments{spb/sub*/before}{2}{sub}{#2} #5{\l__spb_sub_cmd_ii_tl{#2}} \UseHookWithArguments{spb/sub*/after}{2}{sub}{#2} } } } \cs_new:Npn \spb_math_print_store_ii:nn #1#2 { \spb_math_print_store_ii:nnnnn {#1} {#2} { \ensuremath } { \spb@math@super@core } { \spb@math@sub@core } } \cs_new:Npn \spb_text_print_store_ii:nn #1#2 { \spb_math_print_store_ii:nnnnn {#1} {#2} { \use:n } { \spb@textsuperscript@core } { \spb@textsubscript@core } } \cs_set_eq:NN \spbifmath \use_ii:nn \cs_new:Npn \spb@ifmathtrue { \cs_set_eq:NN \spbifmath \use_i:nn } \cs_new:Npn \spb@ifmathfalse { \cs_set_eq:NN \spbifmath \use_ii:nn } \cs_new_protected:Npn \spb_mode_switch:nnn #1#2#3 { \str_case:Vn \l__spb_mode_value_tl { { math } { \spb@ifmathtrue \use:c { spb_math_print_store_#3:nn } {#1} {#2} } { text } { \spb@ifmathfalse \use:c { spb_text_print_store_#3:nn } {#1} {#2} } { match } { \mode_if_math:TF { \spb@ifmathtrue \use:c { spb_math_print_store_#3:nn } {#1} {#2} } { \spb@ifmathfalse \use:c { spb_text_print_store_#3:nn } {#1} {#2} } } } } \spb_define:n { thiswd .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__spb_super_thiswd_mode_tl {#1} } { \tl_set:Nn \l__spb_sub_thiswd_mode_tl {#1} } { } }, regex .code:n = { \spb_local_case_init:nnn { \tl_set:Nn \l__spb_super_regex_next_tl {#1} } { \tl_set:Nn \l__spb_sub_regex_next_tl {#1} } { } }, spthiswd .tl_set:N = \l__spb_super_thiswd_mode_tl, spthiswd .initial:n = keep, sbthiswd .tl_set:N = \l__spb_sub_thiswd_mode_tl, sbthiswd .initial:n = keep, spregex .tl_set:N = \l__spb_super_regex_next_tl, spregex .initial:n = \c{sub}|\c{textsubscript}|\c{sb}|\_, sbregex .tl_set:N = \l__spb_sub_regex_next_tl, sbregex .initial:n = \c{super}|\c{textsuperscript}|\c{sp}|\^, nobox .bool_set:N = \l__spb_nobox_mark_bool } \cs_new:Npn \spb_clear_thiswd:n #1 { \str_case:nn {#1} { { super } { \peek_regex:nF { \exp_not:o { \l__spb_super_regex_next_tl } } { \exp_not:n { \dim_zero:N \llastwd \dim_zero:N \clastwd \dim_zero:N \rlastwd } } } { sub } { \peek_regex:nF { \exp_not:o { \l__spb_sub_regex_next_tl } } { \exp_not:n { \dim_zero:N \llastwd \dim_zero:N \clastwd \dim_zero:N \rlastwd } } } } } \cs_new_protected:Npn \spb_both_newcmd_map:n #1 { \exp_args:Nc \NewDocumentCommand {#1}{sO{}O{}mO{}} { \group_begin: \bool_set_true:N \l__spb_mark_at_local_bool \mode_leave_vertical: \tl_gset:Nn \g__spb_mark_case_init_tl {#1} \spb_set:n { ##2,##3,##5 } \spb_mode_switch:nnn {#1} {##4} { i } \bool_if:NTF \l__spb_nobox_mark_bool { \tl_use:c { g__#1_i_nobox_mark_tl } } { \spb_mark_box_set:nn {#1} {##1} \spb_ht_dp_assign:nnnn {#1} {#1} { i } { _outer } \box_use:c { g__#1_i_outer_box } } \exp_last_unbraced:Nx \group_end: { \UseHookWithArguments{cmd+/#1/after}{2}{#1}{##4} \exp_args:Nv \str_if_eq:nnT { l__spb_#1_thiswd_mode_tl } { auto } { \spb_clear_thiswd:n {#1} } } } } \cs_new_protected:Npn \spb_mark_box_set:nn #1#2 { \dim_gset:Nn \clastwd { (\llastwd + \rlastwd)/2 } \tl_set:Nn \abs@hmove@i { \dim_abs:v { l__spb_#1_hmove_tl } } \hbox_gset:cn { g__#1_i_outer_box } { \dim_compare:vNnTF { l__spb_#1_hmove_tl } < { 0pt } { \hbox_overlap_left:n { \hbox_overlap_right:n { \spb_inner_box_vmove_i:nn {#1} { \tl_use:c { l__spb_#1_vmove_tl } } } \skip_horizontal:n { \abs@hmove@i } } \IfBooleanT{#2} { \dim_compare:nNnT { \abs@hmove@i } < { \rlastwd } { \skip_horizontal:n { \rlastwd - \abs@hmove@i } } } } { \hbox_to_wd:nn { \tl_use:c { l__spb_box_#1_wd_i_tl } + \tl_use:c { l__spb_#1_hmove_tl } } { \hss\spb_inner_box_vmove_i:nn {#1} { \tl_use:c { l__spb_#1_vmove_tl } } } } } \dim_gset:Nv \llastwd { l__spb_box_#1_wd_i_tl } } \clist_map_inline:nn { super,sub } { \spb_both_newcmd_map:n {#1} } \cs_new:Npn \spb_supersub_hmove_if_negative:TF #1#2 { \dim_compare:VNnTF \l__spb_supersub_hmove_tl < { 0pt } {#1} {#2} } \tl_set:Nn \abs@hmove@ii { \dim_abs:V \l__spb_supersub_hmove_tl } \cs_new:Npn \spb_supersub_avoid_overlap:n #1 { \IfBooleanT{#1} { \dim_compare:nNnT { \abs@hmove@ii } < { \maxwd } { \skip_horizontal:n { \maxwd - \abs@hmove@ii } } } } \NewDocumentCommand{\supersub}{sO{}mmO{}} { \group_begin: \bool_set_true:N \l__spb_mark_at_local_bool \mode_leave_vertical: \tl_gset:Nn \g__spb_mark_case_init_tl { supersub } \spb_set:n {#2,#5} \spb_mode_switch:nnn {#3} {#4} { ii } \spb_ht_dp_assign:nnnn { super } { sub } { ii } { } \str_case:VnF \l__spb_supersub_halign_tl { { l } { \use_i:nnn } { c } { \use_ii:nnn } { r } { \use_iii:nnn } } { \msg_warning:nn { spbmark } { unsupported-align } \use_i:nnn } { \spb_supersub_hmove_if_negative:TF { \hbox_overlap_left:n { \spb_hbox_overlap_vmove_ii:n { right } \skip_horizontal:n { \abs@hmove@ii } } \spb_supersub_avoid_overlap:n {#1} } { \hbox:n { \skip_horizontal:n { \l__spb_supersub_hmove_tl } \spb_hbox_overlap_vmove_ii:n { right } \skip_horizontal:n { \maxwd } } } } { \spb_supersub_hmove_if_negative:TF { \hbox_overlap_left:n { \spb_hbox_overlap_vmove_ii:n { center } \skip_horizontal:n { \abs@hmove@ii - \maxwd/2 } } \spb_supersub_avoid_overlap:n {#1} } { \hbox:n { \skip_horizontal:n { \maxwd/2 + \l__spb_supersub_hmove_tl } \spb_hbox_overlap_vmove_ii:n { center } \skip_horizontal:n { \maxwd/2 } } } } { \spb_supersub_hmove_if_negative:TF { \hbox_overlap_left:n { \spb_hbox_overlap_vmove_ii:n { left } \skip_horizontal:n { \abs@hmove@ii - \maxwd } } \spb_supersub_avoid_overlap:n {#1} } { \hbox:n { \skip_horizontal:n { \maxwd + \l__spb_supersub_hmove_tl } \spb_hbox_overlap_vmove_ii:n { left } } } } \group_end: } \msg_new:nnn { spbmark } { unsupported-align } { Alignment~only~supports~l,~c,~and~r. \\ The~l~parameter~will~be~used~by~default. } \providecommand{\IfPackageLoadedTF}{\@ifpackageloaded} \providecommand{\IfFormatAtLeastTF}{\@ifl@t@r\fmtversion} \IfPackageLoadedTF{easybase} {\AddToHook{package/easybase/after}} {\use:n} { \keys_define:nn { } { ctex/tools .inherit:n = spbmark/option } } \IfFormatAtLeastTF{2021/11/15} { \AddToHook{package/altsubsup/after} { \ifaltsbsp@spbmark \SetAltSubSupCommands{\relax} \fi } }{} \cs_set_eq:NN \spb \supersub \endinput % % End of file `spbmark.sty'.