cgnieder / acro

acronyms for LaTeX
LaTeX Project Public License v1.3c
42 stars 9 forks source link

Feature request: list of acronyms of which the short form has been printed #193

Closed bersbersbers closed 3 years ago

bersbersbers commented 3 years ago

I would like to be able to define a (different) inclusion criterion for \printacronyms:

Include all acronyms of which the short form has been used in the document.

In the following MWE, this would not include RAM (not used in its short form), but it would include TIFF.

\documentclass{article}
\usepackage{acro}
\acsetup{single}
\DeclareAcronym{ram}{short=RAM, long=random access memory}
\DeclareAcronym{tiff}{short=TIFF, long=tagged image file format}
\begin{document}
\verb|single| is great!

There's no need to explain \ac{ram} if it's used only once.

Also, many people know \acs{tiff}, so I don't want to explain it, either.

But some don't, so I'd like to include it in the \verb|\printacronyms|.

However, with the \verb|single| option, this does not happen:

\printacronyms[heading=none]

\end{document}

image

bersbersbers commented 3 years ago

Further looking at the manual, I believe what would be helpful while maintaining current behavior could be

  1. A new option single-in-list=_false_|true, which, if single=true, can be set to true to include singles in the list.
  2. Alternatively, macros \printallacronyms (or \allacronymsmapTF) and \acroifusedshortTF to build that functionality oneself.
cgnieder commented 3 years ago

While it may not be a solution in general in the case of your example a \acuse{tiff} would add it to the list.

bersbersbers commented 3 years ago

Interesting - I have just tried that. My idea was to write a wrapper around \DeclareAcronym that adds some code to the short form. When the short form is then used at least once, it defines a command for this short form that I can later check for existence. I would then \acuseall to be able to run \acronymsmap on all acronyms, and reset the ones which have not been used. And this works pretty well, except...

\documentclass{article} 
\usepackage{acro}
\acsetup{single}

\NewAcroTemplate[list]{short-only}{
    \acuseall
    \acronymsmap{
        \ifcsname acroshortused\AcronymID\endcsname
            keeping \AcronymID\newline
        \else
            removing \AcronymID\newline
            \acreset{\AcronymID}
        \fi
    }
    \acronymsmap{\acrowrite{short}\newline}
}

