%
% ***************** THE SPBMARK PACKAGE *****************
%
% Copyright (C) 2021-2022 by Qu Yi <toquyi@163.com>
%
% 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,l3keys2e}
\ProvidesExplPackage{spbmark}{2022/10/15}{1.42}
  {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 \msg_warning:nnn { nnV }
\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 }

\cs_new_protected:Npn \spb_define:n { \keys_define:nn { ctex/style } }
\cs_new_protected:Npn \spb_set:n { \keys_set:nn { ctex/style } }
\cs_set_eq:NN \spbset \spb_set:n
\keys_define:nn { spbmark/option }
  {
    text .bool_set:N        = \l_spb_newsupb_text_bool,
    text .default:n         = true,
    math .bool_set:N        = \l_spb_newsupb_math_bool,
    math .default:n         = true,
    foot .bool_set:N        = \l_spb_newsupb_foot_bool,
    foot .default:n         = true,
    both .meta:n            = { text,math },
    both .value_forbidden:n = true,
    all .meta:n             = { text,math,foot },
    all .value_forbidden:n  = true,
    ctex .code:n            = { },
    newsupb .code:n         = { }
  }

\ProcessKeysOptions{spbmark/option}

\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
\tl_new:N \g__spb_mark_case_init_tl
\cs_new_protected:Npn \spb_local_case_init:nnn #1#2#3
  {
    \str_case:Vn \g__spb_mark_case_init_tl
      {
        { super } {#1}
        { sub } {#2}
        { supersub } {#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} } }
\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 \l__super_i_inner_box } }
\cs_new:Npn \spb_box_sub_move_down_i:n #1
  { \box_move_down:nn {#1} { \box_use:N \l__sub_i_inner_box } }
\cs_new:Npn \spb_box_super_move_up_ii:n #1
  { \box_move_up:nn {#1} { \box_use:N \l__super_ii_box } }
\cs_new:Npn \spb_box_sub_move_down_ii:n #1
  { \box_move_down:nn {#1} { \box_use:N \l__sub_ii_box } }
\cs_new:Npn \spb_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 { l__#1_#3#4_box } { l__#1_height_#3_tl } }
    \tl_if_blank:vF { l__#1_depth_i_tl }
      { \box_set_dp:cv { l__#2_#3#4_box } { l__#2_depth_#3_tl } }
  }

\box_new:N \l__super_i_outer_box
\box_new:N \l__super_i_inner_box
\box_new:N \l__sub_i_outer_box
\box_new:N \l__sub_i_inner_box
\box_new:N \l__super_ii_box
\box_new:N \l__sub_ii_box
\dim_new:N \llastwd
\dim_new:N \clastwd
\dim_new:N \rlastwd
\tl_set:Nn \superwd { \box_wd:N \l__super_ii_box }
\tl_set:Nn \subwd { \box_wd:N \l__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 \l__super_i_inner_box }
\tl_set:Nn \l__spb_box_sub_wd_i_tl { \box_wd:N \l__sub_i_inner_box }
\cs_new:Npn \spb_math_print_store_i:nn #1#2
  {
    \hbox_gset:cn { l__#1_i_inner_box }
      {
        \ensuremath
          {
            \use:c { spb@math@#1@save }
              { \tl_use:c { l__spb_#1_cmd_i_tl }{#2} }
          }
      }
    \dim_gset:Nv \rlastwd { l__spb_box_#1_wd_i_tl }
  }
\cs_new:Npn \spb_text_print_store_i:nn #1#2
  {
    \hbox_gset:cn { l__#1_i_inner_box }
      {
        \use:c { spb@text#1script@save }
          { \tl_use:c { l__spb_#1_cmd_i_tl }{#2} }
      }
    \dim_gset:Nv \rlastwd { l__spb_box_#1_wd_i_tl }
  }
\cs_new:Npn \spb_math_print_store_ii:nn #1#2
  {
    \hbox_gset:Nn \l__super_ii_box
      { \ensuremath{\spb@math@super@save{\l__spb_super_cmd_ii_tl{#1}}} }
    \hbox_gset:Nn \l__sub_ii_box
      { \ensuremath{\spb@math@sub@save{\l__spb_sub_cmd_ii_tl{#2}}} }
  }
\cs_new:Npn \spb_text_print_store_ii:nn #1#2
  {
    \hbox_gset:Nn \l__super_ii_box
      { \spb@textsuperscript@save{\l__spb_super_cmd_ii_tl{#1}} }
    \hbox_gset:Nn \l__sub_ii_box
      { \spb@textsubscript@save{\l__spb_sub_cmd_ii_tl{#2}} }
  }
\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}
            }
        }
      }
    }

\cs_new_protected:Npn \spb_both_newcmd_map:n #1
  {
    \exp_args:Nc \NewDocumentCommand {#1}{sO{}mO{}}
      {
        \group_begin:
        \mode_leave_vertical:
        \tl_gset:Nn \g__spb_mark_case_init_tl {#1}
        \spb_define:n { unknown .undefine: }
        \spb_set:n { ##2,##4 }
        \spb_mode_switch:nnn {#1} {##3} { i }
        \spb_content_hbox_set:nn {#1} {##1}
        \spb_ht_dp_assign:nnnn {#1} {#1} { i } { _outer }
        \box_use:c { l__#1_i_outer_box }
        \group_end:
      }
  }
\cs_new_protected:Npn \spb_content_hbox_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_set:cn { l__#1_i_outer_box }
      {
        \dim_compare:vNnTF { l__spb_#1_hmove_tl } < { 0pt }
          {
            \hbox_overlap_left:n
              {
                \hbox_overlap_right:n
                  { \spb_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_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:
    \mode_leave_vertical:
    \tl_gset:Nn \g__spb_mark_case_init_tl { supersub }
    \spb_define:n { unknown .undefine: }
    \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.
  }

\bool_if:NT \l_spb_newsupb_text_bool
  {
    \cs_set_eq:NN \textsuperscript \super
    \cs_set_eq:NN \textsubscript \sub
  }
\bool_if:NT \l_spb_newsupb_math_bool
  {
    \cs_set_eq:NN \sp \super
    \cs_set_eq:NN \sb \sub
  }
\bool_if:NT \l_spb_newsupb_foot_bool
  {
    \cs_set:Npn \@makefnmark
      { \hbox:n { \fnmarkfont{\super{\@thefnmark}} } }
  }
\cs_set_eq:NN \spb \supersub
\tl_if_exist:NTF \ftntm@font
  { \tl_set_eq:NN \fnmarkfont \ftntm@font }
  { \tl_set_eq:NN \fnmarkfont \normalfont }
\endinput
%
% End of file `spbmark.sty'.