[Tex/LaTex] How to correctly change the side that marginpar appears per case

marginpartodonotes

I'm trying to use marginpar and todonotes to make comments in a latex file as to ease the collaboration. The margins are just quick todo notes and fixes and I don't want to hardcode the position of every margin note since they'll be temporary. So, I'm trying to create small scripts in the preamble and use them as I go.

My problem is with long margin texts that multiples of them in one paragraph/page will either overlap or get too far away from the actual text. Naturally, I I thought I should be able to change the margin to appear on the left or right side of page per case that I have. That is, I want to be able to define to commands, let's say \lmargin and rmargin so that all the margin notes with \lmargin appear on one side and all the ones with \rmargin to appear on the other side. I don't really care about which one is on the left and which one is on the right, as long as they are on opposite sides. Or ideally, it would be great if latex could keep track of the margin notes and alternate between left and right automatically.

Searching through forums, the only solutions change the side of the margins for all the document. The closest solution I could find is to use \reversemarginpar. It works as long as the margin notes are in different paragraphs, but I don't want to break the paragraphs just for each note that I add to text.

Here is a MnonWE for the marginpar, the todonotes package is similar:

\documentclass[]{article}

\usepackage{pgf}
\usepackage[ %
            %top=Bcm, 
            %bottom=Hcm, 
            %outer=Ccm, 
            %inner=Acm, 
            %heightrounded, 
            marginparwidth=2.5cm, 
            %marginparsep=Ecm
            ]{geometry}
\usepackage{lipsum}
\usepackage{soul} % for highlighting the text: \hl
\usepackage{setspace} % for setting the linespace for a portion of the text: \setstretch

\definecolor{dkblue}{rgb}{0.0, 0.0, 0.6}
\definecolor{ltblue}{rgb}{0.6, 0.6, 1.0}

\usepackage{color}

