# Combining content of marginnotes

I use marginnotes (sometimes inside of mdframed environments) to write at the margin whenever a concept is defined, e.g.:

\documentclass{article}
\usepackage{marginnote,tikz,mdframed}
\usepackage{amsthm}

\newmdtheoremenv[linecolor=black]{definition}{Definition}

\newcommand{\defi}[1]{%
\marginnote{\tiny #1}%
\emph{#1}}

\begin{document}

\begin{definition}
An \defi{apple} is a fruit, a \defi{mirror} is an object
and a \defi{fish} is an animal.
\end{definition}
\end{document}


Alas, I have a problem when two or more things are defined in the same line---in the example, "apple", "mirror" and "fish" overlap in the margin.

I am aware that this is a feature, but wonder whether it would be possible to combine the contents of both calls to marginnote.

(Replacing marginnote by marginpar gives me "Float(s) lost.")

Ideally, in the margin I would read "apple, mirror, fish"

I wonder if it is possible to change marginnote so that

• when a \marginnote is reached, its argument is appended to some list (of tokens?) ... ideally, adding some separator such as ,);
• when the marginnote is typeset, it resets this list of tokens to nothing

I am also aware of the advanced sidenotes features of memoir, but I have to stick with article.

As a last resort, if this is not possible, I am considering the following:

• every time \defi is called it appends to a comma-separated list of definitions;
• using something like everypage to then call a tikzpicture to overlay the list on the margin of the document and reset the list contents

Edit: @TeXnician pointed out a similar question at Margin note automatic concatenation, however David's answer there has the side effect of adding the notes inside the mdframed box. (And I did not manage to run Tobi's answer, but I'm guessing I might run into the same Float(s) lost problem.)

You could try something like this. It only checks if the definitions (their begin) are on the same line and the same page.

\documentclass{article}
\usepackage{marginnote}
\usepackage{zref-savepos,zref-abspage}
\usepackage{expl3}

\ExplSyntaxOn\makeatletter
\int_new:N \g_tassio_note_int
\seq_new:N\g_tassio_note_seq

\newcommand{\defi}[1]{%
\int_gincr:N \g_tassio_note_int
\bool_if:nTF
{
\int_compare_p:n
{
\zposy{tassionotepos\int_eval:n{\g_tassio_note_int}}
=
\zposy{tassionotepos\int_eval:n{\g_tassio_note_int +1}}
}
&&
\int_compare_p:n
{
\zref@extractdefault { tassionotepage\int_eval:n{\g_tassio_note_int } }{abspage}{-1}
=
\zref@extractdefault { tassionotepage\int_eval:n{\g_tassio_note_int +1} }{abspage}{-1}
}
}
{
\seq_gput_left:Nn \g_tassio_note_seq {#1}
}
{
\seq_gput_left:Nn \g_tassio_note_seq {#1}
\marginnote{\tiny \seq_use:Nn \g_tassio_note_seq {,~}}%
\seq_gclear:N \g_tassio_note_seq
}
\zref@label {tassionotepage\int_use:N\g_tassio_note_int}\zsaveposy {tassionotepos\int_use:N\g_tassio_note_int}
\emph{#1}}

\ExplSyntaxOff\makeatother

\begin{document}
An \defi{apple} is a fruit, a \defi{mirror} is an object
and a \defi{fish} is an animal.
\\ \defi{duck}

\newpage \defi{snowmann}

\end{document}


• Nice solution :) yet I keep wondering if the expl3 syntax is designed specifically to scare away uninitiated programmers... – Marijn Jun 12 '18 at 14:06
• Nice! How can I shift it down to avoid collisions with previous (long, multi-line) notes? – Tássio Jun 12 '18 at 17:41
• You could add other \zsaveposy-labels in the marginnotes (e.g. at the begin and the end), and use their position to decide about shifts. – Ulrike Fischer Jun 12 '18 at 18:37
• Thank you very much! This is great to begin learning expl3. While I incorporate \zsaveposy, I'll use a hack: put the contents of the marginnote in a parbox and use \setstretch from (setspace package) to mitigate collisions, since the marginnotes rarely reach 3 lines. – Tássio Jun 13 '18 at 9:22