% --------------------------------------------------------------------------
% the ACRO package
% 
%   Typeset Acronyms
% 
% --------------------------------------------------------------------------
% Clemens Niederberger
% Web:    https://bitbucket.org/cgnieder/acro/
% E-Mail: contact@mychemistry.eu
% --------------------------------------------------------------------------
% Copyright 2011--2019 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, acro.history, README
% --------------------------------------------------------------------------
% If you have any ideas, questions, suggestions or bugs to report, please
% feel free to contact me.
% --------------------------------------------------------------------------
\RequirePackage{expl3,xparse,l3keys2e,xtemplate,etoolbox}
\ProvidesExplPackage
  {acro}
  {2019/10/06}
  {2.10b}
  {Typeset Acronyms}

% --------------------------------------------------------------------------
% warning and error messages:
\msg_new:nnn {acro} {undefined}
  {
    You've~ requested~ acronym~ `#1'~ \msg_line_context: \ but~ you~
    apparently~ haven't~ defined~ it,~ yet! \\
    Maybe~ you've~ misspelled~ `#1'?
  }

\msg_new:nnn {acro} {macro}
  {
    A~ macro~ with~ the~ csname~ `#1'~ already~ exists! \\
    Unless~ you~ set~ acro's~ option~ `strict'~ I~ won't~ redefine~ it~
    \msg_line_context: .
  } 

\msg_new:nnn {acro} {replaced}
  {
    The~ #1~ `#2' ~you ~used~ \msg_line_context: \ is~ deprecated~ and~ has~
    been~ replaced~ by~ `#3'. ~Since~ I~ will~ not~ guarantee~ that~ #1~ `#2'~
    will~ be~ kept~ forever~ I~ strongly~ encourage~ you~ to~ switch!
  }

\msg_new:nnn {acro} {deprecated}
  {
    The~ #1~ `#2'~ you~ used~ \msg_line_context: \ is~ deprecated~and~ there~
    is~ no~ replacement.~ Since~ I~ will~ not~ guarantee~ that~ #1~ `#2'~
    will~ be~ kept~ forever~ I~ strongly~ encourage~ you~ to~ remove~ it~
    from~ your~ document.
  }

\msg_new:nnn {acro} {substitute-short}
  {
    There~ is~ no~ short~ form~ set~ for~ acronym~ `#1'! \\
    I~ am~ setting~ the~ short~ form~ equal~ to~ the~ ID~ `#1'. \\
    If~ that~ is~ not~ what~ you~ want~ make~ sure~ to~ add~ an~ explicit~
    short~ form.
  }
\msg_new:nnn {acro} {ending-exists}
  {
    An~ ending~ with~ the~ name~ `#1'~ already~ exists! \\ \\
    I~ am~ overwriting~ the~ defaults.
  }

\msg_new:nnn {acro} {ending-before-acronyms}
  {
    You~ are~ using~ \token_to_str:N \ProvideAcroEnding \ after~ you've~
    declared~ at~ least~ one~ acronym.~ This~ will~ lead~ to~ trouble! \\
    Make~ sure~ to~ define~ endings~ before~ *any*~ acronym~ declarations!
  }

\msg_new:nnn {acro} {no-alternative}
  {
    There~ is~ no~ alternative~ form~ for~ acronym~ `#1'! \\ \\
    I~ am~ using~ the~ short~ form~ instead.
  }

\msg_new:nnn {acro} {unknown}
  {
    You're~ trying~ to~ use~ the~ #1~ `#2'~ \msg_line_context: . \\
    However,~ I~ do~ not~ know~ #1~ `#2'! \\
    If~ this~ is~ no~ typo~ please~ contact~ the~ package~ author. \\ \\
    I~ am~ going~ to~ use~ the~ #1~ `#3'~ instead.
  }
\msg_new:nnn {acro} {definitions-missing}
  {
    I~ cannot~ find~ the~ file~ \c_acro_definition_file_name_tl
    .\c_acro_definition_file_extension_tl !~ This~ file~ contains~ all~
    essential~ user~ commands~ of~ acro~ and~ is~ a~ crucial~ part~ of~ the~
    package!~ Please~ check~ your~ installation.
  }

% --------------------------------------------------------------------------
% logging:
\cs_new:Npn \acro_if_log:T #1 { \use:n {#1} }

\bool_new:N \l__acro_log_acronyms_bool
\bool_new:N \l__acro_log_acronyms_verbose_bool

\keys_define:nn {acro}
  {
    log           .choice: ,
    log / true    .code:n    =
      \bool_set_true:N \l__acro_log_acronyms_bool
      \bool_set_false:N \l__acro_log_acronyms_verbose_bool ,
    log / silent  .meta:n    = { log = true } ,
    log / verbose .code:n    =
      \bool_set_true:N \l__acro_log_acronyms_bool
      \bool_set_true:N \l__acro_log_acronyms_verbose_bool ,
    log / false   .code:n    =
      \bool_set_false:N \l__acro_log_acronyms_bool
      \bool_set_false:N \l__acro_log_acronyms_verbose_bool ,
    log           .default:n = true ,
    log           .initial:n = false
  }

