From 20b79660fb560eb1dd8e80d44837e0d4c17ca03c Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Tue, 12 Oct 2021 03:00:58 +0000 Subject: CTAN sync 202110120300 --- macros/latex/contrib/phfcc/Makefile | 10 + macros/latex/contrib/phfcc/README.md | 19 + macros/latex/contrib/phfcc/phfcc.dtx | 1898 ++++++++++++++++++++++++++++++++++ macros/latex/contrib/phfcc/phfcc.ins | 55 + macros/latex/contrib/phfcc/phfcc.pdf | Bin 0 -> 411573 bytes macros/latex/contrib/phfcc/pkg.mk | 188 ++++ 6 files changed, 2170 insertions(+) create mode 100644 macros/latex/contrib/phfcc/Makefile create mode 100644 macros/latex/contrib/phfcc/README.md create mode 100644 macros/latex/contrib/phfcc/phfcc.dtx create mode 100644 macros/latex/contrib/phfcc/phfcc.ins create mode 100644 macros/latex/contrib/phfcc/phfcc.pdf create mode 100644 macros/latex/contrib/phfcc/pkg.mk (limited to 'macros/latex/contrib/phfcc') diff --git a/macros/latex/contrib/phfcc/Makefile b/macros/latex/contrib/phfcc/Makefile new file mode 100644 index 0000000000..9e513f0870 --- /dev/null +++ b/macros/latex/contrib/phfcc/Makefile @@ -0,0 +1,10 @@ + +PKG = phfcc + +-include pkg.mk + +pkg.mk: + ln -sf ../mkcommon/pkg.mk pkg.mk + +install: install_sty install_doc + diff --git a/macros/latex/contrib/phfcc/README.md b/macros/latex/contrib/phfcc/README.md new file mode 100644 index 0000000000..834c20118e --- /dev/null +++ b/macros/latex/contrib/phfcc/README.md @@ -0,0 +1,19 @@ +# The phfcc package + +Utilities for inline commenting in collaborative documents. + +Easily define helper macros to insert comments in a LaTeX document. A convenient syntax enables you to mark text additions (e.g., "... \phf{I'm adding this text} ..." or "... \phf I'm adding this text\endphf ..."), an in-line comment (e.g., "... We're the best \phf[I'm not sure about this.] ..."), and text removals (e.g., "... \phf*{remove me} ..."). New colors are assigned automatically to each commenter by default, and the appearance of all comments is highly customizable. + +# Documentation + +Run `make sty` to generate the style file, `make pdf` to generate the package +documentation, and `make install` to install the package in your local texmf +tree. Run 'make' or 'make help' for more info. + + +# Author and License + +(C) 2020 Philippe Faist, philippe.faist@bluewin.ch + +License: [LaTeX project public license](http://www.ctan.org/license/lppl1.3), +version 1.3 or above diff --git a/macros/latex/contrib/phfcc/phfcc.dtx b/macros/latex/contrib/phfcc/phfcc.dtx new file mode 100644 index 0000000000..3f957cb9bb --- /dev/null +++ b/macros/latex/contrib/phfcc/phfcc.dtx @@ -0,0 +1,1898 @@ +% \iffalse meta-comment +% +% Copyright (C) 2021 by Philippe Faist, philippe.faist@bluewin.ch +% ------------------------------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in: +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{phfcc.dtx} +% +%\NeedsTeXFormat{LaTeX2e}[2005/12/01] +%\ProvidesPackage{phfcc} +%<*package> + [2021/10/06 v2.0 phfcc package] +% +% +%<*driver> +\documentclass{ltxdoc} +\usepackage{xcolor} +\usepackage{lipsum} +\usepackage[preset=xpkgdoc]{phfnote} +\usepackage{phfcc} + +\usepackage{needspace} + +\usepackage[normalem]{ulem} + +\def\eqsign@{=} +\def\eqsign{\protect\eqsign@} +\robustify\eqsign +\makeatother + +\def\RevTeX{{\small R\raise-0.2ex\hbox{\textsc{ev}}}\TeX} + +\EnableCrossrefs +\CodelineIndex +\RecordChanges + +\begin{document} + \DocInput{phfcc.dtx} +\end{document} +% +% \fi +% +% \CheckSum{0} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \changes{v1.0}{2020/04/02}{Initial version} +% +% \GetFileInfo{phfcc.dtx} +% +% \iffalse Bypass indexing for following commands: \fi +% \DoNotIndex{\newcommand,\newenvironment,\renewcommand,\long,\def,\edef,\gdef,\xdef,\if,\else,\fi,\par,\relax,\vspace,\vskip,\hspace,\hskip,\vbox,\hbox} +% +% \title{\phfqitltxPkgTitle{phfcc}} +% \author{Philippe Faist\quad\email{philippe.faist@bluewin.ch}} +% \date{\pkgfmtdate\filedate} +% \maketitle +% +% \begin{abstract} +% \pkgname{phfcc}---A handy \LaTeX{} package for inline commenting in +% collaborative LaTeX documents. +% \end{abstract} +% +% \phantomsection\label{sec:toc} +% \inlinetoc +% +% \section{Introduction} +% +% When elaborating documents, especially collaborative documents with multiple +% authors, it is useful to leave inline comments and be able to mark text +% changes. Often, authors will choose a text color and define a simple macro, +% like this: +% \begin{verbatim} +% \newcommand{\phf}[1]{{\color{blue}Ph.F.: #1}} % Philippe Faist's comments +% \end{verbatim} +% +% This rudimentary approach has a few drawbacks. The main drawback is when +% highlighting long blocks of text. First of all, it can be hard to visually +% find the matching closing brace in your editor. Then, the synchronization +% between your viewer and the TeX source (|synctex|) will no longer point to the +% correct source line within the highlighted block of text; you will always be +% pointed at the beginning or the end of the entire block. The reason for this +% behavior is that the entire text is passed as a macro argument to |\phf|, so +% |synctex| only sees a single macro call. The fact that a long block of text +% is passed as a macro argument can also lead to other issues, such as errors +% with |\verb+...+|-type constructs. +% +% Also, it is occasionally desirable to make the difference between sections of +% text that were added by an author, and an inline off-hand remark, which is not +% part of the text itself. For instance, with the above macro, we could enclose +% remarks in ``|[|'' and ``|]|'': % +% \newcommand{\phfold}[1]{{\color{blue}(Ph.F.:) #1}} +% \newcommand{\phfoldb}[1]{{\color{blue}\relax #1}} +% \begin{verbatim} +% ... \phf{Observe that $A\geq 0$ by definition.} +% \phf{[I added this sentence because I felt that it wasn't +% clear from the context that $A\geq 0$]} ... +% \end{verbatim} +% to obtain: +% +% {\itshape% +% ... \phfold{Observe that $A\geq 0$ by definition.} +% \phfold{[I added this sentence because I felt that it wasn't +% clear from the context that $A\geq 0$]} ... +% } +% +% Observe how the off-hand remark blends with the text. Wouldn't it be nicer +% if it stood out clearly, and if the initials were perhaps \emph{inside} the +% brackets, like so? +% +% {\itshape% +% ... \phfoldb{Ph.F.: Observe that $A\geq 0$ by definition.} +% \phfoldb{\sffamily\bfseries [(Ph.F.:) I added this sentence because +% I felt that it wasn't +% clear from the context that $A\geq 0$]} ... +% } +% +% \relax +% +% Of course, we could have defined a different macro for the off-hand remark, +% say |\phfremark|. But typing a different macro name is not convenient, +% Wouldn't it be nicer if the off-hand remark could be typed with the syntax +% |\phf[...]|, using square brackets? +% +% Also the initials don't have to be repeated at every macro call, it suffice to +% associate the color to the author perhaps once per page or so. They could +% also be displayed in the margin, to avoid cluttering the text. +% +% Furthermore, to avoid the aforementioned issues with long blocks of text, we +% could imagine marking text with the syntax |\begin{phf} ... \end{phf}| or even +% |\phf ... \endphf|. +% +% And while we're at it, wouldn't it be cool to mark text removals, as well? +% We could use the syntax |\phf*{text to be removed}|. +% +% And because I definitely didn't have time to spare but still got distracted +% into programming \LaTeX{} macros to implement the above features, I have the +% pleasure to present: +% +% \textit{\bfseries Introducing \ldots\ the \pkgname{phfcc} package.}\par +% +% With \pkgname{phfcc}, you simply define your multi-functional commenting +% command using the |\phfMakeCommentingCommand| macro. +% +% \phfMakeCommentingCommand[initials={A.E.}]{AlE}% +% \phfMakeCommentingCommand[initials={J.B.}]{JB}% +% \phfMakeCommentingCommand[initials={PhF}]{phf}% +% Let's start with a simple example. Suppose two authors, Albert Einstein and +% John Bell, are commenting on the same document. They might define the +% commenting commands |\AlE| and |\JB|: +% \begin{verbatim} +% \phfMakeCommentingCommand[initials={A.E.}]{AlE} +% \phfMakeCommentingCommand[initials={J.B.}]{JB} +% \end{verbatim} +% Suppose they edit a paragraph of text, with multiple rounds of editing by both +% authors; they mark their latest changes while leaving comments for the other +% author as follows: +% \begin{verbatim} +% Quantum mechanics developed quickly in the 1920's thanks to the +% works of Schr\"odinger, Heisenberg, and Dirac, who drew inspiration +% from earlier ideas by Planck \AlE{and Einstein} \AlE[@JB, you forgot +% about me!]. Quantum mechanics appears to allow spooky action at a +% distance via some strange thing called ``entanglement,'' \JB*{but +% this can be explained with hidden variables}\JB{which has +% revolutionized our understanding of local realism.} \JB[@Albert, +% we talked about this...] +% \end{verbatim} +% which gives: +% +% {\itshape% +% Quantum mechanics developed quickly in the 1920's thanks to the +% works of Schr\"odinger, Heisenberg, and Dirac, who drew inspiration +% from earlier ideas by Planck \AlE{and Einstein} \AlE[@JB, you forgot +% about me!]. Quantum mechanics appears to allow spooky action at a +% distance via some strange thing called ``entanglement,'' \JB*{but +% this can be explained with hidden variables}\JB{which has +% revolutionized our understanding of local realism.} \JB[@Albert, +% we talked about this...]% +% } +% +% Read on to learn more about how these commands can be used, what their main +% features are, how to customize them, and more. +% +% As an alternative to \pkgname{phfcc}, you can consider the package +% \pkgname{todonotes}\footnote{\url{https://ctan.org/pkg/todonotes}}. The +% commands defined in this package are designed for minimal effort by the +% commenter (e.g., they only have to type |\phf{...}| or |\phf[...]|). On the +% other hand \pkgname{todonotes} offers pretty boxes and more flexibility. +% +% +% \section{Syntax of commenting commands} +% +% Here is the full syntax of the commenting commands generated with +% |\phfMakeCommentingCommand|. Suppose the command |\AlE| was defined by +% issuing |\phfMakeCommentingCommand[initials={A.E.}]{AlE}|. You can write: +% +% +% |\AlE{some text here}| --- \AlE{some text here} --- typeset the given text in +% color, perhaps to mark an addition by author |AlE| to the document. By +% default, the initials associated with the command (here, ``A.E.'') will be +% issued in the margin once per page. +% +% |\AlE[please revise this]| --- \AlE[please revise this] --- typeset an inline +% comment in a different font. This is meant for comments that are not a +% portion of document text itself but rather an inline remark that refers to the +% text around it. +% +% You can use the |footcomments| style to have your comment typeset as a +% footnote. (See also \autoref{sec:styles} below.) +% +% |\AlE*{text to be removed}| --- \AlE*{text to be removed} --- typeset the +% given text in a way to indicate that the text should be suppressed. +% +% If you use Lua\LaTeX, you can get proper text strikethrough accross entire +% chunks of text by using the argument |style={rmstrikethrough}| to +% |\phfMakeCommentingCommand|. (See also \autoref{sec:styles} below.) +% +% |\AlE!{important piece of text}| --- \AlE!{important piece of text} +% --- typeset the given text marking it as important. +% +% |\AlE![a really important comment]| --- \AlE![a really important comment] --- +% typeset the given comment and mark it as important. +% +% In each of these cases (except for comments in square brackets), +% you can use the syntax |\AlE .... \endAlE| instead of specifying the +% argument using curly brackets:\\ +% |\AlE text here\endAlE| --- \AlE text here\endAlE \\ +% |\AlE! important\endAlE| --- \AlE! important\endAlE \\ +% |\AlE* remove\endAlE| --- \AlE* remove\endAlE +% +% For simple text, you can also use the |\begin|/|\end| syntax:\\ +% |\begin{AlE} text here\end{AlE}| --- \begin{AlE} text here\end{AlE} +% +% \begin{pkgtip} +% Note that in contrast to optional arguments in many LaTeX macros, the +% argument is allowed to contain matching square brackets, for instance +% \relax% +% |\AlE[inner brackets [like this] work as you'd expect]| \AlE[inner brackets +% [like this] work as you'd expect] +% +% In any case you can protect the argument as usual with curly braces: +% |\AlE[{this is [weird}]| \AlE[{this is [weird}] +% \end{pkgtip} +% +% \section{Defining your commenting command} +% +% Now let's see exactly how to define your customized |\AlE| command. +% \DescribeMacro{\phfMakeCommentingCommand} The command +% |\phfMakeCommentingCommand| takes the following syntax: +% +% |\phfMakeCommentingCommand|\oarg{key=value,key2=value2,...}\marg{cmd name} +% +% The \marg{command name} should be given as a text name (e.g., +% |{AlE}|), and not as a macro. They key-value pairs may be one of the following: +% +% +% \phfMakeCommentingCommand[color=phfcolor,initials={PhF},formatinitials=box]{phfbox} +% \phfMakeCommentingCommand[color=phfcolor,initials={PhF},formatinitials=nobox]{phfnobox} +% \phfMakeCommentingCommand[color=phfcolor,initials={PhF},formatinitials=hide]{phfhideinitials} +% \phfMakeCommentingCommand[color=green!50!blue,initials={Philippe Faist},formatinitials=footnote]{phffootnote} +% +% \begin{cmdoptions} +% \item[color=\marg{color specification}] The color of the comments generated by +% the new commenting command. By default, a new suitable color is chosen for +% each new commenting command defined. +% +% The color specification may be a name such as |red|, |green|, etc., but also +% a mixture like |blue!40!green| (\textcolor{blue!40!green}{which stands for +% 40\% of blue and 60\% of green}). You can specify any argument you could +% specify to |\colorlet| from the \pkgname{xcolor} package. (The +% \pkgname{xcolor} package is automatically loaded.) +% +% \item[initials=\marg{your initials}] Your name initials, which will by typeset +% at the beginning of a comment (typically in a small box in the margin), +% allowing to identify different comment colors with different people. By +% default, the initials are set to the name of the command itself. +% +% \item[formatinitials=\meta{keyword or command}] The command that will be used +% to format the initials. By default (|formatinitials=default| or +% |formatinitials=margin|), the initials are displayed on the margin of the +% paragraph the first time the change occurs on a given page \phf[like this +% and like in the examples above]. You may also specify |formatinitials=box| +% to typeset the initials inline immediately before your annotation +% \phfbox[like this]. Specify |formatinitials=nobox| to remove the frame +% \phfnobox[like this]. Or specify |formatinitials=hide| to hide the initials +% altogether \phfhideinitials[like this]. You can also specify +% |formatinitials=footnote| to hide the initials at the point of text but with +% a footnote to associate colored comments with the name (for this to work +% more nicely, specify your full name as argument to |initials={...}|) +% \phffootnote[Here is an example]. [See +% \autoref{sec:customize-initials-formatting} for customizing the formatting of +% the margin initials for the |margin| style or for changing the text in the +% footnote in the |footnote| style.] +% +% You may also specify as a value to the |formatinitials=| option any \LaTeX{} +% command, which will then be used to format the initials. The macro should +% accept a single argument, the initials. +% +% The default initials formatting style (|formatinitials=margin|) requires the +% \pkgname{marginnote} package, which is loaded automatically. If you do not +% want to load the \pkgname{marginnote} package, specify the package option +% |usemarginnote=false| and set a different |formatinitials=...| style. +% +% \item[style=\marg{style name(s)}] Load one or more existing style(s) for the +% commenting command. The styles must either be predefined, or must have been +% defined using |\phfDefineCommentingStyle|. Separate style names with a +% comma. +% +% \item[font=\marg{LaTeX commands}] The font commands to invoke when typesetting +% annotations, regardless of type. By default, \phf{the font is unchanged +% other than having the author-specific color set}. Also, the font is not +% reset, so if you type an annotation somewhere where the font is large, the +% annotation's font will match that font by default. (Different annotation +% types may set their own font, see below.) +% \item[spacing=\meta{length}] Spacing to add around normal annotations. This +% amount of horizontal space is added before and after the annotation. +% \item[begin=\marg{LaTeX text and/or commands}] Stuff to typeset at the +% beginning of a general annotation. Nothing is typeset by default. +% \item[end=\marg{LaTeX text and/or commands}] Stuff to typeset at the end of a +% general annotation. Nothing is typeset by default. +% +% \item[cfont=\marg{LaTeX commands}] The font commands to invoke when +% typesetting an in-line comment. By default, use \phf[the default sans serif +% typeface, like this]. +% \item[cspacing=\meta{length}] Spacing to add around comments. This amount of +% horizontal space is added before and after the comment. +% \item[cbegin=\marg{LaTeX text and/or commands}] Stuff to typeset at +% the beginning of a commment. By default, an opening square +% bracket (with some spacing adjustments). +% \item[cend=\marg{LaTeX text and/or commands}] Stuff to typeset at +% the end of a commment. By default, a closing square bracket (with +% some spacing adjustments). +% +% \item[rmfont=\marg{LaTeX commands}] The font commands to issue when +% typesetting text that is to be removed. \phf*{By default, the text is in +% italics like this} (If you're using Lua\LaTeX, it's recommended to use the +% |rmstrikethrough| style for proper strikethrough text; see +% \autoref{sec:styles}.) +% \item[rmspacing=\meta{length}] Spacing to add around text that is marked to be +% removed. This amount of horizontal space is added before and after. +% \item[rmbegin=\marg{LaTeX text and/or commands}] Stuff to typeset at the +% beginning of a piece of text to be removed. By default, a line overlapping +% with the text, to suggest removal. +% \item[rmend=\marg{LaTeX text and/or commands}] Stuff to typeset at the end of +% a piece of text to be removed. By default, a line overlapping with the +% text, to suggest removal. +% +% \item[ifont=\marg{LaTeX commands}] The font commands to issue when +% typesetting important text. \phf!{By default, the text is in +% larger boldface format like this} +% \item[ispacing=\meta{length}] Spacing to add around important text. This +% amount of horizontal space is added before and after. +% \item[ibegin=\marg{LaTeX text and/or commands}] Stuff to typeset at +% the beginning of a piece of important text. By default, three +% exclamation marks. +% \item[iend=\marg{LaTeX text and/or commands}] Stuff to typeset at +% the end of a piece of important text. By default, three +% exclamation marks. +% \end{cmdoptions} +% +% After invoking |\phfMakeCommentingCommand|, the colors |xxxcolor|, +% |xxxrmcolor| and |xxxrmcolorlink| are automatically defined (where |xxx| is to +% be replaced by your commenting macro name). These are used respectively for +% a usual comment color, text to be removed, and for links in text to be +% removed. You may redefine these colors afterwards with |\colorlet| if you +% wish: +% \begin{verbatim} +% \colorlet{AlErmcolor}{gray} +% \end{verbatim} +% +% \DescribeMacro{\phfDisableCommentingCommands} +% The command |\phfDisableCommentingCommands| disables all commenting commands, +% and causes them to emit an error. Use this command when approaching the final +% version of a long document to ensure that no commenting commands are left in +% the document. +% +% \subsection{Commenting Styles} +% \label{sec:styles} +% +% \emph{Styles} regroup a collection of definitions that alter the overall +% behavior and appearance of commenting commands issued with +% |\phfMakeCommentingCommand|. You can assign one or more styles to a +% commenting command definition by using the |style=| keyword: +% \begin{verbatim} +% \phfMakeCommentingCommand[style={footcomments}]{JD} % \JD +% \end{verbatim} +% +% You can combine style names with commas, for instance: +% +% \begin{verbatim} +% \phfMakeCommentingCommand[style={rmstrikethrough,footcomments}]{JD} % \JD +% \end{verbatim} +% +% \phfMakeCommentingCommand[rmbegin={},rmend={},rmspacing=2pt,initials={ZZ}]{dummycmd} +% \phfMakeCommentingCommand[style={footcomments},initials={YY}]{dummyYY} +% The following styles are predefined: +% \begin{itemize} +% \item \leavevmode\PrintMarginLabel{footcomments} The |footcomments| style +% arranges for in-line comments to be typeset as footnotes. +% +% \begin{verbatim} +% \phfMakeCommentingCommand[style={footcomments}]{YY} +% +% For instance, \YY[This would be an example of a comment +% typeset as a footnote.] this text might be suitable to +% comment on. +% \end{verbatim} +% gives: +% +% ``For instance, \dummyYY[This would be an example of a comment typeset as a +% footnote.] this text might be suitable to comment on.'' +% +% This style can be convenient to place comments without interrupting the +% natural flow of the text. +% +% You can redefine |\phfccfootcommentwrapfnmark{..}| to customize the +% appearance of the footnote mark, and |\phfccfootcommenttextstyle| to get +% some handle on the commands issued within the footnote contents. +% \begin{verbatim} +% \renewcommand\phfccfootcommentwrapfnmark[1]{[[#1]]} +% \renewcommand\phfccfootcommenttextstyle{\bfseries} +% \end{verbatim} +% +% \item \leavevmode\PrintMarginLabel{rmstrikethrough} For Lua\LaTeX\ users, the +% style |rmstrikethrough| is available to make text marked for removal drawn +% in strikethrough font, \dummycmd*{\sout{kind of like this}}. You can cross +% out entire paragraphs of text which include display equations. Simply use: +% \begin{verbatim} +% \phfMakeCommentingCommand[style=rmstrikethrough]{ZZ} % requires LuaLaTeX +% +% ... \ZZ*{text to be removed} ... or also ... \ZZ* more +% text that I want to remove\endZZ ... +% \end{verbatim} +% +% The implementation uses the |lua-ul| package, which requires Lua\LaTeX. To +% apply this style to all definitions, use +% |\phfSetDefaultCommentingStyle{style=rmstrikethrough}| (see below). +% +% (We do not support strikethrough for regular \LaTeX\ because we weren't able +% to find an implementation that worked reliably even for large blocks of +% text. For instance, using the |\sout| from the \pkgname{ulem} package, you +% cannot strikethrough multiple paragraphs with displayed equations. Plus, to +% support the extended syntax of |\phfcc|'s commenting commands, we need the +% strikethrough to be implemented by a state change macro (like |\itshape|) or +% an environment, and not by a macro that accepts an argument.) +% +% \item We'll probably add more predefined styles in the future. +% \end{itemize} +% +% \DescribeMacro{\phfDefineCommentingStyle} +% You can define a style using |\phfDefineCommentingStyle|: +% \begin{verbatim} +% \phfDefineCommentingStyle{mystyle}{ +% font={\fontfamily{phv}\selectfont}, % phv = Helvetica +% cfont={\bfseries\large}, +% cbegin={{\ensuremath{\bigl\langle}}~}, +% cend={{~\ensuremath{\bigr\rangle}}} +% } +% \end{verbatim} +% You can then define your commenting command invoking this style: +% \begin{verbatim} +% \phfMakeCommentingCommand[style=mystyle]{me} +% \end{verbatim} +% +% \phfDefineCommentingStyle{mystyle}{ +% font={\fontfamily{phv}\selectfont}, +% cfont={\bfseries\large}, +% cbegin={{\ensuremath{\bigl\langle}}~}, +% cend={{~\ensuremath{\bigr\rangle}}} +% } +% \phfMakeCommentingCommand[style=mystyle]{me} +% +% Then \me{for example}, (which was typeset using |\me{for example}|,) the code +% |\me[A comment]| becomes: \me[A comment]. +% +% Styles are loaded in the order they are specified (separate style names with +% commas). Style definitions may themselves contain |style=...| keys to load +% other styles. Styles are always loaded before user keys, regardless of where +% the `|style|' key appears in the definition. When styles are loaded, and when +% the users' keys are set, later keys are overwrite earlier +% ones.\footnote{Except for an as-of-yet undocumented \phfverb{startcmds} and +% \phfverb{endcmds} keys which might be relevant if you'd like to develop a +% style which requires you to issue definitions at the beginning of every +% annotation.} +% +% \DescribeMacro{\phfSetDefaultCommentingStyle} Instead of defining named styles +% which have to be invoked explicitly, you can also preset the style of all +% future calls of |\phfMakeCommentingCommand|. You can achieve this result with +% the |\phfSetDefaultCommentingStyle| command: +% \begin{verbatim} +% \phfSetDefaultCommentingStyle{ +% font={\large} +% } +% % all annotations defined from here on will appear larger +% \phfMakeCommentingCommand{AB} +% \end{verbatim} +% +% You can also use |\phfMakeCommentingCommand| to set one or more default +% style(s) for all future commenting command definitions: +% \begin{verbatim} +% \phfSetDefaultCommentingStyle{ +% style={rmstrikethrough,footcomments} +% } +% % all annotations defined from here on will have these styles set +% \phfMakeCommentingCommand{AB} +% \end{verbatim} +% +% \subsection{Customizing the formatting of the initials label} +% \label{sec:customize-initials-formatting} +% +% \paragraph{For the \phfverb{formatinitials=margin} style:} +% +% You can customize the appearance of the initials in the margin when using the +% |formatinitials=margin| initials style by redefining the following macros. +% Changes affect all margin labels (i.e., changes affect all commenting commands +% using the |margin| initials formatting style). +% +% \DescribeMacro{\phfccformatmargininitials} The |\phfccformatmargininitials| is +% used to format the initials in the margin. You can redefine it if you'd like +% the initials to appear differently. Adapt the following, which contains the +% default definition, to your liking: +% \begin{verbatim} +% \renewcommand{\phfccformatmargininitials}[1]{% +% \fbox{\normalfont\sffamily\footnotesize #1}% +% } +% \end{verbatim} +% (Technical note: the |\fboxsep| length has been set to |1pt| prior to calling +% this macro.) +% +% \DescribeMacro{\phfccmargininitialssep} The |\phfccmargininitialssep| length +% is the minimal vertical separation between two initials labels. This is a +% length, so you should change it with |\setlength|: +% \begin{verbatim} +% \setlength{\phfccmargininitialssep}{2pt} +% \end{verbatim} +% +% \paragraph{For the \phfverb{formatinitials=box} and +% \phfverb{formatinitials=nobox} styles:} +% +% \DescribeMacro{\phfccformatboxinitials} For the |formatinitials=box| and +% |formatinitials=nobox| initials style, you can redefine the command +% |\phfccformatboxinitials| to typeset the initials, like so: +% \begin{verbatim} +% \renewcommand{\phfccformatboxinitials}[1]{% +% \normalfont\sffamily\tiny#1% +% } +% \end{verbatim} +% +% \paragraph{For the \phfverb{formatinitials=footnote} style:} +% +% \DescribeMacro{\phfCCChangesBy} When using the |formatinitials=footnote| +% initials formatting style, you may redefine |\phfCCChangesBy| to change the +% text in the footnote: +% \begin{verbatim} +% \renewcommand{\phfCCChangesBy}[1]{Changes in this color are by #1} +% \end{verbatim} +% +% \section{Package Options} +% +% This package requires the \pkgname{marginnote} package to generate initials +% labels when using the |margin| initials style (the default style). If you do +% not want to load the \pkgname{marginnote} package, you may use the package +% option |usemarginnote=false| (but then you cannot use the |margin| initials +% style): +% \begin{verbatim} +% \usepackage[usemarginnote=false]{phfcc} +% \end{verbatim} +% +% \section{Known limitations} +% +% There are some cases where it's hard to get everything right. The +% \pkgname{phfcc} commands do their best to get stuff right and to avoid +% generating obscure \LaTeX{} errors, but there might be times where not +% everything works as expected. +% +% \begin{itemize} +% \item If you place a comment inside certain contructs that are processed twice +% by \LaTeX{} (e.g., a figure caption when using e.g. the \pkgname{caption} +% package, etc.) then the margin initials will not appear even if the comment +% is the first of the page. This is because the margin label is produced the +% first time they are typeset, per page; if that happened to be in a temporary +% \TeX{} box that was then discarded, the margin note gets discarded along +% with it. +% +% In the case of AMS equations, there's a hack that make the labels appear +% right. Feel free to send pull requests to address other cases. +% +% \phf[FIXME: A better solution might be to write to the AUX file at each +% comment, so that the information is written when the comment is actually +% typeset, and then process where to put margin labels on the second run of +% \LaTeX{}. +% +% As a bonus, this would enable stuff like ``list of comments'' like the +% \pkgname{todonotes} package does. Even though I don't think it's necessary +% for the standard use case of this package.] +% +% \item Initials in the margin might overlap in some edge cases. See my +% comments and footnotes in the implementation documentation below. +% +% \item Initials in the margin might not appear if the comment immediately +% follows a page break, because the comment might have been processed while +% \LaTeX{} was on the previous page before deciding to start a new page. See +% my comments and footnotes in the implementation doc below. +% \end{itemize} +% +% +% +% \StopEventually{\PrintChangesAndIndex} +% +% \section{Implementation} +% +% Load these internally required packages. +% +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{kvoptions} +\RequirePackage{etoolbox} +\RequirePackage{xparse} +% \end{macrocode} +% +% Ensure we have the \pkgname{xcolor} package to manage text colors. We need +% \pkgname{xcolor} and not \pkgname{color} because we use |\colorlet|. +% \begin{macrocode} +\RequirePackage{xcolor} +% \end{macrocode} +% +% +% \subsection{Set up default settings} +% +% \begin{macro}{\phfCommentingDefault...} +% Provide sensible defaults for commenting formatting. +% +% Bold or semibold CFont sounds like a good idea, but comments would seem more +% aggressive like that, so keep them normal by default. +% \begin{macrocode} +\def\phfCommentingDefaultStartCmds{} +\def\phfCommentingDefaultEndCmds{} +\def\phfCommentingDefaultFont{} +\def\phfCommentingDefaultSpacing{0pt} +\def\phfCommentingDefaultBegin{} +\def\phfCommentingDefaultEnd{} +\def\phfCommentingDefaultCFont{\normalfont\sffamily} +\def\phfCommentingDefaultCSpacing{0.2em} +\def\phfCommentingDefaultCBegin{[\,} +\def\phfCommentingDefaultCEnd{\,]} +\def\phfCommentingDefaultRmFont{\small\itshape}%\itshape\notesmaller[0.9]} +\def\phfCommentingDefaultRmSpacing{.3em} +\def\phfCommentingDefaultRmBegin{% + \mbox{}\vrule height .55ex depth -.45ex width 1.4em\relax\hspace*{0.2em}% + \vrule height .55ex depth -.45ex width 0.6em\relax + \hspace*{-2em}} +\def\phfCommentingDefaultRmEnd{% + \hspace*{-2em}% + \vrule height .55ex depth -.45ex width 0.6em\relax\hspace*{0.2em}% + \vrule height .55ex depth -.45ex width 1.4em\relax} +\def\phfCommentingDefaultIFont{\large\bfseries} +\def\phfCommentingDefaultISpacing{0.25em} +\def\phfCommentingDefaultIBegin{!\hspace*{0.1em}!\hspace*{0.1em}!~} +\def\phfCommentingDefaultIEnd{~!\hspace*{0.1em}!\hspace*{0.1em}!} +% \end{macrocode} +% \end{macro} +% +% A default list of colors for commenting, and a minimal tool to select the next +% available color. The macro |\phf@cc@usedcolors| stores a +% vertical-bar-separated list of color names that have been already used and +% which should not be used again. +% \begin{macrocode} +\definecolor{phfcc0}{RGB}{0,148,240} % blue-y +\definecolor{phfcc1}{RGB}{242,108,13} % orange-brown-y +\definecolor{phfcc2}{RGB}{65,149,42} % green-y +\definecolor{phfcc3}{RGB}{128,55,134} % purple-y +\definecolor{phfcc4}{RGB}{0,129,129} % blue-green-y +\definecolor{phfcc5}{RGB}{148,7,24} % dark red / burgundy +\definecolor{phfcc6}{RGB}{160,120,0} % brownish +\definecolor{phfcc7}{RGB}{35,195,155} % aqua-ish +\csdef{phf@cc@presetcolor@0}{phfcc0} +\csdef{phf@cc@presetcolor@1}{phfcc1} +\csdef{phf@cc@presetcolor@2}{phfcc2} +\csdef{phf@cc@presetcolor@3}{phfcc3} +\csdef{phf@cc@presetcolor@4}{phfcc4} +\csdef{phf@cc@presetcolor@5}{phfcc5} +\csdef{phf@cc@presetcolor@6}{phfcc6} +\csdef{phf@cc@presetcolor@7}{phfcc7} +\def\phf@cc@usedcolors{|} +\def\phf@cc@nextcolor@#1{% + \ifcsname phf@cc@presetcolor@#1\endcsname% try preset + \edef\phf@tmp@testxx{% + \noexpand\in@{|\csname phf@cc@presetcolor@#1\endcsname|}{\phf@cc@usedcolors}}% + \phf@tmp@testxx + \ifin@% color already used, try next + \expandafter\phf@cc@nextcolor@\expandafter{\the\numexpr#1+1\relax}% + \else + \def\phf@cc@thecolor{\csname phf@cc@presetcolor@#1\endcsname}% good, use + \fi + \else% out of colors, fallback to red + \def\phf@cc@thecolor{red}% + \fi +} +% \end{macrocode} +% Read the argument. If non-empty, set |\phf@cc@thecolor| to the argument +% value. If empty, choose the next available preset color and set +% |\phf@cc@thecolor| to that. +% \begin{macrocode} +\def\phf@cc@getcolor#1{% + \edef\phf@tmp@xyz{#1}% + \if\relax\detokenize\expandafter{\phf@tmp@xyz}\relax + \phf@cc@nextcolor@{0}% + \else + \edef\phf@cc@thecolor{#1}% + \fi} +% \end{macrocode} +% +% +% +% Define the keys for |\setkeys| with \pkgname{xkeyval} package, and set the +% overall defaults. +% \begin{macrocode} +\def\phfcc@hook@phfmkccstyle@setstyle@noop#1{} +\let\phfcc@hook@phfmkccstyle@setstyle\phfcc@hook@phfmkccstyle@setstyle@noop +\define@cmdkey{phfmkccstyle}{style}{\phfcc@hook@phfmkccstyle@setstyle{#1}} + +\define@cmdkey{phfmkcc}{color}{} +\define@cmdkey{phfmkcc}{initials}{} +\define@cmdkey{phfmkcc}{formatinitials}{} +\newtoks\cmdKV@phfmkcc@startcmds +\newtoks\cmdKV@phfmkcc@endcmds +\define@key{phfmkcc}{startcmds}{% + \cmdKV@phfmkcc@startcmds=\expandafter{\the\cmdKV@phfmkcc@startcmds#1}% +} +\define@key{phfmkcc}{endcmds}{% + \edef\x{\unexpanded{#1}\the\cmdKV@phfmkcc@endcmds}% + \cmdKV@phfmkcc@endcmds=\expandafter{\x}% +} +\define@cmdkey{phfmkcc}{font}{} +\define@cmdkey{phfmkcc}{spacing}{} +\define@cmdkey{phfmkcc}{begin}{} +\define@cmdkey{phfmkcc}{end}{} +\define@cmdkey{phfmkcc}{cfont}{} +\define@cmdkey{phfmkcc}{cspacing}{} +\define@cmdkey{phfmkcc}{cbegin}{} +\define@cmdkey{phfmkcc}{cend}{} +\define@cmdkey{phfmkcc}{rmfont}{} +\define@cmdkey{phfmkcc}{rmspacing}{} +\define@cmdkey{phfmkcc}{rmbegin}{} +\define@cmdkey{phfmkcc}{rmend}{} +\define@cmdkey{phfmkcc}{ifont}{} +\define@cmdkey{phfmkcc}{ispacing}{} +\define@cmdkey{phfmkcc}{ibegin}{} +\define@cmdkey{phfmkcc}{iend}{} +\define@cmdkey{phfmkcc}{groupcmd}{} +% \end{macrocode} +% +% Factory defaults refer to the |\phfCommentingDefault***| commands. +% \begin{macrocode} +\presetkeys{phfmkcc}{% + color={},% + initials={},% + formatinitials={default},% + startcmds={\phfCommentingDefaultStartCmds},% + endcmds={\phfCommentingDefaultEndCmds},% + font={\phfCommentingDefaultFont},% + spacing={\phfCommentingDefaultSpacing},% + begin={\phfCommentingDefaultBegin},% + end={\phfCommentingDefaultEnd},% + cfont={\phfCommentingDefaultCFont},% + cspacing={\phfCommentingDefaultCSpacing},% + cbegin={\phfCommentingDefaultCBegin},% + cend={\phfCommentingDefaultCEnd},% + rmfont={\phfCommentingDefaultRmFont},% + rmspacing={\phfCommentingDefaultRmSpacing},% + rmbegin={\phfCommentingDefaultRmBegin},% + rmend={\phfCommentingDefaultRmEnd},% + ifont={\phfCommentingDefaultIFont},% + ispacing={\phfCommentingDefaultISpacing},% + ibegin={\phfCommentingDefaultIBegin},% + iend={\phfCommentingDefaultIEnd},% + groupcmd={\@firstofone}% +}{} +% \end{macrocode} +% +% \subsection{Helpers and handlers for styles} +% +% \begin{macro}{\phfDefineCommentingStyle} +% User interface for defining custom comment styles. +% \begin{macrocode} +\newcommand\phfDefineCommentingStyle[2]{% + \csdef{phfcc@style@#1}{#2}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\phfSetDefaultCommentingStyle} +% User interface for defining the default settings for all commenting commands +% declared from now on. Keep note of |style=| keywords separately (in +% |\phfcc@default@style|), because we cannot place them as |\presetkeys| in +% the main options family. +% \begin{macrocode} +\def\phfcc@default@style{} +\def\phfcc@hook@phfmkccstyle@setstyle@savestyle#1{% + \xdef\phfcc@default@style{#1}% +} +\newcommand\phfSetDefaultCommentingStyle[1]{% + \let\phfcc@hook@phfmkccstyle@setstyle\phfcc@hook@phfmkccstyle@setstyle@savestyle + \setkeys*{phfmkccstyle}{#1}% + \let\phfcc@hook@phfmkccstyle@setstyle\phfcc@hook@phfmkccstyle@setstyle@noop + \edef\x{\noexpand\presetkeys{phfmkcc}{\expandonce\XKV@rm}{}}% + \x +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Internal helpers for loading styles} +% +% \begin{macro}{\phfcc@expandstylekeys} +% Helpers to expand style= instructions in a set of key=vals. +% +% The helper macro |\phfcc@expandstylekeys| accepts two arguments. The +% argument |#1| is a list of style names and |#2| is a collection of key=value +% pairs. This macro computes all the key=value settings that should be +% applied from the style definitions, plus all the remaining user key=value +% settings. We will recursively look for style=... keywords so that styles +% can load other styles. +% +% The final expanded key=value pairs is set in the token register +% |\phfcc@val@expanded@keyval|. +% \begin{macrocode} +\newtoks\phfcc@val@expanded@keyval +\def\phfcc@expandstylekeys#1#2{% + \def\phfcc@val@expanded@preexpandstyles{#1}% + \phfcc@val@expanded@keyval={#2}% + \loop + \phfcc@expandstylekeys@once + \def\phfcc@val@expanded@preexpandstyles{}% + \ifnum\phfcc@val@expanded@needmore=1\repeat +} +% \end{macrocode} +% +% The implementation of |\phfcc@expandstylekeys| proceeds by iterating single +% expansions until there are no more |style={}| values left. A single iteration +% is implemented here. The following macro reads its input from +% |\phfcc@val@expanded@preexpandstyles| and |\phfcc@val@expanded@keyval|, and it +% sets the macros |\phfcc@val@expanded@keyval| and +% |\phfcc@val@expanded@needmore|. +% \begin{macrocode} +\def\phfcc@expandstylekeys@once{% + \def\cmdKV@phfmkccstyle@style{} + \edef\x{\noexpand\setkeys*{phfmkccstyle}{\the\phfcc@val@expanded@keyval}}% + \x +% \end{macrocode} +% The |style={...}| values is stored in the macro |\cmdKV@phfmkccstyle@style|. +% If it is empty, there is no style to set and we're done. +% \begin{macrocode} + \if\relax\detokenize\expandafter{\cmdKV@phfmkccstyle@style}\relax + \def\phfcc@val@expanded@needmore{0}% + \else + \def\phfcc@val@expanded@needmore{1}% + \fi +% \end{macrocode} +% We might have one or more styles to expand. Iterate over the comma-separated +% list of styles and we'll append the collected style-specific key=value +% definitions in the macro |\phfcc@val@fullstylekeyvals| for now. Include also +% the predefined style names to expand before the user-specified styles. +% \begin{macrocode} + \def\phfcc@val@fullstylekeyvals{}% + \edef\phfcc@tmp@thestylelist{% + \phfcc@val@expanded@preexpandstyles,\cmdKV@phfmkccstyle@style}% + \@for\phfcc@tmp@next:=\phfcc@tmp@thestylelist \do{% +% \end{macrocode} +% At this point we're requested to expand the style whose name is stored in +% |\phfcc@tmp@next|. Collect the key=value definitions in the macro named +% |\phfcc@style@STYLENAME| or produce an error if such macro does not exist. +% Also, if the style provides a macro named |\phfcc@styleused@STYLENAME|, then +% invoke it at this point, in case the style would like to load any additional +% packages or execute any other preamble-time setup steps. In the following +% |\phfcc@tmp@stylekeyvals| is defined so that its immediate expansion yields +% the styles' key=value definitions. +% \begin{macrocode} + \ifcsname phfcc@style@\phfcc@tmp@next \endcsname + \ifcsname phfcc@styleused@\phfcc@tmp@next \endcsname + \csname phfcc@styleused@\phfcc@tmp@next \endcsname + \fi + \edef\phfcc@tmp@stylekeyvals{% + \expandafter\expandonce\csname phfcc@style@\phfcc@tmp@next \endcsname}% + \edef\phfcc@val@fullstylekeyvals{% + \expandonce\phfcc@val@fullstylekeyvals,% + \expandonce\phfcc@tmp@stylekeyvals}% + \else + \if\relax\detokenize\expandafter{\phfcc@tmp@next}\relax + \else + \PackageError{phfcc}{Requested commenting style `\phfcc@tmp@next' % + is not defined}{}% + \fi + \fi + }% +% \end{macrocode} +% Now we can collect the definitions from the styles and merge them with the +% remaining non-style-related user key/values. The macro |\XKV@rm| is set by +% \pkgname{xkeyval} to those key/values not processed by |\setkeys*|. +% \begin{macrocode} + \edef\x{\noexpand\phfcc@val@expanded@keyval={% + \expandonce\phfcc@val@fullstylekeyvals,% + \expandonce\XKV@rm}}% + \x +} +% \end{macrocode} +% \end{macro} +% +% +% \subsubsection{The \phfverb{rmstrikethrough} predefined style} +% +% \begin{macro}{\phfcc@style@rmstrikethrough} +% The definition of the |rmstrikethrough| style is fairly straightforward. +% \begin{macrocode} +\gdef\phfcc@styleused@rmstrikethrough{% + \RequirePackage{lua-ul} + \newunderlinetype\beginPhfccStrikeThrough{% + \leaders\vrule height .55ex depth -.45ex} + \gdef\phfcc@styleused@rmstrikethrough{}% auto-destruct/only run once +} +\def\phfcc@style@rmstrikethrough{% + rmfont={\beginPhfccStrikeThrough}, + rmbegin={}, + rmend={}, + rmspacing={2pt} +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The \phfverb{footcomments} predefined style} +% +% \begin{macro}{\phfcc@style@footcomments} +% The |footcomments| style uses |startcmds| and |endcmds| to collect material +% and then typeset it into a footnote. +% \begin{macrocode} +\def\phfcc@style@footcomments{% + startcmds={\phfcc@collectcommentfootnote}, + endcmds={\phfcc@endcollectcommentfootnote}, +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\phfccfootcommenttextstyle} +% The macro |\phfccfootcommenttextstyle| can be redefined to customize the +% footnote text appearance. +% \begin{macrocode} +\def\phfccfootcommenttextstyle{\footnotesize} +% \end{macrocode} +% \end{macro} +% +% Now we define helpers to collect the contents of the footnote, and then +% typeset it. +% +% \begin{macro}{\phfcc@collectcommentfootnote} +% \begin{macro}{\phfcc@endcollectcommentfootnote} +% The entry point to these helpers are the macros +% |\phfcc@collectcommentfootnote| and |\phfcc@endcollectcommentfootnote|: They +% check whether this annotation is a comment and then call our main helpers if +% that's the case. +% \begin{macrocode} +\def\phfcc@collectcommentfootnote{% + \if@phfcc@iscomment + \expandafter\phfcc@collectfootnote + \fi} +\def\phfcc@endcollectcommentfootnote{% + \if@phfcc@iscomment + \expandafter\phfcc@endcollectfootnote + \fi} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\phfcc@collectfootnote} +% \begin{macro}{\phfcc@endcollectfootnote} +% \begin{macro}{\phfcc@startfootnote} +% The helper |\phfcc@collectfootnote| collects the material and builds the +% footnote. I had to copy some footnote-building code from |latex.ltx| +% unfortunately: We can't call |\footnote{}| because it requires a macro +% argument; we need begin/end macros to feed all the footnote contents and +% material as \TeX\ parses it. Recall that \LaTeX's |\footnote| basically (1) +% steps the footnote counter (the counter name is stored in |\@mpfn| and the +% printable value is given by |\thempfn|) and prints the footnote mark +% (|\@footnotemark|), and (2) collects material in the |\insert| called +% |\footins|. The code relevant to (1) is collected in +% |\phfcc@startfootnote|. The code relevant to (2) is collected and adapted +% below between |\phfcc@collectfootnote| and |\phfcc@endcollectfootnote|. +% \begin{macrocode} +\def\phfcc@collectfootnote{% + \phfcc@startfootnote + \insert\footins\bgroup% + \reset@font\footnotesize + \interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \protected@edef\@currentlabel{% + \csname p@footnote\endcsname\@thefnmark + }% + \color@begingroup + \@makefntext{% + \rule\z@\footnotesep\@finalstrut\strutbox\phfcc@hackrevtex@skippar}% + \ignorespaces + \footnotesize + \color{\phf@cc@val@cur color}% + \phfccfootcommenttextstyle +} +\def\phfcc@endcollectfootnote{% + \unskip + \color@endgroup + \egroup +} +\def\phfcc@startfootnote{% + \stepcounter\@mpfn + \protected@xdef\@thefnmark{\thempfn}% + \phfccfootcommentwrapfnmark{\@footnotemark}% +} +\def\phfccfootcommentwrapfnmark#1{% + [#1]% +} +% \end{macrocode} +% Above, we used the class-provided |\@makefntext| macro to make comment +% footnotes look like the other document-provided footnotes, but we invoke that +% macro with dummy content because remember, we haven't collected the footnote +% contents yet. But some latex classes, like Rev\TeX, this macro add a +% paragraph; so we need to eliminate that paragraph break that would otherwise +% appear at the beginning of the footnote: +% \begin{macrocode} +\def\phfcc@hackrevtex@skippar{% + \@ifnextchar\par\@gobble\relax +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsection{Define styles for initials formatting} +% +% Define the implementations for the different initials formatting. These are +% by default the small boxes that appear in the margin that match color to +% comment owner. +% +% Define the |margin| initials style as the default: +% \begin{macrocode} +\def\phf@cc@formatinitialsstyle@default{\phf@cc@formatinitialsstyle@margin} +% \end{macrocode} +% +% \subsubsection{Define styles \phfverb{hide}, \phfverb{box}, \phfverb{nobox}} +% +% \begin{macro}{\phf@cc@formatinitialsstyle@hide} +% Define the no-op |hide| style first. +% \begin{macrocode} +\def\phf@cc@formatinitialsstyle@hide#1{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@formatinitialsstyle@box} +% \begin{macro}{\phf@cc@formatinitialsstyle@nobox} +% Define the |box|, and |nobox| styles. In either cases, the label can be +% customized by redefining |\phfccformatboxinitials|. +% \begin{macrocode} +\def\phf@cc@formatinitialsstyle@box#1{% + \hspace{0.25em}\relax + \raisebox{1pt}{{\fboxsep=1pt\relax\fbox{\phfccformatboxinitials{#1}}}}% + \hspace{0.25em}} +\def\phf@cc@formatinitialsstyle@nobox#1{% + \hspace{0.25em}\relax + {\phfccformatboxinitials{#1}}% + \hspace{0.25em}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\phfccformatboxinitials} +% \begin{macrocode} +\def\phfccformatboxinitials#1{% + \normalfont\sffamily\tiny#1% +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Define the style \phfverb{footnote}} +% +% Define the |footnote| style. Note you can redefine |\phfCCChangesBy| to +% whatever you please, and it can even take the name as |#1| argument. +% \begin{macrocode} +\def\phf@cc@formatinitialsstyle@footnote#1{% + \ifcsname phf@cc@valfmtinitialsfootnote@intlspage@\phf@cc@val@cur @\roman{page}\endcsname + % already displayed on this page, don't repeat + \else + \csgdef{phf@cc@valfmtinitialsfootnote@intlspage@\phf@cc@val@cur @\roman{page}}{1}% + \def\phf@cc@tmp@zz{\gdef\@thefnmark{}\@footnotetext}% + \expandafter\phf@cc@tmp@zz\expandafter{\expandafter{% + \expandafter\color\expandafter{\phf@cc@val@cur color}\phfCCChangesBy{#1}}}% + \fi +} +\robustify\phf@cc@formatinitialsstyle@footnote +\def\phfCCChangesBy{Changes by\ } +% \end{macrocode} +% +% \subsubsection{Define the style \phfverb{margin}} +% +% \begin{macro}{\phf@cc@formatinitialsstyle@margin} +% Define the |margin| style now. This one is a little tricky. +% \begin{macrocode} +\def\phf@cc@formatinitialsstyle@margin#1{% +% \end{macrocode} +% +% First thing, we define an auxiliary global macro to remember whenever we've +% already displayed the margin note on a given page. If the label was already +% displayed on this page (as witnessed by the following test macro being +% defined), don't repeat the label display and skip altogether.\footnote{There +% are some edge cases here I'm not sure I want to spend the effort to fix. For +% instance, if the comment appears right after a page break, it might have been +% processed by \TeX\space while on the previous page and this test might get the +% page number wrong. Oh well, the label was on last page already so you should +% know whose comment this is.} +% \begin{macrocode} + \ifcsname phf@cc@valfmtinitialsmargin@intlspage@\phf@cc@val@cur + @\roman{page}\endcsname + \else +% \end{macrocode} +% +% Check for any other reasons why we shouldn't emit a margin note (e.g. for some +% known two-pass environments); this is done by |\phf@cc@margin@ifchecks|. Then +% actually create the margin note with |\phf@cc@margin@emit|. +% \begin{macrocode} + \phf@cc@margin@ifchecks{% + \phf@cc@margin@emit{#1}% + }% + \fi +} +\robustify\phf@cc@formatinitialsstyle@margin +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@margin@ifchecks} +% Detects if we're in a first pass in an AMS equation, for instance, to only +% emit the label in the second pass (actual typesetting). +% \begin{macrocode} +\def\phf@cc@margin@ifchecks#1{% + \phf@cc@ififexists{ifmeasuring@}{% + \message{Detected first pass in environment, not emitting margin + initials label this time.}% + }{% + \phf@cc@ififexists{if@inlabel}{% + \message{Detected comment in latex item label, not emitting margin + initials at this time to avoid messing up everything.}% + }{% + #1% + }% + }% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@ififexists} +% A helper macro. The |\phf@cc@ififexists|\marg{if-cs-name}\marg{commands if +% true}\marg{commands if false} macro checks if the command |\ifXXXX| exists, +% where the name |ifXXXX| is the first argument of |\phf@cc@ififexists|. If it +% exists, then it checks that ``if'' condition and executes \marg{commands if +% true} or \marg{commands if false} as appropriate. If the ``if'' macro doesn't +% exist, then executes \marg{commands if false}. +% \begin{macrocode} +\def\phf@cc@ififexists#1#2#3{% + \ifcsname #1\endcsname + \def\x{\phf@cc@ififexists@{#1}{#2}{#3}}% + \else + \def\x{#3}% + \fi + \x +} +\def\phf@cc@ififexists@#1#2#3{% + \csname #1\endcsname + #2% + \else + #3% + \fi +} +% \end{macrocode} +% \end{macro} +% +% At this point, we are all set to display the initials in the margin. It seems +% like there should be nothing wrong with simply emitting a |\marginpar|, but +% those don't work in footnotes and figure captions, where one would also like +% to be able to introduce comments. One could use the \pkgname{marginnote} +% package instead, which is more reliable, but then we can get overlapping +% margin labels which are not very nice. +% +% {\itshape On the subject of |\marginnote| vs |\marginpar|:} The strategy here +% is use |\marginnote| all the time. Originally I used |\marginpar|, but it +% doesn't work in footnotes and figure captions, where one often wants to +% comment things. It's really hard to detect all cases where |\marginpar| is +% problematic. (|\ifinner| detects minipages/equations, value of |\@captype| +% detects figure captions, but I didn't manage to detect footnotes reliably, and +% I anticipate other problematic situations coming up). So I use +% \pkgname{marginnote} instead, which is more reliable. We could have some +% complex process to decide whether to use |\marginpar| or |\marginnote|, but +% only if we can find a really reliable algorithm. When collaborators are +% commenting on a document in the final hours before a deadline, we really don't +% want to generate obscure LaTeX errors because they happened to hit an edge +% case by placing a comment somewhere I hadn't anticipated. So for now, +% universally use |\marginnote|. If you don't want to load the +% \pkgname{marginnote} package for whatever reason, use a different initials +% label style and specify the |usemarginnote=false| package option. +% +% To avoid margin notes overlapping with \pkgname{marginnote}, we use custom +% code with a simple algorithm to shift the margin notes vertically so that they +% don't overlap. The code is a bit ugly, but it seems to work and it doesn't +% rely on too specific hacks, so it is hopefully not too prone to edge cases. +% +% \begin{macro}{\phf@cc@margin@emit} +% This is the macro that actually creates the margin note. First we create a +% |\hbox| with the label so that we can measure its height. Then we defer to +% |\phf@cc@createmarginnote| to produce the margin note with the formatted +% initials. +% \begin{macrocode} +\newbox\phf@cc@margin@labelbox +\newdimen\phf@cc@margin@labelboxhgt +\def\phf@cc@margin@emit#1{% + \setbox\phf@cc@margin@labelbox=\hbox{\strut + \expandafter\color\expandafter{\phf@cc@val@cur color}% + \fboxsep=1pt\relax + \phfccformatmargininitials{#1}}% + \phf@cc@margin@labelboxhgt=\ht\phf@cc@margin@labelbox + \phf@cc@createmarginnote + \csgdef{phf@cc@valfmtinitialsmargin@intlspage@\phf@cc@val@cur% + @\roman{page}}{1}% +}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phfccformatmargininitials} +% The |\phfccformatmargininitials|\marg{initials} can be redefined to change the +% appearance of the margin intials box. +% \begin{macrocode} +\def\phfccformatmargininitials#1{% + \fbox{\normalfont\sffamily\footnotesize #1}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@createmarginnote} +% The tricky thing with \pkgname{marginnote} is that labels will overlap if +% they are emitted on the same line. Here we use a workaround: We check +% |\pdflastypos| and add some vertical spacing if we are too close to the last +% note's y position on the same page. But the issue is that |\pdfsavepos| and +% |\pdflatexypos| only work while shipping out, so basically all we can do is +% write the values to the AUX file and use them next time latex is run. Here +% we use the same mechanism as \pkgname{marginnote}: define a new \LaTeX\space +% label printing a |\newphfccmarginnote| in the AUX file with the relevant +% meta-info. We use the internal counters |\@mn@thispage| (current absolute +% page number) and |\@mn@atthispage| (number of note on current page) because +% we also need to track which notes are on which page, and there's no use +% duplicating all that code (I do hope those counters don't change, though). +% \begin{macrocode} +\def\phf@cc@createmarginnote{% + \marginnote[{\copy\phf@cc@margin@labelbox}]{\copy\phf@cc@margin@labelbox}[% + \phf@cc@marginextractvshift]% + \phf@cc@savepos + \protected@write\@auxout{}{% + \string\newphfccmarginnote{% + {\@mn@thispage}% + {\@mn@atthispage}% + {\noexpand\number\phf@cc@lastypos sp}% + {\number\phf@cc@margin@labelboxhgt sp}% + }% + }% +} +\ifcsname pdfsavepos\endcsname + \let\phf@cc@savepos\pdfsavepos + \let\phf@cc@lastypos\pdflastypos +\else + \ifcsname savepos\endcsname + \let\phf@cc@savepos\savepos + \let\phf@cc@lastypos\lastypos + \else + \PackageError{phfcc}{Cannot find appropriate \string\pdfsavepos\space + command, neither \string\pdfsavepos\space nor\string\savepos\space + are defined.}{} + \fi +\fi +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@marginextractvshift} +% The macro |\phf@cc@marginextractvshift| is responsible for extracting the +% required vertical shift from the corresponding label created from the +% information saved in the AUX file. \emph{This macro is fully expandable, +% and is meant to be used as the value of the optional vertical-shift argument +% in \phfverb{\marginnote}.} The current note is identified by the internal +% \pkgname{marginnote} counters |\@mn@thispage| (current absolute page number) +% and |\@mn@atthispage| (current note number on this page). +% +% The label |\csname phfccmn@\@mn@thispage.\@mn@atthispage\endcsname| +% generated by |\newphfccmarginnote| expands to |{|\marg{pdf y-pos of the +% point in text}\marg{label box height}|}|\relax |{|\marg{requried vertical +% shift to adjust this note}|}|. The first group of fields are the two last +% arguments specified to |\newphfccmarginnote| written to the AUX file (the +% two first are already in the label/macro name), and the second group +% contains the values (only one currently) computed when calling +% |\newphfccmarginnote|. +% +% Used as |\marginnote|'s vertical shift length. Expands to the vertical +% shift needed to correct the current note. Remember: no assignments in here, +% this command must be fully expandable. +% \begin{macrocode} +\def\phf@cc@marginextractvshift{% + \ifcsname phfccmn@\@mn@thispage.\@mn@atthispage\endcsname + \expandafter\expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\@firstofone + \expandafter\expandafter\expandafter\@secondoftwo + \csname phfccmn@\@mn@thispage.\@mn@atthispage\endcsname + \else + \z@ + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\newphfccmarginnote} +% The |\newphfccmarginnote| command defines the margin label in the AUX file. +% It's not meant as public API, it's only written in the AUX file to be +% re-read on next run. Here is where all the calculations are done. +% +% In this macro we get the page number, y position, and box height of a margin +% note written by the previous run of \LaTeX. We need to compute the vertical +% shift to avoid overlapping with other boxes. +% +% The algorithm is pretty dumb. For each margin note, we loop over all +% already-processed margin notes on the same page. If an overlap is detected, +% we advance the y-position of the margin note according to the height of the +% existing overlapping margin note, and re-start the loop. +% +% This is also the main entry point into our vertical shift calculating +% algorithm. Set the |\phf@cc@marginvshift| to zero, this is where the +% calculated total vertical shift will be stored. Then call our algorithm +% main routine unless we're the first note on the page.\footnote{There's an +% edge case here that I haven't dealt with: In the case of footnotes or figure +% captions, the notes can appear out of order in the AUX file. Our algorithm +% only checks for overlap with note numbers that are less than the current +% note number. So if note 1.1 appears in the AUX file after note 1.2, then +% first 1.2 is processed, no shift is added (it ignores the fact that 1.1 +% doesn't exist yet), then 1.1 is processed and thinks it's the first note so +% doesn't add a shift either. If this ends up really being a problem there +% are ways to fix this but now I don't feel it's worth the effort. So you +% might have a note in a figure caption somehow overlapping with another note +% if they happen to be in different environments and yet on the same line.} +% \begin{macrocode} +\def\phf@cc@marginlastmarginnoteypos{} +\newdimen\phf@cc@marginvshift +\def\newphfccmarginnote#1{\newphfccmarginnote@#1} +\def\newphfccmarginnote@#1#2#3#4{% + \phf@cc@marginvshift=\z@ + \ifnum#2>0\relax + \phf@cc@margin@calculatevshift{#1}{#2}{#3}{#4}% + \else\fi + \csxdef{phfccmn@#1.#2}{% + {{#3}{#4}}{\number\phf@cc@marginvshift sp}% + }% +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\phfccmargininitialssep} +% The dimension |\phfccmargininitialssep| is the minimum vertical separation +% between two margin notes initials. Redefine this length to whatever you +% like (e.g., |\phfccmargininitialssep=1mm\relax| or +% |\setlength{\phfccmargininitialssep}{1mm}|). +% \begin{macrocode} +\newdimen\phfccmargininitialssep +\phfccmargininitialssep=2\p@ +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@margin@calculatevshift} +% This is our note vertical-shifting algorithm. Compute the vertical shift by +% looping through existing notes on the present page. The temporary counter +% |\phf@cc@tmp@cntiter| is the iteration counter and iterates over the notes +% on the present page up to the current note. (If a note with earlier note is +% undefined, skip it, this can happen if the note is in a footnote or figure +% caption; see earlier footnote.) +% +% The total vertical shift that needs to be applied to the present note +% (positive shift = downwards shift) is stored in the dimen +% |\phf@cc@marginvshift|, to be picked up by |\newphfccmarginnote|. Here +% |#1|=absolute page no., |#2|=current note no., |#3|=current note y position, +% |#4|=current note box height. +% \begin{macrocode} +\newcount\phf@cc@tmp@cntiter +\def\phf@cc@margin@calculatevshift#1#2#3#4{% + \phf@cc@marginvshift=\z@ + \phf@cc@tmp@cntiter=0 + \phf@cc@margin@calculatevshift@{#1}{#2}{#3}{#4}% +} +\def\phf@cc@margin@calculatevshift@#1#2#3#4{% + \ifnum\phf@cc@tmp@cntiter<#2\relax + \ifcsname phfccmn@#1.\the\phf@cc@tmp@cntiter\endcsname + \expandafter\let\expandafter + \phf@cc@tmp\csname phfccmn@#1.\the\phf@cc@tmp@cntiter\endcsname + \edef\phf@cc@tmp@otherypos{% + \expandafter\expandafter\expandafter\@firstoftwo + \expandafter\@firstoftwo \phf@cc@tmp}% + \edef\phf@cc@tmp@otherhgt{% + \expandafter\expandafter\expandafter\@secondoftwo + \expandafter\@firstoftwo \phf@cc@tmp}% + \edef\phf@cc@tmp@othervshift{% + \expandafter\expandafter\expandafter\@firstofone + \expandafter\@secondoftwo \phf@cc@tmp}% + \ifdim\dimexpr\phf@cc@tmp@otherypos-\phf@cc@tmp@othervshift + >\dimexpr#3-#4-\phf@cc@marginvshift\relax + \ifdim\dimexpr\phf@cc@tmp@otherypos-\phf@cc@tmp@otherhgt-\phf@cc@tmp@othervshift + <\dimexpr#3-\phf@cc@marginvshift\relax +% \end{macrocode} +% At this point, an overlap is detected between the current note that we're +% adjusting (note number |#2| on page |#1|) and an earlier processed note (note +% number |\phf@cc@tmp@cntiter| on the same page). So we shift the current note +% so that it appears below the other note. The vertical shift is accumulated in +% the |\phf@cc@marginvshift| dimen, this will be stored into the label after +% we're done computing. Note: the y-position reported by |\pdflastypos| is from +% the \emph{bottom}, not the top, so ``higher on the page than'' is ``|>|''; but +% a positive margin vertical shift in \pkgname{marginnote} shifts the margin +% note \emph{downwards}. +% +% Then reset the iteration counter to zero, so that we re-loop over all existing +% notes on the same page to re-check (with the new vertical shift) that we +% didn't generate an overlap with any earlier note (e.g., could happen on a +% two-column page with comments in both columns). +% \begin{macrocode} + \@tempdima=\dimexpr + \phfccmargininitialssep + +(#3-\phf@cc@marginvshift)% + -(\phf@cc@tmp@otherypos-\phf@cc@tmp@otherhgt-\phf@cc@tmp@othervshift)% + \relax + %\message{*** phfcc DEBUG: overlap detected of note #1.#2 with + % note #1.\the\phf@cc@tmp@cntiter, increasing vshift of note + % number #2 on page #1 by \the\@tempdima \space ***}% + \advance\phf@cc@marginvshift \@tempdima + \phf@cc@tmp@cntiter=\z@\relax + \else\fi + \else\fi + \else\fi + \advance\phf@cc@tmp@cntiter 1\relax + \phf@cc@margin@calculatevshift@{#1}{#2}{#3}{#4}% + \fi +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{The main \phfverb{\phfMakeCommentingCommand} macro} +% +% \begin{macro}{\phfMakeCommentingCommand} +% Implementation of |\phfMakeCommentingCommand|. See main package +% documentation for usage details. The inner command definitions are kinda +% tricky because of all the possible syntax options. +% |\phfMakeCommentingCommand|\oarg{color=blue,...}\marg{cmdname} +% \begin{macrocode} +\newcommand\phfMakeCommentingCommand[2][]{% + \cmdKV@phfmkcc@startcmds={}% + \cmdKV@phfmkcc@endcmds={}% + \edef\x{\noexpand\phfcc@expandstylekeys{\phfcc@default@style}{\unexpanded{#1}}}% + \x + %\setrmkeys{phfmkcc}% + \edef\x{\noexpand\setkeys{phfmkcc}{\the\phfcc@val@expanded@keyval}}% + \x + \phf@cc@getcolor{\cmdKV@phfmkcc@color}% + \colorlet{#2color}{\phf@cc@thecolor}% + \edef\phf@tmp@xxappcmd{\noexpand\appto\noexpand\phf@cc@usedcolors{\phf@cc@thecolor|}}% + \phf@tmp@xxappcmd + \colorlet{#2rmcolor}{#2color!70!gray!55!white}% + \colorlet{#2rmcolorlink}{blue!40!#2rmcolor}% + \edef\phf@tmp@xxx{\cmdKV@phfmkcc@initials}% + \if\relax\detokenize\expandafter{\phf@tmp@xxx}\relax + \csedef{phf@cc@val@#2@initials}{#2}% + \else + \csedef{phf@cc@val@#2@initials}{\cmdKV@phfmkcc@initials}% + \fi + \ifcsname phf@cc@formatinitialsstyle@% + \detokenize\expandafter{\cmdKV@phfmkcc@formatinitials}\endcsname% + \expandafter\def\expandafter\phf@cc@tmp@xzx\expandafter{% + \csname phf@cc@formatinitialsstyle@% + \detokenize\expandafter{\cmdKV@phfmkcc@formatinitials}\endcsname}% + \csedef{phf@cc@val@#2@formatinitials}{\expandonce\phf@cc@tmp@xzx}% + \else + \csedef{phf@cc@val@#2@formatinitials}{\expandonce\cmdKV@phfmkcc@formatinitials}% + \fi + \csedef{phf@cc@val@#2@startcmds}{\the\cmdKV@phfmkcc@startcmds}% + \csedef{phf@cc@val@#2@endcmds}{\the\cmdKV@phfmkcc@endcmds}% + %\message{***** STARTCMDS ARE \detokenize\expandafter{\the\cmdKV@phfmkcc@startcmds} *****}% + %\message{***** ENDCMDS ARE \detokenize\expandafter{\the\cmdKV@phfmkcc@endcmds} *****}% + \csedef{phf@cc@val@#2@font}{\expandonce\cmdKV@phfmkcc@font}% + \csedef{phf@cc@val@#2@spacing}{\expandonce\cmdKV@phfmkcc@spacing}% + \csedef{phf@cc@val@#2@begin}{\expandonce\cmdKV@phfmkcc@begin}% + \csedef{phf@cc@val@#2@end}{\expandonce\cmdKV@phfmkcc@end}% + \csedef{phf@cc@val@#2@cfont}{\expandonce\cmdKV@phfmkcc@cfont}% + \csedef{phf@cc@val@#2@cspacing}{\expandonce\cmdKV@phfmkcc@cspacing}% + \csedef{phf@cc@val@#2@cbegin}{\expandonce\cmdKV@phfmkcc@cbegin}% + \csedef{phf@cc@val@#2@cend}{\expandonce\cmdKV@phfmkcc@cend}% + \csedef{phf@cc@val@#2@rmfont}{\expandonce\cmdKV@phfmkcc@rmfont}% + \csedef{phf@cc@val@#2@rmspacing}{\expandonce\cmdKV@phfmkcc@rmspacing}% + \csedef{phf@cc@val@#2@rmbegin}{\expandonce\cmdKV@phfmkcc@rmbegin}% + \csedef{phf@cc@val@#2@rmend}{\expandonce\cmdKV@phfmkcc@rmend}% + \csedef{phf@cc@val@#2@ifont}{\expandonce\cmdKV@phfmkcc@ifont}% + \csedef{phf@cc@val@#2@ispacing}{\expandonce\cmdKV@phfmkcc@ispacing}% + \csedef{phf@cc@val@#2@ibegin}{\expandonce\cmdKV@phfmkcc@ibegin}% + \csedef{phf@cc@val@#2@iend}{\expandonce\cmdKV@phfmkcc@iend}% + \csedef{phf@cc@val@#2@groupcmd}{\expandonce\cmdKV@phfmkcc@groupcmd}% +% \end{macrocode} +% +% Once all the information was gathered and stored, define the commenting command +% itself (as well as its |\end*| counterpart). Make them robust. +% \begin{macrocode} + \csdef{#2}{\phf@cc@do{#2}}% + \expandafter\robustify\csname #2\endcsname% + \csdef{end#2}{\phf@cc@end}% + \expandafter\robustify\csname end#2\endcsname% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phfDisableCommentingCommands} +% This command causes any commenting command declared with +% |\phfMakeCommentingCommand| to emit an error. +% \begin{macrocode} +\newif\ifphf@cc@disabled +\phf@cc@disabledfalse +\def\phfDisableCommentingCommands{% + \phf@cc@disabledtrue +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Implementation of the commenting commands} +% +% Overall, the implementation of a commenting command goes as follows. First, +% gather all the info about the command invocation (e.g., important? starred? +% comment?) and then ultimately call |\phf@cc@begin| and |\phf@cc@end| which +% execute the formatting options. +% +% Within each comment, the following flags are set by the parsing mechanism. +% \begin{macrocode} +\newif\if@phfcc@iscomment +\newif\if@phfcc@isremoved +\newif\if@phfcc@isimportant +% \end{macrocode} +% +% Everything happens within |\begingroup|\ldots|\endgroup|. The group is opened +% at |\phf@cc@do| (the commenting command itself), and is closed by |\phf@cc@end|. +% +% \begin{macro}{\phf@cc@begin} +% The helper macro |\phf@cc@begin| is responsible for issuing all the +% necessary definitions for the comment to be typeset correctly, including +% initials, depending on whether it is a regular text addition, a text removal +% comment, an important comment, a commenting comment, etc. It inspects +% |\if@phfcc@iscomment|, |\if@phfcc@isremoved|, and |\if@phfcc@isimportant| to +% determine the comment type. +% +% This is not the main comment entry point, the main entropy point is +% |\phf@cc@do| and |\phf@cc@begin| is called internally from there. {\itshape +% Execution is already enclosed in a local \TeX\ group; a |\begingroup| has +% already been issued by |\phf@cc@do|.} +% \begin{macrocode} +\def\phf@cc@begin{% +% \end{macrocode} +% +% First, we set the author's color so that by default everything we do will use +% that color. +% \begin{macrocode} + \color{\phf@cc@val@cur color}% +% \end{macrocode} +% +% Issuing \phfverb\leavevmode\ here is annoying because it adds vertical space +% if the command is issued in vertical mode right before an equation or theorem; +% but it is needed immediately after section and paragraph headings so that the +% comment style (eg sans font along with color etc.) is not applied to the +% section/paragraph heading itself. +% \begin{macrocode} + \leavevmode% beurk, see above +% \end{macrocode} +% +% The comment typesetting is constructed in layers, each time adding commands to +% execute at the start and corresponding commmands to execute at the end. The +% start commands are executed in the specified order, with the end commands in +% the reverse order at the end. We use the |\phf@cc@helper@pushgrpcmds| helper +% to this effect. +% +% Introducing the necessary spacing, and issuing the initials. The amount of +% spacing will depend on the type of comment; |\phf@cc@val@spacing| will be set +% appropriately below when setting comment-type specific settings. +% \begin{macrocode} + \phf@cc@helper@pushgrpcmds{% + \csname phf@cc@val@\phf@cc@val@cur @startcmds\endcsname + \hspace{\phf@cc@val@spacing}% + \phf@cc@showinitials% + }{% + \hspace{\phf@cc@val@spacing}% + \csname phf@cc@val@\phf@cc@val@cur @endcmds\endcsname + }% +% \end{macrocode} +% +% See what comment type we're dealing with, and set the appropriate settings. +% +% First, check if we have a commenting-comment. If so, see whether or not it is +% additionally marked as important and issue the relevant commands. Also set +% the relevant spacing. +% \begin{macrocode} + \if@phfcc@iscomment + \if@phfcc@isimportant + \phf@cc@helper@pushgrpcmdsX{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @font\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cfont\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @ifont\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cbegin\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @ibegin\endcsname + }{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @iend\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cend\endcsname + }% + \edef\phf@cc@val@spacing{\csname phf@cc@val@\phf@cc@val@cur @ispacing\endcsname}% + \else + \phf@cc@helper@pushgrpcmdsX{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @font\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cfont\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cbegin\endcsname + }{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @cend\endcsname + }% + \edef\phf@cc@val@spacing{\csname phf@cc@val@\phf@cc@val@cur @cspacing\endcsname}% + \fi + \else +% \end{macrocode} +% Now check if we have an important comment (which is not a commenty-comment). +% \begin{macrocode} + \if@phfcc@isimportant + \phf@cc@helper@pushgrpcmdsX{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @font\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @ifont\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @ibegin\endcsname + }{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @iend\endcsname + }% + \edef\phf@cc@val@spacing{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @ispacing\endcsname% + }% + \else +% \end{macrocode} +% Not a comment, not important. Could be a piece of text marked for removal. +% \begin{macrocode} + \if@phfcc@isremoved + \phf@cc@helper@pushgrpcmdsX{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @font\endcsname + \noexpand\color{\phf@cc@val@cur rmcolor}% + \noexpand\colorlet{docnotelinkcolor}{\phf@cc@val@cur rmcolorlink}% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @rmfont\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @rmbegin\endcsname + }{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @rmend\endcsname + }% + \edef\phf@cc@val@spacing{\csname phf@cc@val@\phf@cc@val@cur @rmspacing\endcsname}% + \else +% \end{macrocode} +% We've got just a plain, old, inline marked text. +% \begin{macrocode} + \phf@cc@helper@pushgrpcmdsX{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @font\endcsname + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @begin\endcsname + }{% + \expandafter\noexpand\csname phf@cc@val@\phf@cc@val@cur @end\endcsname + }% + \edef\phf@cc@val@spacing{\csname phf@cc@val@\phf@cc@val@cur @spacing\endcsname}% + \fi + \fi + \fi +% \end{macrocode} +% +% Actually issue these commmands and kick off the typesetting of the comment. +% \begin{macrocode} + \phf@cc@val@grpcmds +} +\def\phf@cc@helper@pushgrpcmds#1#2{% + \appto\phf@cc@val@grpcmds{#1}% + \preto\phf@cc@val@grpendcmds{#2}% +} +\def\phf@cc@helper@pushgrpcmdsX#1#2{% expands arguments with edef + \edef\phfcc@tmp@x{\noexpand\phf@cc@helper@pushgrpcmds{#1}{#2}}% + \phfcc@tmp@x +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\phf@cc@end} +% Here we execute closing commands and close the group. |\phf@cc@end| is the +% last macro executed when the user invokes a comment, in any case. +% \begin{macrocode} +\def\phf@cc@end{% + \phf@cc@val@grpendcmds + \endgroup +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@showinitials} +% This helper macro prints out the initials, if any. +% \begin{macrocode} +\def\phf@cc@showinitials{% + \edef\phf@cc@tmpx{% + \expandafter\expandonce\csname phf@cc@val@\phf@cc@val@cur @initials\endcsname}% + \expandafter\notblank\expandafter{\phf@cc@tmpx}{% + \csname phf@cc@val@\phf@cc@val@cur @formatinitials% + \expandafter\endcsname\expandafter{\phf@cc@tmpx}}{}% +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\phf@cc@do} +% {\bfseries The macro |\phf@cc@do| is the main entry point of a commenting +% command.} Actually, the user-instantiated commenting commands are an alias +% of this command, with the user macro name as first argument. So the |\AlE| +% command defined in the main documentation of this package was in fact +% defined as an alias to |\phf@cc@do{AlE}|. This is were everything starts. +% \begin{macrocode} +\def\phf@cc@do#1{% +% \end{macrocode} +% First, we need to check if commenting commands were disabled with +% |\phfDisableCommentingCommands|. If this is the case, generate an error. +% \begin{macrocode} + \ifphf@cc@disabled + \PackageError{phfcc}{Commenting commands have been disabled + with \string\phfDisableCommentingCommands.}{}% + \fi +% \end{macrocode} +% Now we start for real. First, we open the \TeX\ group. Then we start parsing +% the invocation syntax. +% +% \begin{macrocode} + \begingroup + \@phfcc@iscommentfalse + \@phfcc@isremovedfalse + \@phfcc@isimportantfalse +% \end{macrocode} +% +% The macros |\phf@cc@val@grp*cmds| store the commands to be executed in +% |\phf@cc@begin| and |\phf@cc@end|. By default, they are empty. They are +% filled by relevant code when parsing the command invocation. +% +% By default, there are no commands at group begin (|\phf@cc@val@grpcmds|), no +% commands at group end (|\phf@cc@val@grpendcmds|), and no spacing on either +% side of the typeset comment (|\phf@cc@val@spacing|). +% \begin{macrocode} + \def\phf@cc@val@grpcmds{}% + \def\phf@cc@val@grpendcmds{}% + \def\phf@cc@val@spacing{0pt}% +% \end{macrocode} +% +% Store the name of the commenting command so we can look up the relevant +% comment settings. This is the name that was given to the commenting command +% itself, e.g. |phf|. +% \begin{macrocode} + \edef\phf@cc@val@cur{#1}% +% \end{macrocode} +% +% Here we start the parsing of the type of comment. First, check for a star +% (e.g., |\phf*{...}|) to see if we're dealing with a removed block of text. +% \begin{macrocode} + \@ifstar\phf@cc@star\phf@cc@nostar% +} +% \end{macrocode} +% +% If we don't have a star, continue parsing to see if we have an important piece +% of text or comment (|\phf!| sytnax). +% \begin{macrocode} +\def\phf@cc@nostar{\@ifnextchar!\phf@cc@important\phf@cc@grp} +% \end{macrocode} +% +% At this point, we have determined whether the invocation is starred (removed +% text) or important. The next execution points are |\phf@cc@star|, +% |\phf@cc@important|, or |\phf@cc@grp|. +% \end{macro} +% +% \begin{macro}{\phf@cc@star} +% \begin{macro}{\phf@cc@important} +% If starred or if important, set up the inner group execution commands to the +% corresponding settings, and defer to |\phf@cc@grp|. +% \begin{macrocode} +\long\def\phf@cc@star{% + \@phfcc@isremovedtrue + \phf@cc@grp} +\long\def\phf@cc@important!{% + \@phfcc@isimportanttrue + \phf@cc@grp} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\phf@cc@grp} +% The command |\phf@cc@grp| parses how the argument content is given. Is it a +% comment (``|[ ... ]|''), a single \LaTeX{} argument group (``|{ ... }|''), +% or should we expect it to end with |\endXXX|? +% \begin{macrocode} +\def\phf@cc@grp{% + \@ifnextchar[\phf@cc@comment\phf@cc@grpnocomment%] +} +\def\phf@cc@grpnocomment{% + \@ifnextchar\bgroup{\phf@cc@grpwarg}{\phf@cc@begin}} +% \end{macrocode} +% \end{macro} +% +% The main commenting command has already defined the |\endXXX| command as an +% alias of |\phf@cc@end|, so in the case of the syntax |\AlE ... \endAlE| we can +% call |\phf@cc@begin| directly. +% +% Now at this point we have determined how the argument is given, and we are +% calling one of |\phf@cc@comment|, |\phf@cc@grpwarg| (with argument), or +% |\phf@cc@begin| directly. +% +% \begin{macro}{\phf@cc@grpwarg} +% Format a simple comment specified as a normal \LaTeX{} block, i.e., provided +% as an argument to the commenting command. (Like |\AlE{text here}| or +% |\AlE!{important text}| or |\AlE*{some stuff to remove}|.) +% \begin{macrocode} +\long\def\phf@cc@grpwarg#1{% + \phf@cc@begin + \csname phf@cc@val@\phf@cc@val@cur @groupcmd\endcsname + {#1}% + \phf@cc@end +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\phf@cc@comment} +% If the argument is a comment, set up the comment font, begin/end chars, and +% go. Use |xparse| to get the argument in square brackets to ensure that the +% argument itself can contain matched square brackets. +% \begin{macrocode} +\NewDocumentCommand\phf@cc@comment{+O{}}{% + \@phfcc@iscommenttrue + \phf@cc@begin% + #1% + \phf@cc@end% +} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Process package options} +% +% Initialization code for \pkgname{kvoptions} for our package options. +% \begin{macrocode} +\SetupKeyvalOptions{ + family=phfcc, + prefix=phfcc@opt@ +} +\DeclareBoolOption[true]{usemarginnote} +% \end{macrocode} +% +% Process package options. +% \begin{macrocode} +\ProcessKeyvalOptions* +% \end{macrocode} +% +% Load the \pkgname{marginnote} package unless requested not to. This package +% is required for the |margin| initials style. +% \begin{macrocode} +\ifphfcc@opt@usemarginnote + \RequirePackage{marginnote} +\fi +% \end{macrocode} +% +%\Finale +\endinput diff --git a/macros/latex/contrib/phfcc/phfcc.ins b/macros/latex/contrib/phfcc/phfcc.ins new file mode 100644 index 0000000000..b9c785e1b1 --- /dev/null +++ b/macros/latex/contrib/phfcc/phfcc.ins @@ -0,0 +1,55 @@ +%% +%% Copyright (C) 2016 by Philippe Faist, philippe.faist@bluewin.ch +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.3 of this license +%% or (at your option) any later version. The latest version of this +%% license is in: +%% +%% http://www.latex-project.org/lppl.txt +%% +%% and version 1.3 or later is part of all distributions of LaTeX version +%% 2005/12/01 or later. +%% + +\input docstrip.tex +\keepsilent + +\usedir{tex/latex/phfqitltx} + +\preamble + +This is a generated file. + +Copyright (C) 2016 by Philippe Faist, philippe.faist@bluewin.ch + +This file may be distributed and/or modified under the conditions of +the LaTeX Project Public License, either version 1.3 of this license +or (at your option) any later version. The latest version of this +license is in: + + http://www.latex-project.org/lppl.txt + +and version 1.3 or later is part of all distributions of LaTeX version +2005/12/01 or later. + +\endpreamble + +\generate{\file{phfcc.sty}{\from{phfcc.dtx}{package}}} + +\obeyspaces +\Msg{*************************************************************} +\Msg{* *} +\Msg{* To finish the installation you have to move the following *} +\Msg{* file into a directory searched by TeX: *} +\Msg{* *} +\Msg{* phfcc.sty *} +\Msg{* *} +\Msg{* To produce the documentation run the .dtx file through *} +\Msg{* (PdF-)LaTeX. *} +\Msg{* *} +\Msg{* Happy TeXing! *} +\Msg{* *} +\Msg{*************************************************************} + +\endbatchfile diff --git a/macros/latex/contrib/phfcc/phfcc.pdf b/macros/latex/contrib/phfcc/phfcc.pdf new file mode 100644 index 0000000000..857065b828 Binary files /dev/null and b/macros/latex/contrib/phfcc/phfcc.pdf differ diff --git a/macros/latex/contrib/phfcc/pkg.mk b/macros/latex/contrib/phfcc/pkg.mk new file mode 100644 index 0000000000..328b5fc36d --- /dev/null +++ b/macros/latex/contrib/phfcc/pkg.mk @@ -0,0 +1,188 @@ + +# +# Common useful definitions +# +LATEX = latex + +PDFLATEXNAME = pdflatex + +PDFLATEX = TEXINPUTS="$$TEXINPUTS:../phfnote" $(PDFLATEXNAME) +PDFLATEXOPTS = -interaction=batchmode +PDFLATEXOPTSLAST = -interaction=batchmode --synctex=1 + +MAKEINDEX = makeindex + + +# +# Set default PREFIX. This can be overridden with 'make install PREFIX=/installation/directory' +# +DEFAULT_PREFIX := $(shell kpsewhich -var-value TEXMFHOME) +PREFIX ?= $(DEFAULT_PREFIX) + + +# +# package should be set in variable PKG +# +PKGREADME = README.md + +# +# packages may specify additional files in the distribution with this variable +# (by default empty) +# +DIST_ADDITIONAL_FILES ?= + +# +# Additional files automatically generated by the .ins file, such as .def files +# (by default empty) +# +ADDITIONAL_GENERATED_FILES ?= + + +# By default, the generated style file is a '.sty' latex package. If it's a +# '.cls' class file instead, the local Makefile will redefine this to 'cls'. +PKGSTYEXT ?= sty + +PKGDTX = $(PKG).dtx +PKGSTY = $(PKG).$(PKGSTYEXT) +PKGINS = $(PKG).ins +PKGPDF = $(PKG).pdf +PKGTDSZIP = $(PKG).tds.zip +PKGZIP = $(PKG).zip + + +.PHONY: help sty cls pdf install install_sty install_cls install_doc tdszip dist clean cleanall cleansty cleancls cleanaux cleanpdf cleantdszip cleandist + + +help: + @echo "Targets for $(PKG):" + @echo "make $(PKGSTYEXT) -- generate LaTeX package file $(PKG).$(PKGSTYEXT)" + @echo "make pdf -- generate pdf documentation" + @echo "make install -- install style and documentation files to $(DEFAULT_PREFIX)" + @echo "make install PREFIX=[specify texmf directory destination]" + @echo "make $(PKG).tds.zip -- create TDS.ZIP package for distribution" + @echo "make dist -- create distribution ZIP, ready for upload to CTAN" + @echo "make clean -- remove LaTeX auxiliary files" + @echo "make clean$(PKGSTYEXT) -- remove generated style file" + @echo "make cleanpdf -- remove generated pdf documentation" + @echo "make cleanall -- remove all generated files, incl. distribution zip" + + +clean: cleanaux + +cleanall: cleansty cleanaux cleanpdf cleantdszip cleandist + +# ------------------------------------------------ +# make sty +# ------------------------------------------------ + +sty: $(PKGSTY) + +# synonym of `sty` in case of LaTeX classes, we use same commands etc. +cls: $(PKGSTY) + +$(PKGSTY): $(PKGINS) $(PKGDTX) + $(LATEX) $< + +cleansty: + @rm -f $(PKGSTY) $(ADDITIONAL_GENERATED_FILES) + +cleancls: cleansty + + +# ------------------------------------------------ +# make pdf +# ------------------------------------------------ + +pdf: $(PKG).pdf + +# +# fake index & glossary so they get a TOC entry from the beginning, and so the page +# numbers in the index are correct. +# +$(PKG).aux $(PKG).idx $(PKG).glo: $(PKGDTX) $(PKGSTY) + DTX=$< ; echo '\\begin{theindex}\\item index here \\end{theindex}' >$${DTX%.dtx}.ind + DTX=$< ; echo '\\begin{theglossary}\\item changes here\\end{theglossary}' >$${DTX%.dtx}.gls + $(PDFLATEX) $(PDFLATEXOPTS) $< + $(PDFLATEX) $(PDFLATEXOPTS) $< + $(PDFLATEX) $(PDFLATEXOPTS) $< + +$(PKG).ind: $(PKG).idx + $(MAKEINDEX) -s gind.ist -o $@ $< + +$(PKG).gls: $(PKG).glo + $(MAKEINDEX) -s gglo.ist -o $@ $< + +# final steps of making the PKG.pdf doc file. At the end, touch the ind and gls files so +# that they don't look out-of-date (because the idx and glo files were overwritten again) +$(PKGPDF): $(PKGDTX) $(PKG).aux $(PKG).ind $(PKG).gls + $(PDFLATEX) $(PDFLATEXOPTS) $< + $(PDFLATEX) $(PDFLATEXOPTS) $< + $(PDFLATEX) $(PDFLATEXOPTSLAST) $< + touch $(PKG).ind $(PKG).gls $(PKG).pdf + + +cleanaux: + @rm -f *.aux *.log *.toc *.glo *.gls *.ind *.idx *.ilg *.out *.bbl *.blg *.synctex.gz *.hd + +cleanpdf: + @rm -f $(PKGPDF) + +# ------------------------------------------------ +# 'make install' partial installation targets +# ------------------------------------------------ + +# +# The install target itself is defined per-package, in case packages want to install more +# files (such as bibtex styles) +# + +install_sty: $(PKGSTY) + mkdir -p $(DESTDIR)$(PREFIX)/tex/latex/$(PKG) + cp $(PKGSTY) $(ADDITIONAL_GENERATED_FILES) $(DESTDIR)$(PREFIX)/tex/latex/$(PKG) + +install_cls: install_sty + +install_doc: $(PKGPDF) + mkdir -p $(DESTDIR)$(PREFIX)/doc/latex/$(PKG) + cp $(PKGPDF) $(PKGREADME) $(DESTDIR)$(PREFIX)/doc/latex/$(PKG) + + + +# ------------------------------------------------ +# make tdszip +# ------------------------------------------------ + +TDSTMPDIR = $(CURDIR)/_install_tds_zip.make.tmp + +tdszip: $(PKGTDSZIP) + +$(PKGTDSZIP): $(PKGSTY) $(PKGPDF) + mkdir $(TDSTMPDIR) + $(MAKE) install PREFIX=$(TDSTMPDIR) + cd $(TDSTMPDIR) && zip -r $(CURDIR)/$(PKGTDSZIP) * + rm -rf $(TDSTMPDIR) + +cleantdszip: + @rm -f $(PKGTDSZIP) + + +# ------------------------------------------------ +# make dist +# ------------------------------------------------ + +DISTTMPDIR = $(CURDIR)/_install_dist_zip.make.tmp + +dist: $(PKGZIP) + +# feedback from CTAN upload manager: prefer not to provide tds.zip in CTAN upload +$(PKGZIP): #$(PKGTDSZIP) + rm -rf $(DISTTMPDIR) + mkdir -p $(DISTTMPDIR)/$(PKG) +# cp $(PKGTDSZIP) $(DISTTMPDIR) + cp $(PKGDTX) $(PKGINS) $(PKGPDF) $(PKGREADME) Makefile pkg.mk $(DIST_ADDITIONAL_FILES) $(DISTTMPDIR)/$(PKG) +# cd $(DISTTMPDIR) && zip -r $(CURDIR)/$(PKGZIP) $(PKG) $(PKGTDSZIP) + cd $(DISTTMPDIR) && zip -r $(CURDIR)/$(PKGZIP) $(PKG) + rm -rf $(DISTTMPDIR) + +cleandist: + @rm -f $(PKGZIP) -- cgit v1.2.3