% --------------------------------------------------------------------------
% the EMBRAC package
%
%   Upright Brackets in Emphasized Text
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://github.com/cgnieder/embrac/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2012--2021 Clemens Niederberger
% 
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% 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
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008/05/04 or later.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% The embrac package consists of the files
%  - embrac.sty, embrac_en.tex, embrac_en.pdf, embrac_kerning_test.tex and
%    README
% --------------------------------------------------------------------------
% > this package is strongly based on an article by Dominik Wa��enhoven in
% > ���Die TeXnische Kom��die��� 2 (2012), pp. 51--53
% > which introduces code by Bruno Le Floch. Code parts and idea used with
% > their kind permission. Many thanks!
% --------------------------------------------------------------------------
\RequirePackage { expl3 , xparse , l3keys2e }
\ProvidesExplPackage
  {embrac}
  {2021/02/20}
  {0.9a}
  {Upright Brackets in Emphasized Text}

% --------------------------------------------------------------------------
\msg_new:nnn {embrac} {patching}
  { Patching~ \token_to_str:c {#1} ... }

\msg_new:nnn {embrac} {not-patching}
  { \token_to_str:c {#1} ~ not~ defined.~ Not~ patching~ it ... }

% --------------------------------------------------------------------------
\bool_new:N \l__embrac_treat_biblatex_bool

\tl_new:N \l__embrac_tmpa_tl
\tl_new:N \l__embrac_treat_biblatex_tl

\int_new:N \l__embrac_penalty_int

\keys_define:nn {embrac}
  {
    biblatex         .choice: ,
    biblatex / true  .code:n =
      \bool_set_true:N \l__embrac_treat_biblatex_bool ,
    biblatex / on    .code:n =
      \bool_set_true:N \l__embrac_treat_biblatex_bool ,
    biblatex / parens .code:n =
      \bool_set_true:N \l__embrac_treat_biblatex_bool ,
    biblatex / false  .code:n =
      \bool_set_false:N \l__embrac_treat_biblatex_bool ,
    biblatex / off    .code:n =
      \bool_set_false:N \l__embrac_treat_biblatex_bool ,
    biblatex / none   .code:n =
      \bool_set_false:N \l__embrac_treat_biblatex_bool ,
    biblatex          .default:n = true
  }

\prg_new_conditional:Npnn \embrac_if_fontspec: { T,F,TF }
  {
    \@ifpackageloaded {fontspec}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_generate_variant:Nn \cs_generate_variant:Nn {c}

% preparations:
\cs_new_eq:NN \embrac_braces_format:n \textup
\cs_new_eq:NN \embrac_kern:n \skip_horizontal:n

\prg_new_conditional:Npnn \embrac_empty_or_no_value:n #1 { F,TF }
  {
    \IfNoValueTF {#1}
      { \prg_return_true: }
      {
        \tl_if_blank:nTF {#1}
          { \prg_return_true: }
          { \prg_return_false: }
      }
  }

\cs_new_protected:Npn \embrac_nobreak:
  { \tex_penalty:D 10000 \scan_stop: }

\cs_new_protected:Npn \embrac_allow_break:
  { \tex_penalty:D 0 \scan_stop: }

% --------------------------------------------------------------------------
% THE MAIN PART:
% storage of the tokens to be replaced:
\prop_new:N \l__embrac_emph_obrackets_symbol_prop
\prop_new:N \l__embrac_emph_obrackets_inner_prop
\prop_new:N \l__embrac_emph_obrackets_outer_prop
\prop_new:N \l__embrac_emph_cbrackets_symbol_prop
\prop_new:N \l__embrac_emph_cbrackets_inner_prop
\prop_new:N \l__embrac_emph_cbrackets_outer_prop

\bool_new:N \l__embrac_opening_bool

% #1: tl macro
% #2: kerning before
% #3: symbol
% #4: kerning after
% #5: code after
\cs_new_protected:Npn \__embrac_replace:Nnnnn #1#2#3#4#5
  {
    \tl_replace_all:Nnn #1 {#3}
      {
        \mode_if_math:TF
          {#3}
          {
            \embrac_nobreak:
            \embrac_kern:n {#2}
            \embrac_nobreak:
            \embrac_braces_format:n {#3}
            \embrac_nobreak:
            \embrac_kern:n {#4}
            #5
          }
      }
  }
\cs_generate_variant:Nn \__embrac_replace:Nnnnn {Nxx,Nnxx}

% do the replacing:
% #1: tl macro
\cs_new_protected:Npn \embrac_replace_brackets:N #1
  {
    \prop_map_inline:Nn \l__embrac_emph_obrackets_inner_prop
      {
        \__embrac_replace:Nxxnn #1
          { \prop_item:Nn \l__embrac_emph_obrackets_outer_prop {##1} }
          { \prop_item:Nn \l__embrac_emph_obrackets_symbol_prop {##1} }
          {##2}
          { \embrac_nobreak: }
      }
    \prop_map_inline:Nn \l__embrac_emph_cbrackets_inner_prop
      {
        \__embrac_replace:Nnxxn #1
          {##2}
          { \prop_item:Nn \l__embrac_emph_cbrackets_symbol_prop {##1} }
          { \prop_item:Nn \l__embrac_emph_cbrackets_outer_prop {##1} }
          {
            \peek_charcode:NTF \c_space_tl
              { \embrac_allow_break: }
              { \embrac_nobreak: }
          }
      }
  }

\cs_new_protected:Npn \embrac_enparen:nnn #1#2#3
  {
    \embrac_nobreak:
    \embrac_kern:n
      { \prop_item:Nn \l__embrac_emph_obrackets_outer_prop {#1} }
    \embrac_nobreak:
    \embrac_braces_format:n
      { \prop_item:Nn \l__embrac_emph_obrackets_symbol_prop {#1} }
    \embrac_nobreak:
    \embrac_kern:n
      { \prop_item:Nn \l__embrac_emph_obrackets_inner_prop {#1} }
    #3
    \embrac_nobreak:
    \embrac_kern:n
      { \prop_item:Nn \l__embrac_emph_cbrackets_inner_prop {#2} }
    \embrac_nobreak:
    \embrac_braces_format:n
      { \prop_item:Nn \l__embrac_emph_cbrackets_symbol_prop {#2} }
    \embrac_nobreak:
    \embrac_kern:n
      { \prop_item:Nn \l__embrac_emph_cbrackets_outer_prop {#2} }
    \peek_charcode:NTF \c_space_tl
      { \embrac_allow_break: }
      { \embrac_nobreak: }
  }

% --------------------------------------------------------------------------
% biblatex compatibility:
\cs_new_protected:Npn \embrac_treat_bibparens:
  {
    \bool_if:NT \l__embrac_treat_biblatex_bool
      {
        \embrac_replace_brackets:N \bibleftbracket
        \embrac_replace_brackets:N \bibrightbracket
        \embrac_replace_brackets:N \bibleftparen
        \embrac_replace_brackets:N \bibrightparen
      }
  }

\cs_new_protected:Npn \embrac_treat_bibemph:
  {
    \bool_if:NT \l__embrac_treat_biblatex_bool
      {
        \patchcmd[\protected\long]\blx@imc@mkbibemph
          {\emph}{\emph*}
          {}{}
        \patchcmd[\protected\long]\blx@imc@mkbibitalic
          {\textit}{\textit*}
          {}{}
      }
  }

% --------------------------------------------------------------------------
% redefine \emph and friends:
\seq_new:N \l__embrac_changed_macros_seq

% #1: name of macro to be treated
\cs_new_protected:Npn \embrac_new_replacement_macro:n #1
  {
    \cs_if_exist:cTF {#1}
      {
        \msg_info:nnn {embrac} {patching} {#1}
        \seq_put_right:Nn \l__embrac_changed_macros_seq {#1}
        \cs_new_eq:cc {embrac_orig_#1:n} {#1~}
        \cs_generate_variant:cn {embrac_orig_#1:n} {V}
        \cs_new_protected:cpn {__embrac_#1:n} ##1
          {
            \tl_set:Nn \l__embrac_tmpa_tl {##1}
            \embrac_replace_brackets:N \l__embrac_tmpa_tl
            \use:c {embrac_orig_#1:V} \l__embrac_tmpa_tl
          }
        \cs_new_protected:cpn {embrac_#1:nn} ##1##2
          {
            \group_begin:
              \embrac_treat_bibparens:
              \tl_if_eq:nnTF {##1} {*}
                { \use:c {embrac_orig_#1:n} {##2} }
                { \use:c {__embrac_#1:n} {##2} }
            \group_end:
          }
        \exp_args:Nc \RenewDocumentCommand {#1} {sm}
          {
            \IfBooleanTF {##1}
              { \use:c {embrac_#1:nn} {*} {##2} }
              { \use:c {embrac_#1:nn} { } {##2} }
          }
      }
      { \msg_info:nnn {embrac} {not-patching} {#1} }
  }

\NewDocumentCommand \EmbracMakeKnown {m}
  { \embrac_new_replacement_macro:n {#1} }
  
\EmbracMakeKnown {emph}
\EmbracMakeKnown {textit}
\EmbracMakeKnown {textsl}
\AtBeginDocument
  { \embrac_if_fontspec:T { \EmbracMakeKnown {textsi} } }

% --------------------------------------------------------------------------
% TURNING EMBRAC OFF AND ON:
% turning embrac off:
\NewDocumentCommand \EmbracOff {}
  {
    \seq_map_inline:Nn \l__embrac_changed_macros_seq
      {
        \exp_args:Nc \RenewDocumentCommand {##1} {sm}
          { \use:c {embrac_orig_##1:n} {####2} }
      }
  }

% turning embrac on:
\NewDocumentCommand \EmbracOn {}
  {
    \seq_map_inline:Nn \l__embrac_changed_macros_seq
      {
        \exp_args:Nc \RenewDocumentCommand {##1} {sm}
          {
            \IfBooleanTF {####1}
              { \use:c {embrac_##1:nn} {*} {####2} }
              { \use:c {embrac_##1:nn} { } {####2} }
          }
      }
  }

% --------------------------------------------------------------------------
% ADDING AND REMOVING BRACKETS:
% internal add commands:
\cs_new_protected:Npn \embrac_add_op_to_emph:nnn #1#2#3
  {
    \prop_put:Nnn \l__embrac_emph_obrackets_symbol_prop {#1} {#1}
    \embrac_empty_or_no_value:nTF {#2}
      { \prop_put_if_new:Nnn \l__embrac_emph_obrackets_inner_prop {#1} {0pt} }
      { \prop_put_if_new:Nnn \l__embrac_emph_obrackets_inner_prop {#1} {#2} }
    \embrac_empty_or_no_value:nTF {#3}
      { \prop_put_if_new:Nnn \l__embrac_emph_obrackets_outer_prop {#1} {0pt} }
      { \prop_put_if_new:Nnn \l__embrac_emph_obrackets_outer_prop {#1} {#3} }
  }

\cs_new_protected:Npn \embrac_add_cl_to_emph:nnn #1#2#3
  {
    \prop_put:Nnn \l__embrac_emph_cbrackets_symbol_prop {#1} {#1}
    \embrac_empty_or_no_value:nTF {#2}
      { \prop_put_if_new:Nnn \l__embrac_emph_cbrackets_inner_prop {#1} {0pt} }
      { \prop_put_if_new:Nnn \l__embrac_emph_cbrackets_inner_prop {#1} {#2} }
    \embrac_empty_or_no_value:nTF {#3}
      { \prop_put_if_new:Nnn \l__embrac_emph_cbrackets_outer_prop {#1} {0pt} }
      { \prop_put_if_new:Nnn \l__embrac_emph_cbrackets_outer_prop {#1} {#3} }
  }

\cs_new_protected:Npn \embrac_add_to_emph:nnnnnn #1#2#3#4#5#6
  {
    \embrac_add_op_to_emph:nnn {#1} {#2} {#3}
    \embrac_add_cl_to_emph:nnn {#4} {#5} {#6}
  }

% internal delete commands:
\cs_new_protected:Npn \embrac_remove_op_from_emph:n #1
  {
    \prop_remove:Nn \l__embrac_emph_obrackets_inner_prop {#1}
    \prop_remove:Nn \l__embrac_emph_obrackets_outer_prop {#1}
  }

\cs_new_protected:Npn \embrac_remove_cl_from_emph:n #1
  {
    \prop_remove:Nn \l__embrac_emph_cbrackets_inner_prop {#1}
    \prop_remove:Nn \l__embrac_emph_cbrackets_outer_prop {#1}
  }
  
\cs_new_protected:Npn \embrac_remove_from_emph:nn #1#2
  {
    \embrac_remove_op_from_emph:n {#1}
    \embrac_remove_cl_from_emph:n {#2}
  }

% internal renew commands:
\cs_new_protected:Npn \embrac_renew_op_emph:nnn #1#2#3
  {
    \embrac_empty_or_no_value:nTF {#2}
      { \prop_put:Nnn \l__embrac_emph_obrackets_inner_prop {#1} {0pt} }
      { \prop_put:Nnn \l__embrac_emph_obrackets_inner_prop {#1} {#2} }
    \embrac_empty_or_no_value:nTF {#3}
      { \prop_put:Nnn \l__embrac_emph_obrackets_outer_prop {#1} {0pt} }
      { \prop_put:Nnn \l__embrac_emph_obrackets_outer_prop {#1} {#3} }
  }

\cs_new_protected:Npn \embrac_renew_cl_emph:nnn #1#2#3
  {
    \embrac_empty_or_no_value:nTF {#2}
      { \prop_put:Nnn \l__embrac_emph_cbrackets_inner_prop {#1} {0pt} }
      { \prop_put:Nnn \l__embrac_emph_cbrackets_inner_prop {#1} {#2} }
    \embrac_empty_or_no_value:nTF {#3}
      { \prop_put:Nnn \l__embrac_emph_cbrackets_outer_prop {#1} {0pt} }
      { \prop_put:Nnn \l__embrac_emph_cbrackets_outer_prop {#1} {#3} }
  }

\cs_new_protected:Npn \embrac_renew_emph:nnnnnn #1#2#3#4#5#6
  {
    \embrac_renew_op_emph:nnn {#1} {#2} {#3}
    \embrac_renew_cl_emph:nnn {#4} {#5} {#6}
  }

% internal change commands:
\cs_new_protected:Npn \embrac_change_op_emph:nnn #1#2#3
  {
    \prop_if_in:NnT \l__embrac_emph_obrackets_inner_prop {#1}
      {
        \embrac_empty_or_no_value:nF {#2}
          { \prop_put:Nnn \l__embrac_emph_obrackets_inner_prop {#1} {#2} }
        \embrac_empty_or_no_value:nF {#3}
          { \prop_put:Nnn \l__embrac_emph_obrackets_outer_prop {#1} {#3} }
      }
  }

\cs_new_protected:Npn \embrac_change_cl_emph:nnn #1#2#3
  {
    \prop_if_in:NnT \l__embrac_emph_cbrackets_inner_prop {#1}
      {
        \embrac_empty_or_no_value:nF {#2}
          { \prop_put:Nnn \l__embrac_emph_cbrackets_inner_prop {#1} {#2} }
        \embrac_empty_or_no_value:nF {#3}
          { \prop_put:Nnn \l__embrac_emph_cbrackets_outer_prop {#1} {#3} }
      }
  }

\cs_new_protected:Npn \embrac_change_emph:nnnnnn #1#2#3#4#5#6
  {
    \embrac_change_op_emph:nnn {#1} {#2} {#3}
    \embrac_change_cl_emph:nnn {#4} {#5} {#6}
  }

% --------------------------------------------------------------------------
% user commands:
\NewDocumentCommand \AddEmph
  {
    m > { \SplitArgument {1} {,} } O{,}
    m > { \SplitArgument {1} {,} } O{,}
  }
  {
    \embrac_add_to_emph:nnnnnn {#1} #2 {#3} #4
    \ignorespaces
  }

\NewDocumentCommand \AddOpEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_add_op_to_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \AddClEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_add_cl_to_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \DeleteEmph { mm }
  {
    \embrac_remove_from_emph:nn {#1} {#2}
    \ignorespaces
  }

\NewDocumentCommand \DeleteOpEmph { mm }
  {
    \embrac_remove_op_from_emph:n {#1}
    \ignorespaces
  }

\NewDocumentCommand \DeleteClEmph { mm }
  {
    \embrac_remove_cl_from_emph:n {#1}
    \ignorespaces
  }

\NewDocumentCommand \RenewEmph
  {
    m > { \SplitArgument {1} {,} } O{,}
    m > { \SplitArgument {1} {,} } O{,}
  }
  {
    \embrac_renew_emph:nnnnnn {#1} #2 {#3} #4
    \ignorespaces
  }

\NewDocumentCommand \RenewOpEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_renew_op_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \RenewClEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_renew_cl_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \ChangeEmph
  {
    m > { \SplitArgument {1} {,} } O{,}
    m > { \SplitArgument {1} {,} } O{,}
  }
  {
    \embrac_change_emph:nnnnnn {#1} #2 {#3} #4
    \ignorespaces
  }

\NewDocumentCommand \ChangeOpEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_change_op_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \ChangeClEmph
  { m > { \SplitArgument {1} {,} } O{,} }
  {
    \embrac_change_cl_emph:nnn {#1} #2
    \ignorespaces
  }

\NewDocumentCommand \embparen {+m}
  { \embrac_enparen:nnn {(} {)} {#1} }

\NewDocumentCommand \embbracket {+m}
  { \embrac_enparen:nnn {[} {]} {#1} }

\NewDocumentCommand \emb {mm+m}
  { \embrac_enparen:nnn {#1} {#2} {#3} }

% --------------------------------------------------------------------------
% add some defaults and finalize package:
\AddEmph{[}{]}[.04em,-.12em]
\AddEmph{(}[-.04em]{)}[,-.15em]

\ProcessKeysOptions {embrac}

\AtBeginDocument { \embrac_treat_bibemph: }

\file_input_stop:

% --------------------------------------------------------------------------
% HISTORY
2012/06/29 - v0.1  - first public release
2012/06/29 - v0.1a - renamed \RenewEmph => \ChangeEmph and added new \RenewEmph
2012/07/24 - v0.1b - adapted to deprecated functions in l3kernel and l3packages
2012/11/04 - v0.2  - extended `biblatex' option: parens/full
                   - changed buggy definition of \EmbracOff and \EmbracOn
2013/03/22 - v0.3  - made definitions robust where appropriate
                   - added support for `fontspec's \textsi
2013/04/04 - v0.3a - bug fix in \EmbracOn and \EmbracOff
2013/05/13 - v0.4  - added versions of \AddEmph, \RenewEmph, \DeleteEmph and
                     \ChangeEmph that allow setting opening or closing parts
                     separately
2014/05/07 - v0.5  - renaming of some internal commands
                   - leave brackets unchanged if in math mode
2014/06/24 - v0.6  - add support for \textsl
2014/07/03 - v0.6a - bugfix: remove unwanted (and unnecessary) expansion in
                     \__embrac_emph:n
2015/09/06 - v0.6b - fix https://github.com/cgnieder/embrac/issues/5
2015/11/13 - v0.6c - avoid code duplication
2016/01/07 - v0.6d - \prop_get:Nn => \prop_item:Nn
2017/07/04 - v0.7  - implement issue #8 (now treatment of symbols with catcode
                     other than 12 is possible)
2019/10/01 - v0.8  - fix issue #9
                   - new macros \embparen, \embbracket and \emb
2019/12/31 - v0.9  - new: \EmbracMakeKnown
                   - change penalties
2021/02/20 - v0.9a - fix issue #13