% --------------------------------------------------------------------------
% the ACRO package
% 
%   Typeset Acronyms
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/acro/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2011-2012 Clemens Niederberger
% 
% This work 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
% and version 1.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
% 
% This work has the LPPL maintenance status `maintained'.
% 
% The Current Maintainer of this work is Clemens Niederberger.
% --------------------------------------------------------------------------
% The acro package consists of the files
%  - acro.sty, acro_en.tex, acro_en.pdf, README
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
\RequirePackage{expl3,xparse,l3keys2e,xtemplate}
\ProvidesExplPackage
  {acro}
  {2012/10/07}
  {0.4a}
  {Typeset Acronyms}

% error messages:
\msg_new:nnnn { acro } { undefined }
  { You've~requested~acronym~`#1'~but~it~seems~that~it~was~never~defined! }
  {
    You've~requested~acronym~`#1'~\msg_line_context: \c_space_tl but~you~
    apperantly~haven't~defined~it,~yet!~Maybe~you've~mispelled~it?
  }

% temporary variables
\tl_new:N   \l__acro_tmpa_tl
\tl_new:N   \l__acro_tmpb_tl
\tl_new:N   \l__acro_tmpc_tl
\prop_new:N \l__acro_tmpa_prop
\seq_new:N  \l__acro_tmpa_seq

% boolean variables:
\bool_new:N \l__acro_use_single_bool
\bool_new:N \l__acro_print_only_used_bool
\bool_set_true:N \l__acro_print_only_used_bool
\bool_new:N \l__acro_use_plural_bool
\bool_new:N \l__acro_hyperref_loaded_bool
\bool_new:N \l__acro_use_hyperref_bool
\bool_new:N \l__acro_custom_format_bool
\bool_new:N \l__acro_strict_bool
\bool_new:N \l__acro_create_macros_bool
\bool_new:N \l__acro_first_upper_bool
\bool_new:N \l__acro_sort_bool
\bool_new:N \l__acro_capitalize_list_bool
\bool_new:N \l__acro_citation_all_bool
\bool_new:N \l__acro_citation_first_bool
\bool_set_true:N \l__acro_citation_first_bool

% tokenlist variables:
\tl_new:N   \l__acro_short_format_tl
\tl_new:N   \l__acro_long_format_tl
\tl_new:N   \l__acro_list_long_format_tl
\tl_new:N   \l__acro_extra_format_tl
\tl_new:N   \l__acro_first_instance_tl
\tl_set:Nn  \l__acro_first_instance_tl { default }
\tl_new:N   \l__acro_extra_instance_tl
\tl_set:Nn  \l__acro_extra_instance_tl { default }
\tl_new:N   \l__acro_page_instance_tl
\tl_set:Nn  \l__acro_page_instance_tl  { none }
\tl_new:N   \l__acro_page_name_tl
\tl_set:Nn  \l__acro_page_name_tl      { p. }
\tl_new:N   \l__acro_list_instance_tl
\tl_set:Nn  \l__acro_list_instance_tl  { list }
\tl_new:N   \l__acro_list_type_tl
\tl_set:Nn  \l__acro_list_type_tl      { description }
\tl_new:N   \l__acro_list_title_tl
\tl_set:Nn  \l__acro_list_title_tl     { section* }
\tl_new:N   \l__acro_list_name_tl
\tl_set:Nn  \l__acro_list_name_tl      { Acronyms }
\tl_new:N   \l__acro_short_tl
\tl_new:N   \l__acro_short_plural_tl
\tl_new:N   \l__acro_default_plural_tl
\tl_set:Nn  \l__acro_default_plural_tl { s }
\tl_new:N   \l__acro_alt_tl
\tl_new:N   \l__acro_long_tl
\tl_new:N   \l__acro_custom_format_tl
\tl_new:N   \l__acro_first_between_tl
\tl_new:N   \l__acro_citation_space_tl
\tl_set:Nn  \l__acro_citation_space_tl { \nobreakspace }

% property list variables:
\prop_new:N \l__acro_short_prop
\prop_new:N \l__acro_alt_prop
\prop_new:N \l__acro_long_prop
\prop_new:N \l__acro_class_prop
\prop_new:N \l__acro_replace_plural_prop
\prop_new:N \l__acro_short_plural_prop
\prop_new:N \l__acro_long_plural_prop
\prop_new:N \l__acro_extra_prop
\prop_new:N \l__acro_format_prop
\prop_new:N \l__acro_citation_prop
\prop_new:N \l__acro_citation_pre_prop
\prop_new:N \l__acro_citation_post_prop

% length variables:
\dim_new:N  \l__acro_table_width_dim
\dim_set:Nn \l__acro_table_width_dim { .7\linewidth }

\cs_new:Npn \__acro_citation_cmd:w { \cite }
\cs_new:Npn \__acro_no_break: { \tex_penalty:D \c_ten_thousand }

