I'm trying to raise a \tikzmark
in order to align it with the top of the current line (for instance to draw a line something like that):
For now I use \raisebox{4mm}{\tikzmark{Hello0}}
, but I don't know how to do it without hardcoding the height of the line (the actual height could be smaller or larger depending on the letters/equations used in the line). Any idea how to do? (If you also know how to lower it to make sure it aligns with the depth I'd also be interested)
MWE:
\documentclass[a4paper,12pt]{memoir}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}
%\usepackage{showframe}
\usepackage{everypage}
\usepackage{changepage}
\usepackage{tikzpagenodes}
\usepackage{lipsum}
\begin{document}
\section{Space wanted (line should be added)}
\noindent Hello my dear.\\
\noindent Goood \rule[-5mm]{1cm}{15mm}
\section{Raising: how to choose the good value to ensure it aligns with top of the line?}
\noindent Hello my dear.
\noindent \raisebox{4mm}{\tikzmark{Hello0}}Goood \rule[-5mm]{1cm}{15mm}\tikzmark{Bye0}
\tikz[remember picture, overlay] \draw (pic cs:Hello0) -- ({pic cs:Bye0}-|{pic cs:Hello0});
\section{Using par: adds space between lines}
\noindent Hello my dear.
\noindent \tikzmark{Hello1}\par \noindent Goood \rule[-5mm]{1cm}{15mm}\tikzmark{Bye1}
\tikz[remember picture, overlay] \draw (pic cs:Hello1) -- ({pic cs:Bye1}-|{pic cs:Hello1});
\section{Baseline does not help}
\noindent Hello my dear.
\noindent \tikzmark{Hello4} Goood \rule[-5mm]{1cm}{15mm} \tikzmark{Bye4}
\tikz[remember picture, overlay] \draw ([yshift=\baselineskip]pic cs:Hello4) -- ({pic cs:Bye4}-|{pic cs:Hello4});
\end{document}
EDIT
To clarify, the proposed answer does not solve my problem, I really want the line to adapt to the content (and the edit also does not work in my case because I can't box my content as it may span multiple pages, see my question/answer here for more details). For instance I don't want this result:
but I'd like something like (of course without hardcoding the values).
I updated my MWE accordingly.
EDIT
I tried the \hrule height0pt
proposition: it's quite nice, but it shifts the tikz mark on the right, not sure why (to copy at the end of the previous MWE):
\section{Hrule: shift the bar on the right}
\noindent Hello my dear.
\noindent \hrule height0pt\tikzmark{Hello5}\hrule height0pt Goood \rule[-5mm]{1cm}{15mm} \hrule height0pt\tikzmark{Bye5}\hrule height0pt
\tikz[remember picture, overlay] \draw (pic cs:Hello5) -- ({pic cs:Bye5}-|{pic cs:Hello5});
EDIT
It seems that we got two solutions: one based on reseting \baselineskip
-like variables, and one using \hrule height0pt
. It turns out that both of these approaches are complementary. For instance, \hrule height0pt
gives the best result when I tried to insert a tikzmark right after a \qed
symbol, but this same approach gives very strange alignment sometimes (I tried to use strut, but then the alignments are much too big):
while \baselineskip
gives better results in that case:
The file I'm using (see the \addZeroWidthLine
function):
% https://tex.stackexchange.com/questions/532948/robustly-add-a-border-to-the-left-of-a-text-spanning-several-pages
\documentclass[a4paper,12pt]{memoir}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc,tikzmark}
\usepackage{lipsum}
%\usepackage{showframe}
\usepackage{everypage}
\usepackage{changepage}
\usepackage{environ}
\def\subproofsDefaultShift{5mm}
% Shift towards the center of the line
%\def\subproofsDefaultFirstPointYShift{.3em} %% Better results when using baselineskip
\def\subproofsDefaultFirstPointYShift{0em} %% Better results when using `\hrule height0pt`
\def\subproofsDefaultSecondPointYShift{0em}
\tikzset{
/subproofs/defaultStyle/.style={
black!30!white,
line width=.4pt,
transform canvas={xshift=-\subproofsDefaultShift/2-.5pt},
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Deal with drawings and marking.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Warning: tikz does not like ExplSyntax since it removes spaces
\def\addTikzmarkAndPagesInfo#1{%
\tikzmark{beginTikzmark#1}%
\tikz[remember picture, overlay] \coordinate (pageInfoNWOf#1) at (current page text area.north west);%
\tikz[remember picture, overlay] \coordinate (pageInfoSEOf#1) at (current page text area.south east);%
}
\def\drawLinesOfTikzmarkSamePage#1{%
\tikz[remember picture, overlay]%
\draw[/subproofs/defaultStyle] ([yshift=-\subproofsDefaultFirstPointYShift]pic cs:beginTikzmark#1) to ([yshift=\subproofsDefaultSecondPointYShift]{{pic cs:endTikzmark#1}-|{pic cs:beginTikzmark#1}});%
}
\def\drawLinesOfTikzmarkStart#1{%
\tikz[remember picture, overlay]%
\draw[/subproofs/defaultStyle] ([yshift=-\subproofsDefaultFirstPointYShift]pic cs:beginTikzmark#1) to ({pic cs:beginTikzmark#1}|-{current page text area.south west});%
}
\def\drawLinesOfTikzmarkMiddle#1{%
\tikz[remember picture,overlay] \draw[/subproofs/defaultStyle] %
let%
\p1=(pic cs:beginTikzmark#1),%
\p2=(pageInfoNWOf#1),%
\p3=(current page text area.north west),%
\p4=(current page text area.south east) in%
(\x1-\x2+\x3,\y3) to (\x1-\x2+\x3,\y4);%
}
\def\drawLinesOfTikzmarkEnd#1{%
\tikz[remember picture,overlay] \draw[/subproofs/defaultStyle] %
let%
\p1=(pic cs:beginTikzmark#1),%
\p2=(pageInfoNWOf#1),%
\p3=(current page text area.north west),%
\p4=(current page text area.south east),%
\p5=([yshift=\subproofsDefaultSecondPointYShift]pic cs:endTikzmark#1) in %
(\x1-\x2+\x3,\y3) to (\x1-\x2+\x3,\y5);%
}
\makeatletter
% \checkmarkpage{label}{if before}{if same page}{if after}
% Apply different codes if we are on a page before, the current page,
\newcommand{\checkmarkpage}[4]% #1 = tikzmark label, #2 = less, #3 = equal, #4 = greater
{\@ifundefined{save@pt@#1}{#2}{%
\edef\markid{\csname save@pt@#1\endcsname}%
\edef\markpage{\csname save@pg@\markid\endcsname}%
\ifnum\thepage<\markpage\relax #2%
\else
\ifnum\thepage=\markpage\relax #3%
\else #4%
\fi
\fi}%
}
\makeatother
%%% Starts expl3 syntax https://mirrors.concertpass.com/tex-archive/macros/latex/contrib/l3kernel/expl3.pdf
%%% For the list of modules and everything http://linorg.usp.br/CTAN/macros/latex/contrib/l3kernel/interface3.pdf
%%% (this also provides a quickstart at the beginning)
%%% For functions https://tex.stackexchange.com/questions/492794/how-to-define-two-expl3-functions-with-the-same-base-name-and-different-signatur
%%% This code is certainly not an example of LaTeX programming as it's the first time I use expl3...
\ExplSyntaxOn
% l=local, name, type. Note that this is only convention, it could be named "\foo" instead.
% clist are list separated by commas.
% To remove stuff https://tex.stackexchange.com/questions/5754/delete-an-element-from-a-comma-delimited-list
\seq_new:N\l_ListOfLinesToDraw_seq{}
\newcounter{nextMarkId}
% Inspired by https://tex.stackexchange.com/questions/528774/excess-vertical-space-in-vdots/528775#528775
% See also https://tex.stackexchange.com/questions/622881/align-element-tikzmark-with-top-of-the-current-line-instead-of-baseline/622936#622936
% TODO: Read also https://fr.overleaf.com/learn/latex/Articles/Boxes_and_Glue%3A_A_Brief%2C_but_Visual%2C_Introduction_Using_LuaTeX
\newlength{\oldbaselineskip}
\newlength{\oldlineskip}
\newlength{\oldlineskiplimit}
%%%% Uncomment to have the "baselinemode" (and comment next definition)
% \long\def\addZeroWidthLine#1{%
% \oldbaselineskip=\baselineskip%
% \oldlineskip=\lineskip%
% \oldlineskiplimit=\lineskiplimit%
% \baselineskip=0pt%
% \lineskip=0pt%
% \lineskiplimit=0pt%
% \noindent#1\par\nobreak%
% \baselineskip=\oldbaselineskip%
% \lineskip=\oldlineskip%
% \lineskiplimit=\oldlineskiplimit%
% }
%%%% Uncomment to have the "hrule" version:
\long\def\addZeroWidthLine#1{%
\hrule height0pt\noindent#1\hrule height0pt%
}
\NewEnviron{subproof}{%
\edef\thisMarkId{\thenextMarkId}% Temporary variable to use at the end.
\seq_gput_right:NV \l_ListOfLinesToDraw_seq \thisMarkId % Add it to the list
\begin{adjustwidth}{\subproofsDefaultShift}{0cm}%
\dealWithOneLine:V{\thisMarkId}% Draw the line for the current one.
\addZeroWidthLine{\addTikzmarkAndPagesInfo{\thenextMarkId}}%
\stepcounter{nextMarkId}%
% Ensures a group is inserted around the BODY
{ \noindent \BODY \par\nobreak}% nobreak is used to ensure the tikzmark is not pushed on a new page.
\addZeroWidthLine{\tikzmark{endTikzmark\thisMarkId}}\nopagebreak%
\end{adjustwidth}%
}%
\NewEnviron{linedproof}{%
\edef\thisMarkId{\thenextMarkId}% Temporary variable to use at the end.
\seq_gput_right:NV \l_ListOfLinesToDraw_seq \thisMarkId % Add it to the list
\begin{proof}\phantom{x}% Not sure why, using ~ does not work.
\begin{adjustwidth}{\subproofsDefaultShift}{0cm}%
\dealWithOneLine:V{\thisMarkId}% Draw the line for the current one.
\addZeroWidthLine{\addTikzmarkAndPagesInfo{\thenextMarkId}}%
\stepcounter{nextMarkId}%
% Ensures a group is inserted around the BODY
{ \noindent \BODY }% nobreak is used to ensure the tikzmark is not pushed on a new page.
% \hrule height0pt also "fake" a zero-width line.
\qedhere\hrule height0pt\tikzmark{endTikzmark\thisMarkId}\end{adjustwidth}%%
\end{proof}
}%
%% Create a new function (see http://linorg.usp.br/CTAN/macros/latex/contrib/l3kernel/interface3.pdf page 14)
\cs_new:Nn \dealWithOneLine:n{
\checkmarkpage{beginTikzmark#1}{%
%%%%%%%%%% We have not yet seen the beginTikzMark... Don't care.
}{ %%%%%%%%%% We are on the page of the start.
\checkmarkpage{endTikzmark#1}%
{%%%%%%%%%% The end is later
\drawLinesOfTikzmarkStart{#1}%
%\printList:N{} Size is \seq_count:N \l_ListOfLinesToDraw_seq%
}%
{%%%%%%%%%% The end is on the same page
\drawLinesOfTikzmarkSamePage{#1}%
%% We can remove the item from the list so that we don't process it anymore.
\seq_gremove_all:Nn \l_ListOfLinesToDraw_seq {#1}%
%\printList:N{} Size is \seq_count:N \l_ListOfLinesToDraw_seq%
}{% The end was on a previous page... impossible
}%
}{ %%%%%%%%%% The start point is on a previous page
\checkmarkpage{endTikzmark#1}%
{%%%%%%%%%% The end is later
\drawLinesOfTikzmarkMiddle{#1}%
%\printList:N{} Size is \seq_count:N \l_ListOfLinesToDraw_seq%
}%
{%%%%%%%%%% The end is on the same page
\drawLinesOfTikzmarkEnd{#1}%
%% We can remove the item from the list so that we don't process it anymore.
\seq_gremove_all:Nn \l_ListOfLinesToDraw_seq {#1}%
%\printList:N{} Size is \seq_count:N \l_ListOfLinesToDraw_seq%
}{%%%%%%%%%% The end has already been seen... I don't care
}%
}%
}
% defines \dealWithOneLine:V that expands its argument
\cs_generate_variant:Nn \dealWithOneLine:n { V }
%% Create a new function (see http://linorg.usp.br/CTAN/macros/latex/contrib/l3kernel/interface3.pdf page 14)
\cs_new:Nn \dealWithAllLines:N {
\seq_map_inline:Nn \l_ListOfLinesToDraw_seq {
\dealWithOneLine:n{##1}
}
}
%% Create a new function (see http://linorg.usp.br/CTAN/macros/latex/contrib/l3kernel/interface3.pdf page 14)
\cs_new:Nn \printList:N {
[
\seq_map_inline:Nn \l_ListOfLinesToDraw_seq {
##1,
}
]
}
\AddEverypageHook{\dealWithAllLines:N{}}
\ExplSyntaxOff
\begin{document}
\newpage
\thispagestyle{empty}
% \begin{subproof}
% ABC
% \end{subproof}
\begin{linedproof}~% Use '~' to ensure the subproof starts on a new line.
% See also https://tex.stackexchange.com/questions/122954/starting-a-proof-with-paragraph
% \begin{subproof}%
We prove now that $1+1+1 = 3$. First we will prove that $1+1+1=3$:
\begin{subproof}%
In order to prove that $1+1+1=3$, we first prove that $1+1=2$.
\begin{subproof}%
By definition $2 = 1+1$.
\end{subproof}%
But we can show that $1+1+1=2+1$.
\begin{subproof}%
Indeed, by associativity of the addition, we know that
\begin{align}
1+1+1=(1+1)+1\label{eq:abc}
\end{align}
But we saw above that $1+1=2$ so $1+1+1=2+1$
\end{subproof}%
It is now possible to see that $1+1+1=3$
\begin{subproof}%
We can use now Eq.~\ref{eq:abc} and the definition of $3$:
\[1+1+1=2+1=3\]
\end{subproof}%
As you can see, the spacing issues are now solved. See \texttt{\subproofsDefaultFirstPointYShift} to move more or less the first point on the y axis (to ensure it's not too close to the above line). It defaults to \texttt{0.3em}.
\begin{subproof}
Also the line adapts to height and depth \rule[-1cm]{2cm}{3cm}.
\end{subproof}%
\lipsum[1-5]
Bla bla bla bla blaBla bla bla bla blaBla bla bla bla blaBla bla bla bla blaBla bla bla bla blaBla bla bla biblobi blabla blabla Bla bla bla bla blaBla bla bla bla blaBla bla bla\qedhere
\end{subproof}%
% bla bla bla blaBla bla bla bla blaBla bla bla bla bla
% bla bla bla blaBla bla bla bla blaBla bla bla bla blabla bla bla blaBla
% Which concludes the proofWhich concludes the proofWhich concludes the proofWhich Which concludes the proof %Which concludes the proofWhich concludes the proofWhich concludes the proofWhich the proof.
\end{linedproof}
Hello
\begin{subproof}
Coucou
\end{subproof}
\end{document}
\tikzmark{<name>}
you need to reserve space for it. It is drawn asoverlay
, i.e. above its background.\tikzmarknode
which knows the dimensions of the node that gets created.yshift=\baselineskip
to reach the baseline of the line above, if this is what you want.