\newcommand{\lmargin}[2]{\sethlcolor{ltblue}\hl{#1}\marginpar{\setstretch{0.5} {\color{dkblue} \tiny note: #2}}}


\begin{document}
And even there \lmargin{are}{there's something here that I need to pay attention to, and I need to be very clear about it, so I am going to write everything that comes to my mind here in the margin so that it doesn't take anyone 400 years to come up with the same thing!}  more things that can be said, but I am \reversemarginpar\lmargin{not sure}{Same thing here: there's something here that I need to pay attention to, and I need to be very clear about it, so I am going to write everything that comes to my mind here in the margin so that it doesn't take anyone 400 years to come up with the same thing!}  exactly what. \lipsum[7] 

Do you see the problem \reversemarginpar\lmargin{here}{And this is what I need}? If I don't go to a new paragraph, everything changes altogether! and overlaps even when I do!


\end{document}

And this is how it looks like:
enter image description here

Best Answer

While I was looking at my old paracol solution I started thinking I could do it better. In particular, I should be able to handle more than one note per paragraph.

The advantage of this solution is that it will never overlap and will break across pages. Because the notes are being written to the AUX file, I put most of the formatting into \marginparformat. Also, it takes two runs.

The main problem in implementing this is that you can only switch columns between paragraphs, which can be solved using \everypar. Even then, you need to know at the beginning of the paragraph what will be coming up later. The solution is to write the needed information to the AUX file. When you switch back to the original column, it immediately kicks off another \everypar which you have to ignore or get trapped in a loop.

It should be noted that \everypar tends not to be preserved. I rewrote \@afterheading, but there are bound to be others.

\documentclass{article}
\usepackage[ %
            %top=Bcm, 
            %bottom=Hcm, 
            %outer=Ccm, 
            %inner=Acm, 
            %heightrounded, 
            textwidth={\dimexpr 5in+5cm+2\columnsep},
            marginparwidth=0pt, 
            marginparsep=0pt
            ]{geometry}
\usepackage[nopar]{lipsum}
\usepackage{soul} % for highlighting the text: \hl
\usepackage{setspace} % for setting the linespace for a portion of the text: \setstretch

\usepackage{color}
\definecolor{dkblue}{rgb}{0.0, 0.0, 0.6}
\definecolor{ltblue}{rgb}{0.6, 0.6, 1.0}

\usepackage{paracol}
  \setcolumnwidth{2.5cm, 5in, 2.5cm}

\newcommand{\marginparformat}% only change between paragraphs
 {\tiny% affects em and ex
  \parindent=2em
  \parskip=1ex
  \sloppy
  \setstretch{0.5}%
  \color{dkblue}%
  \noindent note: }

\newcounter{absparagraph}
\newcounter{leftmarginpar}
\newcounter{rightmarginpar}
\globalcounter{absparagraph}
\globalcounter{leftmarginpar}
\globalcounter{rightmarginpar}


\makeatletter
\newcommand{\leftmarginpar}[1]% #1=text
{\stepcounter{leftmarginpar}%
 \pdfsavepos
 \protected@write\@auxout{}{\string\newleftmarginpar{\theleftmarginpar}{\theabsparagraph}%
   {\thepage}{\noexpand\number\pdflastypos}{#1}}}%

\newcommand{\rightmarginpar}[1]% #1=text
{\stepcounter{rightmarginpar}%
 \pdfsavepos
 \protected@write\@auxout{}{\string\newrightmarginpar{\therightmarginpar}{\theabsparagraph}%
   {\thepage}{\noexpand\number\pdflastypos}{#1}}}%

%begin gory details
\newcommand{\pagetop@y}{\dimexpr \paperheight-1in-\topmargin-\headheight-\headsep}
\newcommand{\current@page}{}% reserve global name

\newif\ifrepeatpar

\newlength{\leftmarginpar@y}
\newlength{\rightmarginpar@y}
\setlength{\leftmarginpar@y}{\pagetop@y}
\setlength{\rightmarginpar@y}{\pagetop@y}

\newcommand{\newleftmarginpar}[5]% #1 = index, #2 = paragraph, $3 = page, #4 = y location, #5 = text
{\expandafter\gdef\csname leftmarginpar@#2\endcsname{#1}%
 \expandafter\gdef\csname leftmarginpar@page@#1\endcsname{#3}%
 \expandafter\gdef\csname leftmarginpar@y@#1\endcsname{#4}%
 \expandafter\gdef\csname leftmarginpar@text@#1\endcsname{#5}}

\newcommand{\newrightmarginpar}[5]% #1 = index, #2 = page, #3 = y location, #4 = text
{\expandafter\gdef\csname rightmarginpar@#2\endcsname{#1}%
 \expandafter\gdef\csname rightmarginpar@page@#1\endcsname{#3}%
 \expandafter\gdef\csname rightmarginpar@y@#1\endcsname{#4}%
 \expandafter\gdef\csname rightmarginpar@text@#1\endcsname{#5}}

\newcommand{\AtBeginParagraph}{\everypar{}%
\ifrepeatpar\repeatparfalse\else
  \stepcounter{absparagraph}%
  \xdef\current@page{\arabic{page}}%
  \switchcolumn[0]
    \loop\ifnum\value{page}<\current@page\relax% sync pages
      \newpage
      \global\leftmarginpar@y=\pagetop@y\relax
    \repeat
    \@ifundefined{leftmarginpar@\theabsparagraph}{}{\bgroup
      \count1=\csname leftmarginpar@\theabsparagraph\endcsname\relax
      \count2=\value{leftmarginpar}%
      \loop\ifnum\count2<\count1
        \advance\count2 by 1
        \count3=\csname leftmarginpar@page@\number\count2\endcsname\relax% check page
        {\loop\ifnum\value{page}<\count3
          \newpage
          \global\leftmarginpar@y=\pagetop@y\relax
        \repeat}% sync page
        \dimen0=\csname leftmarginpar@y@\number\count2\endcsname sp\relax% compute offset
        \ifdim\dimen0<\leftmarginpar@y
          \dimen1=\dimexpr \leftmarginpar@y-\dimen0\relax
        \else
          \dimen1=\topskip
        \fi
        \setbox0=\vbox{\everypar{}%
          {\marginparformat
          \rule{0pt}{\dimen1}% I can't tell is fhis is adding space
          \csname leftmarginpar@text@\number\count2\endcsname
          \par}}%
        \global\advance\leftmarginpar@y by \dimexpr-\ht0-\dp0\relax
        \unvbox0%
      \repeat
    \egroup}%
  \switchcolumn[2]
    \loop\ifnum\value{page}<\current@page\relax% sync pages
      \newpage
      \global\rightmarginpar@y=\pagetop@y\relax
    \repeat
    \@ifundefined{rightmarginpar@\theabsparagraph}{}{\bgroup
      \count1=\csname rightmarginpar@\theabsparagraph\endcsname\relax
      \count2=\value{rightmarginpar}%
      \loop\ifnum\count2<\count1
        \advance\count2 by 1
        \count3=\csname rightmarginpar@page@\number\count2\endcsname\relax% check page
        {\loop\ifnum\value{page}<\count3
          \newpage
          \global\rightmarginpar@y=\pagetop@y\relax
        \repeat}% sync page
        \dimen0=\csname rightmarginpar@y@\number\count2\endcsname sp\relax% compute offset
        \ifdim\dimen0<\rightmarginpar@y
          \dimen1=\dimexpr \rightmarginpar@y-\dimen0\relax
        \else
          \dimen1=\topskip
        \fi
        \setbox0=\vbox{\everypar{}% write text
          {\marginparformat
          \rule{0pt}{\dimen1}%
          \csname rightmarginpar@text@\number\count2\endcsname
          \par}}%
        \global\advance\rightmarginpar@y by \dimexpr-\ht0-\dp0\relax
        \unvbox0%
      \repeat
    \egroup}%
  \switchcolumn[1]
  \everypar{\AtBeginParagraph}%
  \repeatpartrue
\fi}

\def\@afterheading{%
 \@nobreaktrue
 \everypar{%
   \if@nobreak
     \@nobreakfalse
     \clubpenalty \@M
     \if@afterindent \else
       {\setbox\z@\lastbox}%
     \fi
   \else
     \clubpenalty \@clubpenalty
   \everypar{\AtBeginParagraph}%
 \fi
 \AtBeginParagraph}}
\makeatother

\newcommand{\lmargin}[2]{\sethlcolor{ltblue}\hl{#1}\leftmarginpar{#2}}
\newcommand{\rmargin}[2]{\sethlcolor{ltblue}\hl{#1}\rightmarginpar{#2}}

\usepackage{blindtext}

\begin{document}
\begin{paracol}{3}
\switchcolumn[1]
  \everypar{\AtBeginParagraph}

And even there \lmargin{are}{there's something here that I need to pay attention to, and I need to be very clear about it, so I am going to write everything that comes to my mind here in the margin so that it doesn't take anyone 400 years to come up with the same thing!}  more things that can be said, but I am \rmargin{not sure}{Same thing here: there's something here that I need to pay attention to, and I need to be very clear about it, so I am going to write everything that comes to my mind here in the margin so that it doesn't take anyone 400 years to come up with the same thing!}  exactly what. \lipsum[7] 
\lmargin{test}{test}

Do you see the problem \rmargin{here}{And this is what I need}? If I don't go to a new paragraph, everything changes altogether! and overlaps even when I do!

\end{paracol}
\end{document}

demo

Related Question