%
% ***************** THE SPBMARK PACKAGE *****************
%
% Copyright (C) 2021 by Qu Yi <q1jx@foxmail.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}{2021/12/15}{1.2}
  {Customize superscripts and subscripts}

\cs_generate_variant:Nn \dim_max:nn { VV }
\cs_generate_variant:Nn \dim_compare:nNnTF { 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_new_protected:Npn \spb_define:n { \keys_define:nn { ctex/style } }
\cs_new_protected:Npn \spbset { \keys_set:nn { ctex/style } }
\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}

\tl_new:N \l__spb_super_cmd_ii_tl
\tl_new:N \l__spb_sub_cmd_ii_tl
\tl_new:N \g__spb_hshift_init_tl
\tl_new:N \g__spb_vshift_init_tl
\tl_new:N \g__spb_cmd_init_tl

\cs_new_protected:Npn \spb_local_case_init:nnnn #1#2#3#4
  {
    \str_case:xn { \tl_use:c { g__spb_#1_init_tl } }
      {
        { super } {#2}
        { sub } {#3}
        { supersub } {#4}
      }
  }
\spb_define:n
  {
    spvshift .dim_set:N   = \l__spb_super_vshift_dim,
    spvshift .initial:n   = 0pt,
    sphshift .dim_set:N   = \l__spb_super_hshift_dim,
    sphshift .initial:n   = 0pt,
    sbvshift .dim_set:N   = \l__spb_sub_vshift_dim,
    sbvshift .initial:n   = 0pt,
    sbhshift .dim_set:N   = \l__spb_sub_hshift_dim,
    sbhshift .initial:n   = 0pt,
    spbhshift .dim_set:N  = \l__spb_supersub_hshift_dim,
    spbhshift .initial:n  = 0pt,
    vshift .code:n        =
      {
        \spb_local_case_init:nnnn { vshift }
          { \dim_set:Nn \l__spb_super_vshift_dim {#1} }
          { \dim_set:Nn \l__spb_sub_vshift_dim {#1} }
          { \dim_set:Nn \l__spb_supersub_vsep_dim {#1} }
      },
    hshift .code:n        =
      {
        \spb_local_case_init:nnnn { hshift }
          { \dim_set:Nn \l__spb_super_hshift_dim {#1} }
          { \dim_set:Nn \l__spb_sub_hshift_dim {#1} }
          { \dim_set:Nn \l__spb_supersub_hshift_dim {#1} }
      },
    nohshift .meta:n      = { sphshift = 0pt,sbhshift = 0pt },
    novshift .meta:n      = { spvshift = 0pt,sbvshift = 0pt },
    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:n {#1},
    cmd .code:n           =
      {
        \spb_local_case_init:nnnn { cmd }
          { \tl_set:Nn \l__spb_super_cmd_i_tl {#1} }
          { \tl_set:Nn \l__spb_sub_cmd_i_tl {#1} }
          { \spb_both_cmd_assign:n {#1} }
      },
    vsep .dim_set:N       = \l__spb_supersub_vsep_dim,
    vsep .initial:n       = 0.3ex,
    halign .tl_set:N      = \l__spb_supersub_align_tl,
    halign .initial:n     = l,
    mode .tl_set:N        = \l__spb_mode_value_tl,
    mode .initial:n       = match
  }

\tl_set:Nn \l__spb_boxa_wd_tl { \box_wd:N \l_tmpa_box }
\tl_set:Nn \l__spb_boxb_wd_tl { \box_wd:N \l_tmpb_box }
\tl_set:Nn \l__spb_box_max_wd_tl
  { \dim_max:VV \l__spb_boxa_wd_tl \l__spb_boxb_wd_tl }
\providecommand{\hbox_overlap_center:n}[1]
  { \hbox_to_zero:n { \hss #1\hss } }
\cs_new:Npn \spb_boxa_move_up:n #1
  { \box_move_up:nn {#1} { \box_use:N \l_tmpa_box } }
\cs_new:Npn \spb_boxa_move_down:n #1
  { \box_move_down:nn {#1} { \box_use:N \l_tmpa_box } }
\cs_new:Npn \spb_boxb_move_down:n #1
  { \box_move_down:nn {#1} { \box_use:N \l_tmpb_box } }
\cs_new:Npn \spb_boxa_vshift:nn #1
  {
    \str_case:nn {#1}
      {
        { super } { \spb_boxa_move_up:n }
        { sub } { \spb_boxa_move_down:n }
      }
  }
\cs_generate_variant:Nn \spb_boxa_move_up:n { V }
\cs_generate_variant:Nn \spb_boxb_move_down:n { V }
\cs_new:Npn \spb_hbox_overlap_vshift:n #1
  {
    \use:c { hbox_overlap_#1:n }
      { \spb_boxa_move_up:V \l__spb_supersub_vsep_dim }
    \use:c { hbox_overlap_#1:n }
      { \spb_boxb_move_down:V \l__spb_supersub_vsep_dim }
  }
\cs_new:Npn \spb_math_print_store_i:nn #1#2
  {
    \hbox_set:Nn \l_tmpa_box
      { \ensuremath{\tl_use:c { l__spb_#1_cmd_i_tl }{\spb_math:nn {#1} {#2}}} }
  }
\cs_new:Npn \spb_text_print_store_i:nn #1#2
  {
    \hbox_set:Nn \l_tmpa_box
      { \tl_use:c { l__spb_#1_cmd_i_tl }{\use:c { spb@text#1script@save }{#2}} }
  }
\cs_new:Npn \spb_math_print_store_ii:nn #1#2
  {
    \hbox_set:Nn \l_tmpa_box 
      { \ensuremath{\l__spb_super_cmd_ii_tl{\spb@sp@save{#1}}} }
    \hbox_set:Nn \l_tmpb_box
      {
        \ensuremath
          {
            \tl_if_novalue:VF \l__spb_sub_cmd_ii_tl
              { \l__spb_sub_cmd_ii_tl }
              { \spb@sb@save{#2} }
          } 
      }
  }
\cs_new:Npn \spb_text_print_store_ii:nn #1#2
  {
    \hbox_set:Nn \l_tmpa_box
      { \l__spb_super_cmd_ii_tl{\spb@textsuperscript@save{#1}} }
    \hbox_set:Nn \l_tmpb_box
      {
        \tl_if_novalue:VF \l__spb_sub_cmd_ii_tl
          { \l__spb_sub_cmd_ii_tl }
          { \spb@textsubscript@save{#2} } 
      }
  }
\cs_set_eq:NN \spb@textsuperscript@save \textsuperscript
\cs_set_eq:NN \spb@textsubscript@save \textsubscript
\cs_set_eq:NN \spb@sp@save \sp
\cs_set_eq:NN \spb@sb@save \sb
\cs_new:Npn \spb_math:nn #1
  {
    \str_case:nn {#1}
      {
        { super } { \spb@sp@save }
        { sub } { \spb@sb@save }
      }
  }
\cs_new_protected:Npn \spb_box_ht_dp_assign:nn #1#2
  {
    \tl_if_empty:nF {#1} { \box_set_ht:Nn \l_tmpb_box {#1} }
    \tl_if_novalue:nF {#2} { \box_set_dp:Nn \l_tmpb_box {#2} }
  }
\NewDocumentCommand{\spb_both_cmd_assign:n}
  {>{\SplitArgument{1}{,}}m}
  {\spb_supersub_both_cmd:nn #1}
\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_mode_switch:nnn #1#2#3
  {
    \str_case:Vn \l__spb_mode_value_tl
      {
        { math } {#1}
        { text } {#2}
        { match } {#3}
      }
   }
\cs_new_protected:Npn \spb_local_value_init:n #1
  {
    \tl_gset:Nn \g__spb_hshift_init_tl {#1}
    \tl_gset:Nn \g__spb_vshift_init_tl {#1}
    \tl_gset:Nn \g__spb_cmd_init_tl {#1}
  }

\cs_new_protected:Npn \spb_both_newcmd_map:n #1
  {
    \exp_args:Nc \NewDocumentCommand {#1}
      {O{}>{\SplitArgument{1}{,}}O{}mO{}}
      {
        \group_begin:
        \spb_local_value_init:n {#1}
        \keys_set:nn { ctex/style } {##1,##4}
        \spb_mode_switch:nnn
          { \spb_math_print_store_i:nn {#1} {##3} }
          { \spb_text_print_store_i:nn {#1} {##3} }
          {
            \mode_if_math:TF
              { \spb_math_print_store_i:nn {#1} {##3} }
              { \spb_text_print_store_i:nn {#1} {##3} }
          }
        \spb_content_hbox_set:n {#1}
        \spb_box_ht_dp_assign:nn ##2
        \box_use:N \l_tmpa_box
        \group_end:
      }
  }
\cs_new_protected:Npn \spb_content_hbox_set:n #1
   {
     \hbox_set:Nn \l_tmpa_box
       {
         \dim_compare:nNnTF { \dim_use:c { l__spb_#1_hshift_dim } } < { 0pt }
           {
             \hbox_overlap_left:n
               {
                 \hbox_to_wd:nn
                   { \l__spb_boxa_wd_tl - \dim_use:c { l__spb_#1_hshift_dim } }
                   {
                      \spb_boxa_vshift:nn {#1}
                        { \dim_use:c { l__spb_#1_vshift_dim } }\hss
                   }
               }
           }
           {
             \hbox_to_wd:nn
               { \l__spb_boxa_wd_tl + \dim_use:c { l__spb_#1_hshift_dim } }
               {
                  \hss\spb_boxa_vshift:nn {#1}
                    { \dim_use:c { l__spb_#1_vshift_dim } }
               }
           }
       }
   }
\clist_map_inline:nn { super,sub } { \spb_both_newcmd_map:n {#1} }

\cs_new:Npn \spb_supersub_hshift_if_negative:TF #1#2
  { \dim_compare:VNnTF \l__spb_supersub_hshift_dim < { 0pt } {#1} {#2} }
\NewDocumentCommand{\supersub}{O{}mmO{}}
  {
    \group_begin:
    \spb_local_value_init:n { supersub }
    \keys_set:nn { ctex/style } {#1,#4}
    \spb_mode_switch:nnn
      { \spb_math_print_store_ii:nn {#2} {#3} }
      { \spb_text_print_store_ii:nnnn {#2} {#3} }
      {
        \mode_if_math:TF
          { \spb_math_print_store_ii:nn {#2} {#3} }
          { \spb_text_print_store_ii:nn {#2} {#3} }
      }
    \str_case:VnF \l__spb_supersub_align_tl
      {
        { l } { \use_i:nnn }
        { c } { \use_ii:nnn }
        { r } { \use_iii:nnn }
      }
      {
        \msg_warning:nn { spbmark } { unsupported-align }
        \use_i:nnn
      }
      {
        \spb_supersub_hshift_if_negative:TF
          {
            \hbox_overlap_left:n
              {
                \spb_hbox_overlap_vshift:n { right }
                \skip_horizontal:n { -\l__spb_supersub_hshift_dim }
              }
          }
          {
            \hbox:n
              {
                \skip_horizontal:n { \l__spb_supersub_hshift_dim }
                \spb_hbox_overlap_vshift:n { right } 
                \skip_horizontal:n { \l__spb_box_max_wd_tl }
              }
          }
      }
      {
        \spb_supersub_hshift_if_negative:TF
          {
            \hbox_overlap_left:n
              {
                \spb_hbox_overlap_vshift:n { center }
                \skip_horizontal:n
                  { \l__spb_box_max_wd_tl/2 - \l__spb_supersub_hshift_dim }
              }
          }
          {
            \hbox:n
              {
                \skip_horizontal:n
                  { \l__spb_box_max_wd_tl/2 + \l__spb_supersub_hshift_dim }
                \spb_hbox_overlap_vshift:n { center } 
                \skip_horizontal:n { \l__spb_box_max_wd_tl/2 }
              }
          }
      }
      {
        \spb_supersub_hshift_if_negative:TF
          {
            \hbox_overlap_left:n
              {
                \spb_hbox_overlap_vshift:n { left }
                \skip_horizontal:n { -\l__spb_supersub_hshift_dim }
              }
          }
          {
            \hbox:n
              {
                \skip_horizontal:n
                  { \l__spb_box_max_wd_tl + \l__spb_supersub_hshift_dim }
                \spb_hbox_overlap_vshift: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'.