jgm/citeproc

Indention of note++ in references fails in hanging indent style

Dearwolf opened this issue · 11 comments

Versions

pandoc 2.14.0.3
Compiled with pandoc-types 1.22, texmath 0.12.3, skylighting 0.10.5.2,
citeproc 0.4.0.1, ipynb 0.1.0.1

Some bibliography styles have (numeric) hanging indent layout. Some of these even include note, abstract and/or archive in separate “right-inline” blocks in the reference listing. Such an example is ISO-690 (numeric, English) at http://www.zotero.org/styles/iso690-numeric-en.

From the style:

...
            <text macro="url"/>
          </group>
        </else>
      </choose>
      <group display="right-inline">
        <text macro="archive"/>
      </group>
      <group display="right-inline">
        <text macro="abstract"/>
      </group>
      <group display="right-inline">
        <text macro="note"/>
      </group>
    </layout>
  </bibliography>
</style>

The style will (for all types) include separate “right-inline” blocks in the references listing for archive, note and/or abstract. This should be legal, from the CSL 1.0.1 Specification we have:

“right-inline” - block starting to the right of a preceding “left-margin” block (behaves as “block” in the absence of such a “left-margin” block). Extends to the right margin.

---https://docs.citationstyles.org/en/stable/specification.html#display

As I understand: it does not specify immediately preceding “left-margin” block, so this should hold true for all “right-inline” – blocks following a single “left-margin” block.

The problem is the subsequently “right-inline” blocks are not indented. This is an MWE:

---
csl: iso690-numeric-en.csl
references:
- id: withnote
  title: Copyright guidelines for Dummies
  type: book
  author: Peter Writer
  edition: 4
  volume: 2
  issued:
  - year: '2018'
    month: '09'
  ISBN: 0-85131-041-9
  publisher: The Best Book Company
  note: This is the note for this book reference.  It is rather long and should take more than one line.  In fact I hope it will take more than two lines to clearly see where the "right-margin" is for the note.
...

Citation [@withnote]

# References {-}

<div id="refs"></div>

Compiled with

pandoc -f markdown --citeproc --o out.pdf clstest.md

produces:

image

Looking at the intermediate TeX file I see:

Citation {[}1{]}

\hypertarget{references}{%
\section*{References}\label{references}}
\addcontentsline{toc}{section}{References}

\hypertarget{refs}{}
\begin{CSLReferences}{0}{0}
\leavevmode\vadjust pre{\hypertarget{ref-withnote}{}}%
\CSLLeftMargin{1. }
\CSLRightInline{PETER WRITER. \emph{Copyright guidelines for Dummies}.
4. The Best Book Company, 2018.
ISBN~\href{https://worldcat.org/isbn/0-85131-041-9}{0-85131-041-9}. }
\CSLRightInline{This is the note for this book reference. It is rather
long and should take more than one line. In fact I hope it will take
more than two lines to clearly see where the {``right-margin''} is for
the note.}

\end{CSLReferences}

So, it looks like citeproc correctly parses and translates “right-inline” display directives in the style file. The problem is that the CLS macros in the (default) Pandoc LaTeX template do not have awareness of the context. Indention of the right-margin blocks as implemented in the \CSLRightInline macro depends solely on an \CSLLeftMargin immediately before. It is worth to note that it gets the text length correct.

From default.latex:

...
\newcommand{\CSLBlock}[1]{#1\hfill\break}
\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
...

Thinking of potential solutions. Caution: I’m in no way an expert in pandoc, TeX, cls… at best a novice - so you have been warned! I can’t see that it can be solved in the (default) Pandoc LaTeX template by cleaver definitions of the CLS macros: It has no awareness of the reference style context. It seems to me that it must be addressed in citeproc:

Solution 1

citeproc to generate empty \CSLLeftMargin for each continuing \CSLRightInline if dealing with a style with hanging indent.

Solution 2

citeproc to generate a special continuing \CSLRightInline e.g., \CSLRightInlineContinue if it is a hanging indent style. This macro must then be defined in all templates as an indented \hbox.

Solution 3

citeproc to collect all text for a series of \CSLRightInline into one and force at line break (or paragraph break?) between each.

Solution (2) will require all templates to implement a new macro and (1) seems to have minimal ramifications. Also (3) should have no ramifications on any template. So (1) and (3) seems like best options as they are transparent to templates. Not pretty – but should work.

I have most likely overlooked some (unintended) side effects of the proposed solutions.

Thanks,

jgm commented

I'd be surprised if there isn't a way to design the tex macro so that it adds an hfill or something if the current position is not already a certain distance from the left margin. Can we consult some TeX experts on this?

jgm commented

Maybe this would help:
https://www.ctan.org/pkg/tabto-ltx

jgm commented

The thought would be to redefine

\newcommand{\CSLRightInline}[1]{\tabto{\csllabelwidth}\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
jgm commented

This would also mean that, when labels exceed \csllabelwidth, the right-inline content would go on the next line instead of being pushed to the right. Actually I think that's better behavior, since with our fixed parwidth the pushed-right content would flow past the right margin.

Tried the redefine in a local copy of default.latex, but not the expected result:

image

Two problems: First time it is at exactly \csllabelwidth and tabto then decides to make a new line. Second call starts odd, may have something to do with the \break being suppressed by tabto.

So tabtois not the solution. But I think I'm convinced that a TeX expert can find a working solution. i'll open the issue against the default pandoc template.

jgm commented

What if we do something like \hspace{-1pt}\tabto{\csllinewidth}?
(for the first problem)
Not sure about the second problem, but one at a time!

No cigar, same result - surprise to me. Read the tabto manual - using \tabto*seems to address problem 1:

\newcommand{\CSLRightInline}[1]{\tabto*{\csllabelwidth}\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}

image

Adding an extra \break "solves" problem 2:

\newcommand{\CSLRightInline}[1]{\tabto*{\csllabelwidth}\parbox[t]{\linewidth - \csllabelwidth}{#1}\break\break}

image

But that feels very wrong - and I would assume side effects on other bib styles.

Thinking about it, using \tabto* would backspace over a long label (exceeding \csllabelwidth) and not the nice behavior of forcing a new line.

jgm commented

What about

\newcommand{\CSLRightInline}[1]{%
  \parbox[t]{\linewidth - \csllabelwidth}{#1}\hfill\break\tabto*\csllabelwidth} 

Very odd, the first and second block is not perfectly aligned:

image

Experimented a bit:

  • First, I don't think a \tabto*after a \break makes any functional change over just a \tabto. Tried both versions and the results are the same.
  • Tried with multiple entries in the bibliography and added citations to them. All good but 1st and following blocks is not allinged.
  • Added abstract to one of the entries, which will generate 3 \CSLRightInline. Not a good result as 2'nd and 3'rd block overlaps (tried with both \tabto*and \tabto):

image