\newcommand{\newacro}[3]{
    \DeclareAcronym{#1}{long=#2, short=#3%
    \expandafter\gdef\csname acroshortused#1\endcsname{}}}

\newacro{ram}{random access memory}{RAM}
\newacro{tiff}{tagged image file format}{TIFF}

\begin{document}

\acs{tiff} and \acl{ram}

\section{List}
\printacronyms[template=short-only]
\end{document}

... that \acreset (and even \acresetall) do not seem to impact \printacronyms:

\documentclass{article} 
\usepackage{acro}
\DeclareAcronym{ram}{short=RAM, long=random access memory}
\begin{document}
\ac{ram}
\acresetall
\printacronyms
\end{document}

Is this intended?

bersbersbers commented 3 years ago

I feel kind of stupid - this is so much easier and more direct, and it works. It basically marks an acronym as used if it's short form is used, even if only once:

\documentclass{article} 
\usepackage{acro}
\acsetup{single}
\newcommand{\newacro}[3]{\DeclareAcronym{#1}{long=#2, short=#3\acuse{#1}}}

\newacro{ram}{random access memory}{RAM}
\newacro{tiff}{tagged image file format}{TIFF}

\begin{document}

\acs{tiff} and \ac{ram}

\printacronyms
\end{document}
bersbersbers commented 3 years ago

The approach above only has a single problem: if I compile this code first, where RAM is intended to be shown in the list, and then the one from the post above, RAM will not disappear from the list until I clean auxiliary files:

\documentclass{article} 
\usepackage{acro}
\acsetup{single}
\newcommand{\newacro}[3]{\DeclareAcronym{#1}{long=#2, short=#3\acuse{#1}}}

\newacro{ram}{random access memory}{RAM}
\newacro{tiff}{tagged image file format}{TIFF}

\begin{document}

\acs{tiff} and \ac{ram} and \ac{ram}

\printacronyms
\end{document}
cgnieder commented 3 years ago

I actually thought about this usage:

\documentclass{article}
\usepackage{acro}
\acsetup{single}
\DeclareAcronym{ram}{short=RAM, long=random access memory}
\DeclareAcronym{tiff}{short=TIFF, long=tagged image file format}
\begin{document}

There's no need to explain \ac{ram} if it's used only once.

Also, many people know \acs{tiff}, so I don't want to explain it, either.

\acuse{tiff}
\printacronyms[heading=none]

\end{document}
bersbersbers commented 3 years ago

Sure, that works. But I'll be required to maintain a list of things that are used in single short form. In my opinion, one of the strengths of acro is the possibility to have this decided automatically. And deleting aux files regularly is still a smaller price to pay than maintaining such a list ;)

bersbersbers commented 3 years ago

One more issue with this solution is that it interferes with first-style=short-long and single-style=short.

(The former is understandable: it gets marked as used after printing short, then omitting long. The latter I have more difficulties understanding, but it probably simply does not count as single use any more.)

Any chance I can delay \acuse using something like \protect?

\documentclass{article}
\usepackage{acro}
\DeclareAcronym{id1}{short=short\acuse{id1}, long=long}
\DeclareAcronym{id2}{short=short\acuse{id2}, long=long}
\begin{document}
Expected: short (long) and short

Actual: short and long (short)

\ac[first-style=short-long]{id1} and \ac[single=true, single-style=short]{id2}
\end{document}
bersbersbers commented 3 years ago

For the record: I believe this solution should solve both issues, the one with old aux files (https://github.com/cgnieder/acro/issues/193#issuecomment-742013824) and the one with impact on first-style and single-style=short starting with short (https://github.com/cgnieder/acro/issues/193#issuecomment-742551381).

This is blocked on #194, however.

\documentclass{article}
\usepackage{acro}
\acsetup{single, barriers/use=true, list/local=true}
\newcommand{\acshort}{}
\newcommand{\newacro}[4][]{
    \DeclareAcronym{#2}{#1, long={#4},
        short={#3}\global\edef\acshort{{#2},\acshort}}}
\newcommand{\printacshort}{%
    \acbarrier%
    \expandafter\acuse\expandafter{\acshort}%
    \printacronyms}

\newacro{ram}{RAM}{random access memory}
\newacro{tiff}{TIFF}{tagged image file format}
\newacro{id1}{short1}{long1}
\newacro{id2}{short2}{long2}

\begin{document}

\acs{tiff} and \ac{ram}

\ac[first-style=short-long]{id1} and \ac{id1} and \ac[single=true, single-style=short]{id2}

\printacshort

\end{document}
cgnieder commented 3 years ago

I never considered \acuse to work inside an acronym at all. Every command like \ac or \acs is calling the internal equivalent, anyway (except the starred variants). Apparently it does, though…

One more issue with this solution is that it interferes with first-style=short-long and single-style=short.

(The former is understandable: it gets marked as used after printing short, then omitting long. The latter I have more difficulties understanding, but it probably simply does not count as single use any more.)

Exactly: it is not used a single time anymore but twice. In the acr file you will find:

\ACRO{usage}{id1=={2}||id2=={2}}

This cannot be delayed: it is a global property that is true throughout the document.

For the record: I believe this solution should solves both issues, the one with old aux files (#193 (comment)) and the one with impact on first-style and single-style=short starting with short (#193 (comment)).

I don't think so. With issue #194 fixed the acr file contains

\ACRO{pages}{tiff=={0@1@1}||ram=={0@1@1}||id1=={0@1@1}||id2=={0@1@1}}
\ACRO{barriers}{ram=={1,0}||tiff=={1,1}||id1=={2,2}||id2=={1,1}}

and the list (correctly) only prints acronym id1 which has been used twice after the barrier.

IMHO what you need is a version of the option list/include that does not exclude other acronyms. I just added an option list/add which does this:

\documentclass{article}
\usepackage{acro}
\acsetup{
  single,
  barriers/use=true,
  list/local=true
}

\DeclareAcronym{ram}{
  short = RAM,
  long = random access memory
}
\DeclareAcronym{tiff}{
  short = TIFF,
  long = tagged image file format,
  tag = include
}
\DeclareAcronym{id1}{
  short = short1,
  long = long1
}
\DeclareAcronym{id2}{
  short = short2,
  long = long2
}

\begin{document}

\acs{tiff} and \ac{ram}

\ac{id1} and \ac{id1} and \ac{id2}

\printacronyms[add=include]

\end{document}

image

cgnieder commented 3 years ago

The option list/add has been added. I'll close this issue for now. You can reopen it if necessary.

bersbersbers commented 3 years ago

Great, thanks! Sorry for being so quiet, I'll test this in detail as soon as it's available via TeX Live (which it is not yet).

bersbersbers commented 3 years ago

For the record: I believe this solution should solves both issues, the one with old aux files (#193 (comment)) and the one with impact on first-style and single-style=short starting with short (#193 (comment)).

I don't think so. With issue #194 fixed the acr file contains

\ACRO{pages}{tiff=={0@1@1}||ram=={0@1@1}||id1=={0@1@1}||id2=={0@1@1}}
\ACRO{barriers}{ram=={1,0}||tiff=={1,1}||id1=={2,2}||id2=={1,1}}

and the list (correctly) only prints acronym id1 which has been used twice after the barrier.

You are right, I overlooked the impact of single=true after the barrier. But this is easy to fix, it turns out: I just use it twice after the barrier, using short={#3}\global\edef\acshort{{#2},{#2},\acshort}}. So that modified solution from https://github.com/cgnieder/acro/issues/193#issuecomment-742705273 looks like this, and it is working for me:

\documentclass{article}
\usepackage{acro}
\acsetup{single, barriers/use=true, list/local=true}
\newcommand{\acshort}{}
\newcommand{\newacro}[4][]{
    \DeclareAcronym{#2}{#1, long={#4},
        short={#3}\global\edef\acshort{{#2},{#2},\acshort}}}
\newcommand{\printacshort}{%
    \acbarrier%
    \expandafter\acuse\expandafter{\acshort}%
    \printacronyms}

\newacro{ram}{RAM}{random access memory}
\newacro{tiff}{TIFF}{tagged image file format}
\newacro{id1}{short1}{long1}
\newacro{id2}{short2}{long2}

\begin{document}

\acs{tiff} and \ac{ram}

\ac[first-style=short-long]{id1} and \ac{id1} and \ac[single=true, single-style=short]{id2}

\printacshort

\end{document}

This has all the shorts in the list of acronyms, and nothing else: image

I will also try list/add for completeness (in a separate comment).

bersbersbers commented 3 years ago

Alright, final comment for now :) The tag=include plus list/add=include is working, but again requires me to maintain a list of acronyms of which the short form has been used. My revised solution does not require that. Thanks a lot for your help nonetheless, your fixing #194 and pointing out the mistakes in the previous solution helped get me on the right track.

Last question: how do you enable syntax highlighting here? When quoting your posts, I do not see a different between my code and yours. (Ah, never mind. "```latex" works. GitHub just removes that when quoting --> https://github.com/dear-github/dear-github/issues/395)

cgnieder commented 3 years ago

As long as you have a working solution for yourself :)

I must confess I don't understand why still need your workaround, though.

\documentclass{article}
\usepackage{acro}

\acsetup{single}

\DeclareAcronym{ram}{
  short = RAM,
  long = random access memory
}
\DeclareAcronym{tiff}{
  short = TIFF,
  long = tagged image file format,
  first-style = short,
  single-style = short,
  tag = required
}
\DeclareAcronym{id1}{
  short = short1,
  long = long1
}
\DeclareAcronym{id2}{
  short = short2,
  long = long2
}

\begin{document}

\ac{tiff} and \ac{ram}

\ac{id1} and \ac{id2} and \ac{id1} and \ac{id2}

\printacronyms[add=required]

\end{document}

image

bersbersbers commented 3 years ago

I must confess I don't understand why still need your workaround, though.

Because your solution requires me to maintain the list of tag = required in all acronyms. Imagine I don't reference "TIFF" in the document any more, because I end up storing files as "JPEG":

\documentclass{article}
\usepackage{acro}

\acsetup{single}

\DeclareAcronym{ram}{
  short = RAM,
  long = random access memory
}
\DeclareAcronym{tiff}{
  short = TIFF,
  long = tagged image file format,
  first-style = short,
  single-style = short,
  tag = required
}
\DeclareAcronym{id1}{
  short = short1,
  long = long1
}
\DeclareAcronym{id2}{
  short = short2,
  long = long2
}

\begin{document}

% \ac{tiff} and \ac{ram}

\ac{id1} and \ac{id2} and \ac{id1} and \ac{id2}

\printacronyms[add=required]

\end{document}

"TIFF" will still appear in the list although it's never used - so I have to notice first, and then remove tag = required manually from "TIFF". My solution removes "TIFF" automatically (at least with clean aux files, I have not tested the aux-file "memory effect" yet).

cgnieder commented 3 years ago

Aha! You never mentioned that you were declaring acronyms that you were not using! This means what you actually need is a way to add acronyms to the list that are

Is that correct?

bersbersbers commented 3 years ago

Aha! You never mentioned that you were declaring acronyms that you were not using!

Correct - sorry! I think I see that as one (implicit) strength acro to handle all that (including unused and single-use acronyms) for me. It just happens with long documents, I suppose.

This means what you actually need is a way to add acronyms to the list that are

  • used at least once but
  • excluded from the list because of the single option

Almost - see the title of this issue. "Symptomatically", I want the reader to be able to find exactly those acronyms of which the short form has been printed, through whatever mechanism (unused - excluded; normal, including single use - included; single use with single=true - excluded; single use with single=true and single-style=*short* - included; etc.).

cgnieder commented 3 years ago

IMHO the solution should not depend on the symptom (short form) – remember that I don't (and can't) think from a single use case perspective:

Let x = “number of usages” and y = “single threshold”. (\acsetup{single=y}, where \acsetup{single=true} sets y=1 and \acsetup{single=false} sets y=0. Other values can be chosen.) Acronyms are added to the list if x > y.

Now, you have some acronyms for which you want them added to list when x > 0, independent from the value of y. (And for which you will only use the short form. But one could decide differently.)

Maybe there should be an possibility to release an acronym from the single threshold restriction. That wouldn't be too hard to implement. (Such an acronym never were single even if x =1). I'll open this issue again.

bersbersbers commented 3 years ago

IMHO the solution should not depend on the symptom (short form)

Well, that is my requirement. And the solution should very well depend on the requirement in my opinion :)

remember that I don't (and can't) think from a single use case perspective:

Of course not! That's why I opened this issue starting with "I would like to be able to" - I was not asking for a single-line solution: I was looking for the minimum amount of functionality that would allow me to do that on my own, in my own setting and my own set of set of constraints. Which you have enabled me to do, so I am happy.

Let x = “number of usages” and y = “single threshold”. (\acsetup{single=y}, where \acsetup{single=true} sets y=1 and \acsetup{single=false} sets y=0. Other values can be chosen.)

I was no aware of that. Now, since my document uses single=true, I do not not need do, either. So my solution may not generalizable to that case, true - but I don't need that.

Acronyms are added to the list if x > y.

Now, you have some acronyms for which you want them added to list when x > 0, independent from the value of y. (And for which you will only use the short form. But one could decide differently.)

Yes, I think this is one way to put it. Remember that "for which you will only use the short form" is implied by single=true and single-form=*short*, if it is used only < y times. It is not a consequence of me wanting to use only the short form. I do not want a macro included when I change my mind and use the long form exclusively for that macro.

Maybe there should be an possibility to release an acronym from the single threshold restriction. That wouldn't be too hard to implement. (Such an acronym never were single even if x =1). I'll open this issue again.

This might work, but this exception should then apply only to list inclusion. I really like the general in-text behavior as it is right now, and would not like that changed.

Again, to summarize, I think you are trying to generalize my very specific use case that is hard to generalize. My use case is "in an automated way, list all acronyms of which the short form has been used in the text", and I believe my solution achieves that in my setting. Of course, feel free to use that as motivation for further development, but I expect it to be hard to come up with a new functionality useful for many users and at the same time fulfilling my exact requirement.

Trying to generalize myself, I think the biggest lack in \acro (if you can call it that) that I had to hack in there was to obtain a list of acronyms of which the short form has been printed (\acshort in my solution). I think this would allow people to do a lot of interesting stuff if you simply exposed such macros (maybe with a more understandable name such as acros_used_in_short_form - same for long form etc.). And I would use that as well, because I could be sure it does what I need without changing behavior throughout the text. You would not even need to include them twice as I do in my hack to circumvent single=true behind the barrier - as soon as the user has that macro, they can \acuse them once, twice, ...

cgnieder commented 3 years ago

Obtaining such lists is not that hard, actually. It is only two lines added to \acroprintfield:

\RenewDocumentCommand \acroprintfield {mm}
  {
    \seq_if_exist:cF {g_acro_#2_seq} { \seq_new:c {g_acro_#2_seq} }% <<< new
    \seq_if_in:cxF {g_acro_#2_seq} {#1} { \seq_gput_right:cx {g_acro_#2_seq} {#1} }% <<< new
    \acro_property_if_eq:nnTF {#2} {list}
      {
        \bool_if:NT \l__acro_upper_list_bool { \acro_upper: }
        \acro_write:en {#1} {#2}
      }
      { \acro_write:en {#1} {#2} }
  }

Together with

\cs_generate_variant:Nn \acro_use:n {V}
\NewDocumentCommand \acuseshort {}
  {
    \clist_set_from_seq:NN \l_tmpa_clist \g_acro_short_seq
    \acro_use:V \l_tmpa_clist
  }

(and the whole code wrapped up between \ExplSyntaxOn and \ExplSyntaxOff in the preamble)

\acuseshort
\printacronyms

would meet your requirement:

\documentclass{article}

\usepackage{acro}
\acsetup{single}

\ExplSyntaxOn
\cs_generate_variant:Nn \acro_use:n {V}

\RenewDocumentCommand \acroprintfield {mm}
  {
    \seq_if_exist:cF {g_acro_#2_seq} { \seq_new:c {g_acro_#2_seq} }% <<< new
    \seq_if_in:cxF {g_acro_#2_seq} {#1} { \seq_gput_right:cx {g_acro_#2_seq} {#1} }% <<< new
    \acro_property_if_eq:nnTF {#2} {list}
      {
        \bool_if:NT \l__acro_upper_list_bool { \acro_upper: }
        \acro_write:en {#1} {#2}
      }
      { \acro_write:en {#1} {#2} }
  }

\NewDocumentCommand \acuseshort {}
  {
    \clist_set_from_seq:NN \l_tmpa_clist \g_acro_short_seq
    \acro_use:V \l_tmpa_clist
  }
\ExplSyntaxOff

\DeclareAcronym{ram}{
  short = RAM,
  long = random access memory
}
\DeclareAcronym{tiff}{
  short = TIFF,
  long = tagged image file format,
  first-style = short,
  single-style = short
}
\DeclareAcronym{id1}{
  short = short1,
  long = long1
}
\DeclareAcronym{id2}{
  short = short2,
  long = long2
}

\begin{document}

\ac{tiff} and \ac{ram}

\ac{id1} and \ac{id2} and \ac{id1} and \ac{id2}

\acuseshort
\printacronyms

\end{document}
bersbersbers commented 3 years ago

Interesting - I have zero experience with expl3 syntax, so it looks a bit like magic to me. But the result is close. I would probably add a barrier again, because \acuseshort influences the single appearance if you don't also override the first-style, which I usually don't do. Because this MWE prints "tagged image file format (TIFF)" although TIFF should be single use, so short:

\documentclass{article}

\usepackage{acro}
\acsetup{single}

\ExplSyntaxOn
\cs_generate_variant:Nn \acro_use:n {V}

\RenewDocumentCommand \acroprintfield {mm}
  {
    \seq_if_exist:cF {g_acro_#2_seq} { \seq_new:c {g_acro_#2_seq} }% <<< new
    \seq_if_in:cxF {g_acro_#2_seq} {#1} { \seq_gput_right:cx {g_acro_#2_seq} {#1} }% <<< new
    \acro_property_if_eq:nnTF {#2} {list}
      {
        \bool_if:NT \l__acro_upper_list_bool { \acro_upper: }
        \acro_write:en {#1} {#2}
      }
      { \acro_write:en {#1} {#2} }
  }

\NewDocumentCommand \acuseshort {}
  {
    \clist_set_from_seq:NN \l_tmpa_clist \g_acro_short_seq
    \acro_use:V \l_tmpa_clist
  }
\ExplSyntaxOff

\DeclareAcronym{ram}{
  short = RAM,
  long = random access memory
}
\DeclareAcronym{tiff}{
  short = TIFF,
  long = tagged image file format,
%  first-style = short, <<< only change
  single-style = short
}
\DeclareAcronym{id1}{
  short = short1,
  long = long1
}
\DeclareAcronym{id2}{
  short = short2,
  long = long2
}

\begin{document}

\ac{tiff} and \ac{ram}

\ac{id1} and \ac{id2} and \ac{id1} and \ac{id2}

\acuseshort
\printacronyms

\end{document}

But that seems easy enough to fix.

For more future-proofness, I'd probably also convert the \RenewDocumentCommand into some \PreToCmd patch to not duplicate code unnecessarily.

cgnieder commented 3 years ago

I probably misunderstood you again but I thought tiff was an example for acronyms that always only should show the short form in running text. If that is the case then of course you need first-style=short (unless you definitely know you are going to use it only once…). If I were you I'd define

\newcommand\DeclareKnownAcronym[2]{%
  \DeclareAcronym{#2}{%
    #2,
    first-style = short,
    single-style = short
  }%
}

for those acronyms that you only want short…

and maybe

\newcommand\printacronymlist[1][]{\acuseshort\printacronyms[#1]}
bersbersbers commented 3 years ago

Hi again, so for people like me, unaware of the benefits of expl3, the solution you proposed translates into this pure (La)TeX code:

\let\oldacroprintfield\acroprintfield
\renewcommand{\acroprintfield}[2]{%
    \ifnum\pdfstrcmp{#2}{short}=0%
        \global\edef\acprintedshort{{#1}%
            \ifcsname acprintedshort\endcsname,\acprintedshort\fi}%
    \fi%
    \oldacroprintfield{#1}{#2}}
\newcommand{\acuseshort}{%
    \providecommand{\acprintedshort}{}
    \expandafter\acuse\expandafter{\acprintedshort}}

So this is very usable for me, and probably better than hacking the short representation. Thanks for pointing out \acroprintfield to me!

bersbersbers commented 3 years ago

I probably misunderstood you again but I thought tiff was an example for acronyms that always only should show the short form in running text. If that is the case then of course you need first-style=short ...

Well, I use several first-styles, including short, but also short-long for example. It's hard to predict what I will want to see for each single acronym. I feel the barrier is great now that it's working, and I see no issues with prepending things to \acroprintfield (rather than hacking the short representation itself). My main thing remains that I want to see the printed short representations in the list, and I am able to get that. So again, thanks to your endless help, I have a very-well-working solution now.

bersbersbers commented 3 years ago

For the record, I further wrapped the \ifnum...\fi part into an \acroifstarredF{...} to prevent recording a short form from a starred call.