1

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

1

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

  • Thanks. this looks like a lot of heavy lifting for something simple, but the fact that it avoids tikz is a big one. Thank you for working it out. – Keivan Feb 7 '18 at 19:31
  • Ok. I got this to work on my document. It is very neat actually. I also added the counters to the text and to the notes so now I can see it like a footnote but in the margin, it makes it less confusing as what comment is for what highlight. Thanks again. – Keivan Feb 10 '18 at 23:51
2

Would the following link,

http://www.texample.net/tikz/examples/todo-notes/

be helpful?

Probably some more is needed than todo-notes. One should take into account http://www.texample.net/tikz/examples/global-nodes/

A modification of this, far from perfect, but of some comfort, is the following code, where now two macros for left and right margins are defined, holding as arguments the highlighted text in the body and the text of the remark:

      \documentclass{scrartcl}
      \usepackage{ccfonts}
      \renewcommand{\bfdefault}{sbc}
      \usepackage[T1]{fontenc}
      \usepackage[utf8]{inputenc}
      \usepackage{tikz}
      \usetikzlibrary{calc}
      \newcommand{\tikzrmargin}[2]{%
        \tikz[anchor=base, baseline]{\node [fill=blue!20] (rm) {#1};}
        \begin{tikzpicture}[overlay]
        \coordinate (rightbottom) at ($(rm)+(\paperwidth,0)$);
        \coordinate (se1) at (current page.south east);
        \coordinate (ne1) at (current page.north east);
        \coordinate (rightmargin) at (intersection of rm--rightbottom and se1--ne1);
        \node[left,align=flush right ,text width=2cm, fill=red!20] at (rightmargin)  {\color{gray!70}\footnotesize\bfseries{#2}};
        \end{tikzpicture}
      }
      \newcommand{\tikzlmargin}[2]{%
        \tikz[anchor=base, baseline]{\node [fill=blue!20] (lm) {#1};}
        \begin{tikzpicture}[overlay]
        \coordinate (leftbottom) at ($(lm)-(\paperwidth,0)$);
        \coordinate (sw1) at (current page.south west);
        \coordinate (nw1) at (current page.north west);
        \coordinate (leftmargin) at (intersection of lm--leftbottom and sw1--nw1);
        \node[right,align=flush left ,text width=2cm, fill=green!20] at (leftmargin)  {\color{gray!70}\footnotesize\bfseries{#2}};
        \end{tikzpicture}
      }
      \begin{document}
      \pagestyle{empty}
      \tikzstyle{every picture}+=[remember picture]

      \tikzrmargin{Remark in the right margin!}{This is the Remark.} bla bla bla bla bla gjqp bla bla bla bla blabla bla bla
      bla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla bla bla bla bla bla blabla bla bla bla bla blabla bla bla \tikzlmargin{Remark in the left margin!}{This is the Remark.}
      bla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla bla bla blabla bla bla bla bla blabla bla bla
      bla bla blabla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla bla bla blabla bla bla bla bla blabla bla bla
      bla bla blabla bla blabla bla \tikzrmargin{ 2nd remark in the right margin!}{This is the 2\textsuperscript{nd} remark}blabla bla blabla bla blabla bla blabla bla bla bla bla blabla bla bla bla bla blabla bla bla
      bla bla blabla bla blabla bla blabla bla blabla bla blabla bla bla

      This should be put inside a suitable macro! \tikzlmargin{On the left}{again!}



      \end{document}
  • This looks very cool. It seems like all the answers come down to tikz at some point. I might adopt this. Thanks for the workaround. Just one question, do you know if it's possible to make the numbering automatic? – Keivan Feb 5 '18 at 4:50
  • And, about the first link. I've been looking at the todonotes, but as far as I figured out it behaves the same as marginpar regarding which side it appears. – Keivan Feb 5 '18 at 4:52
  • @Keivan: Automatic numbering is obsolete now with the new version. Is this right? – Jens Schwaiger Feb 5 '18 at 10:56
  • Yup. That's right – Keivan Feb 6 '18 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.