\cs_new:Npn \__acro_write_log:nn #1#2 { \ \ \ #1 ~ = ~ {#2} }
\cs_new:Npn \__acro_write_log_property:nnn #1#2#3
  { \__acro_write_log:nn {#2} { \__acro_get_property:nn {#3} {#1} } }

\cs_new:Npn \__acro_ending_log_entry:nn #1#2
  {
    | \\
    | \__acro_write_log_property:nnn {#1} {short-#2} {short_#2} \\
    | \__acro_write_log_property:nnn {#1} {short-#2-form} {short_#2_form} \\
    | \__acro_write_log_property:nnn {#1} {long-#2} {long_#2} \\
    | \__acro_write_log_property:nnn {#1} {long-#2-form} {long_#2_form} \\
    | \__acro_write_log_property:nnn {#1} {alt-#2} {alt_#2} \\
    | \__acro_write_log_property:nnn {#1} {alt-#2-form} {alt_#2_form} \\
    | \__acro_write_log_property:nnn {#1} {foreign-#2} {foreign_#2} \\
    | \__acro_write_log_property:nnn {#1} {foreign-#2-form} {foreign_#2_form} \\
  }
  
\msg_new:nnn {acro} {log-acronym-verbose}
  {
    ================================================= \\
    | ~ \msg_info_text:n {acro}~ --~ defining~ new~ acronym: \\
    | \__acro_write_log:nn {ID} {#1} \\
    | \__acro_write_log_property:nnn {#1} {short} {short} \\
    | \__acro_write_log_property:nnn {#1}{long} {long} \\
    | \__acro_write_log_property:nnn {#1}{alt} {alt} \\
    | \__acro_write_log_property:nnn {#1}{sort} {sort} \\
    | \__acro_write_log_property:nnn {#1}{class} {class} \\
    | \__acro_write_log_property:nnn {#1} {list} {list} \\
    | \__acro_write_log_property:nnn {#1} {extra} {extra} \\
    | \__acro_write_log_property:nnn {#1} {foreign} {foreign} \\
    | \__acro_write_log_property:nnn {#1} {single} {single} \\
    | \__acro_write_log_property:nnn {#1} {pdfstring} {pdfstring} \\
    | \__acro_write_log_property:nnn {#1} {accsupp} {accsupp} \\
    | \__acro_write_log_property:nnn {#1} {tooltip} {tooltip} \\
    | \\
    | \__acro_write_log_property:nnn {#1} {short-indefinite} {short_indefinite} \\
    | \__acro_write_log_property:nnn {#1} {long-indefinite} {long_indefinite} \\
    | \__acro_write_log_property:nnn {#1} {alt-indefinite} {alt_indefinite} \\
    \seq_map_function:NN \l__acro_endings_seq \__acro_ending_log_entry:n
    | \\
    | \__acro_write_log_property:nnn {#1} {short-format} {short_format} \\
    | \__acro_write_log_property:nnn {#1} {long-format} {long_format} \\
    | \__acro_write_log_property:nnn {#1} {first-long-format} {first_long_format} \\
    | \__acro_write_log_property:nnn {#1} {single-format} {single_format} \\
    | \__acro_write_log_property:nnn {#1} {foreign-lang} {foreign_lang} \\    
    | \\
    | \__acro_write_log_property:nnn {#1} {cite} {citation} \\
    | \__acro_write_log_property:nnn {#1} {index} {index} \\
    | \__acro_write_log_property:nnn {#1} {index-sort} {index_sort} \\
    | \\
    | \__acro_write_log_property:nnn {#1} {long-pre} {long_pre} \\
    | \__acro_write_log_property:nnn {#1} {long-post} {long_post} \\
    | \__acro_write_log_property:nnn {#1} {post} {post} \\
    | \__acro_write_log_property:nnn {#1} {index-cmd} {index_cmd} \\
    | \__acro_write_log_property:nnn {#1} {first-style} {first_style} \\
    =================================================
  }

\msg_new:nnn {acro} {log-acronym-silent}
  {
    ================================================= \\
    | ~ \msg_info_text:n {acro}~ --~ defining~ new~ acronym: \\
    | \__acro_write_log:nn {ID} {#1} \\
    | \__acro_write_log_property:nnn {#1} {short} {short} \\
    | \__acro_write_log_property:nnn {#1} {long} {long} \\
    | \__acro_write_log_property:nnn {#1} {alt} {alt} \\
    | \__acro_write_log_property:nnn {#1} {sort} {sort} \\
    | \__acro_write_log_property:nnn {#1} {class} {class} \\
    | \__acro_write_log_property:nnn {#1} {list} {list} \\
    | \__acro_write_log_property:nnn {#1} {extra} {extra} \\
    | \__acro_write_log_property:nnn {#1} {foreign} {foreign} \\
    | \__acro_write_log_property:nnn {#1} {pdfstring} {pdfstring} \\
    | \__acro_write_log_property:nnn {#1} {cite} {citation} \\
    =================================================
  }
  
\cs_new_protected:Npn \__acro_log_acronym:n #1
  {
    \bool_if:NT \l__acro_log_acronyms_bool
      {
        \cs_set:Npn \__acro_ending_log_entry:n ##1
          { \__acro_ending_log_entry:nn {#1} {##1} }
        \bool_if:NTF \l__acro_log_acronyms_verbose_bool
          { \msg_log:nnn {acro} {log-acronym-verbose} {#1} }
          { \msg_log:nnn {acro} {log-acronym-silent} {#1} }
      }
  }   

% --------------------------------------------------------------------------
% message macros:
\cs_new:Npn \__acro_remove_backslash:N #1
  { \exp_after:wN \use_none:n \token_to_str:N #1 }

\cs_new_protected:Npn \acro_new_message_commands:Nnnn #1#2#3#4
  {
    \clist_map_inline:nn {#2}
      {
        \cs_new_protected:cpn { \__acro_remove_backslash:N #1 ##1 }
          {
            \bool_if:NTF \l__acro_silence_bool
              { \use:c { \__acro_remove_backslash:N #3 n##1 } {acro} }
              { \use:c { \__acro_remove_backslash:N #4 n##1 } {acro} }
          }
      }
  }

\acro_new_message_commands:Nnnn \acro_serious_message: {n,nn,nnn}
  { \msg_warning: }
  { \msg_error: }

\acro_new_message_commands:Nnnn \acro_harmless_message: {n,nn,nnn,nnnn}
  { \msg_info: }
  { \msg_warning: }

\cs_new_protected:Npn \acro_option_deprecated:nn #1#2
  {
    \tl_if_blank:nTF {#2}
      { \acro_harmless_message:nnn  {deprecated} {option} {#1} }
      { \acro_harmless_message:nnnn {replaced}   {option} {#1} {#2} }
  }
\cs_new_protected:Npn \acro_option_deprecated:n #1
  { \acro_option_deprecated:nn {#1} {} }

\cs_new_protected:Npn \acro_command_deprecated:NN #1#2
  {
    \tl_if_blank:nTF {#2}
      {
        \acro_harmless_message:nnn {deprecated} {command}
          { \token_to_str:N #1 }
      }
      {
        \acro_harmless_message:nnnn {replaced} {command}
          { \token_to_str:N #1 }
          { \token_to_str:N #2 }
      }
  }

% --------------------------------------------------------------------------
% 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
\prop_new:N \l__acro_tmpb_prop
\seq_new:N  \l__acro_tmpa_seq
\seq_new:N  \l__acro_tmpb_seq
\int_new:N  \l__acro_tmpa_int
\int_new:N  \l__acro_tmpb_int
\int_new:N  \l__acro_tmpc_int
\int_new:N  \l__acro_tmpd_int

% --------------------------------------------------------------------------
% variants of kernel commands
\cs_generate_variant:Nn \quark_if_no_value:nTF  { V }
\cs_generate_variant:Nn \tl_put_right:Nn        { NV, Nv }
\cs_generate_variant:Nn \tl_if_eq:nnT           { V }
\cs_generate_variant:Nn \tl_if_eq:nnF           { V }
\cs_generate_variant:Nn \seq_use:Nnnn           { c }
\cs_generate_variant:Nn \seq_gset_split:Nnn     { c }
\cs_generate_variant:Nn \seq_set_split:Nnn      { NnV }
\cs_generate_variant:Nn \seq_if_in:NnT          { NV }
\cs_generate_variant:Nn \prop_put:Nnn           { NnV, cnx, cnv }
\cs_generate_variant:Nn \prop_get:NnNTF         { cnc }
\cs_generate_variant:Nn \prop_get:NnNF          { cn, cnc }
\cs_generate_variant:Nn \prop_get:NnN           { cnc }
\cs_generate_variant:Nn \cs_generate_variant:Nn { c }
\cs_generate_variant:Nn \str_case:nn            { V }

% --------------------------------------------------------------------------
% variables:
\bool_new:N      \l__acro_silence_bool
\bool_new:N      \l__acro_mark_as_used_bool
\bool_new:N      \g__acro_mark_first_as_used_bool
\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_hyperref_loaded_bool
\bool_new:N      \l__acro_use_hyperref_bool
\bool_new:N      \l__acro_xspace_bool
\bool_new:N      \l__acro_custom_short_format_bool
\bool_new:N      \l__acro_custom_alt_format_bool
\bool_new:N      \l__acro_custom_long_format_bool
\bool_new:N      \l__acro_override_list_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_upper_short_bool
\bool_new:N      \l__acro_indefinite_bool
\bool_new:N      \l__acro_upper_indefinite_bool
\bool_new:N      \l__acro_foreign_bool
\bool_set_true:N \l__acro_foreign_bool
\bool_new:N      \l__acro_sort_bool
\bool_set_true: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
\bool_new:N      \l__acro_group_citation_bool
\bool_new:N      \l__acro_acc_supp_bool
\bool_new:N      \l__acro_tooltip_bool
\bool_new:N      \l__acro_inside_tooltip_bool
\bool_new:N      \l__acro_following_page_bool
\bool_new:N      \l__acro_following_pages_bool
\bool_new:N      \l__acro_addto_index_bool
\bool_new:N      \l__acro_is_excluded_bool
\bool_new:N      \l__acro_is_included_bool
\bool_new:N      \l__acro_page_punct_bool
\bool_new:N      \l__acro_page_brackets_bool
\bool_new:N      \l__acro_page_display_bool
\bool_new:N      \l__acro_new_page_numbering_bool
\bool_new:N      \l__acro_first_use_brackets_bool
\bool_new:N      \l__acro_first_only_short_bool
\bool_new:N      \l__acro_first_only_long_bool
\bool_new:N      \l__acro_first_reversed_bool
\bool_new:N      \l__acro_first_switched_bool
\bool_new:N      \l__acro_use_note_bool
\bool_new:N      \l__acro_extra_punct_bool
\bool_new:N      \l__acro_extra_use_brackets_bool
\bool_new:N      \l__acro_in_list_bool
\bool_new:N      \l__acro_place_label_bool
\bool_new:N      \l__acro_list_all_pages_bool
\bool_set_true:N \l__acro_list_all_pages_bool
\bool_new:N      \g__acro_first_acronym_declared_bool
\bool_new:N      \l__acro_include_endings_format_bool
\bool_new:N      \l__acro_list_reverse_long_extra_bool
\bool_new:N      \l__acro_use_acronyms_bool
\bool_set_true:N \l__acro_use_acronyms_bool

\tl_new:N   \l__acro_ignore_tl
\tl_new:N   \l__acro_default_indefinite_tl
\tl_set:Nn  \l__acro_default_indefinite_tl {a}
\tl_new:N   \l__acro_foreign_sep_tl
\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_new:N   \l__acro_pages_name_tl
\tl_new:N   \l__acro_next_page_tl
\tl_new:N   \l__acro_next_pages_tl
\tl_new:N   \l__acro_list_instance_tl
\tl_set:Nn  \l__acro_list_instance_tl  {description}
\tl_new:N   \l__acro_list_type_tl
% \tl_new:N   \l__acro_list_tl
\tl_new:N   \l__acro_list_heading_cmd_tl
\tl_set:Nn  \l__acro_list_heading_cmd_tl {section*}
\tl_new:N   \l__acro_list_name_tl
\tl_new:N   \l__acro_list_before_tl
\tl_new:N   \l__acro_list_after_tl
\tl_new:N   \l__acro_custom_short_format_tl
\tl_new:N   \l__acro_first_between_tl
\tl_new:N   \l__acro_citation_connect_tl
\tl_new:N   \l__acro_between_group_connect_citation_tl
\tl_new:N   \l__acro_extra_brackets_tl
\tl_new:N   \l__acro_extra_punct_tl
\tl_new:N   \l__acro_first_brackets_tl
\tl_new:N   \l__acro_page_punct_tl
\tl_new:N   \l__acro_page_brackets_tl
\tl_new:N   \l__acro_last_page_tl
\tl_new:N   \l__acro_current_page_tl
\tl_new:N   \l__acro_list_table_tl
\tl_new:N   \l__acro_list_table_spec_tl
\tl_new:N   \l__acro_acc_supp_tl
\tl_new:N   \l__acro_acc_supp_options_tl
\tl_new:N   \l__acro_label_prefix_tl
\tl_set:Nn  \l__acro_label_prefix_tl { ac: }
\tl_new:N   \l__acro_index_short_tl
\tl_new:N   \l__acro_first_instance_tl
\tl_set:Nn  \l__acro_first_instance_tl {default}

\tl_new:N   \l__acro_short_tl
\tl_new:N   \l__acro_short_format_tl
\tl_new:N   \l__acro_list_short_format_tl

\tl_new:N   \l__acro_alt_tl
\tl_new:N   \l__acro_alt_format_tl

\tl_new:N   \l__acro_long_tl
\tl_new:N   \l__acro_list_long_format_tl

\tl_new:N   \l__acro_single_form_tl
\tl_set:Nn  \l__acro_single_form_tl {long}

\tl_new:N   \l__acro_extra_format_tl

\tl_new:N   \l__acro_foreign_format_tl
\tl_new:N   \l__acro_foreign_list_format_tl
\tl_set:Nn  \l__acro_foreign_list_format_tl { \acroenparen }

\tl_new:N   \l__acro_index_format_tl


\skip_new:N  \l__acro_page_space_skip

\dim_new:N  \l__acro_short_width_dim
\dim_set:Nn \l__acro_short_width_dim {3em}

\prop_new:N \l__acro_list_styles_prop
\prop_new:N \l__acro_list_headings_prop
\prop_new:N \l__acro_first_styles_prop
\prop_new:N \l__acro_extra_styles_prop
\prop_new:N \l__acro_page_styles_prop

% --------------------------------------------------------------------------
% small commands for use at various places
\cs_new:Npn \acro_no_break: { \tex_penalty:D 10000 \scan_stop: }

\cs_new_protected:Npn \__acro_first_upper_case:n #1
  { \tl_upper_case:n { \tl_head:n {#1} } \tl_tail:n {#1} }
\cs_generate_variant:Nn \__acro_first_upper_case:n { x }
\cs_generate_variant:Nn \tl_mixed_case:n { x }

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

\NewDocumentCommand \acfirstupper { m }
  { \acro_first_upper_case:n {#1} }

% --------------------------------------------------------------------------
% options:
\keys_define:nn {acro}
  {
    messages          .choice: ,
    messages / silent .code:n     =
      \bool_set_true:N \l__acro_silence_bool ,
    messages / loud .code:n       =
      \bool_set_false:N \l__acro_silence_bool ,
    messages          .value_required:n = true ,
    accsupp           .bool_set:N = \l__acro_acc_supp_bool ,
    accsupp-options   .tl_set:N   = \l__acro_acc_supp_options_tl ,
    tooltip           .bool_set:N = \l__acro_tooltip_bool ,
    tooltip-cmd       .code:n     = \cs_set:Npn \__acro_tooltip_cmd:nn {#1} ,
    tooltip-cmd       .value_required:n = true ,
    macros            .bool_set:N = \l__acro_create_macros_bool ,
    xspace            .bool_set:N = \l__acro_xspace_bool ,
    % xspace            .code:n     = \acro_option_deprecated:nn {xspace} {} ,
    strict            .bool_set:N = \l__acro_strict_bool ,
    sort              .bool_set:N = \l__acro_sort_bool ,
    short-format      .code:n     =
      \tl_set:Nn \l__acro_short_format_tl {#1}
      \tl_set_eq:NN \l__acro_alt_format_tl \l__acro_short_format_tl
      \tl_set:Nn \l__acro_list_short_format_tl {#1} ,
    short-format      .value_required:n = true ,
    alt-format      .code:n     =
      \tl_set:Nn \l__acro_alt_format_tl {#1} ,
    long-format       .code:n     =
      \tl_set:Nn \l__acro_long_format_tl {#1}
      \tl_set:Nn \l__acro_first_long_format_tl {#1}
      \tl_set:Nn \l__acro_list_long_format_tl {#1} ,
    long-format       .value_required:n = true ,
    first-long-format .code:n     =
      \tl_set:Nn \l__acro_first_long_format_tl {#1} ,
    first-long-format .value_required:n = true ,
    single-format     .tl_set:N   = \l__acro_single_format_tl ,
    single-format     .value_required:n = true ,
    format-include-endings .bool_set:N = \l__acro_include_endings_format_bool ,
    display-foreign   .bool_set:N = \l__acro_foreign_bool ,
    foreign-format    .tl_set:N   = \l__acro_foreign_format_tl ,
    foreign-format    .value_required:n = true ,
    list-short-format .tl_set:N   = \l__acro_list_short_format_tl ,
    list-short-format .value_required:n = true ,
    list-short-width  .dim_set:N  = \l__acro_short_width_dim ,
    list-short-width  .value_required:n = true ,
    list-long-format  .tl_set:N   = \l__acro_list_long_format_tl ,
    list-long-format  .value_required:n = true ,
    list-foreign-format .tl_set:N = \l__acro_foreign_list_format_tl ,
    list-foreign-format .value_required:n = true ,
    override-list-format .bool_set:N = \l__acro_override_list_format_bool ,
    override-list-format .initial:n  = true ,
    extra-format      .tl_set:N   = \l__acro_extra_format_tl ,
    extra-format      .value_required:n = true ,
    single            .bool_set:N = \l__acro_use_single_bool ,
    single-form       .tl_set:N   = \l__acro_single_form_tl ,
    single-form       .value_required:n = true ,
    first-style       .code:n     = \acro_set_first_style:n {#1} ,
    first-style       .value_required:n = true ,
    extra-style       .code:n     = \acro_set_extra_style:n {#1} ,
    extra-style       .value_required:n = true ,
    label             .bool_set:N = \l__acro_place_label_bool ,
    label-prefix      .tl_set:N   = \l__acro_label_prefix_tl ,
    label-prefix      .value_required:n = true ,
    pages             .choice: ,
    pages / all       .code:n     =
      \bool_set_true:N \l__acro_list_all_pages_bool ,
    pages / first     .code:n     =
      \bool_set_true:N \l__acro_place_label_bool
      \bool_set_false:N \l__acro_list_all_pages_bool ,
    pages             .value_required:n = true ,
    page-ref          .code:n     =
      \acro_option_deprecated:nn {page-ref} {page-style}
      \acro_set_page_style:n {#1} ,
    page-style        .code:n     = \acro_set_page_style:n {#1} ,
    page-style        .value_required:n = true ,
    page-name         .tl_set:N   = \l__acro_page_name_tl ,
    page-name         .value_required:n = true ,
    pages-name        .tl_set:N   = \l__acro_pages_name_tl ,
    pages-name        .value_required:n = true ,
    following-page    .bool_set:N = \l__acro_following_page_bool ,
    following-pages   .bool_set:N = \l__acro_following_pages_bool ,
    following-pages*  .meta:n     =
      { following-page = #1 , following-pages = #1 } ,
    following-pages*  .default:n  = true ,
    next-page         .tl_set:N   = \l__acro_next_page_tl ,
    next-page         .value_required:n = true ,
    next-pages        .tl_set:N   = \l__acro_next_pages_tl ,
    next-pages        .value_required:n = true ,
    list-style        .code:n     = \acro_set_list_style:n {#1} ,
    list-style        .value_required:n = true ,
    list-heading      .code:n     = \acro_set_list_heading:n {#1} ,
    list-heading      .value_required:n = true ,
    list-name         .tl_set:N   = \l__acro_list_name_tl ,
    list-name         .value_required:n = true ,
    hyperref          .bool_set:N = \l__acro_use_hyperref_bool ,
    only-used         .bool_set:N = \l__acro_print_only_used_bool ,
    mark-as-used      .choice: ,
    mark-as-used / first .code:n  =
      \bool_gset_true:N \g__acro_mark_first_as_used_bool ,
    mark-as-used / any   .code:n  =
      \bool_gset_false:N \g__acro_mark_first_as_used_bool ,
    mark-as-used      .default:n  = any ,
    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              .default:n  = all ,
    cite-cmd          .code:n     =
      \cs_set:Npn \__acro_citation_cmd:w {#1} ,
    cite-cmd          .value_required:n = true ,
    group-cite-cmd    .code:n     =
      \cs_set:Npn \__acro_group_citation_cmd:w {#1} ,
    group-cite-cmd    .value_required:n = true ,
    group-citation    .bool_set:N = \l__acro_group_citation_bool ,
    cite-connect      .tl_set:N   = \l__acro_citation_connect_tl ,
    cite-connect      .initial:n  = \nobreakspace ,
    cite-connect      .value_required:n = true ,
    group-cite-connect .tl_set:N = \l__acro_between_group_connect_citation_tl ,
    group-cite-connect .initial:n = {,\nobreakspace} ,
    group-cite-connect .value_required:n = true ,
    index             .bool_set:N = \l__acro_addto_index_bool ,
    index-cmd         .code:n     =
      \cs_set:Npn \__acro_index_cmd:n {#1} ,
    index-cmd         .value_required:n = true ,
    uc-cmd            .code:n     =
      \cs_set_eq:NN \__acro_first_upper_case:n #1 ,
    uc-cmd            .value_required:n = true ,
    uppercase-short   .bool_set:N = \l__acro_upper_short_bool ,
    uppercase-short   .initial:n  = true
  }

\AtBeginDocument
  {
    \bool_if:NTF \l__acro_xspace_bool
      {
        \@ifpackageloaded {xspace}
          { }
          { \RequirePackage {xspace} }
        \cs_new_eq:NN \acro_xspace: \xspace
      }
      { \cs_new:Npn \acro_xspace: {} }
  }

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

% --------------------------------------------------------------------------
% we use xtemplate for different object types and with a different number of
% arguments; let's declare functions for usage later so we don't have to
% bother

% objects with one argument:
\cs_new_protected:Npn \acro_page_number_instance:nn #1#2
  { \UseInstance {acro-page-number} {#1} {#2} }
\cs_generate_variant:Nn \acro_page_number_instance:nn {V}

\cs_new_protected:Npn \acro_extra_instance:nn #1#2
  { \UseInstance {acro-extra} {#1} {#2} }
\cs_generate_variant:Nn \acro_extra_instance:nn {VV}

\cs_new_protected:Npn \acro_title_instance:nn #1#2
  { \UseInstance {acro-title} {#1} {#2} }
\cs_generate_variant:Nn \acro_title_instance:nn {VV}

% objects with two arguments:
\cs_new_protected:Npn \acro_list_instance:nnn #1#2#3
  { \UseInstance {acro-list} {#1} {#2} {#3} }
\cs_generate_variant:Nn \acro_list_instance:nnn {VVV}

\cs_new_protected:Npn \acro_first_instance:nn #1#2
  {
    \acro_if_property:nnTF {#1} {first-style}
      {
        \tl_set_eq:NN
          \l__acro_tmpa_tl
          \l__acro_first_style_tl
      }
      {
        \tl_set_eq:NN
          \l__acro_tmpa_tl
          \l__acro_first_instance_tl
      }
    \acro_if_defined:nT {#1}
      {
        \use:x {
          \UseInstance {acro-first}
            { \exp_not:V \l__acro_tmpa_tl }
            { \exp_not:n {#1} }
            { \exp_not:n {#2} }
          }
      }
  }
\cs_generate_variant:Nn \acro_first_instance:nn {nV}
  
% --------------------------------------------------------------------------
% 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_protected: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 }
      }
  }

% #1: tl var
% #2: id
% #3: text
\cs_new_protected:Npn \__acro_make_link:Nnn #1#2#3
  {
    \bool_if:nTF
      { \l__acro_use_hyperref_bool && \l__acro_hyperref_loaded_bool }
      {
        \tl_set:Nn #1
           {
             \acro_hyper_link:nn {#2} { \phantom {#3} }
             \acro_if_is_single:nTF {#2}
               { \hbox_overlap_left:n {#3} }
               { \acro_color_link:n { \hbox_overlap_left:n {#3} } }
           }
       }
       { \tl_set:Nn #1 {#3} }
  }
\cs_generate_variant:Nn \__acro_make_link:Nnn {NnV}

\cs_new:Npn \acro_color_link:n #1
  {
    \cs_if_exist:NTF \hypersetup
      {
        \ifHy@colorlinks
          \exp_after:wN \use_i:nn
        \else
          \ifHy@ocgcolorlinks
            \exp_after:wN \use_i:nn
          \else
            \exp_after:wN \exp_after:wN \exp_after:wN \use_ii:nn
          \fi
        \fi
        { \textcolor { \@linkcolor } {#1} }
        {#1}
      }
      {#1}
  }

\AtBeginDocument{
  \cs_if_exist:NF \textcolor { \cs_new_eq:NN \textcolor \use_ii:nn }
}

% --------------------------------------------------------------------------
% output style of the first time an acronym is used

% helper macros for the styles
% #1: short|long
% #2: id
% #3: long
\cs_new_protected:Npn \__acro_print_form_and_indefinite:nnn #1#2#3
  {
    \group_begin:
      \acro_for_all_trailing_tokens_do:n
        { \acro_deactivate_trailing_action:n {##1} }
      \str_case:nn {#1}
        {
          {long} {
            \bool_if:nT
              {
                \l__acro_first_only_long_bool ||
                !\l__acro_first_only_short_bool
              }
              {
                \acro_write_indefinite:nn {#2} {long}
                \acro_write_expanded:nnn {#2} {first-long} {#3}
              }
          }
          {short} {
            \bool_if:nT
              {
                !\l__acro_first_only_long_bool ||
                \l__acro_first_only_short_bool
              }
              {
                \acro_soft_upper:
                \acro_write_indefinite:nn {#2} {short}
                \acro_write_compact:nn {#2} {short}
              }
          }
        }
    \group_end:
  }

\cs_new_protected:Npn \__acro_open_bracket:
  {
    \bool_if:nT
      {
        !\l__acro_first_only_long_bool &&
        !\l__acro_first_only_short_bool
      }
      {
        \acro_space:
        \tl_if_blank:VF \l__acro_first_between_tl
          {
            \tl_use:N \l__acro_first_between_tl
            \acro_space:
          }
        \bool_if:NT \l__acro_first_use_brackets_bool
          { \tl_head:N \l__acro_first_brackets_tl }
      }
  }

\cs_new_protected:Npn \__acro_close_bracket:
  {
    \bool_if:nT
      {
        \l__acro_first_use_brackets_bool &&
        !\l__acro_first_only_short_bool &&
        !\l__acro_first_only_long_bool
      }
      { \tl_tail:N \l__acro_first_brackets_tl }
  }
  
% #1: short|long
% #2: id
% #3: long
\cs_new_protected:Npn \__acro_print_form:nnn #1#2#3
  {
    \str_case:nn {#1}
      {
        {long} {
          \bool_if:nT
            {
              \l__acro_first_only_long_bool ||
              !\l__acro_first_only_short_bool
            }
            {
              \group_begin:
                \bool_set_false:N \l__acro_first_upper_bool
                \acro_write_expanded:nnn {#2} {first-long} {#3}
              \group_end:
            }
        }
        {short} {
          \bool_if:nT
            {
              !\l__acro_first_only_long_bool ||
              \l__acro_first_only_short_bool
            }
            {
              \group_begin:
                \bool_set_false:N \l__acro_first_upper_bool
                \acro_write_compact:nn {#2} {short}
              \group_end:
            }
        }
      }
  }

% #1: id
\cs_new_protected:Npn \__acro_foreign_sep:n #1
  {
    \bool_if:nT
      {
         \l__acro_foreign_bool &&
        !\l__acro_first_only_short_bool &&
        !\l__acro_first_only_long_bool
      }
      { \acro_if_foreign:nT {#1} { \tl_use:N \l__acro_foreign_sep_tl } }
  }
  
% #1: id
\cs_new_protected:Npn \__acro_print_foreign:n #1
  {
    \acro_if_foreign:nT {#1}
      {
        \bool_if:nT
          {
             \l__acro_foreign_bool &&
            !\l__acro_first_only_short_bool &&
            !\l__acro_first_only_long_bool
          }
          {
            \acro_write_foreign:n {#1}
            \acro_endings:nn {#1} {foreign}
          }
      }
  }

\cs_new_protected:Npn \__acro_print_citation:n #1
  {
    \bool_if:NT \l__acro_group_citation_bool
      { \acro_group_cite:n {#1} }
  }

\cs_new_protected:Npn \__acro_finalize_first:n #1
  {
    \bool_if:NF \l__acro_group_citation_bool
      { \acro_cite_if:nn { \l__acro_citation_first_bool } {#1} }
    \acro_index_if:nn { \l__acro_addto_index_bool } {#1}
    \acro_get_property:nnT {#1} {post}
      { \tl_use:N \l__acro_post_tl }
  }

% --------------------------------------------------------------------------
% the `acro-first' object, templates, instances:
% #1: id
% #2: long
\DeclareObjectType {acro-first} {2}

% template for inline appearance:
\DeclareTemplateInterface {acro-first} {inline} {2}
  {
    brackets      : boolean   = true  ,
    brackets-type : tokenlist = ()    ,
    only-short    : boolean   = false ,
    only-long     : boolean   = false ,
    reversed      : boolean   = false ,
    between       : tokenlist         ,
    foreign-sep   : tokenlist = {,~}
  }
\DeclareTemplateCode {acro-first} {inline} {2}
  {
    brackets      = \l__acro_first_use_brackets_bool ,
    brackets-type = \l__acro_first_brackets_tl       ,
    only-short    = \l__acro_first_only_short_bool   ,
    only-long     = \l__acro_first_only_long_bool    ,
    reversed      = \l__acro_first_reversed_bool     ,
    between       = \l__acro_first_between_tl        ,
    foreign-sep   = \l__acro_foreign_sep_tl
  }
  {
    \AssignTemplateKeys
    \bool_set_true:N \l__acro_first_instance_bool
    \bool_if:NTF \l__acro_first_reversed_bool
      { % zuerst kurze Form, dann lange Form:
        \__acro_print_form_and_indefinite:nnn {short} {#1} {#2}
        \__acro_open_bracket:
        \__acro_print_foreign:n {#1}
        \__acro_foreign_sep:n {#1}
        \__acro_print_form:nnn {long} {#1} {#2}
        \__acro_print_citation:n {#1}
        \__acro_close_bracket:
        \__acro_finalize_first:n {#1}
      }
      { % zuerst lange Form, dann kurze Form:
        \__acro_print_form_and_indefinite:nnn {long} {#1} {#2}
        \__acro_open_bracket:
        \__acro_print_foreign:n {#1}
        \__acro_foreign_sep:n {#1}
        \__acro_print_form:nnn {short} {#1} {#2}
        \__acro_print_citation:n {#1}
        \__acro_close_bracket:
        \__acro_finalize_first:n {#1}
      }
  }

\bool_new:N \l__acro_first_instance_bool
  
\NewExpandableDocumentCommand \aciffirst {+m+m}
  { \bool_if:NTF \l__acro_first_instance_bool {#1} {#2} }
  
% template for footnotes, sidenotes, ...
\cs_new:Npn \__acro_note_command:n #1 {#1}
\DeclareTemplateInterface {acro-first} {note} {2}
  {
    use-note     : boolean    = true ,
    note-command : function 1 = \footnote {#1} ,
    foreign-sep  : tokenlist  = {,~} ,
    reversed      : boolean   = false ,
  }

\DeclareTemplateCode {acro-first} {note} {2}
  {
    use-note     = \l__acro_use_note_bool  ,
    note-command = \__acro_note_command:n  ,
    foreign-sep  = \l__acro_foreign_sep_tl ,
    reversed     = \l__acro_first_reversed_bool
  }
  {
    \AssignTemplateKeys
    \bool_if:NTF \l__acro_first_reversed_bool
      { % long in text and short in note
        \__acro_print_form_and_indefinite:nnn {long} {#1} {#2}
        \bool_if:NT \l__acro_use_note_bool
          {
            \__acro_note_command:n
              {
                \__acro_print_foreign:n {#1}
                \__acro_foreign_sep:n {#1}
                \__acro_print_form:nnn {short} {#1} {#2}
                \__acro_print_citation:n {#1}
                \__acro_finalize_first:n {#1}
              }
          }
      }
      { % short in text and long in note
        \__acro_print_form_and_indefinite:nnn {short} {#1} {#2}
        \bool_if:NT \l__acro_use_note_bool
          {
            \__acro_note_command:n
              {
                \__acro_print_foreign:n {#1}
                \__acro_foreign_sep:n {#1}
                \__acro_print_form:nnn {long} {#1} {#2}
                \__acro_print_citation:n {#1}
                \__acro_finalize_first:n {#1}
              }
          }
      }
  }

% --------------------------------------------------------------------------
% declare new first styles:
\cs_new_protected:Npn \acro_declare_first_style:nnn #1#2#3
  {
    \DeclareInstance {acro-first} {#1} {#2} {#3}
    \prop_put:Nnn \l__acro_first_styles_prop  {#1} {#2}
  }

% #1: name
% #2: template
% #3: settings
\NewDocumentCommand \DeclareAcroFirstStyle {mmm}
  { \acro_declare_first_style:nnn {#1} {#2} {#3} }

% set a list style
\cs_new_protected:Npn \acro_set_first_style:n #1
  {
    \prop_if_in:NnTF \l__acro_first_styles_prop {#1}
      { \__acro_set_first_style:n {#1} }
      {
        \msg_warning:nnnnn {acro} {unknown}
          {first~ style}
          {#1}
          {default}
        \__acro_set_first_style:n {default}
      }
  }

\cs_new_protected:Npn \__acro_set_first_style:n #1
  {
    \tl_set:Nn \l__acro_first_instance_tl {#1}
    \prop_get:NnN \l__acro_first_styles_prop {#1} \l__acro_tmpa_tl
  }

% --------------------------------------------------------------------------
% formatting the extras information:
\DeclareObjectType {acro-extra} {1}

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

\DeclareTemplateCode {acro-extra} {inline} {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:Vn \l__acro_extra_format_tl {#1}
    \bool_if:NT \l__acro_extra_use_brackets_bool
      { \tl_tail:N \l__acro_extra_brackets_tl }
  }

% declare new extra styles:
\cs_new_protected:Npn \acro_declare_etxra_style:nnn #1#2#3
  {
    \DeclareInstance {acro-etxra} {#1} {#2} {#3}
    \prop_put:Nnn \l__acro_etxra_styles_prop  {#1} {#2}
  }

% #1: name
% #2: template
% #3: settings
\NewDocumentCommand \DeclareAcroExtraStyle {mmm}
  { \acro_declare_extra_style:nnn {#1} {#2} {#3} }

% set an extra style
\cs_new_protected:Npn \acro_set_extra_style:n #1
  {
    \prop_if_in:NnTF \l__acro_extra_styles_prop {#1}
      { \__acro_set_extra_style:n {#1} }
      {
        \msg_warning:nnnnn {acro} {unknown}
          {extra~ style}
          {#1}
          {default}
        \__acro_set_extra_style:n {default}
      }
  }

\cs_new_protected:Npn \__acro_set_extra_style:n #1
  {
    \tl_set:Nn \l__acro_extra_instance_tl {#1}
    \prop_get:NnN \l__acro_extra_styles_prop {#1} \l__acro_tmpa_tl
  }

\cs_new_protected:Npn \acro_declare_extra_style:nnn #1#2#3
  {
    \DeclareInstance {acro-extra} {#1} {#2} {#3}
    \prop_put:Nnn \l__acro_extra_styles_prop  {#1} {#2}
  }

% --------------------------------------------------------------------------
% outputting the page numbers:
\RequirePackage {zref-abspage}

\cs_new_protected:Npn \__acro_create_page_records:n #1
  {
    \seq_new:c { g__acro_#1_pages_seq }
    \tl_new:c  { g__acro_#1_recorded_pages_tl }
  }

\cs_new_protected:Npn \acro_hyper_page:n #1 { \use:n {#1} }

\cs_new:Npn \acro_get_thepage:nnn #1#2#3 { \acro_hyper_page:n {#1} }
\cs_new:Npn \acro_get_thepage_from:N #1
  { \exp_after:wN \acro_get_thepage:nnn #1 }

\cs_new:Npn \acro_get_page_number:nnn #1#2#3 {#2}
\cs_new:Npn \acro_get_page_number_from:N #1
  { \exp_after:wN \acro_get_page_number:nnn #1 }

\cs_new:Npn \acro_get_abspage:nnn #1#2#3 {#3}
\cs_new:Npn \acro_get_abspage_from:N #1
  { \exp_after:wN \acro_get_abspage:nnn #1 }

\cs_new:Npn \acro_page_range_comma: {}

\cs_new_protected:Npn \acro_print_page_numbers:n #1
  {
    \seq_if_empty:cF {g__acro_#1_pages_seq}
      {
        \bool_if:NTF \l__acro_list_all_pages_bool
          {
            % have the numbers changed?
            \tl_set:Nx \l__acro_tmpa_tl
              { \seq_use:cn {g__acro_#1_pages_seq} {|} }
            \tl_if_eq:cNF {g__acro_#1_recorded_pages_tl} \l__acro_tmpa_tl
              {
                \@latex@warning@no@line
                  {Rerun~to~get~page~numbers~of~acronym~#1~in~acronym~list~right}
              }
            \tl_clear:N \l__acro_write_pages_tl
            \tl_clear:N \l__acro_last_page_tl
            \tl_clear:N \l__acro_current_page_tl
            \seq_set_eq:Nc \l__acro_tmpb_seq { g__acro_#1_pages_seq }
            \seq_remove_duplicates:N \l__acro_tmpb_seq
            \seq_clear:N \l__acro_tmpa_seq
            \cs_set_protected:Npn \acro_page_range_comma:
              { \cs_set:Npn \acro_page_range_comma: { ,~ } }
            % get the numbers:
            \int_compare:nNnTF { \seq_count:N \l__acro_tmpb_seq } = { 1 }
              {
                \tl_use:N \l__acro_page_name_tl
                \seq_get_right:cN { g__acro_#1_pages_seq } \l__acro_tmpa_tl
                \acro_get_thepage_from:N \l__acro_tmpa_tl
              }
              {
                \tl_use:N \l__acro_pages_name_tl
                \seq_map_inline:cn { g__acro_#1_pages_seq }
                  {
                    \tl_if_blank:VTF \l__acro_last_page_tl
                      {% we're at the beginning
                        \seq_put_right:Nn \l__acro_tmpa_seq {##1}
                        \tl_set:Nn \l__acro_last_page_tl {##1}
                      }
                      {% we'at least at the second page
                         % current page:
                         \tl_set:Nn  \l__acro_current_page_tl {##1}
                         % last page:
                         \seq_get_right:NN \l__acro_tmpa_seq \l__acro_last_page_tl
                         \tl_if_eq:NNTF \l__acro_current_page_tl \l__acro_last_page_tl
                           {% there were more than one appearance on the current page
                             \seq_put_right:Nn \l__acro_tmpa_seq {##1}
                           }
                           {% new page
                             \acro_determine_page_ranges:NNn
                               \l__acro_tmpa_seq
                               \l__acro_write_pages_tl
                               {##1}
                           }
                      }
                  }
                \seq_if_empty:NF \l__acro_tmpa_seq
                  {
                    \acro_determine_page_ranges:NNV
                      \l__acro_tmpa_seq
                      \l__acro_write_pages_tl
                      \l__acro_current_page_tl
                  }
                \tl_use:N \l__acro_write_pages_tl
                \tl_clear:N \l__acro_write_pages_tl
              }
          }
          {
            \tl_use:N \l__acro_page_name_tl
            \pageref{\l__acro_label_prefix_tl #1}
          }
      }
    \seq_clear:N \l__acro_tmpa_seq
    \seq_clear:N \l__acro_tmpb_seq
  }

\cs_new:Npn \acro_determine_page_ranges:NNn #1#2#3
  {
    \seq_remove_duplicates:N #1
    % current page:
    \int_set:Nn \l__acro_tmpa_int { \acro_get_abspage:nnn #3 }
    \int_set:Nn \l__acro_tmpb_int { \acro_get_page_number:nnn #3 }
    % last page:
    \seq_get_right:NN #1 \l__acro_last_page_tl
    \int_set:Nn \l__acro_tmpc_int
      { \acro_get_abspage_from:N \l__acro_last_page_tl }
    \int_set:Nn \l__acro_tmpd_int
      { \acro_get_page_number_from:N \l__acro_last_page_tl }
    \bool_if:nTF
      {
        \int_compare_p:nNn
          { \l__acro_tmpa_int - \l__acro_tmpc_int }
           =
          { \l__acro_tmpb_int - \l__acro_tmpd_int }
        &&
        \int_compare_p:nNn
        { \l__acro_tmpb_int - \l__acro_tmpd_int } = {1}
      }
      {% same kind of page numbering, one page ahead
       % => possible range
         \seq_put_right:Nn #1 {#3}
      }
      {% any possible range ended
        \tl_put_right:Nn #2 { \acro_page_range_comma: }
        \int_compare:nNnTF
          { \seq_count:N #1 } > {2}
          {% real range
            \seq_get_left:NN #1 \l__acro_tmpa_tl
            \tl_put_right:Nx #2 { \acro_get_thepage_from:N \l__acro_tmpa_tl }
            \bool_if:NTF \l__acro_following_pages_bool
              { \tl_put_right:Nn #2 { \l__acro_next_pages_tl } }
              {
                \tl_put_right:Nn #2 { -- }
                \seq_get_right:NN #1 \l__acro_tmpa_tl
                \tl_put_right:Nx #2 { \acro_get_thepage_from:N \l__acro_tmpa_tl }
              }
          }
          {
            \int_compare:nNnTF
              { \seq_count:N #1 } = {2}
              {% range of two pages
                \seq_get_left:NN #1 \l__acro_tmpa_tl
                \tl_put_right:Nx #2 { \acro_get_thepage_from:N \l__acro_tmpa_tl }
                \bool_if:NTF \l__acro_following_page_bool
                  { \tl_put_right:Nn #2 { \l__acro_next_page_tl } }
                  {
                    \tl_put_right:Nn #2 { ,~ }
                    \seq_get_right:NN #1 \l__acro_tmpa_tl
                    \tl_put_right:Nx #2 { \acro_get_thepage_from:N \l__acro_tmpa_tl }
                  }
              }
              {% no range at all
                \seq_get_right:NN #1 \l__acro_tmpa_tl
                \tl_put_right:Nx #2 { \acro_get_thepage_from:N \l__acro_tmpa_tl }
              }
          }
        \seq_clear:N #1
        \seq_put_right:Nn #1 {#3}
      }
  }
\cs_generate_variant:Nn \acro_determine_page_ranges:NNn { NNV }

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

\DeclareTemplateInterface {acro-page-number} {inline} {1}
  {
    display       : boolean   = true  ,
    punct         : boolean   = false ,
    punct-symbol  : tokenlist = {,}   ,
    brackets      : boolean   = false ,
    brackets-type : tokenlist = ()    ,
    space         : skip      = .333333em plus .166666em minus .111111em
  }

\DeclareTemplateCode {acro-page-number} {inline} {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_skip
  }
  {
    \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
        \dim_compare:nNnF { \l__acro_page_space_skip } = { 0pt }
          { \skip_horizontal:N \l__acro_page_space_skip }
        \bool_if:NT \l__acro_page_brackets_bool
          { \tl_head:N \l__acro_page_brackets_tl }
        \acro_print_page_numbers:n {#1}
        \bool_if:NT \l__acro_page_brackets_bool
          { \tl_tail:N \l__acro_page_brackets_tl }
      }
  }

% declare new page styles:
\cs_new_protected:Npn \acro_declare_page_style:nnn #1#2#3
  {
    \DeclareInstance {acro-page-number} {#1} {#2} {#3}
    \prop_put:Nnn \l__acro_page_styles_prop  {#1} {#2}
  }

% #1: name
% #2: template
% #3: settings
\NewDocumentCommand \DeclareAcroPageStyle {mmm}
  { \acro_declare_page_style:nnn {#1} {#2} {#3} }

% set a page style
\cs_new_protected:Npn \acro_set_page_style:n #1
  {
    \prop_if_in:NnTF \l__acro_page_styles_prop {#1}
      { \__acro_set_page_style:n {#1} }
      {
        \msg_warning:nnnnn {acro} {unknown}
          {page~ style}
          {#1}
          {none}
        \__acro_set_page_style:n {none}
      }
  }

\cs_new_protected:Npn \__acro_set_page_style:n #1
  {
    \tl_set:Nn \l__acro_page_instance_tl {#1}
    \prop_get:NnN \l__acro_page_styles_prop {#1} \l__acro_tmpa_tl
  }

% --------------------------------------------------------------------------
% 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}
  }

% set a list heading:
\cs_new_protected:Npn \acro_set_list_heading:n #1
  {
    \prop_if_in:NnTF \l__acro_list_headings_prop {#1}
      { \__acro_set_list_heading:n {#1} }
      {
        \msg_warning:nnnnn {acro} {unknown}
          {list~ heading}
          {#1}
          {section*}
        \__acro_set_list_heading:n {section*}
      }
  }

\cs_new_protected:Npn \__acro_set_list_heading:n #1
  {
    \tl_set:Nn \l__acro_list_heading_cmd_tl {#1}
    % \prop_get:NnN \l__acro_list_headings_prop
    %   {#1}
    %   \l__acro_list_heading_cmd_tl
  }
  
\cs_new_protected:Npn \acro_declare_list_heading:nn #1#2
  {
    \prop_put:Nnn \l__acro_list_headings_prop {#1} {#2}
    \DeclareInstance {acro-title} {#1} {sectioning}
      { name-format = #2 {##1} }
  }

\NewDocumentCommand \DeclareAcroListHeading {mm}
  { \acro_declare_list_heading:nn {#1} {#2} }

% --------------------------------------------------------------------------
% typesetting the acronym list
\DeclareObjectType {acro-list} {2}

% #1: id
% #2: excluded classes
\prg_new_protected_conditional:Npnn \acro_if_is_excluded:nn #1#2 {T,F,TF}
  {
    \bool_set_false:N \l__acro_is_excluded_bool
    \tl_if_blank:nF {#2}
      {
        \clist_map_inline:nn {#2}
          {
            \prop_get:NnNT \l__acro_class_prop {#1} \l__acro_tmpa_tl
              {
                \seq_set_split:NnV \l__acro_tmpa_seq {,} \l__acro_tmpa_tl
                \seq_if_in:NnT \l__acro_tmpa_seq {##1}
                  { \bool_set_true:N \l__acro_is_excluded_bool }
              }
          }
      }
    \bool_if:NTF \l__acro_is_excluded_bool
      { \prg_return_true: }
      { \prg_return_false: }
  }

% #1: id
% #2: included classes
\prg_new_protected_conditional:Npnn \acro_if_is_included:nn #1#2 {T,F,TF}
  {
    \bool_set_false:N \l__acro_is_included_bool
    \tl_if_blank:nTF {#2}
      { \bool_set_true:N \l__acro_is_included_bool }
      {
        \clist_map_inline:nn {#2}
          {
            \prop_get:NnNT \l__acro_class_prop {#1} \l__acro_tmpa_tl
              {
                \seq_set_split:NnV \l__acro_tmpa_seq {,} \l__acro_tmpa_tl
                \seq_if_in:NnT \l__acro_tmpa_seq {##1}
                  { \bool_set_true:N \l__acro_is_included_bool }
              }
          }
      }
    \bool_if:NTF \l__acro_is_included_bool
      { \prg_return_true: }
      { \prg_return_false: }
  }

% #1: id
\cs_new_protected:Npn \__acro_list_entry_short:n #1
  {
    \group_begin:
      \acro_get:n {#1}
      \acro_hyper_target:nn
        {#1}
        {
          \acro_acc_supp:nn
            {#1}
            {
              \bool_if:nTF
                {
                  \l__acro_custom_short_format_bool &&
                  \l__acro_override_list_format_bool
                }
                { \l__acro_custom_short_format_tl }
                { \l__acro_list_short_format_tl }
              \__acro_get_property:nn {short} {#1}
            }
        }
    \group_end:
  }

% #1: id
\cs_new_protected:Npn \__acro_list_entry_long:n #1
  {
    \group_begin:
      \bool_if:NT \l__acro_capitalize_list_bool
        { \bool_set_true:N \l__acro_first_upper_bool }
      \acro_write_long:Vf \l__acro_list_long_format_tl
        {
          \prop_if_in:NnTF \l__acro_list_prop {#1}
            { \__acro_get_property:nn {list} {#1} }
            { \__acro_get_property:nn {long} {#1} }
        }
    \group_end:
    \bool_if:NT \l__acro_foreign_bool
      { \acro_get_foreign:n {#1} }
    \acro_cite_if:nn { \l__acro_citation_all_bool } {#1}
  }

% #1: id
\cs_new_protected:Npn \__acro_list_entry_extra:n #1
  {
    \prop_get:NnNT \l__acro_extra_prop {#1} \l__acro_tmpa_tl
      {
        \acro_extra_instance:VV
          \l__acro_extra_instance_tl
          \l__acro_tmpa_tl
      }
  }

% #1: id
\cs_new_protected:Npn \__acro_list_entry_page:n #1
  {
    \bool_if:nT { \cs_if_exist_p:c { acro@#1@once } }
      {
        \acro_page_number_instance:Vn
          \l__acro_page_instance_tl
          {#1}
      }
  }
  
% macro for retrieval of items in the list:
% #1: property
% #2: id
\cs_new_protected:Npn \acro_list_entry:nn #1#2
  {
    \str_case:nnF {#1}
      {
        {short} { \__acro_list_entry_short:n {#2} }
        {long}  { \__acro_list_entry_long:n {#2} }
        {extra} { \__acro_list_entry_extra:n {#2} }
        {page}  { \__acro_list_entry_page:n {#2} }
      }
      { \__acro_get_property:nn {#1} {#2} }
  }

% this macro may/should be redefined in templates:
% #1: short
% #2: long
% #3: extra
% #4: page number(s)
\cs_new_protected:Npn \acro_print_list_entry:nnnn #1#2#3#4
  { #1 #2 #3 #4 }

\cs_new_protected:Npn \acro_for_all_acronyms_do:n #1
  { \prop_map_inline:Nn \l__acro_short_prop {#1} }

% test, if acronyms should be printed or not; needs testing for in/excluded
% classes and options `only-used' and `single' -- this macro should be used in
% the template code for retrieving the list
  
% #1: id
% #2: included classes
% #3: excluded classes
\prg_new_protected_conditional:Npnn \acro_if_entry:nnn #1#2#3 {T,F,TF}
  {
    \bool_if:nTF
      {
        \bool_if_p:c { g__acro_#1_in_list_bool } &&
        (
          ( \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_if_is_excluded:nnTF {#1} {#3}
          { \prg_return_false: }
          {
            \acro_if_is_included:nnTF {#1} {#2}
              {
                \bool_if:nTF
                  { \g__acro_use_barriers_bool && \l__acro_use_barrier_bool }
                  {
                    \acro_if_in_barrier:nxTF {#1}
                      { \int_use:N \g__acro_barrier_int }
                      { \prg_return_true: }
                      { \prg_return_false: }
                  }
                  { \prg_return_true: }
              }
              { \prg_return_false: }
          }
      }
      { \prg_return_false: }
  }

\tl_new:N \l__acro_list_entries_tl

% this macro is used in templates for fetching all items to be printed; it
% collects all entries in a tl which then is used where needed
%
% #1: tl containing the entries
% #2: included classes
% #3: excluded classes
\cs_new_protected:Npn \acro_build_list_entries:Nnn #1#2#3
  {
    \tl_clear:N #1
    \acro_for_all_acronyms_do:n
      {% ##1: id; ##2: short form
        \group_begin:
          \acro_get:n {##1}
          \acro_if_entry:nnnT {##1} {#2} {#3}
            {
              \tl_gput_right:Nn #1
                {
                  \acro_print_list_entry:nnnn
                    { \acro_list_entry:nn {short} {##1} }
                    { \acro_list_entry:nn {long} {##1} }
                    { \acro_list_entry:nn {extra} {##1} }
                    { \acro_list_entry:nn {page} {##1} }
                }
            }
        \group_end:  
      }
  }

% this macro is used in templates for fetching all items to be printed:
\cs_new_protected:Npn \acro_list_items:nn #1#2
  {
    \acro_build_list_entries:Nnn \l__acro_list_entries_tl {#1} {#2}
    \tl_use:N \l__acro_list_entries_tl
  }
  
% --------------------------------------------------------------------------
% declare templates for the list:
% `list' template:
\DeclareTemplateInterface {acro-list} {list} {2}
  {
    foreign-sep : tokenlist = {~} ,
    list        : tokenlist = {description} ,
    reverse     : boolean   = false ,
    before      : tokenlist = ,
    after       : tokenlist =
  }

\DeclareTemplateCode {acro-list} {list} {2}
  {
    foreign-sep = \l__acro_foreign_sep_tl ,
    list        = \l__acro_list_tl ,
    reverse     = \l__acro_list_reverse_long_extra_bool ,
    before      = \l__acro_list_before_tl ,
    after       = \l__acro_list_after_tl
  }
  {
    \AssignTemplateKeys
    \bool_set_true:N \l__acro_in_list_bool
    \acro_activate_hyperref_support:
    \bool_if:NTF \l__acro_list_reverse_long_extra_bool
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { \item [##1] ##3 ##2 ##4 }
      }
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { \item [##1] ##2 ##3 ##4 }
      }
    \use:x
      {
        \exp_not:V \l__acro_list_before_tl
        \exp_not:N \begin { \exp_not:V \l__acro_list_tl }
          \exp_not:n { \acro_list_items:nn {#1} {#2} }
        \exp_not:N \end { \exp_not:V \l__acro_list_tl }
        \exp_not:V \l__acro_list_after_tl
      }
  }

% `list-of' template:
\DeclareTemplateInterface {acro-list} {list-of} {2}
  {
    foreign-sep : tokenlist = {~} ,
    style       : tokenlist = {toc} ,
    reverse     : boolean   = false ,
    before      : tokenlist = ,
    after       : tokenlist =
  }

\DeclareTemplateCode {acro-list} {list-of} {2}
  {
    foreign-sep = \l__acro_foreign_sep_tl ,
    style       = \l__acro_list_of_style ,
    reverse     = \l__acro_list_reverse_long_extra_bool ,
    before      = \l__acro_list_before_tl ,
    after       = \l__acro_list_after_tl
  }
  {
    \AssignTemplateKeys
    \bool_set_true:N \l__acro_in_list_bool
    \tl_if_eq:VnT \l__acro_page_instance_tl {none}
      { \tl_set:Nn \l__acro_page_instance_tl {plain} }
    \tl_set:Nn \l__acro_page_name_tl {}
    \tl_set:Nn \l__acro_pages_name_tl {}
    \acro_activate_hyperref_support:
    \str_case:Vn \l__acro_list_of_style
      {
        {toc}
        { % similar to the table of contents
          \bool_if:NTF \l__acro_list_reverse_long_extra_bool
            {
              \cs_if_exist:NTF \chapter
                {
                  \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                    {
                      \contentsline{chapter}{##1}{}{}
                      \contentsline{section}{##3##2}{##4}{}
                    } 
                }
                {
                  \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                    {
                      \contentsline{section}{##1}{}{}
                      \contentsline{subsection}{##3##2}{##4}{}
                    }
                }
            }
            {
              \cs_if_exist:NTF \chapter
                {
                  \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                    {
                      \contentsline{chapter}{##1}{}{}
                      \contentsline{section}{##2##3}{##4}{}
                    } 
                }
                {
                  \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                    {
                      \contentsline{section}{##1}{}{}
                      \contentsline{subsection}{##2##3}{##4}{}
                    }
                }
            }
        }
        {lof}
        { % similar to the list of figures
          \cs_set_protected:Npn \l@acro
            { \@dottedtocline {1} {1.5em} {\l__acro_short_width_dim} }
          \bool_if:NTF \l__acro_list_reverse_long_extra_bool
            {
              \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                { \contentsline{acro}{\numberline{##1}{##3##2}}{##4}{} }
            }
            {
              \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
                { \contentsline{acro}{\numberline{##1}{##2##3}}{##4}{} }
            }
        }
      }
    \use:x
      {
        \exp_not:V \l__acro_list_before_tl
        \exp_not:n { \acro_list_items:nn {#1} {#2} }
        \exp_not:V \l__acro_list_before_tl
      }
  }
  
% `table' template:
\DeclareTemplateInterface {acro-list} {table} {2}
  {
    table       : tokenlist = tabular ,
    table-spec  : tokenlist = lp{.7\linewidth} ,
    foreign-sep : tokenlist = {~} ,
    reverse     : boolean   = false ,
    before      : tokenlist = ,
    after       : tokenlist = 
  }

\DeclareTemplateCode {acro-list} {table} {2}
  {
    table       = \l__acro_list_table_tl      ,
    table-spec  = \l__acro_list_table_spec_tl ,
    foreign-sep = \l__acro_foreign_sep_tl ,
    reverse     = \l__acro_list_reverse_long_extra_bool ,
    before      = \l__acro_list_before_tl ,
    after       = \l__acro_list_after_tl
  }
  {
    \AssignTemplateKeys
    \acro_activate_hyperref_support:
    \bool_if:NTF \l__acro_list_reverse_long_extra_bool
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { ##1 & ##3 ##2 ##4 \tabularnewline }
      }
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { ##1 & ##2 ##3 ##4 \tabularnewline }
      }
    \acro_build_list_entries:Nnn \l__acro_list_entries_tl {#1} {#2}
    \use:x
      {
        \exp_not:V \l__acro_list_before_tl
        \exp_not:N \begin { \exp_not:V \l__acro_list_table_tl }
          { \exp_not:V \l__acro_list_table_spec_tl }
        \exp_not:V \l__acro_list_entries_tl
        \exp_not:N \end { \exp_not:V \l__acro_list_table_tl }
        \exp_not:V \l__acro_list_after_tl
      }
  }

% `extra-table' template:
\DeclareTemplateInterface {acro-list} {extra-table} {2}
  {
    table       : tokenlist = tabular ,
    table-spec  : tokenlist = llll ,
    foreign-sep : tokenlist = {~} ,
    reverse     : boolean   = false ,
    before      : tokenlist = ,
    after       : tokenlist = 
  }

\DeclareTemplateCode {acro-list} {extra-table} {2}
  {
    table       = \l__acro_list_table_tl      ,
    table-spec  = \l__acro_list_table_spec_tl ,
    foreign-sep = \l__acro_foreign_sep_tl ,
    reverse     = \l__acro_list_reverse_long_extra_bool ,
    before      = \l__acro_list_before_tl ,
    after       = \l__acro_list_after_tl
  }
  {
    \AssignTemplateKeys
    \acro_activate_hyperref_support:
    \bool_if:NTF \l__acro_list_reverse_long_extra_bool
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { ##1 & ##3 & ##2 & ##4 \tabularnewline }
      }
      {
        \cs_set_protected:Npn \acro_print_list_entry:nnnn ##1##2##3##4
          { ##1 & ##2 & ##3 & ##4 \tabularnewline }
      }
    \acro_build_list_entries:Nnn \l__acro_list_entries_tl {#1} {#2}
    \use:x
      {
        \exp_not:V \l__acro_list_before_tl
        \exp_not:N \begin { \exp_not:V \l__acro_list_table_tl }
          { \exp_not:V \l__acro_list_table_spec_tl }
        \exp_not:V \l__acro_list_entries_tl
        \exp_not:N \end { \exp_not:V \l__acro_list_table_tl }
        \exp_not:V \l__acro_list_after_tl
      }
  }

% --------------------------------------------------------------------------
% declare new list styles:
\cs_new_protected:Npn \acro_declare_list_style:nnn #1#2#3
  {
    \DeclareInstance {acro-list} {#1} {#2} {#3}
    \prop_put:Nnn \l__acro_list_styles_prop  {#1} {#2}
  }

% #1: name
% #2: template
% #3: settings
\NewDocumentCommand \DeclareAcroListStyle {mmm}
  { \acro_declare_list_style:nnn {#1} {#2} {#3} }

% set a list style
\cs_new_protected:Npn \acro_set_list_style:n #1
  {
    \prop_if_in:NnTF \l__acro_list_styles_prop {#1}
      { \__acro_set_list_style:n {#1} }
      {
        \msg_warning:nnnnn {acro} {unknown}
          {list~ style}
          {#1}
          {description}
        \__acro_set_list_style:n {description}
      }
  }

\cs_new_protected:Npn \__acro_set_list_style:n #1
  {
    \tl_set:Nn \l__acro_list_instance_tl {#1}
    \prop_get:NnN \l__acro_list_styles_prop {#1} \l__acro_list_type_tl
  }

% --------------------------------------------------------------------------
% automatic typesetting, the internals of \ac:
% #1: id

\cs_new_protected:Npn \acro_soft_upper:
  {
    \bool_if:NF \l__acro_upper_short_bool
      { \bool_set_false:N \l__acro_first_upper_bool }
  }

\cs_new_protected:Npn \acro_use:n #1
  {
    % get the acronym and the plural settings:
    \acro_get:n {#1}
    \acro_is_used:nTF {#1}
      {
        \acro_soft_upper:
        % this is not the first time
        \acro_write_indefinite:nn {#1} {short}
        \acro_write_compact:nn {#1} {short}
        \acro_after:n {#1}
      }
      {
        % this is the first time
        \bool_gset_true:c { g__acro_#1_first_use_bool }
        \acro_if_is_single:nTF {#1}
          { \acro_single:n {#1} }
          { \acro_first_instance:nV {#1} \l__acro_long_tl }
      }
  }

% single appearances:
\cs_new_protected:Npn \acro_single:n #1
  {
    \acro_cite:
    \acro_single_form:nV {#1} \l__acro_single_form_tl
    \acro_after:n {#1}
  }
  
% #1: ID
% #2: long|first|<other>
\cs_new_protected:Npn \acro_single_form:nn #1#2
  {
    \acro_write_indefinite:nn {#1} {#2}
    \str_case:nnF {#2}
      {
        {long} {
          \tl_if_blank:VT \l__acro_single_format_tl
            {
              \bool_if:NTF \l__acro_custom_long_format_bool
                {
                  \tl_set_eq:NN
                    \l__acro_single_format_tl
                    \l__acro_custom_long_format_tl
                }
                {
                  \tl_set_eq:NN
                    \l__acro_single_format_tl
                    \l__acro_long_format_tl
                }
            }
          \tl_if_blank:VT \l__acro_single_tl
            { \tl_set_eq:NN \l__acro_single_tl \l__acro_long_tl }
          % BUG: should that be \acro_write_expanded:nn ?
          % \acro_write_expanded:nnn {#1} {#2} {\l__acro_single_tl}
          \acro_write_long:VV \l__acro_single_format_tl \l__acro_single_tl
          \acro_endings:nn {#1} {single}
          \l__acro_long_post_tl
        }
        {first} {
          \tl_if_blank:VF \l__acro_single_format_tl
            {
              \tl_set_eq:NN
                \l__acro_first_long_format_tl
                \l__acro_single_format_tl
            }
          \tl_if_blank:VT \l__acro_single_tl
            { \tl_set_eq:NN \l__acro_single_tl \l__acro_long_tl }
          \acro_first_instance:nV {#1} \l__acro_single_tl
        }
      }
      { % other (e.g. short)
        \acro_soft_upper:
        \tl_if_blank:VF \l__acro_single_tl
          { \tl_set_eq:cN {l__acro_#2_tl} \l__acro_single_tl }
        \tl_if_blank:VF \l__acro_single_format_tl
          { \tl_set_eq:cN {l__acro_#2_format_tl} \l__acro_single_format_tl }
        \acro_write_compact:nn {#1} {#2}
      }
  }
\cs_generate_variant:Nn \acro_single_form:nn {nV}

\prg_new_conditional:Npnn \acro_if_is_single:n #1 { p,T,TF }
  {
    \bool_if:nTF
      { !\l__acro_use_single_bool || \cs_if_exist_p:c { acro@#1@twice } }
      { \prg_return_false: }
      { \prg_return_true: }
  }

\cs_new_protected:Npn \acro_use_acronym:n #1
  { \use:c {bool_set_#1:N} \l__acro_mark_as_used_bool }

% --------------------------------------------------------------------------
% some helpers we'll need more often:
\seq_new:N \g__acro_declared_acronyms_seq

\prg_new_conditional:Npnn \acro_if_defined:n #1 {p,T,F,TF}
  {
    \seq_if_in:NnTF \g__acro_declared_acronyms_seq {#1}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \acro_defined:n #1
  {
    \acro_if_defined:nF {#1}
      { \acro_serious_message:nn {undefined} {#1} }
  }

% expandably gets property but doesn't transform property name -- internal
% name is needed
% #1: property
% #2: id
\cs_new:Npn \__acro_get_property:nn #1#2
  { \prop_item:cn {l__acro_#1_prop} {#2} }

% #1: id
% #2: property
% #3: set case
% #4: not set case
\prg_new_protected_conditional:Npnn \acro_get_property:nn #1#2 {T,F,TF}
  {
    \tl_set:Nn \l__acro_tmpa_tl {#2}
    \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
    \prop_get:cncTF
      {l__acro_ \l__acro_tmpa_tl _prop}
      {#1}
      {l__acro_ \l__acro_tmpa_tl _tl}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \acro_get_property:nn #1#2
  { \acro_get_property:nnTF {#1} {#2} {} {} }
\cs_generate_variant:Nn \acro_get_property:nn {V}

% #1: id
% #2: property
% #3: set case
% #4: not set case
\prg_new_protected_conditional:Npnn \acro_if_property:nn #1#2 {T,F,TF}
  {
    \tl_set:Nn \l__acro_tmpa_tl {#2}
    \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
    \prop_if_in:cnTF
      {l__acro_ \l__acro_tmpa_tl _prop}
      {#1}
      { \prg_return_true: }
      { \prg_return_false: }
  }

\seq_new:N \l__acro_actions_seq

% within this command one can refer to the current id with `#1'
\cs_new_protected:Npn \acro_add_action:n #1
  { \seq_put_right:Nn \l__acro_actions_seq {#1} }

\tl_new:N \l_acro_current_id_tl
\cs_new_protected:Npn \__acro_get_actions:n #1
  {
    \seq_map_inline:Nn \l__acro_actions_seq
      {
        \cs_set:Npn \__acro_action:n ####1 {##1}
        \__acro_action:n {#1}
      }
  }

\cs_new_protected:Npn \acro_get:n #1
  {
    \bool_if:NF \l__acro_in_list_bool { \leavevmode }
    \acro_activate_hyperref_support:
    % short:
    \prop_get:NnNF \l__acro_short_prop {#1} \l__acro_tmpa_tl {}
    \__acro_make_link:NnV \l__acro_short_tl {#1} \l__acro_tmpa_tl
    % \acro_get_property:nn {#1} {short-format}
    % alt:
    \prop_get:NnNTF \l__acro_alt_prop {#1} \l__acro_tmpa_tl
      { \__acro_make_link:NnV \l__acro_alt_tl {#1} \l__acro_tmpa_tl }
      { \tl_set_eq:NN \l__acro_alt_tl \l__acro_short_tl }
    % long:
    \acro_get_property:nn {#1} {long}
    % \acro_get_property:nn {#1} {long-format}
    % foreign:
    \acro_get_property:nn {#1} {foreign}
    % foreign-lang:
    \acro_get_property:nn {#1} {foreign-lang}
    % extra:
    \acro_get_property:nn {#1} {extra}
    % \acro_get_property:nn {#1} {extra-format}
    % single:
    \acro_get_property:nn {#1} {single}
    % \acro_get_property:nn {#1} {single-format}
    % first-style:
    \acro_get_property:nn {#1} {first-style}
    % formatting
    \prop_get:NnNTF \l__acro_long_format_prop {#1}
      \l__acro_custom_long_format_tl
      { \bool_set_true:N  \l__acro_custom_long_format_bool }
      { \bool_set_false:N \l__acro_custom_long_format_bool }
    \acro_get_property:nn {#1} {first-long-format}
    \prop_get:NnNTF \l__acro_format_prop {#1} \l__acro_custom_short_format_tl
      { \bool_set_true:N \l__acro_custom_short_format_bool }
      { \bool_set_false:N \l__acro_custom_short_format_bool }
    \prop_get:NnNTF \l__acro_alt_format_prop {#1} \l__acro_custom_alt_format_tl
      { \bool_set_true:N \l__acro_custom_alt_format_bool }
      { \bool_set_false:N \l__acro_custom_alt_format_bool }
    \acro_get_property:nn {#1} {single-format}
    \acro_for_endings_do:n
      {
        \bool_if:cT {l__acro_##1_bool}
          { \__acro_set_ending_for:nnn {##1} {#1} {long} }
      }
    \acro_get_property:nnF {#1} {long-post}
      { \tl_clear:N \l__acro_long_post_tl }
    \acro_get_property:nnT {#1} {long-pre}
      { \tl_put_left:NV \l__acro_long_tl \l__acro_long_pre_tl }
    \__acro_get_actions:n {#1}
  }

% --------------------------------------------------------------------------
% plural endings and similar concepts:
\seq_new:N \l__acro_endings_seq

\cs_new_protected:Npn \acro_for_endings_do:n #1
  { \seq_map_inline:Nn \l__acro_endings_seq {#1} }

% #1: ending
% #2: ID
\cs_new_protected:Npn \__acro_set_ending:nn #1#2
  {
    \bool_if:cT {l__acro_#1_bool}
      {
        \__acro_set_ending_for:nnn {#1} {#2} {short}
        \__acro_set_ending_for:nnn {#1} {#2} {alt}
        \__acro_set_ending_for:nnn {#1} {#2} {long}
        \__acro_set_ending_for:nnn {#1} {#2} {foreign} % XXX
      }
  }

\tl_new:N \l__acro_endings_tl

\bool_new:N \l__acro_use_ending_form_bool

% this does nothing if a non-existent ending (#1) or non-existent form (#3) is
% input
% #1: ending
% #2: id
% #3: short|alt|long
\cs_new_protected:Npn \__acro_set_ending_for:nnn #1#2#3
  {
    \acro_if_ending_form_exist:nnT {#1} {#3}
      {
        \bool_if:cTF
          { c_ \prop_item:cn {l__acro_#3_#1_form_prop} {#2} _bool }
          { \prop_get:cnc {l__acro_#3_#1_prop} {#2} {l__acro_#3_tl}  }
          { \prop_get:cnc {l__acro_#3_#1_prop} {#2} {l__acro_#3_#1_tl} }
      }
  }

\cs_new_protected:Npn \__acro_set_endings:n #1
  {
    \acro_for_endings_do:n
      { \__acro_set_ending:nn {##1} {#1} }
  }

% #1: id
% #2: short|alt|…
\cs_new_protected:Npn \acro_get_ending_form:nn #1#2
  {
    \acro_for_endings_do:n
      {
        \acro_if_ending_form_exist:nnT {##1} {#2}
          {
            \bool_if:nT
              {
                \use:c { c_ \prop_item:cn {l__acro_#2_##1_form_prop} {#1} _bool }
                &&
                \use:c {l__acro_##1_bool}
              }
              { \prop_get:cncF {l__acro_#2_##1_prop} {#1} {l__acro_#2_tl} {} }
          }
      }
  }

% #1: id
% #2: short|alt|…
\cs_new_protected:Npn \acro_endings:nn #1#2
  {
    \group_begin:
      \str_if_eq:nnTF {#2} {single}
        {
          \keys_set:nn {acro}
            { long-format= \l__acro_single_format_tl }
          \__acro_endings:nn {#1} {long}
        }
        { \__acro_endings:nn {#1} {#2} }
    \group_end:
  }

\cs_new_protected:Npn \__acro_endings:nn #1#2
  {
    \acro_for_endings_do:n
      {
        \__acro_set_ending_for:nnn {##1} {#1} {#2}
        \bool_if:cT {l__acro_##1_bool}
          { \__acro_ending_format:nn {#2} { \tl_use:c {l__acro_#2_##1_tl} } }
      }
  }

% #1: long|short|alt
% #2: string
\cs_new_protected:Npn \__acro_ending_format:nn #1#2
  {
    \bool_if:NTF \l__acro_include_endings_format_bool
      {
        \str_case:nn {#1}
          {
            {long}
            {
              \bool_if:NTF \l__acro_custom_long_format_bool
                { \l__acro_custom_long_format_tl }
                {
                  \bool_if:NTF \l__acro_first_instance_bool
                    { \l__acro_first_long_format_tl }
                    { \l__acro_long_format_tl }
                }
            }
            {short}
            {
              \bool_if:NTF \l__acro_custom_short_format_bool
                { \l__acro_custom_short_format_tl }
                { \l__acro_short_format_tl }
            }
            {alt}
            {
              \bool_if:NTF \l__acro_custom_alt_format_bool
                { \l__acro_custom_alt_format_tl }
                { \l__acro_alt_format_tl }
            }
          }
      }
      { \use:n }
      {#2}
  }
  
\prg_new_conditional:Npnn \acro_if_ending_exist:n #1 {p,T,F,TF}
  {
    \seq_if_in:NnTF \l__acro_endings_seq {#1}
      { \prg_return_true: }
      { \prg_return_false: }
  }

% #1: ending
% #2: short|alt|…
\prg_new_conditional:Npnn \acro_if_ending_form_exist:nn #1#2 {p,T,F,TF}
  {
    \cs_if_exist:cTF {l__acro_#2_#1_prop}
      { \prg_return_true: }
      { \prg_return_false: }
  }
  
% #1: name
% #2: default short
% #3: default long
\cs_new_protected:Npn \acro_provide_ending:nnn #1#2#3
  {
    \acro_if_ending_exist:nTF {#1}
      {
        \acro_harmless_message:nn {ending-exists} {#1}
        % short variables
        \acro_set_ending_variables:nnn {short} {#1} {#2}
        % alt variables
        \acro_set_ending_variables:nnn {alt} {#1} {#2}
        % long variables
        \acro_set_ending_variables:nnn {long} {#1} {#3}
        % foreign variables % XXX
        \acro_set_ending_variables:nnn {foreign} {#1} {#3}
      }
      {
        % registering:
        \bool_if:NT \g__acro_first_acronym_declared_bool
          { \acro_serious_message:n {ending-before-acronyms} }
        \seq_put_right:Nn \l__acro_endings_seq {#1}
        \bool_new:c {l__acro_#1_bool}
        % short variables
        \acro_define_and_set_ending_variables:nnn {short} {#1} {#2}
        % alt variables
        \acro_define_and_set_ending_variables:nnn {alt} {#1} {#2}
        % long variables
        \acro_define_and_set_ending_variables:nnn {long} {#1} {#3}
        % foreign variables % XXX
        \acro_define_and_set_ending_variables:nnn {foreign} {#1} {#3}
        % define setup command:
        \tl_set:Nn \l__acro_tmpa_tl {#1}
        \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
        \cs_new_protected:cpn {acro_ \l__acro_tmpa_tl :}
          { \bool_set_true:c {l__acro_#1_bool} }
        % acronym properties:
        % short-<ending>:
        \acro_declare_property:nnn {short_#1} {short-#1}
          {
            \prop_put:cnn {l__acro_short_#1_form_prop} {##1} {false}
            \prop_put:cnx {l__acro_pdfstring_short_#1_prop}
              {##1} { \prop_item:Nn \l__acro_short_prop {##1} \exp_not:n {##2} }
          }
        % short-<ending>-form:
        \acro_declare_property_generic:nnn {short_#1_form} {short-#1-form}
          {
            \__acro_property_check:nn {##1} {short-#1-form}
            \prop_put:cnn {l__acro_short_#1_form_prop} {##1} {true}
            \prop_put:cnn {l__acro_short_#1_prop} {##1} {##2}
            \prop_put:cnn {l__acro_pdfstring_short_#1_prop} {##1} {##2}
          }
        % alt-<ending>:
        \acro_declare_property:nnn {alt_#1} {alt-#1}
          {
            \prop_put:cnn {l__acro_alt_#1_form_prop} {##1} {false}
            \prop_put:cnx {l__acro_pdfstring_alt_#1_prop}
              {##1} { \prop_item:Nn \l__acro_alt_prop {##1} \exp_not:n {##2} }
          }
        % alt-<ending>-form:
        \acro_declare_property_generic:nnn {alt_#1_form} {alt-#1-form}
          {
            \__acro_property_check:nn {##1} {alt-#1-form}
            \prop_put:cnn {l__acro_alt_#1_form_prop} {##1} {true}
            \prop_put:cnn {l__acro_alt_#1_prop} {##1} {##2}
            \prop_put:cnn {l__acro_pdfstring_alt_#1_prop} {##1} {##2}
          }
        % long-<ending>:
        \acro_declare_property:nnn {long_#1} {long-#1}
          { \prop_put:cnn {l__acro_long_#1_form_prop} {##1} {false} }
        % long-<ending>-form:
        \acro_declare_property_generic:nnn {long_#1_form} {long-#1-form}
          {
            \__acro_property_check:nn {##1} {long-#1-form}
            \prop_put:cnn {l__acro_long_#1_form_prop} {##1} {true}
            \prop_put:cnn {l__acro_long_#1_prop} {##1} {##2}
          }
        % foreign-<ending>: % XXX
        \acro_declare_property:nnn {foreign_#1} {foreign-#1}
          { \prop_put:cnn {l__acro_foreign_#1_form_prop} {##1} {false} }
        % foreign-<ending>-form: % XXX
        \acro_declare_property_generic:nnn {foreign_#1_form} {foreign-#1-form}
          {
            \__acro_property_check:nn {##1} {foreign-#1-form}
            \prop_put:cnn {l__acro_foreign_#1_form_prop} {##1} {true}
            \prop_put:cnn {l__acro_foreign_#1_prop} {##1} {##2}
          }
        % options:
        %   short-<ending>-ending
        %   alt-<ending>-ending
        %   long-<ending>-ending
        %   foreign-<ending>-ending % XXX
        %   <ending>-ending
        \keys_define:nn {acro}
          {
            short-#1-ending .code:n =
              \bool_if:NT \g__acro_first_acronym_declared_bool
                { \acro_serious_message:n {ending-before-acronyms} }
              \tl_set:cn {l__acro_default_short_#1_tl} {##1} ,
            alt-#1-ending   .code:n =
              \bool_if:NT \g__acro_first_acronym_declared_bool
                { \acro_serious_message:n {ending-before-acronyms} }
              \tl_set:cn {l__acro_default_alt_#1_tl} {##1} ,
            long-#1-ending  .code:n =
              \bool_if:NT \g__acro_first_acronym_declared_bool
                { \acro_serious_message:n {ending-before-acronyms} }
                \tl_set:cn {l__acro_default_long_#1_tl} {##1} ,
            foreign-#1-ending .code:n =
              \bool_if:NT \g__acro_first_acronym_declared_bool
                { \acro_serious_message:n {ending-before-acronyms} }
              \tl_set:cn {l__acro_default_foreign_#1_tl} {##1} ,
            #1-ending       .code:n   =
              \bool_if:NT \g__acro_first_acronym_declared_bool
                { \acro_serious_message:n {ending-before-acronyms} }
              \__acro_read_ending_settings:nww {#1} ##1// \acro_stop:
          }
        % pdfstrings:
        % TODO: add long forms:
        \prop_new:c {l__acro_pdfstring_short_#1_prop}
        \cs_new:cpn {acro_pdf_string_short_#1:n} ##1
          {
            \acro_if_star_gobble:nTF {##1}
              { \prop_item:cn {l__acro_pdfstring_short_#1_prop} }
              { \prop_item:cn {l__acro_pdfstring_short_#1_prop} {##1} }
          }
        \cs_new:cpn {acpdfstring#1} { \use:c {acro_pdf_string_short_#1:n} }
        \prop_new:c {l__acro_pdfstring_alt_#1_prop}
        \cs_new:cpn {acro_pdf_string_alt_#1:n} ##1
          {
            \acro_if_star_gobble:nTF {##1}
              { \prop_item:cn {l__acro_pdfstring_alt_#1_prop} }
              { \prop_item:cn {l__acro_pdfstring_alt_#1_prop} {##1} }
          }
        \cs_new:cpn {acpdfstringalt#1} { \use:c {acro_pdf_string_alt_#1:n} }
      }
  }

% #1: short|alt|long
% #2: ending name
% #3: default ending
\cs_new_protected:Npn \acro_define_and_set_ending_variables:nnn #1#2#3
  {
    \acro_define_ending_variables:nn {#1} {#2}
    \acro_set_ending_variables:nnn {#1} {#2} {#3}
  }

% #1: short|alt|long
% #2: ending name
\cs_new_protected:Npn \acro_define_ending_variables:nn #1#2
  {
    \prop_new:c {l__acro_#1_#2_prop}
    \prop_new:c {l__acro_#1_#2_form_prop}
    \tl_new:c   {l__acro_#1_#2_tl}
    \tl_new:c   {l__acro_default_#1_#2_tl}
  }

% #1: short|alt|long
% #2: ending name
% #3: default ending
\cs_new_protected:Npn \acro_set_ending_variables:nnn #1#2#3
  { \tl_set:cn  {l__acro_default_#1_#2_tl} {#3} }

% #1: ending name
% #2: short (and long if #4 is blank)
% #3: long
\cs_new_protected:Npn \__acro_read_ending_settings:nww #1#2/#3/#4 \acro_stop:
  {
    \acro_set_ending_variables:nnn {short} {#1} {#2}
    \acro_set_ending_variables:nnn {alt} {#1} {#2}
    \tl_if_blank:nTF {#4}
      {
        \acro_set_ending_variables:nnn {long} {#1} {#3}
        \acro_set_ending_variables:nnn {foreign} {#1} {#3}
      }
      {
        \acro_set_ending_variables:nnn {long} {#1} {#2}
        \acro_set_ending_variables:nnn {foreign} {#1} {#2}
      }
  }

\NewDocumentCommand \ProvideAcroEnding {mmm}
  { \acro_provide_ending:nnn {#1} {#2} {#3} }

% --------------------------------------------------------------------------
% enable us to know if the acronym is used only once and provide a different
% style for that:
\prg_new_protected_conditional:Npnn \acro_is_used:n #1 { T,F,TF }
  {
    \acro_record_barrier:n {#1}
    \bool_if:nTF
      {
        \bool_if_p:c { g__acro_#1_used_bool } &&
        (
          (
            \bool_if_p:c { g__acro_#1_first_use_bool } &&
            \g__acro_mark_first_as_used_bool
          )
          ||
          ! \g__acro_mark_first_as_used_bool
        )
      }
      {
        \bool_if:NTF \l__acro_mark_as_used_bool
          {
            \__acro_aux_file:Nxxxx \acro@used@twice
              {#1}
              { \thepage }
              { \arabic {page} }
              { \arabic {abspage} }
          }
          { \__acro_aux_file:Nxxxx \acro@used@twice {#1} {} {} {} }
        \prg_return_true:
      }
      {
        \bool_if:NTF \l__acro_mark_as_used_bool
          {
            \__acro_aux_file:Nxxxx \acro@used@once
              {#1}
              { \thepage }
              { \arabic {page} }
              { \arabic {abspage} }
            \bool_if:nT
              {
                !\bool_if_p:c { g__acro_#1_label_bool } &&
                \l__acro_place_label_bool
              }
              {
                \bool_gset_true:c { g__acro_#1_label_bool }
                \label{\l__acro_label_prefix_tl #1}
              }
            \bool_gset_true:c { g__acro_#1_used_bool }
          }
          {}
          % I can't remember why I want an empty first use case for starred
          % acronyms…
          % { \__acro_aux_file:Nxxxx \acro@used@once {#1} {} {} {} }
        \prg_return_false:
      }
  }

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

\cs_new_protected:Npn \__acro_aux_file:Nnnnn #1#2#3#4#5
  { \iow_shipout:Nn \@auxout { #1 {#2} {#3} {#4} {#5} } }
\cs_generate_variant:Nn \__acro_aux_file:Nnnnn { Nxxxx }
  
\cs_new_protected:Npn \__acro_aux_file_now:n #1
  { \iow_now:Nn \@auxout {#1} }
\cs_generate_variant:Nn \__acro_aux_file_now:n { x }

% --------------------------------------------------------------------------
% the commands for the auxiliary file:
\cs_new_protected:Npn \acro@used@once #1#2#3#4
  {
    \cs_gset_nopar:cpn {acro@#1@once} {#1}
    \bool_gset_true:c {g__acro_#1_in_list_bool}
    \tl_if_empty:nF {#2#3#4}
      {
        % \bool_gset_true:c { g__acro_#1_used_bool }
        \seq_gput_right:cn {g__acro_#1_pages_seq} { {#2}{#3}{#4} }
      }
  }
\cs_new_protected:Npn \acro@used@twice #1#2#3#4
  {
    \cs_gset_nopar:cpn {acro@#1@twice} {#1}
    \tl_if_empty:nF {#2#3#4}
      { \seq_gput_right:cn {g__acro_#1_pages_seq} { {#2}{#3}{#4} } }
  }

\cs_new_protected:Npn \acro@pages #1#2
  { \tl_gset:cn {g__acro_#1_recorded_pages_tl} {#2} }

\bool_new:N \g__acro_rerun_bool

\cs_new_protected:Npn \acro@rerun@check
  {
    \bool_if:NT \g__acro_rerun_bool
      {
        \@latex@warning@no@line
          {Acronyms~ may~ have~ changed.~ Please~ rerun~ LaTeX}
      }
  }

\AtEndDocument
  {
    \bool_gset_false:N \g__acro_rerun_bool
    \cs_gset_protected:Npn \acro@used@once #1#2#3#4
      {
        \tl_set:Nn \l__acro_tmpa_tl {#1}
        \tl_if_eq:cNF {acro@#1@once} \l__acro_tmpa_tl
          { \bool_gset_true:N \g__acro_rerun_bool }
      }
    \cs_gset_protected:Npn \acro@used@twice #1#2#3#4
      {
        \tl_set:Nn \l__acro_tmpa_tl {#1}
        \tl_if_eq:cNF {acro@#1@twice} \l__acro_tmpa_tl
          { \bool_gset_true:N \g__acro_rerun_bool }
      }
    \acro_for_all_acronyms_do:n
      {
        \seq_if_empty:cF {g__acro_#1_pages_seq}
          {
            \__acro_aux_file_now:x
              {
                \token_to_str:N \acro@pages {#1}
                  { \seq_use:cn {g__acro_#1_pages_seq} {|} } ^^J
                \token_to_str:N \acro@barriers {#1}
                  { \seq_use:cn {g__acro_#1_barriers_seq} {,} }
              }
          }
        \acro_check_barriers:n {#1}
      }
    \__acro_aux_file_now:n { \acro@rerun@check }
  }

% if `acro' is deactivated prevent unnecessary errors from aux file:
\if@filesw
\AtBeginDocument
  {
    \__acro_aux_file_now:n
      {
        \providecommand \acro@used@once [4] {} ^^J
        \providecommand \acro@used@twice [4] {} ^^J
        \providecommand \acro@pages [2] {} ^^J
        \providecommand \acro@rerun@check {} ^^J
        \providecommand \acro@print@list {} ^^J
        \providecommand \acro@barriers [2] {}
      }
  }
\fi

% --------------------------------------------------------------------------
% #1: short|alt|long
% #2: string to be typeset
\cs_new_protected:Npn \__acro_typeset:nn #1#2
  {
    \mode_if_horizontal:F { \leavevmode }
    \group_begin:
      \use:x
        {
          \bool_if:cTF {l__acro_custom_#1_format_bool}
            { \exp_not:v {l__acro_custom_#1_format_tl} }
            { \exp_not:v {l__acro_#1_format_tl} }
            {#2}
        }
    \group_end:
  }

% typeset the short form:
% #1: ID
% #2: short form
\cs_new_protected:Npn \acro_write_short:nn #1#2
  {
    \__acro_typeset:nn {short}
      {
        \bool_if:nTF
          { \l__acro_first_upper_bool }
          { \exp_not:N \__acro_first_upper_case:n { \exp_not:n {#2} } }
          { \exp_not:n {#2} }
      }
  }
\cs_generate_variant:Nn \acro_write_short:nn { nV , nv }

% typeset the alternative form:
% #1: ID
% #2: alt form
\cs_new_protected:Npn \acro_write_alt:nn #1#2
  {
    \__acro_typeset:nn {alt}
      {
        \bool_if:nTF
          { \l__acro_first_upper_bool && \l__acro_upper_short_bool }
          { \exp_not:N \__acro_first_upper_case:n { \exp_not:n {#2} } }
          { \exp_not:n {#2} }
      }
  }
\cs_generate_variant:Nn \acro_write_alt:nn { nV , nv }

% typeset a long form:
%   TODO: rethink the formatting mechanism
%   right now a custom format gets applied additionally to the global one
%   although before it
% #1: format
% #2: long form
\cs_new_protected:Npn \acro_write_long:nn #1#2
  {
    \__acro_typeset:nn {long}
      {
        \exp_not:n {#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} }
        }
      }
  }
\cs_generate_variant:Nn \acro_write_long:nn { VV,Vo,Vf,V,v,vv }

\prg_new_conditional:Npnn \acro_if_foreign:n #1 {T,F,TF}
  {
    \bool_if:nTF
      {
        \l__acro_foreign_bool
        &&
        \prop_if_in_p:Nn \l__acro_foreign_prop {#1}
      }
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \acro_foreign_language:nn #1#2 {}
\AtBeginDocument{
  \cs_if_exist:NTF \foreignlanguage
    {
      \cs_set_protected:Npn \acro_foreign_language:nn #1#2
        {
          \tl_if_blank:nTF {#1}
            {#2}
            { \foreignlanguage {#1} {#2} }
        }
    }
    {
      \cs_set_protected:Npn \acro_foreign_language:nn #1#2
        { \use_ii:nn {#1} {#2} }
    }
}
\cs_generate_variant:Nn \acro_foreign_language:nn {VV}

\cs_new_protected:Npn \acro_write_foreign:n #1
  {
    \acro_if_foreign:nT {#1}
      {
        \prop_get:NnNT \l__acro_foreign_prop {#1} \l__acro_foreign_tl
          {
            \group_begin:
              \tl_use:N \l__acro_foreign_format_tl
              {
                \acro_foreign_language:VV
                  \l__acro_foreign_lang_tl
                  \l__acro_foreign_tl
              }
            \group_end:
          }
      }
  }

\cs_new:Npn \acroenparen #1 { ( #1 ) }

\cs_new_protected:Npn \acro_get_foreign:n #1
  {
    \prop_if_in:NnT \l__acro_foreign_prop {#1}
      {
        \tl_use:N \l__acro_foreign_sep_tl
        \prop_get:NnN \l__acro_foreign_prop {#1} \l__acro_foreign_tl
        \group_begin:
          \tl_use:N \l__acro_foreign_list_format_tl
          {
            \acro_foreign_language:VV
              \l__acro_foreign_lang_tl
              \l__acro_foreign_tl
          }
        \group_end:
      }
  }

% --------------------------------------------------------------------------
% #1: id
% #2: short|alt
\cs_set_protected:Npn \acro_write_compact:nn #1#2
  {
    \acro_get_ending_form:nn {#1} {#2}
    \acro_acc_supp:nn
      {#1}
      {
        \acro_write_tooltip:nnV
          {#1}
          {
            \use:c {acro_write_#2:nv} {#1} {l__acro_#2_tl}
            \acro_endings:nn {#1} {#2}
          }
          \l__acro_long_tl
      }
  }

% TODO: get rid of argument #3?
% #1: ID
% #2: long|first-long|list-long|extra
% #3: long form
\cs_new_protected:Npn \acro_write_expanded:nnn #1#2#3
  {
    \tl_set:Nn \l__acro_tmpa_tl {#2}
    \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
    \acro_write_long:vn {l__acro_ \l__acro_tmpa_tl _format_tl} {#3}
    \acro_endings:nn {#1} {long}
    \tl_if_in:nnT {#2} {long}
      { \l__acro_long_post_tl }
  }
\cs_generate_variant:Nn \acro_write_expanded:nnn { nnV }

% #1: ID
% #2: long|first-long|list-long|extra
\cs_new_protected:Npn \acro_write_expanded:nn #1#2
  {
    \tl_set:Nn \l__acro_tmpa_tl {#2}
    \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
    \acro_write_long:vv
      {l__acro_ \l__acro_tmpa_tl _format_tl}
      {l__acro_ \l__acro_tmpa_tl _tl}
    \acro_endings:nn {#1} {long}
    \tl_if_in:nnT {#2} {long}
      { \l__acro_long_post_tl }
  }

% #1: id
\cs_new_protected:Npn \acro_after:n #1
  {
    \acro_cite_if:nn { \l__acro_citation_all_bool } {#1}
    \acro_index_if:nn { \l__acro_addto_index_bool } {#1}
    \acro_get_property:nnT {#1} {post}
      { \tl_use:N \l__acro_post_tl }
  }

\cs_new_protected:Npn \acro_check_single:n #1
  {
    \acro_if_is_single:nT {#1}
      { \cs_set_eq:NN \acro_hyper_link:nn \use_ii:nn }
  }

% --------------------------------------------------------------------------
% #1: id
\cs_new_protected:Npn \acro_before:n #1
  {
    \acro_get:n {#1}
    \acro_is_used:n {#1}
    \acro_check_single:n {#1}
  }

% the standard internals:
% #1: id
\cs_new_protected:Npn \acro_short:n #1
  {
    \acro_before:n {#1}
    \acro_write_indefinite:nn {#1} {short}
    \acro_write_compact:nn {#1} {short}
    \acro_after:n {#1}
  }

% get alternative entry:
% #1: id
\cs_new_protected:Npn \acro_alt:n #1
  {
    \acro_before:n {#1}
    \acro_alt_error:n {#1}
    \acro_write_indefinite:nn {#1} {alt}
    \acro_write_compact:nn {#1} {alt}
    \acro_after:n {#1}
  }

% get long entry:
% #1: id
\cs_new_protected:Npn \acro_long:n #1
  {
    \acro_before:n {#1}
    \acro_write_indefinite:nn {#1} {long}
    \acro_write_expanded:nn {#1} {long}
    \acro_after:n {#1}
  }

% get foreign entry:
% #1: id
\cs_new_protected:Npn \acro_foreign:n #1
  {
    \acro_get:n {#1}
    \tl_if_blank:VF \l__acro_foreign_tl
      {
        \acro_is_used:n {#1}
        \acro_check_single:n {#1}
        \acro_write_long:VV \l__acro_foreign_format_tl \l__acro_foreign_tl
        \acro_after:n {#1}
      }
  }

% get extra entry:
% #1: id
\cs_new_protected:Npn \acro_extra:n #1
  {
    \acro_get:n {#1}
    \tl_if_blank:VF \l__acro_extra_tl
      {
        \acro_is_used:n {#1}
        \acro_check_single:n {#1}
        \acro_write_long:VV \l__acro_extra_format_tl \l__acro_extra_tl
        \acro_after:n {#1}
      }
  }

% output like the first time:
% #1: id
\cs_new_protected:Npn \acro_first:n #1
  {
    \bool_gset_true:c {g__acro_#1_first_use_bool}
    \acro_before:n {#1}
    \acro_first_instance:nV {#1} \l__acro_long_tl
  }

% output like the first time with own long version:
% #1: id
% #2: instead of long entry
\cs_new_protected:Npn \acro_first_like:nn #1#2
  {
    \bool_gset_true:c {g__acro_#1_first_use_bool}
    \acro_before:n {#1}
    \acro_first_instance:nn {#1} {#2}
  }

% ----------------------------------------------------------------------------
% citations:
\cs_new:Npn \__acro_citation_cmd:w { \cite } %{}
\cs_new:Npn \__acro_group_citation_cmd:w { \cite } %{}

% #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_protected:Npn \acro_cite:n #1
  {
    \prop_get:NnNT \l__acro_citation_prop {#1} \l__acro_tmpa_tl
      {
        \prop_get:NnN \l__acro_citation_pre_prop {#1} \l__acro_tmpb_tl
        \prop_get:NnN \l__acro_citation_post_prop {#1} \l__acro_tmpc_tl
        \acro_no_break:
        \tl_use:N \l__acro_citation_connect_tl
        \__acro_cite:VVV
          \l__acro_tmpb_tl
          \l__acro_tmpc_tl
          \l__acro_tmpa_tl
      }
  }

\cs_new_protected:Npn \acro_group_cite:n #1
  {
    \group_begin:
      \cs_set_eq:NN \__acro_citation_cmd:w \__acro_group_citation_cmd:w
      \tl_set_eq:NN
        \l__acro_citation_connect_tl
        \l__acro_between_group_connect_citation_tl
      \acro_cite_if:nn { \l__acro_citation_first_bool } {#1}
    \group_end:
  }

\cs_new_protected:Npn \acro_cite_if:nn #1#2
  { \bool_if:nT {#1} { \acro_cite:n {#2} } }

% ----------------------------------------------------------------------------
% indexing:
\cs_new_protected:Npn \acro_index_if:nn #1#2
  {
    \bool_if:nT { (#1) && \l__acro_mark_as_used_bool }
      {
        \prop_get:NnN \l__acro_index_cmd_prop  {#2} \l__acro_tmpa_tl
        \prop_get:NnN \l__acro_index_sort_prop {#2} \l__acro_tmpb_tl
        \prop_get:NnN \l__acro_index_prop      {#2} \l__acro_tmpc_tl
        \__acro_index:VnVV
          \l__acro_tmpa_tl
          {#2}
          \l__acro_tmpb_tl
          \l__acro_tmpc_tl
      }
  }

\cs_new:Npn \__acro_index_cmd:n { \index }

% #1: cmd
% #2: key
% #3: sort
% #4: replace
\cs_new_protected:Npn \__acro_index:nnnn #1#2#3#4
  {
    \prop_get:NnNF \l__acro_short_prop  {#2} \l__acro_index_short_tl {}
    \prop_get:NnNF \l__acro_format_prop {#2} \l__acro_index_format_tl {}
    \quark_if_no_value:VTF \l__acro_index_format_tl
      { \tl_set:Nn \l__acro_tmpa_tl { \l__acro_short_format_tl \l__acro_index_short_tl } }
      { \tl_set:Nn \l__acro_tmpa_tl { \l__acro_index_format_tl \l__acro_index_short_tl } }
    \quark_if_no_value:nF {#1}
      { \cs_set:Npn \__acro_index_cmd:n {#1} }
    \quark_if_no_value:nTF {#4}
      {
        \quark_if_no_value:nTF {#3}
          { \__acro_index_cmd:n { #2 @ { \l__acro_tmpa_tl } } }
          { \__acro_index_cmd:n { #3 @ { \l__acro_tmpa_tl } } }
      }
      { \__acro_index_cmd:n {#4} }
  }
\cs_generate_variant:Nn \__acro_index:nnnn { VnVV }

% ----------------------------------------------------------------------------
% accessability support
\cs_new_eq:NN \acro_acc_supp:nn \use_ii:nn

\cs_new_protected:Npn \acro_get_acc_supp:nn #1#2
  {
    \prop_get:NnNF \l__acro_acc_supp_prop {#1} \l__acro_acc_supp_tl
      { \prop_get:NnNF \l__acro_short_prop {#1} \l__acro_acc_supp_tl {} }
    \acro_for_endings_do:n
      {
        \bool_if:cT {l__acro_##1_bool}
          {
            \tl_put_right:Nv
              \l__acro_acc_supp_tl
              {l__acro_short_##1_tl}
          }
      }
    \acro_do_acc_supp:VVn
      \l__acro_acc_supp_tl
      \l__acro_acc_supp_options_tl
      {#2}
  }

\cs_new:Npn \acro_do_acc_supp:nnn #1#2#3
  {
    \BeginAccSupp { ActualText = #1 , #2 }
      #3
    \EndAccSupp { }
  }
\cs_generate_variant:Nn \acro_do_acc_supp:nnn { VV }

\AtEndPreamble
  {
    \bool_if:NT \l__acro_acc_supp_bool
      {
        \RequirePackage {accsupp}
        \cs_set_eq:NN \acro_acc_supp:nn \acro_get_acc_supp:nn
      }
    \bool_if:NT \l__acro_tooltip_bool
      {
        \RequirePackage {pdfcomment}
        \cs_if_eq:NNT \__acro_tooltip_cmd:nn \use_i:nn
          { \cs_set:Npn \__acro_tooltip_cmd:nn { \pdftooltip } }
      }
  }

% --------------------------------------------------------------------------
% tooltips for acronyms

% #1: id
% #2: printed text
% #3: tool tip text
\cs_new_protected:Npn \acro_write_tooltip:nnn #1#2#3
  {
    \prop_get:NnNTF \l__acro_tooltip_prop {#1} \l__acro_tmpa_tl
      { \__acro_check_tooltip:nV {#2} \l__acro_tmpa_tl }
      { \__acro_check_tooltip:nn {#2} {#3} }
  }
\cs_generate_variant:Nn \acro_write_tooltip:nnn { nnV }

% #1: printed text
% #2: tool tip text
\cs_new_protected:Npn \__acro_check_tooltip:nn #1#2
  {
    \bool_if:NTF \l__acro_inside_tooltip_bool
      {#1}
      {
        \bool_set_true:N \l__acro_inside_tooltip_bool
        \__acro_tooltip_cmd:nn {#1} {#2}
      }
  }
\cs_generate_variant:Nn \__acro_check_tooltip:nn { nV }

% use whatever command you like for creating tooltips here:
% #1: printed text
% #2: tool tip text
\cs_new_eq:NN \__acro_tooltip_cmd:nn \use_i:nn
  
% --------------------------------------------------------------------------
% indefinite articles:

% #1: ID
% #2: short|long|alt
\cs_new_protected:Npn \acro_write_indefinite:nn #1#2
  {
    \bool_if:NT \l__acro_indefinite_bool
      { \prop_item:cn { l__acro_#2_indefinite_prop } {#1} ~ }
    \bool_if:NT \l__acro_upper_indefinite_bool
      { %  \bool_set_true:N \l__acro_first_upper_bool
         \__acro_first_upper_case:x
           { \prop_item:cn { l__acro_#2_indefinite_prop } {#1} } ~
      }
  }

% --------------------------------------------------------------------------
% experimental sorting feature:

% the following code is an adaption of expl3 code used for \str_if_eq:NN(TF)
\sys_if_engine_luatex:TF
  {
    \tl_set:Nn \l__acro_tmpa_tl
      {
        acro ~ = ~ acro ~ or ~ { ~ } ~
        function ~ acro.strcmp ~ (A, B) ~
          if ~ A ~ == ~ B ~ then ~
            tex.write ("0") ~
          elseif ~ A ~ < ~ B ~ then ~
            tex.write ("-1") ~
          else ~
            tex.write ("1") ~
          end ~
        end
      }
    \lua_now:e { \l__acro_tmpa_tl }
    \cs_new_protected:Npn \acro_strcmp:nn #1#2
      {
        \lua_now:e
          {
            acro.strcmp
              (
                " \__acro_escape_x:n {#1} " ,
                " \__acro_escape_x:n {#2} "
              )
          }
      }
    \cs_new:Npn \__acro_escape_x:n #1
      {
        \lua_escape:e
          { \__kernel_tl_to_str:w \use:e { {#1} } }
      }
  }
  { \cs_new_eq:NN \acro_strcmp:nn \tex_strcmp:D }

\AtBeginDocument
  {
    \bool_if:NT \l__acro_sort_bool
      {
        \cs_new_protected:Npn \acro_sort_prop:NN #1#2
          {
            \seq_clear:N  \l__acro_tmpa_seq
            \prop_clear:N \l__acro_tmpa_prop
            \prop_clear:N \l__acro_tmpb_prop
            \prop_map_inline:Nn #2
              {
                \seq_put_right:Nn \l__acro_tmpa_seq {##2}
                \prop_put:Nnn \l__acro_tmpa_prop {##1} {##2}
              }
            \seq_sort:Nn \l__acro_tmpa_seq
              {
                \int_compare:nTF
                  {
                    \acro_strcmp:nn
                      { \str_fold_case:n {##1} }
                      { \str_fold_case:n {##2} }
                        = -1
                  }
                  { \sort_return_same: }
                  { \sort_return_swapped: }
              }
            \seq_map_inline:Nn \l__acro_tmpa_seq
              {
                \prop_map_inline:Nn \l__acro_tmpa_prop
                  {
                    \str_if_eq:nnT {##1} {####2}
                      {
                        \prop_get:NnN #1 {####1} \l__acro_tmpa_tl
                        \prop_put:NnV \l__acro_tmpb_prop {####1}
                          \l__acro_tmpa_tl
                      }
                  }
              }
            \prop_set_eq:NN #1 \l__acro_tmpb_prop
          }
      }
  }

% --------------------------------------------------------------------------
% regarding list printing:
% this command ensures that a rerun warning is given when \printacronyms
% is set the first time. This mechanism doesn't make very much sense,
% should be replaced by a different and more efficient one
%
\cs_new_protected:Npn \acro@print@list
  { \cs_if_exist:NF \acro@printed@list { \cs_new:Npn \acro@printed@list { printed } } }

% --------------------------------------------------------------------------
% trailing tokens and what to do when present
\prop_new:N \l__acro_trailing_tokens_prop
\prop_new:N \l__acro_trailing_actions_prop
\bool_new:N \l__acro_trailing_tokens_bool
\tl_new:N   \l__acro_trailing_tokens_tl

\cs_new_protected:Npn \acro_new_trailing_token:n #1
  { \bool_new:c {l__acro_trailing_#1_bool} }
\cs_new_protected:Npn \acro_activate_trailing_action:n #1
  { \bool_set_true:c {l__acro_trailing_#1_bool} }
\cs_new_protected:Npn \acro_deactivate_trailing_action:n #1
  { \bool_set_false:c {l__acro_trailing_#1_bool} }

% register a new token but don't activate its action:
% #1: token
% #2: name
\cs_new_protected:Npn \acro_register_trailing_token:Nn #1#2
  {
    \prop_put:Nnn \l__acro_trailing_tokens_prop {#2} {#1}
    \prop_put:Nnn \l__acro_trailing_actions_prop {#1}
      { \acro_activate_trailing_action:n {#2} }
    \acro_new_trailing_token:n {#2}
  }
  
\NewDocumentCommand \AcroRegisterTrailing {mm}
  { \acro_register_trailing_token:Nn #1 {#2} }

\cs_new_protected:Npn \acro_for_all_trailing_tokens_do:n #1
  { \prop_map_inline:Nn \l__acro_trailing_tokens_prop {#1} }

% activate a token:
\cs_new_protected:Npn \acro_activate_trailing_token:n #1
  {
    \prop_get:NnN \l__acro_trailing_tokens_prop {#1} \l__acro_tmpa_tl
    \tl_put_right:NV \l__acro_trailing_tokens_tl \l__acro_tmpa_tl
  }

% deactivate a token:
\cs_new_protected:Npn \acro_deactivate_trailing_token:n #1
  {
    \prop_get:NnN \l__acro_trailing_tokens_prop {#1} \l__acro_tmpa_tl
    \tl_remove_all:NV \l__acro_trailing_tokens_tl \l__acro_tmpa_tl
  }

% #1: name
\prg_new_conditional:Npnn \acro_if_trailing_token:n #1 {p,T,F,TF}
  {
    \bool_if:cTF {l__acro_trailing_#1_bool}
      { \prg_return_true: }
      { \prg_return_false: }
  }

% #1: csv list of names
\prg_new_protected_conditional:Npnn \acro_if_trailing_tokens:n #1 {T,F,TF}
  {
    \bool_set_false:N \l__acro_trailing_tokens_bool
    \clist_map_inline:nn {#1}
      {
        \bool_if:cT {l__acro_trailing_##1_bool}
          {
            \bool_set_true:N \l__acro_trailing_tokens_bool
            \clist_map_break:
          }
      }
    \bool_if:NTF \l__acro_trailing_tokens_bool
      { \prg_return_true: }
      { \prg_return_false: }
  }

\cs_new_protected:Npn \aciftrailing { \acro_if_trailing_tokens:nTF }

\cs_new_protected:Npn \__acro_check_trail:N #1
  {
    \tl_map_inline:Nn \l__acro_trailing_tokens_tl
      {
        \token_if_eq_meaning:NNT #1 ##1
          { \prop_item:Nn \l__acro_trailing_actions_prop {##1} }
      }
  }

% options for activating actions:
\keys_define:nn {acro}
  {
    activate-trailing-tokens   .code:n =
      \clist_map_inline:nn {#1} { \acro_activate_trailing_token:n {##1} } ,
    deactivate-trailing-tokens .code:n =
      \clist_map_inline:nn {#1} { \acro_deactivate_trailing_token:n {##1} }
  }

% some user macros:
\cs_new_protected:Npn \acro_dot:
  { \acro_if_trailing_tokens:nF {dot} {.\@} }

\cs_new_protected:Npn \acro_space:
  { \acro_if_trailing_tokens:nF {dash,babel-hyphen} { \c_space_tl } }

\NewDocumentCommand \acdot   {} { \acro_dot: }
\NewDocumentCommand \acspace {} { \acro_space: }
  
% ---------------------------------------------------------------------------
% reset outputs, they'll behave like the first time again (!not like the _only_
% time!):
\cs_new_protected:Npn \acro_reset:n #1
  {
    \bool_gset_false:c { g__acro_#1_used_bool }
    \bool_gset_false:c { g__acro_#1_first_use_bool }
  }

\cs_new_protected:Npn \acro_mark_as_used:n #1
  {
    \bool_gset_true:c { g__acro_#1_used_bool }
    \bool_gset_true:c { g__acro_#1_first_use_bool }
    \bool_gset_true:c { g__acro_#1_in_list_bool }
    \if@filesw
      \__acro_aux_file_now:n { \acro@used@once {#1} {} {} {} }
      \__acro_aux_file_now:n { \acro@used@twice {#1} {} {} {} }
    \fi
  }

\cs_new_protected:Npn \acro_reset_all:
  { \acro_for_all_acronyms_do:n { \acro_reset:n {##1} } }

% make sure that no acronym is used at the beginning of the document, see
% issue #81 for reasons why this may be necessary:
\AfterEndPreamble { \acro_reset_all: }
  
\cs_new_protected:Npn \acro_mark_all_as_used:
  { \acro_for_all_acronyms_do:n { \acro_mark_as_used:n {##1} } }

\DeclareExpandableDocumentCommand \acifused { m }
  { \acro_if_acronym_used:nTF {#1} }

\prg_new_conditional:Npnn \acro_if_acronym_used:n #1 { p,T,F,TF }
  {
    \bool_if:nTF
      {
        \bool_if_p:c { g__acro_#1_used_bool } &&
        ( !\acro_if_is_single_p:n {#1} )
      }
      { \prg_return_true: }
      { \prg_return_false: }
  }

\NewDocumentCommand \acresetall {}
  { \acro_reset_all: }

\NewDocumentCommand \acuseall {}
  { \acro_mark_all_as_used: }

\NewDocumentCommand \acreset { > { \SplitList { , } } m }
  { \ProcessList {#1} { \acro_reset:n } \ignorespaces }

\NewDocumentCommand \acuse { > { \SplitList { , } } m }
  { \ProcessList {#1} { \acro_mark_as_used:n } \ignorespaces }

% --------------------------------------------------------------------------
% acronym barriers: allow local lists of only those acronyms used between two
% barriers

\int_new:N  \g__acro_barrier_int
\bool_new:N \g__acro_use_barriers_bool
\bool_new:N \g__acro_reset_at_barrier_bool
\bool_new:N \l__acro_use_barrier_bool

\keys_define:nn {acro}
  {
    use-barriers      .bool_gset:N = \g__acro_use_barriers_bool ,
    use-barriers      .initial:n   = false ,
    reset-at-barriers .bool_gset:N = \g__acro_reset_at_barrier_bool ,
    reset-at-barriers .initial:n   = false
  }

\cs_new_protected:Npn \acro_barrier:
  {
    \int_gincr:N \g__acro_barrier_int
    \bool_if:NT \g__acro_reset_at_barrier_bool
      { \acro_reset_all: }
  }

\NewDocumentCommand \acbarrier {}
  { \acro_barrier: }

\cs_new_protected:Npn \acro_check_barriers:n #1
  {
    \bool_if:NT \g__acro_use_barriers_bool
      {
        \tl_set:Nx \l__acro_tmpa_tl
          { \seq_use:cn {g__acro_#1_barriers_seq} {} }
        \tl_set:Nx \l__acro_tmpb_tl
          { \seq_use:cn {g__acro_#1_recorded_barriers_seq} {} }
        \tl_if_eq:NNF \l__acro_tmpa_tl \l__acro_tmpb_tl
          {
            \@latex@warning@no@line
              {Rerun~to~get~barriers~of~acronym~#1~right}
          }
      }
  }

\cs_new_protected:Npn \acro_record_barrier:n #1
  {
    \bool_if:NT \g__acro_use_barriers_bool
      {
        \seq_if_in:cxF {g__acro_#1_barriers_seq}
          { \int_use:N \g__acro_barrier_int }
          {
            \seq_gput_right:cx  {g__acro_#1_barriers_seq}
              { \int_use:N \g__acro_barrier_int }
          }
      }
  }

% #1: id
% #2: barrier number
\prg_new_protected_conditional:Npnn \acro_if_in_barrier:nn #1#2 {T,F,TF}
  {
    \seq_if_in:cnTF {g__acro_#1_recorded_barriers_seq} {#2}
      { \prg_return_true: }
      { \prg_return_false: }
  }
\cs_generate_variant:Nn \acro_if_in_barrier:nnTF {nx}

\cs_new:Npn \acro@barriers #1#2
  { \seq_gset_split:cnn {g__acro_#1_recorded_barriers_seq} {,} {#2} }

% --------------------------------------------------------------------------
% the user commands -- preparation:
\cs_new_protected:Npn \acro_begin:
  {
    \group_begin:
    \__acro_check_after_end:w
  }

\cs_new_protected:Npn \__acro_check_after_end:w #1 \acro_end:
  {
    \cs_set:Npn \__acro_execute:
      {
        \__acro_check_trail:N \l_peek_token
        #1
        \acro_end: % this will end the group opened by \acro_begin:
      }
    \peek_after:Nw \__acro_execute:
  }

\cs_new_protected:Npn \acro_end: { \group_end: }

\cs_new_protected:Npn \acro_reset_specials:
  {
    \bool_set_false:N \l__acro_indefinite_bool
    \bool_set_false:N \l__acro_first_upper_bool
    \bool_set_false:N \l__acro_upper_indefinite_bool
    % \bool_set_false:N \l__acro_citation_all_bool
    % \bool_set_false:N \l__acro_citation_first_bool
    % \bool_set_false:N \l__acro_addto_index_bool
    \acro_for_endings_do:n { \bool_set_false:c {l__acro_##1_bool} }
  }

% #1: ID
% #2: true|false
\cs_new_protected:Npn \acro_check_acronym:nn #1#2
  {
    \acro_defined:n {#1}
    \acro_use_acronym:n {#2}
  }

% #1: boolean
% #2: ID
\cs_new_protected:Npn \acro_check_and_mark_if:nn #1#2
  {
    \bool_if:nTF
      { (#1) || !\l__acro_use_acronyms_bool }
      { \acro_check_acronym:nn {#2} {false} }
      { \acro_check_acronym:nn {#2} {true} }
  }

\cs_new_protected:Npn \acro_switch_off:
  { \bool_set_false:N \l__acro_use_acronyms_bool }

\cs_new_protected:Npn \acro_switch_on:
  { \bool_set_true:N \l__acro_use_acronyms_bool }

\NewDocumentCommand \acswitchoff {}
  { \acro_switch_off: }

\NewDocumentCommand \acswitchon {}
  { \acro_switch_on: }

% commands for (re)defining \ac-like macros:
\cs_new_protected:Npn \acro_define_new_acro_command:NN #1#2
  {
    % #1: csname
    % #2: definition where `#1' refers to the ID
    \cs_new_protected:Npn #1 ##1##2
      {
        \cs_set:Npn \__acro_tmp_command:n ####1 {##2}
        \exp_args:NNnx #2 ##1 {sO{}m}
          {
            \acro_begin:
              \acro_reset_specials:
              \keys_set:nn {acro} {########2}
              \acro_check_and_mark_if:nn {########1} {########3}
              \exp_not:o { \__acro_tmp_command:n {####3} }
            \acro_end:
          }
      }
  }
\cs_generate_variant:Nn \acro_define_new_acro_command:NN {cc}

% commands for (re)defining \acflike-like macros:
\cs_new_protected:Npn \acro_define_new_acro_pseudo_command:NN #1#2
  {
    % #1: csname
    % #2: definition where `#1' refers to the ID and `#2' to the pseudo long form
    \cs_new_protected:Npn #1 ##1##2
      {
        \cs_set:Npn \__acro_tmp_command:nn ####1####2 {##2}
        \exp_args:NNnx #2 ##1 {smm}
          {
            \acro_begin:
              \acro_reset_specials:
              \acro_check_and_mark_if:nn {########1} {########2}
              \exp_not:o { \__acro_tmp_command:nn {####2} {####3} }
            \acro_end:
          }
      }
  }
\cs_generate_variant:Nn \acro_define_new_acro_pseudo_command:NN {cc}

\clist_map_inline:nn {New,Renew,Declare,Provide}
  {
    \acro_define_new_acro_command:cc
      {#1AcroCommand}
      {#1DocumentCommand}
    \acro_define_new_acro_pseudo_command:cc
      {#1PseudoAcroCommand}
      {#1DocumentCommand}
  }

% --------------------------------------------------------------------------
% user commands -- facilities
\cs_new_protected:Npn \acro_first_upper:
  {
    \bool_if:NTF \l__acro_indefinite_bool
      {
        \bool_set_false:N \l__acro_indefinite_bool
        \bool_set_true:N \l__acro_upper_indefinite_bool
      }
      { \bool_set_true:N \l__acro_first_upper_bool }
  }

\cs_new_protected:Npn \acro_indefinite:
  {
    \bool_if:NTF \l__acro_first_upper_bool
      {
        \bool_set_true:N \l__acro_upper_indefinite_bool
        \bool_set_false:N \l__acro_first_upper_bool
      }
      { \bool_set_true:N \l__acro_indefinite_bool }
  }

\cs_new_protected:Npn \acro_cite:
  {
    \bool_set_true:N \l__acro_citation_all_bool
    \bool_set_true:N \l__acro_citation_first_bool
  }

\cs_new_protected:Npn \acro_no_cite:
  {
    \bool_set_false:N \l__acro_citation_all_bool
    \bool_set_false:N \l__acro_citation_first_bool
  }

\cs_new_protected:Npn \acro_index:
  { \bool_set_true:N \l__acro_addto_index_bool }

% similar macros \acro_<ending>: are defined by \acro_provide_ending:nnn

% ---------------------------------------------------------------------------
% process options:
\ProcessKeysPackageOptions {acro}

% ---------------------------------------------------------------------------
% PDF bookmark support
\cs_new:Npn \acpdfstring
  { \acro_pdf_string_short:n }

\cs_new:Npn \acpdfstringalt
  { \acro_pdf_string_alt:n }

\cs_new:Npn \acpdfstringlong
  { \acro_pdf_string_long:n }

\cs_new:Npn \acpdfstringfirst #1
  { \acpdfstringlong {#1} ~ ( \acpdfstring {#1} ) }

% TODO: place this somewhere where endings are defined:
\cs_new:Npn \acpdfstringlongplural
  { \acro_pdf_string_long_plural:n }

\prg_new_conditional:Npnn \acro_if_star_gobble:n #1 {TF}
  {
    \if_meaning:w *#1
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }

\cs_new:Npn \acro_expandable_long:n #1
  { \prop_item:Nn \l__acro_long_prop {#1} }

\cs_new:Npn \acro_expandable_long_plural:n #1
  {
    \bool_if:nTF
      { \prop_item:Nn \l__acro_long_plural_form_prop {#1} }
      { \prop_item:Nn \l__acro_long_plural_prop {#1} }
      {
        \prop_item:Nn \l__acro_long_prop {#1}
        \prop_item:Nn \l__acro_long_plural_prop {#1}
      }
  }

\cs_new:Npn \acro_pdf_string_long:n #1
  {
    \acro_if_star_gobble:nTF {#1}
      { \acro_expandable_long:n }
      { \acro_expandable_long:n {#1} }
  }

% TODO: place this somewhere where endings are defined:
\cs_new:Npn \acro_pdf_string_long_plural:n #1
  {
    \acro_if_star_gobble:nTF {#1}
      { \acro_expandable_long_plural:n }
      { \acro_expandable_long_plural:n {#1} }
  }
  
\cs_new:Npn \acro_pdf_string_short:n #1
  {
    \acro_if_star_gobble:nTF {#1}
      { \prop_item:Nn \l__acro_pdfstring_short_prop }
      { \prop_item:Nn \l__acro_pdfstring_short_prop {#1} }
  }
  
\cs_new:Npn \acro_pdf_string_alt:n #1
  {
    \acro_if_star_gobble:nTF {#1}
      { \prop_item:Nn \l__acro_pdfstring_alt_prop }
      { \prop_item:Nn \l__acro_pdfstring_alt_prop {#1} }
  }

\AtBeginDocument
  {
    \@ifpackageloaded {hyperref}
      {
        \bool_set_true:N \l__acro_hyperref_loaded_bool
        \pdfstringdefDisableCommands
          {
            \cs_set_eq:NN \ac   \acpdfstring
            \cs_set_eq:NN \Ac   \acpdfstring
            \cs_set_eq:NN \acs  \acpdfstring
            \cs_set_eq:NN \acl  \acpdfstringlong
            \cs_set_eq:NN \Acl  \acpdfstringlong
            \cs_set_eq:NN \acf  \acpdfstringfirst
            \cs_set_eq:NN \Acf  \acpdfstringfirst
            \cs_set_eq:NN \aca  \acpdfstringalt
            \cs_set_eq:NN \acp  \acpdfstringplural
            \cs_set_eq:NN \Acp  \acpdfstringplural
            \cs_set_eq:NN \acsp \acpdfstringplural
            \cs_set_eq:NN \aclp \acpdfstringlongplural
            \cs_set_eq:NN \Aclp \acpdfstringlongplural
            \cs_set_eq:NN \acfp \acpdfstringplural
            \cs_set_eq:NN \Acfp \acpdfstringplural
            \cs_set_eq:NN \acap \acpdfstringaltplural
          }
        \cs_set_protected:Npn \acro_hyper_page:n #1 { \hyperpage {#1} }
      } {}
  }

% --------------------------------------------------------------------------
% additional variables:
\tl_new:N \l__acro_current_property_tl

% --------------------------------------------------------------------------
% key and order checking
\msg_new:nnn {acro} {no-id}
  {
    Something~ has~ gone~ wrong,~ you've~ probably~ forgotten~ to~ set~ the~
    acronym~ ID.
  }

\msg_new:nnn {acro} {before-short}
  {
    You've~ set~ the~ property~ `#2'~ before~ the~ `short'~ property~ for~
    acronym~ `#1'~ but~ it~ needs~ to~ be~ set~ after~ it.
  }

\msg_new:nnn {acro} {missing}
  { The~ `#2'~ property~ for~ acronym~ `#1'~ is~ missing. }

\msg_new:nnn {acro} {doubled-property}
  {
    It~ seems~ to~ me~ you~ have~ used~ the~ `#2'~ property~ twice~ in~ the~
    declaration~ of~ acronym~ `#1'.~ If~ you~ haven't~ there's~
    something~ different~ wrong~ and~ I'm~ lost.~ You~'re~ on~ your~ own~
    then.
  }

% #1: acronym
% #2: property
\cs_new_protected:Npn \__acro_property_check:nn #1#2
  {
    \tl_if_blank:VT \l__acro_current_property_tl
      { \acro_serious_message:n {no-id} }
    \str_if_eq:nnF {#2} {short}
      {
        \bool_if:cF { l__acro_#1_short_set_bool }
          {
            \keys_set:nn { acro / declare-acronym } { short = {#1} }
            \acro_harmless_message:nn {substitute-short} {#1}
          }
      }
    % \bool_new:c { l__acro_#1_#2_set_bool }
    \bool_set_true:c { l__acro_#1_#2_set_bool }
  }

\cs_new_protected:Npn \__acro_first_property_check:nn #1#2
  {
    \cs_if_exist:cTF { l__acro_#1_short_set_bool }
      {
         \bool_if:cT { l__acro_#1_short_set_bool }
           { \acro_serious_message:nnn {doubled-property} {#1} {#2} }
      }
      {
        \bool_new:c { l__acro_#1_short_set_bool }
        \bool_set_true:c { l__acro_#1_short_set_bool }
      }
  }

% --------------------------------------------------------------------------
% the internal property selection functions for \DeclareAcronym:
\prop_new:N \g__acro_properties_prop

\cs_new_protected:Npn \acro_for_properties_do:n
  { \prop_map_inline:Nn \g__acro_properties_prop }

% #1: name in associated cs
% #2: property name
% #3: action
\cs_new_protected:Npn \acro_declare_property_generic:nnn #1#2#3
  {
    \prop_clear_new:c {l__acro_#1_prop}
    \cs_new_protected:cpn   {__acro_declare_#1:nn} ##1##2 {#3}
    \cs_generate_variant:cn {__acro_declare_#1:nn} {V}
    % \bool_new:c {l__acro_ \l__acro_current_property_tl _#1_set_bool}
    \keys_define:nn {acro/declare-acronym}
      {
        #2 .code:n =
          \use:c {__acro_declare_#1:Vn} \l__acro_current_property_tl {##1}
          \bool_set_true:c {l__acro_ \l__acro_current_property_tl _#2_set_bool}
      }
    \prop_gput:Nnn \g__acro_properties_prop {#2} {#1}
  }

% #1: name in associated cs
% #2: property name
% #3: action
\cs_new_protected:Npn \acro_declare_property:nnn #1#2#3
  {
    \acro_declare_property_generic:nnn {#1} {#2}
      {
        \__acro_property_check:nn {##1} {#2}
        \prop_put:cnn {l__acro_#1_prop} {##1} {##2}
        #3
      }
  }

% #1: name in associated cs
% #2: property name
\cs_new_protected:Npn \acro_declare_property:nn #1#2
  { \acro_declare_property:nnn {#1} {#2} {} }
\cs_generate_variant:Nn \acro_declare_property:nn { V }

\cs_new_protected:Npn \acro_declare_simple_property:n #1
  {
    \tl_set:Nn \l__acro_tmpa_tl {#1}
    \tl_replace_all:Nnn \l__acro_tmpa_tl {-} {_}
    \tl_clear_new:c  {l__acro_ \l__acro_tmpa_tl _tl}
    \acro_declare_property:Vn \l__acro_tmpa_tl {#1}
  }

% #1: new alias property
% #2: old property
\cs_new_protected:Npn \acro_declare_property_alias:nn #1#2
  {
    \keys_define:nn {acro/declare-acronym}
      { #1 .meta:n = { #2 = {##1} } }
  }

% --------------------------------------------------------------------------
% declare the properties for \DeclareAcronym:
% short:
\acro_declare_property_generic:nnn {short} {short}
  {
    \__acro_first_property_check:nn {#1} {short}
    \prop_put:Nnn \l__acro_short_prop      {#1} {#2}
    \prop_put:Nnn \l__acro_sort_prop       {#1} {#1}
    \prop_put:Nnn \l__acro_index_sort_prop {#1} {#1}
    \prop_put:Nnn \l__acro_alt_prop        {#1} {#2}
    \prop_put:Nnn \l__acro_pdfstring_short_prop {#1} {#2}
    \prop_put:Nnn \l__acro_pdfstring_alt_prop {#1} {#2}
    \acro_for_endings_do:n
      {
        \prop_put:cnv {l__acro_short_##1_prop}
          {#1} {l__acro_default_short_##1_tl}
        \prop_put:cnx {l__acro_pdfstring_short_##1_prop}
          {#1} { \exp_not:n {#2} \exp_not:v {l__acro_default_short_##1_tl} }
        \prop_put:cnn {l__acro_short_##1_form_prop} {#1} {false}
        \prop_put:cnv {l__acro_alt_##1_prop}
          {#1} {l__acro_default_alt_##1_tl}
        \prop_put:cnx {l__acro_pdfstring_alt_##1_prop}
          {#1} { \exp_not:n {#2} \exp_not:v {l__acro_default_short_##1_tl} }
        \prop_put:cnn {l__acro_alt_##1_form_prop} {#1} {false}
      }
    \prop_put:NnV \l__acro_short_indefinite_prop
      {#1} \l__acro_default_indefinite_tl
    \prop_put:NnV \l__acro_alt_indefinite_prop
      {#1} \l__acro_default_indefinite_tl
  }

% long:
\acro_declare_property:nnn {long} {long}
  {
    \prop_put:NnV \l__acro_long_indefinite_prop
      {#1}
      \l__acro_default_indefinite_tl
    \acro_for_endings_do:n
      {
        \prop_put:cnn {l__acro_long_##1_form_prop} {#1} {false}
        \bool_if:cF {l__acro_#1_long-##1_set_bool}
          { \prop_put:cnv {l__acro_long_##1_prop} {#1} {l__acro_default_long_##1_tl} }
        \prop_put:cnn {l__acro_foreign_##1_form_prop} {#1} {false}
        \bool_if:cF {l__acro_#1_foreign-##1_set_bool}
          { \prop_put:cnv {l__acro_foreign_##1_prop} {#1} {l__acro_default_foreign_##1_tl} }
      }
  }

\acro_declare_simple_property:n {first-style}

% list:
\acro_declare_simple_property:n {list}

% defines `short-plural', `long-plural' and `long-plural-form' as well as the
% options `plural-ending', `short-plural-ending' and `long-plural-ending':
% \ProvideAcroEnding {plural} {s} {s}

% short indefinite article:
\acro_declare_simple_property:n {short-indefinite}

% long indefinite article:
\acro_declare_simple_property:n {long-indefinite}

% pre long:
\acro_declare_simple_property:n {long-pre}

% post long:
\acro_declare_simple_property:n {long-post}

% post:
\acro_declare_simple_property:n {post}

% sort:
\acro_declare_property:nnn {sort} {sort}
  {
    \bool_if:cF { l__acro_#1_index-sort_set_bool }
      { \prop_put:Nnn \l__acro_index_sort_prop {#1} {#2} }
  }

% alternative:
\acro_declare_property:nnn {alt} {alt}
  {
    \prop_put:Nnn \l__acro_pdfstring_alt_prop {#1} {#2}
    \prop_put:NnV \l__acro_alt_indefinite_prop
      {#1} \l__acro_default_indefinite_tl
  }

\cs_set_protected:Npn \acro_alt_error:n #1
  {
    \bool_if:cF {l__acro_#1_alt_set_bool} 
      { \acro_harmless_message:nn {no-alternative} {#1} }
  }

% alt. indefinite article:
\acro_declare_simple_property:n {alt-indefinite}

% foreign:
\acro_declare_simple_property:n {foreign}

% foreign-lang:
\acro_declare_simple_property:n {foreign-lang}

% format:
\acro_declare_simple_property:n {format}

% short format:
\acro_declare_property_alias:nn {short-format} {format}

% alt format:
\acro_declare_simple_property:n {alt-format}

% long format:
\acro_declare_simple_property:n {long-format}

% first long format:
\acro_declare_simple_property:n {first-long-format}

% pdfstring -- currently needs to be done `by hand':
\prop_new:N \l__acro_pdfstring_short_prop
\cs_new_protected:Npn \__acro_declare_pdfstring:nw #1#2/#3/#4 \acro_stop:
  {
    \__acro_property_check:nn {#1} {pdfstring}
    \prop_put:Nnx \l__acro_pdfstring_short_prop {#1} {#2}
    \acro_for_endings_do:n
      {
        \tl_if_blank:nTF {#4}
          {
            \prop_put:cnx {l__acro_pdfstring_short_##1_prop}
              {#1} { \exp_not:n {#2} \exp_not:v {l__acro_default_short_##1_tl} }
          }
          {
            \prop_put:cnn {l__acro_pdfstring_short_##1_prop}
              {#1} {#2#3}
          }
      }
  }
\cs_generate_variant:Nn \__acro_declare_pdfstring:nw { V }
\keys_define:nn { acro / declare-acronym }
  {
    pdfstring    .code:n =
      \__acro_declare_pdfstring:Vw \l__acro_current_property_tl #1 // \acro_stop: ,
  }

\prop_new:N \l__acro_pdfstring_alt_prop
\cs_new_protected:Npn \__acro_declare_pdfstring_alt:nw #1#2/#3/#4 \acro_stop:
  {
    \__acro_property_check:nn {#1} { pdfstring-alt }
    \prop_put:Nnn \l__acro_pdfstring_alt_prop {#1} {#2}
    \acro_for_endings_do:n
      {
        \tl_if_empty:nTF {#3}
          {
            \prop_put:cnx {l__acro_pdfstring_alt_##1_prop}
              {#1} { \exp_not:n {#2} \exp_not:v {l__acro_default_alt_##1_tl} }
          }
          { \prop_put:cnn {l__acro_pdfstring_alt_##1_prop} {#1} {#2#3} }
      }
  }
\cs_generate_variant:Nn \__acro_declare_pdfstring_alt:nw { V }
\keys_define:nn { acro / declare-acronym }
  {
    pdfstring-alt .code:n =
      \__acro_declare_pdfstring_alt:Vw \l__acro_current_property_tl #1 // \acro_stop: ,
  }
  
% class:
\acro_declare_simple_property:n {class}

% extra information:
\acro_declare_simple_property:n {extra}

% single appearances:
\acro_declare_simple_property:n {single}

% single format:
\acro_declare_simple_property:n {single-format}

% acc supp:
\acro_declare_property:nn {acc_supp} {accsupp}

% tooltip:
\acro_declare_simple_property:n {tooltip}

% citation -- currently needs to be done `by hand':
\prop_new:N \l__acro_citation_prop
\prop_new:N \l__acro_citation_pre_prop
\prop_new:N \l__acro_citation_post_prop
\cs_new_protected:Npn \__acro_declare_citation:nw #1#2[#3]#4[#5]#6#7 \acro_stop:
  {
    % no options: #1: ID, #2: property, #3 is blank
    % 1 option:   #1: ID, #4: property, #3: option, #5 is blank
    % 2 options:  #1: ID: #6: property, #3: first option, #5: second option
    \tl_if_blank:nF { #2#4#6 }
      {
        \tl_if_empty:nTF {#3}
          { \__acro_declare_citation_aux:nnnn {#1} { } { } {#2} }
          {
            \tl_if_empty:nTF {#5}
              { \__acro_declare_citation_aux:nnnn {#1} {#3} {  } {#4} }
              { \__acro_declare_citation_aux:nnnn {#1} {#3} {#5} {#6} }
          }
      }
  }
\cs_generate_variant:Nn \__acro_declare_citation:nw { V }

\keys_define:nn { acro / declare-acronym }
  {
    cite .code:n =
      \__acro_declare_citation:Vw
        \l__acro_current_property_tl #1 [][] \scan_stop: \acro_stop:
  }

\cs_new_protected:Npn \__acro_declare_citation_aux:nnnn #1#2#3#4
  {
    \__acro_property_check:nn {#1} {cite}
    \prop_put:Nnn \l__acro_citation_prop {#1} {#4}
    \tl_if_empty:nF {#2}
      { \prop_put:Nnn \l__acro_citation_pre_prop {#1} {#2} }
    \tl_if_empty:nF {#3}
      { \prop_put:Nnn \l__acro_citation_post_prop {#1} {#3} }
  }

% TODO:
% add index entries, by default \index{<sort>@<short>}
% index: overwrite default <sort>@<short> entry completely
% index-sort: overwrite the <sort> part of <sort>@<short> entry

% need to take care of custom index cmd, at least
%  - \index{}
%  - \index[]{}
% question is, though, if it should be the same one for all acronyms?
% I go for yes but would also add a `post' property that allows to add arbitrary
% TeX code after an acronym is typeset

% index:
\acro_declare_simple_property:n {index}

% index-sort:
\acro_declare_simple_property:n {index-sort}

% index-cmd:
\acro_declare_simple_property:n {index-cmd}

% --------------------------------------------------------------------------
% acronym macros:
\cs_new_protected:Npn \__acro_define_acronym_macro:n #1
  {
    \bool_if:NT \l__acro_create_macros_bool
      {
        \cs_if_exist:cTF {#1}
          {
            \bool_if:NTF \l__acro_strict_bool
              { \cs_set:cpn {#1} { \ac {#1} \acro_xspace: } }
              { \acro_serious_message:nn {macro} {#1} }
          }
          { \cs_new:cpn {#1} { \ac {#1} \acro_xspace: } }
      }
  }

% --------------------------------------------------------------------------
% internal acronym declaring function:
\cs_new_protected:Npn \acro_declare_acronym:nn #1#2
  {
    \seq_gput_right:Nn \g__acro_declared_acronyms_seq {#1}
    \bool_gset_true:N \g__acro_first_acronym_declared_bool
    \tl_set:Nn \l__acro_current_property_tl {#1}
    \acro_for_properties_do:n
      { \bool_new:c {l__acro_#1_##1_set_bool} }
    \keys_set:nn { acro / declare-acronym } {#2}
    \bool_new:c {g__acro_#1_first_use_bool}
    \bool_new:c {g__acro_#1_used_bool}
    \bool_new:c {g__acro_#1_label_bool}
    \bool_new:c {g__acro_#1_in_list_bool}
    \seq_new:c  {g__acro_#1_barriers_seq}
    \seq_new:c  {g__acro_#1_recorded_barriers_seq}
    \bool_if:NF \l__acro_print_only_used_bool
      { \bool_gset_true:c {g__acro_#1_in_list_bool} }
    \__acro_create_page_records:n {#1}
    \__acro_define_acronym_macro:n {#1}
    \tl_clear:N \l__acro_current_property_tl
    \bool_if:cF {l__acro_#1_short_set_bool}
      { \acro_serious_message:nnn {missing} {#1} {short} }
    \bool_if:cF {l__acro_#1_long_set_bool}
      { \acro_serious_message:nnn {missing} {#1} {long} }
    \__acro_log_acronym:n {#1}
  }

% --------------------------------------------------------------------------
% the user command:
\NewDocumentCommand \DeclareAcronym {mm}
  { \acro_declare_acronym:nn {#1} {#2} }

% --------------------------------------------------------------------------
% print the list:
% #1: list of classes
% #2: list of excluded classes
\tl_new:N \l__acro_included_classes_tl
\tl_new:N \l__acro_excluded_classes_tl

\keys_define:nn { acro / print-acronyms }
  {
    include-classes   .tl_set:N   = \l__acro_included_classes_tl ,
    exclude-classes   .tl_set:N   = \l__acro_excluded_classes_tl ,
    name              .tl_set:N   = \l__acro_list_name_tl ,
    heading           .code:n     = \__acro_set_list_heading:n {#1} ,
    sort              .bool_set:N = \l__acro_sort_bool ,
    local-to-barriers .bool_set:N = \l__acro_use_barrier_bool
  }

\cs_new_protected:Npn \acro_print_acronyms:n #1
  {
    \group_begin:
      % this is a cheap trick to prevent the \@noitemerr
      % if one forgot to delete either the aux file or
      % remove \printacronyms -- but it's local:
      \cs_set:Npn \@noitemerr {}
      \tl_clear:N \l__acro_included_classes_tl
      \tl_clear:N \l__acro_excluded_classes_tl
      \keys_set:nn { acro / print-acronyms } {#1}
      \__acro_aux_file_now:n { \acro@print@list }
      \bool_if:NT \l__acro_sort_bool
        { \acro_sort_prop:NN \l__acro_short_prop \l__acro_sort_prop }
      \acro_title_instance:VV
        \l__acro_list_heading_cmd_tl
        \l__acro_list_name_tl
      \cs_if_exist:NTF \acro@printed@list
        {
          \acro_list_instance:VVV
            \l__acro_list_instance_tl
            \l__acro_included_classes_tl
            \l__acro_excluded_classes_tl
        }
        { \@latex@warning@no@line {Rerun~to~get~acronym~list~right} }
    \group_end:
  }

\NewDocumentCommand \printacronyms { O{} }
  { \acro_print_acronyms:n {#1} }

% --------------------------------------------------------------------------
% language support
\RequirePackage {translations}

\cs_new_protected:Npn \__acro_declare_translation:www #1 \q_mark #2=#3 \q_stop
  {
    \tl_set:Nx \l__acro_tmpa_tl { \tl_trim_spaces:n {#1} }
    \tl_set:Nx \l__acro_tmpb_tl { \tl_trim_spaces:n {#2} }
    \tl_if_in:nnT {#3} {=}
      {} % TODO: misplaced equal sign
    \tl_set:Nx \l__acro_tmpc_tl { \tl_trim_spaces:n {#3} }
    \__acro_declare_translation:VVV
      \l__acro_tmpb_tl
      \l__acro_tmpa_tl
      \l__acro_tmpc_tl
  }

% #1: key
% #2: lang
% #3: translation
\cs_new_protected:Npn \__acro_declare_translation:nnn #1#2#3
  { \DeclareTranslation {#1} {#2} {#3} }
\cs_generate_variant:Nn \__acro_declare_translation:nnn {VVV}

% #1: key
% #2: csv list: { <lang1> = <translation1> , <lang2> = <translation2> }
\cs_new_protected:Npn \acro_declare_translation:nn #1#2
  {
    \clist_map_inline:nn {#2}
      {
        \tl_if_blank:nF {##1}
          { \__acro_declare_translation:www #1 \q_mark ##1 \q_stop }
      }
  }

\NewDocumentCommand \DeclareAcroTranslation {mm}
  { \acro_declare_translation:nn {#1} {#2} }
\@onlypreamble \DeclareAcroTranslation

% tokenlists using the translations:
\tl_set:Nn \l__acro_list_name_tl  { \GetTranslation {acronym-list-name} }
\tl_set:Nn \l__acro_page_name_tl  { \GetTranslation {acronym-page-name}\@\, }
\tl_set:Nn \l__acro_pages_name_tl { \GetTranslation {acronym-pages-name}\@\, }
\tl_set:Nn \l__acro_next_page_tl  { \,\GetTranslation {acronym-next-page}\@ }
\tl_set:Nn \l__acro_next_pages_tl { \,\GetTranslation {acronym-next-pages}\@ }

% --------------------------------------------------------------------------
% definition file:
% \tl_const:Nn \c_acro_definition_file_name_tl      {acro}
% \tl_const:Nn \c_acro_definition_file_extension_tl {def}

% \file_if_exist:nTF
%   { \c_acro_definition_file_name_tl .\c_acro_definition_file_extension_tl }
%   {
%     \@onefilewithoptions
%       {\c_acro_definition_file_name_tl} [] []
%       \c_acro_definition_file_extension_tl
%   }
%   { \acro_serious_message:n {definitions-missing} }


% --------------------------------------------------------------------------
% first appearance styles:
\DeclareAcroFirstStyle {default} {inline}
  { }

\DeclareAcroFirstStyle {reversed} {inline}
  { reversed = true }

\DeclareAcroFirstStyle {short} {inline}
  {
    only-short = true ,
    brackets = false
  }

\DeclareAcroFirstStyle {long} {inline}
  {
    only-long = true ,
    brackets = false
  }

\DeclareAcroFirstStyle {square} {inline}
  { brackets-type = [] }

\DeclareAcroFirstStyle {plain} {inline}
  {
    brackets = false ,
    between = --
  }

\DeclareAcroFirstStyle {plain-reversed} {inline}
  { 
    brackets = false ,
    between = -- ,
    reversed = true
  }

\DeclareAcroFirstStyle {footnote} {note}
  { }

\DeclareAcroFirstStyle {footnote-reversed} {note}
  { reversed = true }

\DeclareAcroFirstStyle {sidenote} {note}
  { note-command = \sidenote {#1} }

\DeclareAcroFirstStyle {sidenote-reversed} {note}
  {
    note-command = \sidenote {#1} ,
    reversed     = true
  }

\DeclareAcroFirstStyle {empty} {note}
  { use-note = false }

% --------------------------------------------------------------------------
% extra info appearance styles:
\DeclareAcroExtraStyle {default} {inline}
  {
    brackets     = false ,
    punct        = true ,
    punct-symbol = .
  }

\DeclareAcroExtraStyle {plain} {inline}
  {
    brackets     = false ,
    punct        = true ,
    punct-symbol =
  }

\DeclareAcroExtraStyle {paren} {inline}
  {
    brackets     = true ,
    punct        = true ,
    punct-symbol =
  }

\DeclareAcroExtraStyle {bracket} {inline}
  {
    brackets      = true ,
    punct         = true ,
    punct-symbol  = ,
    brackets-type = []
  }

\DeclareAcroExtraStyle {comma} {inline}
  {
    punct         = true,
    punct-symbol  = {,} ,
    brackets      = false
  }

% --------------------------------------------------------------------------
% page number appearance styles:
\DeclareAcroPageStyle {default} {inline}
  {
    punct = true ,
    punct-symbol = .
  }
  
\DeclareAcroPageStyle {plain}   {inline}
  { punct = false }

\DeclareAcroPageStyle {comma}   {inline}
  { punct = true }

\DeclareAcroPageStyle {paren}   {inline}
  {
    brackets=true ,
    punct-symbol = ~
  }

\DeclareAcroPageStyle {none}    {inline}
  { display = false }

% --------------------------------------------------------------------------
% list heading styles:
\DeclareAcroListHeading {part}           {\part}
\DeclareAcroListHeading {part*}          {\part*}
\DeclareAcroListHeading {chapter}        {\chapter}
\DeclareAcroListHeading {chapter*}       {\chapter*}
\DeclareAcroListHeading {addchap}        {\addchap}
\DeclareAcroListHeading {section}        {\section}
\DeclareAcroListHeading {section*}       {\section*}
\DeclareAcroListHeading {addsec}         {\addsec}
\DeclareAcroListHeading {subsection}     {\subsection}
\DeclareAcroListHeading {subsection*}    {\subsection*}
\DeclareAcroListHeading {subsubsection}  {\subsubsection}
\DeclareAcroListHeading {subsubsection*} {\subsubsection*}
\DeclareAcroListHeading {none}           {\use_none:n}

% --------------------------------------------------------------------------
% list styles:
\DeclareAcroListStyle {description} {list}
  { }

\DeclareAcroListStyle {toc} {list-of}
  { }

\DeclareAcroListStyle {lof} {list-of}
  { style = lof }

\DeclareAcroListStyle {tabular} {table}
  { table = tabular }

\DeclareAcroListStyle {longtable} {table}
  { table = longtable }

\DeclareAcroListStyle {extra-tabular} {extra-table}
  { table = tabular }

\DeclareAcroListStyle {extra-longtable} {extra-table}
  { table = longtable }

\DeclareAcroListStyle {extra-tabular-rev} {extra-table}
  {
    table   = tabular ,
    reverse = true
  }

\DeclareAcroListStyle {extra-longtable-rev} {extra-table}
  {
    table   = longtable ,
    reverse = true
  }

% --------------------------------------------------------------------------
% register some tokens to be checked for:
\AcroRegisterTrailing . {dot}
\AcroRegisterTrailing - {dash}
\AcroRegisterTrailing \babelhyphen {babel-hyphen}

\keys_set:nn {acro} { activate-trailing-tokens = dot }

% --------------------------------------------------------------------------
% the user commands
% automatic:
\NewAcroCommand \ac
  { \acro_use:n {#1} }

\NewAcroCommand \Ac
  {
    \acro_first_upper:
    \acro_use:n {#1}
  }

\NewAcroCommand \iac
  {
    \acro_indefinite:
    \acro_use:n {#1}
  }

\NewAcroCommand \Iac
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_use:n {#1}
  }

\NewAcroCommand \acp
  {
    \acro_plural:
    \acro_use:n {#1}
  }

\NewAcroCommand \Acp
  {
    \acro_plural:
    \acro_first_upper:
    \acro_use:n {#1}
  }

\NewAcroCommand \acsingle
  {
    \acro_get:n {#1}
    \acro_single:n {#1}
  }

\NewAcroCommand \Acsingle
  {
    \acro_get:n {#1}
    \acro_first_upper:
    \acro_single:n {#1}
  }

% short:
\NewAcroCommand \acs
  { \acro_short:n {#1} }

\NewAcroCommand \Acs
  {
    \acro_first_upper:
    \acro_short:n {#1}
  }

\NewAcroCommand \iacs
  {
    \acro_indefinite:
    \acro_short:n {#1}
  }

\NewAcroCommand \Iacs
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_short:n {#1}
  }

\NewAcroCommand \acsp
  {
    \acro_plural:
    \acro_short:n {#1}
  }

\NewAcroCommand \Acsp
  {
    \acro_first_upper:
    \acro_plural:
    \acro_short:n {#1}
  }

% alt:
\NewAcroCommand \aca
  { \acro_alt:n {#1} }

\NewAcroCommand \Aca
  {
    \acro_first_upper:
    \acro_alt:n {#1}
  }
  
\NewAcroCommand \iaca
  {
    \acro_indefinite:
    \acro_alt:n {#1}
  }

\NewAcroCommand \Iaca
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_alt:n {#1}
  }

\NewAcroCommand \acap
  {
    \acro_plural:
    \acro_alt:n {#1}
  }

\NewAcroCommand \Acap
  {
    \acro_first_upper:
    \acro_plural:
    \acro_alt:n {#1}
  }

% long:
\NewAcroCommand \acl
  { \acro_long:n {#1} }

\NewAcroCommand \Acl
  {
    \acro_first_upper:
    \acro_long:n {#1}
  }

\NewAcroCommand \iacl
  {
    \acro_indefinite:
    \acro_long:n {#1}
  }

\NewAcroCommand \Iacl
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_long:n {#1}
  }

\NewAcroCommand \aclp
  {
    \acro_plural:
    \acro_long:n {#1}
  }

\NewAcroCommand \Aclp
  {
    \acro_plural:
    \acro_first_upper:
    \acro_long:n {#1}
  }

% first:
\NewAcroCommand \acf
  { \acro_first:n {#1} }

\NewAcroCommand \Acf
  {
    \acro_first_upper:
    \acro_first:n {#1}
  }

\NewAcroCommand \iacf
  {
    \acro_indefinite:
    \acro_first:n {#1}
  }

\NewAcroCommand \Iacf
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_first:n {#1}
  }

\NewAcroCommand \acfp
  {
    \acro_plural:
    \acro_first:n {#1}
  }

\NewAcroCommand \Acfp
  {
    \acro_plural:
    \acro_first_upper:
    \acro_first:n {#1}
  }

% first-like:
\NewPseudoAcroCommand \acflike
  { \acro_first_like:nn {#1} {#2} }

\NewPseudoAcroCommand \iacflike
  {
    \acro_indefinite:
    \acro_first_like:nn {#1} {#2}
  }

\NewPseudoAcroCommand \Iacflike
  {
    \acro_first_upper:
    \acro_indefinite:
    \acro_first_like:nn {#1} {#2}
  }

\NewPseudoAcroCommand \acfplike
  {
    \acro_plural:
    \acro_first_like:nn {#1} {#2}
  }

% --------------------------------------------------------------------------
% endings:
\ProvideAcroEnding {plural} {s} {s}

% --------------------------------------------------------------------------
% translations:
% list name
\DeclareAcroTranslation {acronym-list-name}
  {
    Fallback   = Acronyms ,
    English    = Acronyms ,
    French     = Acronymes ,
    German     = Abk\"urzungen ,
    Italian    = Acronimi ,
    Portuguese = Acr\'onimos ,
    Spanish    = Siglas ,
    Catalan    = Sigles ,
    Turkish    = K\i saltmalar
  }

% page name
\DeclareAcroTranslation {acronym-page-name}
  {
    Fallback   = p. ,
    English    = p. ,
    German     = S. ,
    Portuguese = p.
  }

% pages name
\DeclareAcroTranslation {acronym-pages-name}
  {
    Fallback   = pp. ,
    English    = pp. ,
    German     = S. ,
    Portuguese = pp.
  }

% following page
\DeclareAcroTranslation {acronym-next-page}
  {
    Fallback   = f. ,
    English    = f. ,
    German     = f. ,
    Portuguese = s.
  }

% following pages
\DeclareAcroTranslation {acronym-next-pages}
  {
    Fallback   = ff. ,
    English    = ff. ,
    German     = ff. ,
    Portuguese = ss.
  }

% --------------------------------------------------------------------------
% allow for a configuration file:
\tl_const:Nn \c_acro_config_file_name_tl      {acro}
\tl_const:Nn \c_acro_config_file_extension_tl {cfg}

\file_if_exist:nT
  { \c_acro_config_file_name_tl .\c_acro_config_file_extension_tl }
  {
    \@onefilewithoptions
      {\c_acro_config_file_name_tl} [] []
      \c_acro_config_file_extension_tl
  }

\file_input_stop:
