# Margin note automatic concatenation

I'm trying to use \marginpar to annotate the line where a piece of data occurs in the text. That means, I want them in the precise line where they are declared, there will frequently be more than one in the line, and I don't know in advance how many (may change when I modify the text or change the layout). The problem is that when more than one \marginpar is used, they are pushed down vertically. Ideally, I'd wish for concatenation (with whitespace and/or a comma inbetween). I looked if the marginnote and marginfix packages, but they don't do what I want (however, it's very possible that I didn't find the right configuration arguments). This feels like something that might have been solved before, but I couldn't find it, so please point me in the right direction.

I want this:

A pendulum of length $5\,\rm cm$\marginpar{$l$} and mass $10\,\rm g$\marginpar{$m$}
is displaced by $6^\circ$\marginpar{$\phi$} and released.
Calculate the momentum in the equilibrium position.


to produce "l, m" in the first line margin and "φ" in the second, if the linebreak occurs inbetween, but "l, m, φ" in the first line, if there is no linebreak (depending on the layout).

Don't pay attention to the rest of the markup, it's a stub to make the point.

• Welcome to TeX.SX! A comment on markup: \rm is deprecated. Use \textrm{cm} etc in appropiate mode. It would be nice to see more of your document, i.e a working document – user31729 Nov 5 '15 at 7:27
• First, please do not use {\rm ...}, but \mathrm{...} instead. Second, this seems to require a LuaTeX post_linebreak_filter, this TUGboat article seems to be interesting. – Henri Menke Nov 5 '15 at 7:27
• I'm using siunitx anyway. This is just a quick stub. – orion Nov 5 '15 at 10:45

Please always post compete documents not just fragments, your fragment if used at default article text width puts all three notes on the same line. So I had to experiment with widths to get the requested effect:

\documentclass{article}
\newcounter{xmarginpar}
\newlength\xmarginparshift
\setlength\textwidth{8cm}
\makeatletter
\def\xmarginpar#1{%
\stepcounter{xmarginpar}%
\strut\pdfsavepos
\protected@write\@auxout{}{%
\global\string\@namedef{pos@\thexmarginpar}{\thepage/\noexpand\the\pdflastypos}%
}%
% if defined
\expandafter\ifx\csname pos@\thexmarginpar\endcsname\relax\else
% if on same line as previous
\expandafter\ifx\csname pos@\thexmarginpar\expandafter\endcsname
\csname pos@\the\numexpr\thexmarginpar-1\relax\endcsname
\setbox0\hbox{\kern\xmarginparshift,#1}%
\else
\setbox0\hbox{\kern\textwidth\,#1}%
\fi
\global\xmarginparshift\wd\z@
\fi
\relax}

\begin{document}

A pendulum of length $5\,\mathrm{cm}$\xmarginpar{$l$} and
mass $10\,\mathrm{g}$\xmarginpar{$m$}
is displaced by $6^\circ$\xmarginpar{$\phi$} and released.
Calculate the momentum in the equilibrium position.

\end{document}

• Thank you for a nice solution. I'll post a full example next time, this was written on a phone, so I couldn't paste from the original. – orion Nov 5 '15 at 11:12

Based on Davids idea a made up a version using \marginpar which has the advantage that 1. the notes are alway on the right side of the text and that the settings for margin pars (\marginparsep and \marginparwidth) apply here too.

The main difference compared to David’s implementation is that I check if another note follows (David checks for preceding ones). And only if no other follows in this line (or at all, i.e. at end of the document) the previously collected noted get printed combined in one \marginpar.

\documentclass{scrbook}

\usepackage{geometry}
\geometry{paper=a5paper,textwidth=8cm,showframe}

\usepackage{xparse}

\ExplSyntaxOn\makeatletter

\cs_generate_variant:Nn \cs_if_eq:NNTF { ccTF }

% Variables
%% Counter for itentifiying mpars
\newcounter { combinedmpars }
%% Sequence for storing the mpars to be combined
\seq_new:N \g_tobi_mpars_seq

% User level macro to set the margin par
\NewDocumentCommand { \mpar } { m } {
% increment counter
\stepcounter { combinedmpars }
% save current absolute position on page
\strut \pdfsavepos
% write position of this note to aux file
\protected@write \@auxout { } {
\global \string \@namedef
{ tobi_mpar_pos_ \number \value { combinedmpars } }
{ \thepage / \noexpand\the\pdflastypos }
}
% append current ref to list of refs
\seq_gput_right:Nn \g_tobi_mpars_seq { #1 }
% check if a _next_ mpar position is defined
\cs_if_exist:cTF { tobi_mpar_pos_ \int_eval:n { \value { combinedmpars } + 1 } } {
% if TRUE
% check if it has the same position
\cs_if_eq:ccF
{ tobi_mpar_pos_ \number \value { combinedmpars } }
{ tobi_mpar_pos_ \int_eval:n { \value { combinedmpars } + 1 } }
{
% if FALSE
% ship out complete margin par
\tobi_print_mpars:
}
} {
% if FALSE
% ship out complete margin par
\tobi_print_mpars:
}
}

% internal macro to print all marginpars of a line
\cs_new:Nn \tobi_print_mpars: {
\marginline {
\seq_map_function:NN \g_tobi_mpars_seq \tobi_format_mpar:n
}
\seq_gclear:N \g_tobi_mpars_seq
}

% internal macro to format a marginpar (cross reference in my case)
\cs_new:Nn \tobi_format_mpar:n {
$\to$ ~ #1
}

\ExplSyntaxOff\makeatother

\begin{document}
odd page\clearpage

A pendulum of length $5\,\mathrm{cm}$\mpar{$l$} and
mass $10\,\mathrm{g}$\mpar{$m$}
is displaced by $6^\circ$\mpar{$\phi$} and released.
Calculate the momentum in the equilibrium position.

\clearpage
A pendulum of length $5\,\mathrm{cm}$\mpar{$l$} and
mass $10\,\mathrm{g}$\mpar{$m$}
is displaced by $6^\circ$\mpar{$\phi$} and released.
Calculate the momentum in the equilibrium position.

\end{document}


Edit/Fix (2017/06/29): The incrementation of \g_tobi_mpar_int must be done globally.

Edit/Fix (2017/06/30): Change from L3 int to L2 counter. This has the advantage that the counter value is stored in the aux file and the solution works with multiple \includes, where the L3 version would require an additional manual saving of the value at each chapter end. Since \stepcounter is always global, there is no need to take special care of \mpars in environment etc.