10

Is it possible to define an environment that strikes out all text, even in enumerated lists?

I am basically trying automate what is currently being done manually in Microsoft Word. I have a body of text and I'm told which parts are new, which parts are unchanged, and which parts have been removed since the last update.

Newly added text has to appear in bold (which is straightforward enough), but anything that has been removed needs to appear struck out. The soul and ulem packages get me partly there, and although they can strike out entire paragraphs, they fail when given more than one paragraph at once. I also cannot do e.g. \sout{\begin{enumerate}\item asdf\end{enumerate}}, and if I just wrap each \item in with \sout, then the actual item number still appears unstruckout.

The type of text that I am trying to strike out is pretty much limited to ordinary paragraphic text and nested enumerated lists (i.e. no maths, no graphics, no figures, no headings, etc.) and will likely never be longer around half a page for each new/deleted region.

I'm not looking for anything precise or pretty, e.g. if the strikeout spans the entire width of the page just to strike out one word, that is fine. I'm also open to suggestions about alternative ways to typeset deleted text.

What I have so far is borrowed from @Werner's answer here, and I can place a horizontal rule through each line of a paragraph, but it borks enumerated lists.

\documentclass[a4paper]{article}

\usepackage{lipsum}

\newbox\strikeoutlinebox

% sorry for the messy boxes ... is there a cleaner way?
\def\strikeoutline{%
  \vbox to 0pt{%
    \vskip -4pt%
    \hbox to 0pt{%
      \vbox{\hsize\wd\strikeoutlinebox\hrule width \hsize}%
      \hskip 0pt minus 1fil%
    }%
    \vskip 0pt plus 1fil%
  }%
  \box\strikeoutlinebox
}

\def\fullstrikeout{%
  \setbox\strikeoutlinebox\lastbox
  \ifvoid\strikeoutlinebox
    \noindent\ignorespaces
  \else
    \unskip\unpenalty
    \begingroup\fullstrikeout\space\endgroup
    \strikeoutline
  \fi
}

% is this bad? it's probably bad ...
\newenvironment{strikethrough}{%
  \begingroup
    \let\oldpar=\par
    \def\par{\oldpar\fullstrikeout}%
    \vbox\bgroup
}{%
    \par\egroup
    \let\par=\oldpar
  \endgroup
}

\begin{document}

\begin{strikethrough}
\lipsum[0-3]
\end{strikethrough}

\end{document}

