summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2023-08-27 10:54:59 -0700
committerJohn MacFarlane <jgm@berkeley.edu>2023-08-29 09:23:50 -0700
commit353177f9e7eadd60d66846325abd537b85fd46bb (patch)
tree07ffbf78b3f670e83c462ea1d8d8d9abac74578b
parent9d28e6029f71f769756ee6d121822de5b0f2aed6 (diff)
Use `\cite` and `\bibitem` to link up citations, even with citeproc.
See #9031 and discussion in #9020. This will give us better accessibility; when tagging is enabled, the citation can be linked to the bibliography entry. This changes some of the details of the layout and the default template. We now make CSLReferences a special enumitem list that will contain `\bibitem`s. Internal links inside citations to ids beginning in `ref-` are put inside a `\cite` instead of `\hyperref`. Closes #9031.
-rw-r--r--data/templates/default.latex32
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs55
-rw-r--r--src/Text/Pandoc/Writers/LaTeX/Types.hs2
3 files changed, 54 insertions, 35 deletions
diff --git a/data/templates/default.latex b/data/templates/default.latex
index e2cfce1f1..c177c00e8 100644
--- a/data/templates/default.latex
+++ b/data/templates/default.latex
@@ -335,24 +335,28 @@ $if(pagestyle)$
\pagestyle{$pagestyle$}
$endif$
$if(csl-refs)$
+% definitions for citeproc citations
+\NewDocumentCommand\citeproctext{}{}
+\NewDocumentCommand\citeproc{mm}{%
+ \begingroup\def\citeproctext{#2}\cite{#1}\endgroup}
+% avoid brackets around text for \cite:
+\makeatletter
+ \def\@biblabel#1{}
+ \def\@cite#1#2{{#1\if@tempswa , #2\fi}}
+\makeatother
\newlength{\cslhangindent}
\setlength{\cslhangindent}{1.5em}
\newlength{\csllabelwidth}
\setlength{\csllabelwidth}{3em}
-\newlength{\cslentryspacingunit} % times entry-spacing
-\setlength{\cslentryspacingunit}{\parskip}
-\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
- {% don't indent paragraphs
- \setlength{\parindent}{0pt}
- % turn on hanging indent if param 1 is 1
- \ifodd #1
- \let\oldpar\par
- \def\par{\hangindent=\cslhangindent\oldpar}
- \fi
- % set entry spacing
- \setlength{\parskip}{#2\cslentryspacingunit}
- }%
- {}
+\newlength{\cslentryspacing}
+\setlength{\cslentryspacing}{0em}
+\usepackage{enumitem}
+\newlist{CSLReferences}{itemize}{1}
+\setlist[CSLReferences]{label={},
+ leftmargin=\cslhangindent,
+ itemindent=-1\cslhangindent,
+ parsep=\parskip,
+ itemsep=\cslentryspacing}
\usepackage{calc}
\newcommand{\CSLBlock}[1]{#1\hfill\break}
\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index d12890bd5..bdfa96c1a 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -339,22 +339,30 @@ blockToLaTeX (Div (identifier,classes,kvs) bs) = do
then do
modify $ \st -> st{ stHasCslRefs = True }
inner <- blockListToLaTeX bs
- return $ "\\begin{CSLReferences}" <>
- (if "hanging-indent" `elem` classes
- then braces "1"
- else braces "0") <>
- (case lookup "entry-spacing" kvs of
- Nothing -> braces "0"
- Just s -> braces (literal s))
+ return $ (if "hanging-indent" `notElem` classes
+ then "\\setlength{\\cslhangindent}{0em}"
+ else mempty)
+ $$ ("\\setlength{\\cslentryspacing}" <> braces
+ (case lookup "entry-spacing" kvs of
+ Nothing -> "0em"
+ Just s -> (literal s <> "\\baselineskip")))
+ $$ "\\begin{CSLReferences}"
$$ inner
$+$ "\\end{CSLReferences}"
else blockListToLaTeX bs
modify $ \st -> st{ stIncremental = oldIncremental }
- linkAnchor <- hypertarget identifier
- let wrapNotes txt = if beamer && "notes" `elem` classes
- then "\\note" <> braces txt -- speaker notes
- else linkAnchor $$ txt
- wrapNotes <$> wrapDiv (identifier,classes,kvs) result
+ let wrap txt
+ | beamer && "notes" `elem` classes
+ = pure ("\\note" <> braces txt) -- speaker notes
+ | "ref-" `T.isPrefixOf` identifier
+ = do
+ lab <- toLabel identifier
+ pure $ ("\\bibitem" <> brackets "\\citeproctext"
+ <> braces (literal lab)) $$ txt
+ | otherwise = do
+ linkAnchor <- hypertarget identifier
+ pure $ linkAnchor $$ txt
+ wrapDiv (identifier,classes,kvs) result >>= wrap
blockToLaTeX (Plain lst) =
inlineListToLaTeX lst
-- . . . indicates pause in beamer slides
@@ -816,12 +824,14 @@ inlineToLaTeX (Subscript lst) =
inlineToLaTeX (SmallCaps lst) =
inCmd "textsc"<$> inlineListToLaTeX lst
inlineToLaTeX (Cite cits lst) = do
- st <- get
- let opts = stOptions st
- case writerCiteMethod opts of
- Natbib -> citationsToNatbib inlineListToLaTeX cits
- Biblatex -> citationsToBiblatex inlineListToLaTeX cits
- _ -> inlineListToLaTeX lst
+ opts <- gets stOptions
+ modify $ \st -> st{ stInCite = True }
+ res <- case writerCiteMethod opts of
+ Natbib -> citationsToNatbib inlineListToLaTeX cits
+ Biblatex -> citationsToBiblatex inlineListToLaTeX cits
+ _ -> inlineListToLaTeX lst
+ modify $ \st -> st{ stInCite = False }
+ pure res
inlineToLaTeX (Code (_,classes,kvs) str) = do
opts <- gets stOptions
@@ -945,11 +955,14 @@ inlineToLaTeX (Link (id',_,_) txt (src,_)) =
Just ('#', ident) -> do
contents <- inlineListToLaTeX txt
lab <- toLabel ident
+ inCite <- gets stInCite
beamer <- gets stBeamer
return $
- if beamer
- then text "\\hyperlink" <> braces (literal lab) <> braces contents
- else text "\\hyperref" <> brackets (literal lab) <> braces contents
+ if inCite && "#ref-" `T.isPrefixOf` src
+ then "\\citeproc" <> braces (literal lab) <> braces contents
+ else if beamer
+ then "\\hyperlink" <> braces (literal lab) <> braces contents
+ else "\\hyperref" <> brackets (literal lab) <> braces contents
_ -> case txt of
[Str x] | unEscapeString (T.unpack x) == unEscapeString (T.unpack src) -> -- autolink
do modify $ \s -> s{ stUrl = True }
diff --git a/src/Text/Pandoc/Writers/LaTeX/Types.hs b/src/Text/Pandoc/Writers/LaTeX/Types.hs
index 97ac1dcf9..0e0582948 100644
--- a/src/Text/Pandoc/Writers/LaTeX/Types.hs
+++ b/src/Text/Pandoc/Writers/LaTeX/Types.hs
@@ -26,6 +26,7 @@ data WriterState =
, stInHeading :: Bool -- ^ true if in a section heading
, stInItem :: Bool -- ^ true if in \item[..]
, stInFigure :: Bool -- ^ true if in figure environment
+ , stInCite :: Bool -- ^ true if in a Cite
, stNotes :: [Doc Text] -- ^ notes in a minipage
, stOLLevel :: Int -- ^ level of ordered list nesting
, stOptions :: WriterOptions -- ^ writer options, so they don't have to
@@ -61,6 +62,7 @@ startingState options =
, stInMinipage = False
, stInItem = False
, stInFigure = False
+ , stInCite = False
, stNotes = []
, stOLLevel = 1
, stOptions = options