\cs_new:Npn \__acro_first_upper_case:n #1
  { \tl_expandable_uppercase:n { \tl_head:n { #1 } } \tl_tail:n { #1 } }

\cs_new_eq:NN \acro_first_upper_case:n \__acro_first_upper_case:n

% options:
\keys_define:nn { acro }
  {
    macros           .bool_set:N = \l__acro_create_macros_bool   ,
    strict           .bool_set:N = \l__acro_strict_bool          ,
    sort             .bool_set:N = \l__acro_sort_bool            ,
    short-format     .tl_set:N   = \l__acro_short_format_tl      ,
    long-format      .code:n     =
      \tl_set:Nn \l__acro_long_format_tl { #1 }
      \tl_set:Nn \l__acro_list_long_format_tl { #1 } ,
    list-long-format .tl_set:N   = \l__acro_list_long_format_tl  ,
    extra-format     .tl_set:N   = \l__acro_extra_format_tl      ,
    single           .bool_set:N = \l__acro_use_single_bool      ,
    first-style      .tl_set:N   = \l__acro_first_instance_tl    ,
    extra-style      .tl_set:N   = \l__acro_extra_instance_tl    ,
    page-ref         .tl_set:N   = \l__acro_page_instance_tl     ,
    page-name        .tl_set:N   = \l__acro_page_name_tl         ,
    list-style       .tl_set:N   = \l__acro_list_instance_tl     ,
    list-type        .tl_set:N   = \l__acro_list_type_tl         ,
    list-header      .tl_set:N   = \l__acro_list_title_tl        ,
    list-name        .tl_set:N   = \l__acro_list_name_tl         ,
    list-table-width .dim_set:N  = \l__acro_table_width_dim      ,
    hyperref         .bool_set:N = \l__acro_use_hyperref_bool    ,
    only-used        .bool_set:N = \l__acro_print_only_used_bool ,
    plural-ending    .tl_set:N   = \l__acro_default_plural_tl    ,
    list-caps        .bool_set:N = \l__acro_capitalize_list_bool ,
    cite             .choice:                                    ,
    cite / all       .code:n     =
      \bool_set_true:N \l__acro_citation_all_bool
      \bool_set_true:N \l__acro_citation_first_bool              ,
    cite / none      .code:n     =
      \bool_set_false:N \l__acro_citation_all_bool
      \bool_set_false:N \l__acro_citation_first_bool             ,
    cite / first     .code:n     =
      \bool_set_false:N \l__acro_citation_all_bool
      \bool_set_true:N  \l__acro_citation_first_bool             ,
    cite-all         .default:n  = all                           ,
    cite-cmd         .code:n     =
      \cs_set:Npn \__acro_citation_cmd:w { #1 }                  ,
    cite-space       .tl_set:N   = \l__acro_citation_space_tl    ,
    uc-cmd           .code:n     =
      \cs_set_eq:NN \__acro_first_upper_case:n #1
  }

% setup command:
\NewDocumentCommand \acsetup { m }
  { \keys_set:nn { acro } { #1 } \ignorespaces }

% --------------------------------------------------------------------------
% adding an acronym, internal command:
% #1: use/replace plural (boolean)
% #2: id
% #3: short
% #4: short plural
% #5: alt
% #6: long
% #7: long plural
% #8: class
% #9: extra
\cs_new:Npn \acro_new:nnnnnnnnn #1#2#3#4#5#6#7#8#9
  {
    \IfBooleanTF { #1 }
      { \prop_put:Nnn \l__acro_replace_plural_prop { #2 } { \c_true_bool } }
      { \prop_put:Nnn \l__acro_replace_plural_prop { #2 } { \c_false_bool } }
    \prop_put:Nnn \l__acro_short_prop { #2 } { #3 }
    \IfNoValueTF { #4 }
      { \prop_put:Nnn \l__acro_short_plural_prop { #2 } { \l__acro_default_plural_tl } }
      { \prop_put:Nnn \l__acro_short_plural_prop { #2 } { #4 } }
    \IfNoValueTF { #5 }
      { \prop_put:Nnn \l__acro_alt_prop { #2 } { #2 } }
      { \prop_put:Nnn \l__acro_alt_prop { #2 } { #5 } }
    \prop_put:Nnn \l__acro_long_prop { #2 } { #6 }
    \IfNoValueTF { #7 }
      { \prop_put:Nnn \l__acro_long_plural_prop { #2 } { \l__acro_default_plural_tl } }
      { \prop_put:Nnn \l__acro_long_plural_prop { #2 } { #7 } }
    \IfNoValueF { #8 }
      { \prop_put:Nnn \l__acro_class_prop { #2 } { #8} }
    \IfNoValueF { #9 }
      { \prop_put:Nnn \l__acro_extra_prop { #2 } { #9 } }
    \bool_new:c { g_acro_#2_used_bool }
    \bool_new:c { g_acro_#2_label_bool }
    \bool_if:NT \l__acro_create_macros_bool
      {
        \cs_if_exist:cTF { #2 }
          {
            \bool_if:NT \l__acro_strict_bool
              { \cs_set:cpn { #2 } { \ac { #2 } } }
          }
          { \cs_new:cpn { #2 } { \ac { #2 } } }
      }
  }

% typeset the short form:
\cs_new:Npn \__acro_write_short:n #1
  {
    \mode_if_horizontal:F { \leavevmode }
    \group_begin:
      \bool_if:NTF \l__acro_custom_format_bool
        { \l__acro_custom_format_tl }
        { \l__acro_short_format_tl }
      { \hbox:n { #1 } }
    \group_end:
    \bool_if:NT \l__acro_use_plural_bool
      { \tl_use:N \l__acro_short_plural_tl }
  }
\cs_generate_variant:Nn \__acro_write_short:n { V }

% typeset the longform,...:
\cs_new:Npn \__acro_write_long:Nn #1#2
  {
    \mode_if_horizontal:F { \leavevmode }
    \group_begin:
      \exp_args:Nx #1
        {
          \bool_if:NTF \l__acro_first_upper_bool
            { \exp_not:N \__acro_first_upper_case:n { \exp_not:n { #2 } } }
            { \exp_not:n { #2 } }
        }
    \group_end:
  }
\cs_generate_variant:Nn \__acro_write_long:Nn { NV,No,Nf }

% --------------------------------------------------------------------------
% hyperref support
\cs_new_eq:NN \acro_hyper_target:nn \use_ii:nn
\cs_new_eq:NN \acro_hyper_link:nn \use_ii:nn

\cs_new:Npn \__acro_activate_hyperref_support:
  {
    \bool_if:nT { \l__acro_hyperref_loaded_bool && \l__acro_use_hyperref_bool }
      {
        \cs_set_eq:NN \acro_hyper_link:nn \hyperlink
        \cs_set:Npn \acro_hyper_target:nn ##1##2
          { \raisebox { 3ex } [ 0pt ] { \hypertarget { ##1 } { } } ##2 }
      }
  }

\cs_new:Npn \__acro_make_link:nNN #1#2#3
  {
    \tl_set:Nn #2
       {
         \acro_hyper_link:nn { #1 } { \phantom { #3 } }
         \__acro_is_single:nTF { #1 } { \hbox_overlap_left:n { #3 } }
           {
             \bool_if:nTF { \l__acro_use_hyperref_bool && \l__acro_hyperref_loaded_bool }
               { \textcolor { \@linkcolor } { \hbox_overlap_left:n { #3 } } }
               { \hbox_overlap_left:n { #3 } }
           }
       }
  }

% --------------------------------------------------------------------------
% output style of the first time an acronym is used
\bool_new:N \l__acro_first_use_brackets_bool
\bool_new:N \l__acro_first_only_short_bool
\bool_new:N \l__acro_first_reversed_bool
\tl_new:N   \l__acro_first_brackets_tl

% #1: id
% #2: short
% #3: long
\DeclareObjectType { acro-first } { 3 }

\DeclareTemplateInterface { acro-first } { text } { 3 }
  {
    brackets      : boolean   = true  ,
    brackets-type : tokenlist = ()    ,
    only-short    : boolean   = false ,
    reversed      : boolean   = false ,
    between       : tokenlist         ,
  }
\DeclareTemplateCode { acro-first } { text } { 3 }
  {
    brackets      = \l__acro_first_use_brackets_bool ,
    brackets-type = \l__acro_first_brackets_tl       ,
    only-short    = \l__acro_first_only_short_bool   ,
    reversed      = \l__acro_first_reversed_bool     ,
    between       = \l__acro_first_between_tl        ,
  }
  {
    \AssignTemplateKeys
    \bool_if:nT { !\l__acro_first_only_short_bool && !\l__acro_first_reversed_bool }
      {
        \__acro_write_long:No \l__acro_long_format_tl { #3 }
        \tl_use:N \c_space_tl
        \tl_if_blank:VF \l__acro_first_between_tl
          {
            \tl_use:N \l__acro_first_between_tl
            \tl_use:N \c_space_tl
          }
      }
    \bool_if:nT { \l__acro_first_use_brackets_bool && !\l__acro_first_reversed_bool }
      { \tl_head:N \l__acro_first_brackets_tl }
    \__acro_write_short:n { #2 }
    \bool_if:nT { \l__acro_first_use_brackets_bool && !\l__acro_first_reversed_bool }
      { \tl_tail:N \l__acro_first_brackets_tl }
    \bool_if:nT { !\l__acro_first_only_short_bool && \l__acro_first_reversed_bool }
      {
        \tl_if_blank:VF \l__acro_first_between_tl
          {
            \tl_use:N \c_space_tl
            \tl_use:N \l__acro_first_between_tl
          }
        \tl_use:N \c_space_tl
        \bool_if:nT { \l__acro_first_use_brackets_bool && \l__acro_first_reversed_bool }
          { \tl_head:N \l__acro_first_brackets_tl }
        \__acro_write_long:No \l__acro_long_format_tl { #3 }
        \bool_if:nT { \l__acro_first_use_brackets_bool && \l__acro_first_reversed_bool }
          { \tl_tail:N \l__acro_first_brackets_tl }
      }
    \__acro_cite_if:Nn \l__acro_citation_first_bool { #1 }
  }

\DeclareTemplateInterface { acro-first } { footnote } { 3 } { }
\DeclareTemplateCode { acro-first } { footnote } { 3 } { }
  {
    \AssignTemplateKeys
    \__acro_write_short:n { #2 }
    \footnote
      {
        \__acro_write_long:No \l__acro_long_format_tl { #3 }
        \__acro_cite_if:Nn \l__acro_citation_first_bool { #1 }
      } 
  }

% the different styles:
\DeclareInstance { acro-first } { default        } { text     } { }
\DeclareInstance { acro-first } { square         } { text     }
  { brackets-type = [] }
\DeclareInstance { acro-first } { plain          } { text     }
  { brackets = false , between = -- }
\DeclareInstance { acro-first } { plain-reversed } { text     }
  { brackets = false , between = -- , reversed = true }
\DeclareInstance { acro-first } { footnote       } { footnote } { }
\DeclareInstance { acro-first } { short          } { text     }
  { only-short = true , brackets = false }
\DeclareInstance { acro-first } { reversed       } { text     }
  { reversed = true }

% --------------------------------------------------------------------------
% formatting the extras information:
\bool_new:N \l__acro_extra_punct_bool
\bool_new:N \l__acro_extra_use_brackets_bool
\tl_new:N   \l__acro_extra_brackets_tl
\tl_new:N   \l__acro_extra_punct_tl

\DeclareObjectType { acro-extra } { 1 }

\DeclareTemplateInterface { acro-extra } { default } { 1 }
  {
    punct         : boolean   = false ,
    punct-symbol  : tokenlist = {,}   ,
    brackets      : boolean   = true  ,
    brackets-type : tokenlist = ()
  }

\DeclareTemplateCode { acro-extra } { default } { 1 }
  {
    punct         = \l__acro_extra_punct_bool        ,
    punct-symbol  = \l__acro_extra_punct_tl          ,
    brackets      = \l__acro_extra_use_brackets_bool ,
    brackets-type = \l__acro_extra_brackets_tl
  }
  {
    \AssignTemplateKeys
    \bool_if:NT \l__acro_extra_punct_bool
      { \tl_use:N \l__acro_extra_punct_tl \tl_use:N \c_space_tl }
    \bool_if:NT \l__acro_extra_use_brackets_bool
      { \tl_head:N \l__acro_extra_brackets_tl }
    \__acro_write_long:Nn \l__acro_extra_format_tl { #1 }
    \bool_if:NT \l__acro_extra_use_brackets_bool
      { \tl_tail:N \l__acro_extra_brackets_tl }
  }

% the different styles:
\DeclareInstance { acro-extra } { default } { default }
  { brackets = false , punct = true , punct-symbol = . }
\DeclareInstance { acro-extra } { plain   } { default }
  { brackets = false , punct = false }
\DeclareInstance { acro-extra } { paren   } { default } { }
\DeclareInstance { acro-extra } { bracket } { default } { brackets-type=[] }
\DeclareInstance { acro-extra } { comma   } { default }
  { punct = true, brackets = false }

% --------------------------------------------------------------------------
% outputting the page number:
\bool_new:N \l__acro_page_punct_bool
\bool_new:N \l__acro_page_display_bool
\tl_new:N   \l__acro_page_punct_tl
\dim_new:N  \l__acro_page_space_dim

\cs_new:Npn \acro_no_break: { \tex_penalty:D \c_ten_thousand }

\DeclareObjectType { acro-page-number } { 1 }

\DeclareTemplateInterface { acro-page-number } { default } { 1 }
  {
    display       : boolean   = true  ,
    punct         : boolean   = false ,
    punct-symbol  : tokenlist = {,}   ,
    brackets      : boolean   = false ,
    brackets-type : tokenlist = ()    ,
    space         : length    = .3ex  ,
    name          : tokenlist         ,
  }

\DeclareTemplateCode { acro-page-number } { default } { 1 }
  {
    display       = \l__acro_page_display_bool  ,
    punct         = \l__acro_page_punct_bool    ,
    punct-symbol  = \l__acro_page_punct_tl      ,
    brackets      = \l__acro_page_brackets_bool ,
    brackets-type = \l__acro_page_brackets_tl   ,
    space         = \l__acro_page_space_dim     ,
    name          = \l__acro_page_name_tl       ,
  }
  {
    \AssignTemplateKeys
    \bool_if:NT \l__acro_page_display_bool
      {
        \bool_if:NT \l__acro_page_punct_bool
          { \tl_use:N \l__acro_page_punct_tl }
        \tl_use:N \c_space_tl
        \bool_if:NT \l__acro_page_brackets_bool
          { \tl_head:N \l__acro_page_brackets_tl }
        \tl_use:N \l__acro_page_name_tl
        \acro_no_break:
        \skip_horizontal:N \l__acro_page_space_dim
        \acro_no_break:
        \pageref { ac:#1 }
        \bool_if:NT \l__acro_page_brackets_bool
          { \tl_tail:N \l__acro_page_brackets_tl }
      }
  }

% the different styles:
\DeclareInstance { acro-page-number } { default } { default }
  { punct = true , punct-symbol = . }
\DeclareInstance { acro-page-number } { plain   } { default }
  { punct = false }
\DeclareInstance { acro-page-number } { comma   } { default } { punct = true }
\DeclareInstance { acro-page-number } { paren   } { default }
  { brackets=true , punct-symbol = ~ }
\DeclareInstance { acro-page-number } { none    } { default }
  { display = false }

% --------------------------------------------------------------------------
% the title of the list:
\cs_new:Npn \acro_list_title_format:n #1 { #1 }

\DeclareObjectType { acro-title } { 1 }

\DeclareTemplateInterface { acro-title } { sectioning } { 1 }
  { name-format : function 1 = #1 }

\DeclareTemplateCode { acro-title } { sectioning } { 1 }
  { name-format = \acro_list_title_format:n }
  {
    \AssignTemplateKeys
    \acro_list_title_format:n { #1 }
  }

% the different styles:
\DeclareInstance { acro-title } { chapter*    } { sectioning }
  { name-format = \chapter* { #1 } }
\DeclareInstance { acro-title } { part*       } { sectioning }
  { name-format = \part* { #1 } }
\DeclareInstance { acro-title } { section*    } { sectioning }
  { name-format = \section* { #1 } }
\DeclareInstance { acro-title } { subsection* } { sectioning }
  { name-format = \subsection* { #1 } }
\DeclareInstance { acro-title } { chapter     } { sectioning }
  { name-format = \chapter { #1 } }
\DeclareInstance { acro-title } { part        } { sectioning }
  { name-format = \part { #1 } }
\DeclareInstance { acro-title } { section     } { sectioning }
  { name-format = \section { #1 } }
\DeclareInstance { acro-title } { subsection  } { sectioning }
  { name-format = \subsection { #1 } }

% --------------------------------------------------------------------------
% outputting the whole list
\DeclareObjectType { acro-list } { 3 }

% excluded items:
\bool_new:N \l__acro_is_excluded_bool
\cs_generate_variant:Nn \tl_if_eq:nnT { nV }
% #1: id
% #2: excluded classes
% #3: continue if not excluded
\cs_new:Npn \acro_is_excluded:nnF #1#2#3
  {
    \bool_set_false:N \l__acro_is_excluded_bool
    \IfNoValueTF { #2 }
      { #3 }
      {
        \clist_map_inline:nn { #2 }
          {
            \prop_get:NnN \l__acro_class_prop { #1 } \l__acro_tmpa_tl
            \tl_if_eq:nVT { ##1 } \l__acro_tmpa_tl
              { \bool_set_true:N \l__acro_is_excluded_bool }
          }
        \bool_if:NF \l__acro_is_excluded_bool { #3 }
      }
  }

% build the list, dummy functions to be redefined in the template code:
\cs_new:Npn \acro_print_list_short:nn #1#2 { }
\cs_new:Npn \acro_print_list_long:n   #1   { }
\cs_new:Npn \acro_print_list_extra:n  #1   { }
\cs_new:Npn \acro_print_list_page:n   #1   { }

% Test, if acronyms should be printed or not; needs testing for in/excluded
% classes and options `only-used' and `single':
\cs_new:Npn \acro_list_allow_items:nn #1#2
  {
    \prop_map_inline:Nn \l__acro_short_prop
      {
        \acro_get:n { ##1 }
        \bool_if:nT
          {
            ( \l__acro_use_single_bool && \cs_if_exist_p:c { acro@##1@twice } ) ||
            ( !\l__acro_use_single_bool && \cs_if_exist_p:c { acro@##1@once } && \l__acro_print_only_used_bool ) ||
            ( !\l__acro_use_single_bool && !\l__acro_print_only_used_bool )
          }
          {
            \acro_is_excluded:nnF { ##1 } { #2 }
              {
                \tl_if_blank:nTF { #1 }
                  {
                    \acro_print_list_short:nn { ##1 } { ##2 }
                    \bool_if:NT \l__acro_capitalize_list_bool
                      { \bool_set_true:N \l__acro_first_upper_bool }
                    \acro_print_list_long:n { ##1 }
                    \bool_set_false:N \l__acro_first_upper_bool
                    \acro_print_list_extra:n { ##1 }
                    \acro_print_list_page:n { ##1 }
                  }
                  {
                    \clist_map_inline:nn { #1 }
                      {
                        \prop_get:NnNT \l__acro_class_prop { ##1 } \l__acro_tmpa_tl
                          {
                            \tl_set:Nn \l__acro_tmpb_tl { ####1 }
                            \tl_trim_spaces:N \l__acro_tmpa_tl
                            \tl_trim_spaces:N \l__acro_tmpb_tl
                            \tl_if_eq:NNT \l__acro_tmpa_tl \l__acro_tmpb_tl
                              {
                                \acro_print_list_short:nn { ##1 } { ##2 }
                                \bool_if:NT \l__acro_capitalize_list_bool
                                  { \bool_set_true:N \l__acro_first_upper_bool }
                                \acro_print_list_long:n { ##1 }
                                \bool_set_false:N \l__acro_first_upper_bool
                                \acro_print_list_extra:n { ##1 }
                                \acro_print_list_page:n { ##1 }
                              }
                          }
                      }
                  }
              }
          }
      }
  }

% list template:
\DeclareTemplateInterface { acro-list } { list } { 3 }
  {  }

\DeclareTemplateCode { acro-list } { list } { 3 }
  {  }
  {
    \AssignTemplateKeys
    \__acro_activate_hyperref_support:
    \cs_set:Npn \acro_print_list_short:nn ##1##2
      { \item [ \acro_hyper_target:nn { ##1 } { \__acro_write_short:n { ##2 } } ] }
    \cs_set:Npn \acro_print_list_long:n ##1
      {
        \__acro_write_long:Nf \l__acro_list_long_format_tl
          { \prop_get:Nn \l__acro_long_prop { ##1 } }
        \__acro_cite_if:Nn \l__acro_citation_all_bool { ##1 }
      }
    \cs_set:Npn \acro_print_list_extra:n ##1
      {
        \prop_get:NnNT \l__acro_extra_prop { ##1 } \l__acro_tmpa_tl
          {
            \UseInstance { acro-extra } { \l__acro_extra_instance_tl }
              { \l__acro_tmpa_tl }
          }
      }
    \cs_set:Npn \acro_print_list_page:n ##1
      {
        \bool_if:nT { \cs_if_exist_p:c { acro@##1@once } }
          { \UseInstance { acro-page-number } { \l__acro_page_instance_tl } { ##1 } }
      }
    \begin { #1 }
      \acro_list_allow_items:nn { #2 } { #3 }
    \end { #1 }
  }

% table template:
\tl_new:N \l__acro_list_table_tl
\tl_new:N \l__acro_list_table_spec_tl

\DeclareTemplateInterface { acro-list } { table } { 3 }
  {
    table      : tokenlist = longtable         ,
    table-spec : tokenlist = lp{\l__acro_table_width_dim}
  }

\DeclareTemplateCode { acro-list } { table } { 3 }
  {
    table      = \l__acro_list_table_tl      ,
    table-spec = \l__acro_list_table_spec_tl
  }
  {
    \AssignTemplateKeys
    \__acro_activate_hyperref_support:
    \cs_set:Npn \acro_print_list_short:nn ##1##2
      { \acro_hyper_target:nn { ##1 } { \__acro_write_short:n { ##2 } } & }
    \cs_set:Npn \acro_print_list_long:n ##1
      {
        \__acro_write_long:Nf \l__acro_list_long_format_tl
          { \prop_get:Nn \l__acro_long_prop { ##1 } }
        \__acro_cite_if:Nn \l__acro_citation_all_bool { ##1 }
      }
    \cs_set:Npn \acro_print_list_extra:n ##1
      {
        \prop_get:NnNT \l__acro_extra_prop { ##1 } \l__acro_tmpa_tl
          {
            \UseInstance { acro-extra } { \l__acro_extra_instance_tl }
              { \l__acro_tmpa_tl }
          }
      }
    \cs_set:Npn \acro_print_list_page:n ##1
      {
        \bool_if:nT { \cs_if_exist_p:c { acro@##1@once } }
          { \UseInstance { acro-page-number } { \l__acro_page_instance_tl } { ##1 } }
        \tabularnewline
      }
    \exp_args:Noo \begin { \l__acro_list_table_tl } { \l__acro_list_table_spec_tl }
      \acro_list_allow_items:nn { #2 } { #3 }
    \exp_args:No \end { \l__acro_list_table_tl }
  }

% extra-table template:
\DeclareTemplateInterface { acro-list } { extra-table } { 3 }
  {
    table      : tokenlist = longtable         ,
    table-spec : tokenlist = lp{\l__acro_table_width_dim}ll
  }

\DeclareTemplateCode { acro-list } { extra-table } { 3 }
  {
    table      = \l__acro_list_table_tl      ,
    table-spec = \l__acro_list_table_spec_tl
  }
  {
    \AssignTemplateKeys
    \__acro_activate_hyperref_support:
    \cs_set:Npn \acro_print_list_short:nn ##1##2
      { \acro_hyper_target:nn { ##1 } { \__acro_write_short:n { ##2 } } & }
    \cs_set:Npn \acro_print_list_long:n ##1
      {
        \__acro_write_long:Nf \l__acro_list_long_format_tl
          { \prop_get:Nn \l__acro_long_prop { ##1 } }
        \__acro_cite_if:Nn \l__acro_citation_all_bool { ##1 }
        &
      }
    \cs_set:Npn \acro_print_list_extra:n ##1
      {
        \prop_get:NnNT \l__acro_extra_prop { ##1 } \l__acro_tmpa_tl
          {
            \UseInstance { acro-extra } { \l__acro_extra_instance_tl }
              { \l__acro_tmpa_tl }
          }
        &
      }
    \cs_set:Npn \acro_print_list_page:n ##1
      {
        \bool_if:nT { \cs_if_exist_p:c { acro@##1@once } }
          { \UseInstance { acro-page-number } { \l__acro_page_instance_tl } { ##1 } }
        \tabularnewline
      }
    \exp_args:Noo \begin { \l__acro_list_table_tl } { \l__acro_list_table_spec_tl }
      \acro_list_allow_items:nn { #2 } { #3 }
    \exp_args:No \end { \l__acro_list_table_tl }
  }

% extra-table-rev template:
\DeclareTemplateInterface { acro-list } { extra-table-rev } { 3 }
  {
    table      : tokenlist = longtable         ,
    table-spec : tokenlist = llp{\l__acro_table_width_dim}l
  }

\DeclareTemplateCode { acro-list } { extra-table-rev } { 3 }
  {
    table      = \l__acro_list_table_tl      ,
    table-spec = \l__acro_list_table_spec_tl
  }
  {
    \AssignTemplateKeys
    \__acro_activate_hyperref_support:
    \cs_set:Npn \acro_print_list_short:nn ##1##2
      { \acro_hyper_target:nn { ##1 } { \__acro_write_short:n { ##2 } } & }
    \cs_set:Npn \acro_print_list_extra:n ##1
      {
        \bool_if:NT \l__acro_capitalize_list_bool
          { \bool_set_true:N \l__acro_first_upper_bool }
        \__acro_write_long:Nf \l__acro_long_format_tl
          { \prop_get:Nn \l__acro_long_prop { ##1 } }
        \__acro_cite_if:Nn \l__acro_citation_all_bool { ##1 }
        &
      }
    \cs_set:Npn \acro_print_list_long:n ##1
      {
        \prop_get:NnNT \l__acro_extra_prop { ##1 } \l__acro_tmpa_tl
          {
            \UseInstance { acro-extra } { \l__acro_extra_instance_tl }
              { \l__acro_tmpa_tl }
          }
        &
      }
    \cs_set:Npn \acro_print_list_page:n ##1
      {
        \bool_if:nT { \cs_if_exist_p:c { acro@##1@once } }
          { \UseInstance { acro-page-number } { \l__acro_page_instance_tl } { ##1 } }
        \tabularnewline
      }
    \exp_args:Noo \begin { \l__acro_list_table_tl } { \l__acro_list_table_spec_tl }
      \acro_list_allow_items:nn { #2 } { #3 }
    \exp_args:No \end { \l__acro_list_table_tl }
  }

% the different styles:
\DeclareInstance { acro-list } { list }                { list }  { }
\DeclareInstance { acro-list } { tabular }             { table }
  { table = tabular }
\DeclareInstance { acro-list } { longtable }           { table }
  { table = longtable }
\DeclareInstance { acro-list } { extra-longtable }     { extra-table }
  { table      = longtable }
\DeclareInstance { acro-list } { extra-tabular }       { extra-table }
  { table      = tabular }
\DeclareInstance { acro-list } { extra-longtable-rev } { extra-table-rev }
  { table      = longtable }
\DeclareInstance { acro-list } { extra-tabular-rev }   { extra-table-rev }
  { table      = tabular }

% --------------------------------------------------------------------------
% automatic typesetting, the internals of \ac:
% #1: id
\cs_new:Npn \acro_use:n #1
  {
    % get the acronym and the plural settings:
    \acro_get:n { #1 }
    \acro_set_plural:n { #1 }
    \acro_is_used:nTF { #1 }
      {
        % this is not the first time
        \__acro_write_short:V \l__acro_short_tl
        \__acro_cite_if:Nn \l__acro_citation_all_bool { #1 }
      }
      {
        % this is the first time
        \__acro_is_single:nTF { #1 }
          { \__acro_write_long:NV \l__acro_long_format_tl \l__acro_long_tl }
          { 
            \UseInstance { acro-first } { \l__acro_first_instance_tl }
              { #1 }
              { \l__acro_short_tl }
              { \l__acro_long_tl }
          }
      }
  }

\cs_new:Npn \__acro_is_single:nTF #1#2#3
  {
    \bool_if:nTF { !\l__acro_use_single_bool || \cs_if_exist_p:c { acro@#1@twice } }
      { #3 } { #2 }
  }

\cs_new:Npn \__acro_is_single:nT #1#2
  {
    \bool_if:nF { !\l__acro_use_single_bool || \cs_if_exist_p:c { acro@#1@twice } }
      { #2 }
  }

% --------------------------------------------------------------------------
% some helpers we'll need more often:
\cs_new:Npn \acro_get:n #1
  {
    \__acro_activate_hyperref_support:
    \prop_get:NnNF \l__acro_short_prop { #1 } \l__acro_tmpa_tl
      { \msg_error:nnx { acro } { undefined } { #1 } }
    \__acro_make_link:nNN { #1 } \l__acro_short_tl \l__acro_tmpa_tl
    \prop_get:NnN \l__acro_short_plural_prop { #1 } \l__acro_short_plural_tl
    \prop_get:NnN \l__acro_long_prop { #1 } \l__acro_long_tl
    \prop_get:NnN \l__acro_alt_prop { #1 } \l__acro_tmpb_tl
    \__acro_make_link:nNN { #1 } \l__acro_alt_tl \l__acro_tmpb_tl
    \prop_get:NnNTF \l__acro_format_prop { #1 } \l__acro_custom_format_tl
      { \bool_set_true:N \l__acro_custom_format_bool }
      { \bool_set_false:N \l__acro_custom_format_bool }
  }

\cs_generate_variant:Nn \tl_put_right:Nn { NV }

\cs_new:Npn \acro_set_plural:n #1
  {
    \bool_if:NT \l__acro_use_plural_bool
      {
        \bool_if:nTF { \prop_get:Nn \l__acro_replace_plural_prop { #1 } }
          {
            \prop_get:NnN \l__acro_short_plural_prop { #1 } \l__acro_alt_tl
            \prop_get:NnN \l__acro_long_plural_prop { #1 } \l__acro_long_tl
          }
          {
            \tl_put_right:Nn \l__acro_long_tl
              { \prop_get:Nn \l__acro_long_plural_prop { #1 } }
          }
      }
  }

% --------------------------------------------------------------------------
% enable us to know if the acronym is used only once and provide a different
% style for that:
\cs_new:Npn \acro_is_used:nTF #1#2#3
  {
    \bool_if:cTF { g_acro_#1_used_bool }
      { \iow_now:Nx \@auxout { \string \acro@used@twice { #1 } } #2 }
      {
        \iow_now:Nx \@auxout { \string \acro@used@once { #1 } }
        \bool_if:cF { g_acro_#1_label_bool }
          {
            \bool_gset_true:c { g_acro_#1_label_bool }
            \label{ac:#1}
          }
        \bool_gset_true:c { g_acro_#1_used_bool }
        #3
      }
  }

\cs_new:Npn \acro_is_used:n #1
  { \acro_is_used:nTF { #1 } { } { } }

\cs_new:Npn \acro@used@once #1
  { \expandafter\xdef\csname acro@#1@once \endcsname { #1 } }
\cs_new:Npn \acro@used@twice #1
  { \expandafter\xdef\csname acro@#1@twice \endcsname { #1 } }

\AtEndDocument
  {
    \cs_set:Npn \acro@used@twice #1
      {
        \def\reserved@a{#1}%
        \expandafter\ifx\csname acro@#1@twice \endcsname\reserved@a\else
        \@tempswatrue\fi
      }
  }

% --------------------------------------------------------------------------
% the standard internals:
\cs_new:Npn \acro_short:n #1
  {
    \acro_get:n { #1 }
    \acro_set_plural:n { #1 }
    \acro_is_used:n { #1 }
    \__acro_is_single:nT { #1 }
      { \cs_set_eq:NN \acro_hyper_link:nn \use_ii:nn }
    \__acro_write_short:V \l__acro_short_tl
    \__acro_cite_if:Nn \l__acro_citation_all_bool { #1 }
  }

% get alternative entry:
\cs_new:Npn \acro_alt:n #1
  {
    \acro_get:n { #1 }
    \acro_set_plural:n { #1 }
    \acro_is_used:n { #1 }
    \__acro_is_single:nT { #1 }
      { \cs_set_eq:NN \acro_hyper_link:nn \use_ii:nn }
    \__acro_write_short:V \l__acro_alt_tl
    \__acro_cite_if:Nn \l__acro_citation_all_bool { #1 }
  }

% get long entry:
\cs_new:Npn \acro_long:n #1
  {
    \acro_get:n { #1 }
    \acro_set_plural:n { #1 }
    \acro_is_used:n { #1 }
    \__acro_is_single:nT { #1 }
      { \cs_set_eq:NN \acro_hyper_link:nn \use_ii:nn }
    \__acro_write_long:NV \l__acro_long_format_tl \l__acro_long_tl
    \__acro_cite_if:Nn \l__acro_citation_all_bool { #1 }
  }

% output like the first time:
\cs_new:Npn \acro_first:n #1
  {
    \acro_get:n { #1 }
    \acro_set_plural:n { #1 }
    \acro_is_used:n { #1 }
    \__acro_is_single:nT { #1 }
      { \cs_set_eq:NN \acro_hyper_link:nn \use_ii:nn }
    \UseInstance { acro-first } { \l__acro_first_instance_tl }
      { #1 }
      { \l__acro_short_tl }
      { \l__acro_long_tl }
  }

% set custom format:
\cs_new:Npn \acro_format:nn #1#2
  { \prop_put:Nnn \l__acro_format_prop { #1 } { #2 } }

% add citation:
\cs_new:Npn \acro_citation:nnnn #1#2#3#4
  {
    \prop_put:Nnn \l__acro_citation_prop { #1 } { #4 }
    \IfNoValueF { #2 }
      { \prop_put:Nnn \l__acro_citation_pre_prop { #1 } { #2 } }
    \IfNoValueF { #3 }
      { \prop_put:Nnn \l__acro_citation_post_prop { #1 } { #3 } }
  }

% #1 pre
% #2 post
% #3 key
\cs_new:Npn \__acro_cite:nnn #1#2#3
  {
    \quark_if_no_value:nTF { #1 }
      { \__acro_citation_cmd:w { #3 } }
      {
        \quark_if_no_value:nTF { #2 }
          { \__acro_citation_cmd:w [ #1 ] { #3 } }
          { \__acro_citation_cmd:w [ #1 ] [ #2 ] { #3 } }
      }
  }
\cs_generate_variant:Nn \__acro_cite:nnn { VVV }

\cs_new:Npn \__acro_cite_if:Nn #1#2
  {
    \bool_if:NT #1
      {
        \prop_get:NnNT \l__acro_citation_prop { #2 } \l__acro_tmpa_tl
          {
            \prop_get:NnN \l__acro_citation_pre_prop { #2 } \l__acro_tmpb_tl
            \prop_get:NnN \l__acro_citation_post_prop { #2 } \l__acro_tmpc_tl
            \__acro_no_break:
            \tl_use:N \l__acro_citation_space_tl
            \__acro_cite:VVV
              \l__acro_tmpb_tl
              \l__acro_tmpc_tl
              \l__acro_tmpa_tl
          }
      }
  }

% --------------------------------------------------------------------------
% experimental sorting feature:
\AtBeginDocument
  {
    \bool_if:NT \l__acro_sort_bool
      {
        \RequirePackage { l3sort }
        \cs_new:Npn \acro_sort_prop:N #1
          {
            \seq_clear:N \l__acro_tmpa_seq
            \prop_map_inline:Nn #1
              { \seq_put_right:Nn \l__acro_tmpa_seq { ##1 } }
            \seq_sort:Nn \l__acro_tmpa_seq
              {
                \tl_to_lowercase:n {
                  \int_compare:nTF { \pdfstrcmp { ##1 } { ##2 } = -1 }
                    { \sort_ordered: }
                    { \sort_reversed: }
                }
              }
            \prop_clear:N \l__acro_tmpa_prop
            \seq_map_inline:Nn \l__acro_tmpa_seq
              {
                \prop_get:NnN #1 { ##1 } \l__acro_tmpa_tl
                \prop_put:NnV \l__acro_tmpa_prop { ##1 } \l__acro_tmpa_tl
              }
            \prop_set_eq:NN #1 \l__acro_tmpa_prop
          }
      }
  }

% --------------------------------------------------------------------------
% print the whole list:
\cs_new:Npn \acro_print_acronyms:nn #1#2
  {
    \iow_now:Nx \@auxout { \string \acro@print@list }
    \bool_if:NT \l__acro_sort_bool
      { \acro_sort_prop:N \l__acro_short_prop }
    \UseInstance { acro-title } { \l__acro_list_title_tl }
      { \l__acro_list_name_tl }
    \cs_if_exist:NTF \acro@printed@list
      {
        \UseInstance { acro-list } { \l__acro_list_instance_tl }
          { \l__acro_list_type_tl } { #1 } { #2 }
      }
      { \@latex@warning@no@line {Rerun~to~get~acronym~list~right} }
  }

\cs_new:Npn \acro@print@list
  { \cs_if_exist:NF \acro@printed@list { \cs_new:Npn \acro@printed@list {} } }

% --------------------------------------------------------------------------
% USER COMMANDS
% adding an acronym, user command:
% #1: use/replace plural (boolean)
% #2: id
% #3: short
% #4: short plural
% #5: alt
% #6: long
% #7: long plural
% #8: class
% #9: extra
\NewDocumentCommand \DeclareAcronym
  { sm>{\SplitArgument{1}{,}}mo>{\SplitArgument{1}{,}}+mgo }
  { \acro_new:nnnnnnnnn { #1 } { #2 } #3 { #4 } #5 { #7 } { #6 } }
\@onlypreamble \DeclareAcronym

\NewDocumentCommand \DeclareAcronymFormat { mm }
  { \acro_format:nn { #1 } { #2 } }
\@onlypreamble \DeclareAcronymFormat

\NewDocumentCommand \DeclareAcronymCitation { moom }
  { \acro_citation:nnnn { #1 } { #2 } { #3 } { #4 } }
\@onlypreamble \DeclareAcronymCitation

% automatic:
\NewDocumentCommand \ac { m }
  {
    \group_begin:
      \acro_use:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Ac { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_use:n { #1 }
    \group_end:
  }

\NewDocumentCommand \acp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \acro_use:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Acp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_use:n { #1 }
    \group_end:
  }

% short:
\NewDocumentCommand \acs { m }
  {
    \group_begin:
      \acro_short:n { #1 }
    \group_end:
  }

\NewDocumentCommand \acsp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \acro_short:n { #1 }
    \group_end:
  }

% alt:
\NewDocumentCommand \aca { m }
  {
    \group_begin:
      \acro_alt:n { #1 }
    \group_end:
  }

\NewDocumentCommand \acap { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \acro_alt:n { #1 }
    \group_end:
  }

% long:
\NewDocumentCommand \acl { m }
  {
    \group_begin:
      \acro_long:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Acl { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_long:n { #1 }
    \group_end:
  }

\NewDocumentCommand \aclp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \acro_long:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Aclp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_long:n { #1 }
    \group_end:
  }

% first:
\NewDocumentCommand \acf { m }
  {
    \group_begin:
      \acro_first:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Acf { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_first:n { #1 }
    \group_end:
  }

\NewDocumentCommand \acfp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \acro_first:n { #1 }
    \group_end:
  }

\NewDocumentCommand \Acfp { m }
  {
    \group_begin:
      \bool_set_true:N \l__acro_use_plural_bool
      \bool_set_true:N \l__acro_first_upper_bool
      \acro_first:n { #1 }
    \group_end:
  }

% reset outputs, they'll behave like the first time again (!not like the _only_
% time!):
\NewDocumentCommand \acresetall {}
  {
    \prop_map_inline:Nn \l__acro_short_prop
      { \bool_gset_false:c { g_acro_##1_used_bool } }
  }

% typeset the list:
\NewDocumentCommand \printacronyms { G{}o }
  { \acro_print_acronyms:nn { #1 } { #2 } }

\ProcessKeysOptions { acro }

\AtBeginDocument
  {
    \@ifpackageloaded { hyperref }
      { \bool_set_true:N \l__acro_hyperref_loaded_bool } {}
  }

\tex_endinput:D
% --------------------------------------------------------------------------
% HISTORY:
2012/06/22 v0.1  - first public release
2012/06/23 v0.1a - bug fix, added `strict' and `macros' option and creation of
                   shortcut macros
                 - added capitalized version of long forms
                 - added `sort' option
2012/06/24 v0.1b - added \Acf and \Acfp, added option `plural-ending'
2012/06/24 v0.1c - added excluded argument to \printacronyms
2012/06/24 v0.2  - renamed \NewAcronym => \DeclareAcronym
                   \AcronymFormat => \DeclareAcronymFormat
2012/06/25 v0.2a - new first-style's: `short' and `reversed'
2012/06/25 v0.3  - new list formats: extra-tabular, extra-longtable,
                   extra-tabular-rev, extra-longtable-rev
                 - extra precaution when using \printacronyms to avoid errors.
2012/06/27 v0.3a - new option `list-caps', \Acp added
2012/06/29 v0.3b - extended the `text' template to the `acro-first' object
                 - added `acro-first' instances `plain' and `plain-reversed'
2012/07/16 v0.3c - small adjustments to the documentation
2012/07/23 v0.3d - first CTAN version
2012/07/24 v0.3e - adapted to updated l3kernel
2012/09/28 v0.4  - added means to add citations to acronyms
2012/10/07 v0.4a - new options: "uc-cmd", "list-long-format"

% --------------------------------------------------------------------------
% TODO:
- Sprach-Support Überschrift der Acronym-Liste
- Option `totoc'?