The above is a WIP but as you can probably tell I really have little clue what I'm doing.

  • Three suggestions: 1. don't copy Word. 2. use a "strikeout font". 3. \usepackage{xcolor} \newcommand\sout[1]{{\color{gray}#1}} (redefine colour as you like; and don't load soul or ulem). – jon Jul 12 '15 at 5:31
  • @jon: re (1) it's a long story, but basically the we have to "typeset" this data according to a specification. Currently the data is being "typeset" manually in Word, but we're trying to automate it through TeX instead. We can't change the specification, but we can change how we get the result. We have successfully moved a lot of this document creation away from Word using TeX but this particular one is a bit trickier. – dreamlax Jul 12 '15 at 5:40
  • I figured 1. would be out. What about combingin soul's \so for individual items, and you use the font I linked to for the enumerated lists. (Won't be pretty, but if you're strking out huge swaths of text, you probably are not be going for pretty.) Caveat: it would require using XeTeX or LuaTeX (but still in LaTeX format). – jon Jul 12 '15 at 5:58
  • @jon: Cheers for the suggestion, I'll give it a go. The font used is actually part of the spec (it's supposed to be Swiss 721, but they can't tell I'm just using Helvetica instead [and I can't tell the difference between those two anyway]) but given how much time it will save in the long run, they may just decide to go with it. – dreamlax Jul 13 '15 at 3:28
  • 1
    Sounds like a job appropriate for latexdiff. – Sean Allred Jul 15 '15 at 16:46
4

FWIW, in ConTeXt, the \overstike macro works well with enumerated lists. Here is an example:

\starttext

\overstrike{
\startitemize[n]
  \item \input ward
    \startitemize[i]
      \item \input zapf
    \stopitemize
  \item \input tufte
\stopitemize}


\stoptext

which gives

enter image description here

  • This is definitely simpler than the other approach but we are currently using a few different LaTeX packages to meet specifications in other areas, but I'll have a look and see how hard it would be to migrate to ConTeXt. Your idea is definitely a valuable one. – dreamlax Jul 18 '15 at 6:48
7
+100

Maybe you can use something based on Tikz.

Option 1:

The following is based on Gonzalo Medina's answer:

enter image description here

\documentclass{article}
\usepackage{tikzpagenodes}
\usetikzlibrary{patterns}
\usetikzlibrary{calc}

\makeatletter
\tikzset{%
  remember picture with id/.style={%
    remember picture,
    overlay,
    save picture id=#1,
  },
  save picture id/.code={%
    \edef\pgf@temp{#1}%
    \immediate\write\pgfutil@auxout{%
      \noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
  },
  if picture id/.code args={#1#2#3}{%
    \@ifundefined{save@pt@#1}{%
      \pgfkeysalso{#3}%
    }{
      \pgfkeysalso{#2}%
    }
  }
}

\def\savepointas#1#2{%
  \expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
  \def\tmk@label{#1}%
  \def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
  \pgfutil@in@,{#1}%
  \ifpgfutil@in@%
    \tmk@labeldef#1\@nil
  \else
    \tmk@labeldef#1,(0pt,0pt)\@nil
  \fi
  \@ifundefined{save@pt@\tmk@label}{%
    \tikz@scan@one@point\pgfutil@firstofone\tmk@def
  }{%
  \pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
  \pgfsys@getposition{\pgfpictureid}\save@this@pic%
  \pgf@process{\pgfpointorigin\save@this@pic}%
  \pgf@xa=\pgf@x
  \pgf@ya=\pgf@y
  \pgf@process{\pgfpointorigin\save@orig@pic}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother

\newcommand\BoxedText[3][]{%
\begin{tikzpicture}[remember picture,overlay]
\draw[#1]
  let \p1=(pic cs:#2), \p2=(pic cs:#3) in
  ([yshift=-0.8ex]\p1) --
  ([yshift=2ex]\p1) --
  ([xshift=3pt,yshift=2ex]\p1-|current page text area.east) --
  ([xshift=3pt,yshift=2ex]\p2-|current page text area.east) --
  ([yshift=2ex]\p2) --
  ([yshift=-0.8ex]\p2) --
  ([xshift=-3pt,yshift=-0.8ex]\p2-|current page text area.west) --
  ([xshift=-3pt,yshift=-0.8ex]\p1-|current page text area.west) --
  cycle
;
\end{tikzpicture}%
}



\usepackage{lipsum}

\begin{document}

\BoxedText[pattern=horizontal lines]{start1}{end1}
\BoxedText[draw=gray!70!black,fill=gray!50,ultra thick]{start2}{end2}

Some text goes here.\tikzmark{start1} \lipsum[1]
\begin{enumerate}
\item An item
\item Another item
\item Final item
\end{enumerate}
\lipsum[2]
\section{A section head}
A line of text.
\tikzmark{end1}
After the strikeout. Some text goes here. Some text goes here. Some
text goes here. Some text goes here.Some text goes
here.\tikzmark{start2} Some text goes here. Some text goes here. Some
text goes here. Some text goes here. Some text Some text goes
here.\tikzmark{end2}

\end{document}

The down side is that each section that has to be marked must have its own start and end \tikzmark defined. Note, LaTeX has to be run three times to make a correct PDF.

Option 2:

If the text is always in full paragraphs (not starting or ending mid-sentence like option 1), you could use the mdframed package, which leads to simpler code:

enter image description here

\documentclass{article}

\usepackage{lipsum}
\usepackage[framemethod=tikz]{mdframed}
\usetikzlibrary{patterns}

\mdfdefinestyle{strikeoutbox}{%
  linecolor=black,%
  apptotikzsetting={\tikzset{mdfbackground/.append style={%
        draw=gray!10,pattern=horizontal lines}
                                %color=blue!20}
      }},%
  innertopmargin=\topskip,
}

\begin{document}

Some text goes here.
\begin{mdframed}[style=strikeoutbox]
\lipsum[1]
\begin{enumerate}
\item An item
\item Another item
\item Final item
\end{enumerate}
\lipsum[2]

\section{A section head}
A line of text.
\end{mdframed}
After the strikeout. Some text goes here. Some text goes here. Some
text goes here. Some text goes here.Some text goes
here. Some text goes here. Some text goes here. Some
text goes here. Some text goes here. Some text Some text goes
here.

\end{document}

Final remark

For both options you can use Philippe Goutet's answer on customizing an existing pattern in order to get the stripes further apart, in a different colour, etc.

  • Thanks for your insight - I'll explore both options and let you know how I get on. – dreamlax Jul 15 '15 at 23:29
  • You get the bounty because you've put a lot of effort/detail into your answer, but as it turns out, ConTeXt may be better suited to our needs anyway. – dreamlax Jul 20 '15 at 23:15

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.