Skip to content

Commit

Permalink
Add more equation templates
Browse files Browse the repository at this point in the history
See #444
  • Loading branch information
lierdakil committed Aug 31, 2024
1 parent 56c14dc commit f15f77c
Show file tree
Hide file tree
Showing 16 changed files with 169 additions and 36 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## Unreleased

- Add `eqnInlineTableTemplate` and `eqnDisplayTemplate` options.

- Tweak how equation templates work.

Cleaned-up and generalized the logic in equation templates. This should be
mostly backwards-compatible, however some exotic workflows may need minor
tweaks. Specific changes to look out for:

- `eqnBlockInlineMath` will affect formatting when `tableEqns: false`.
- `eqnInlineTemplate` has new template variables in scope: `t`, `nmi`,
`nmri`.
- `eqnBlockTemplate` has new template variables in scope: `e`, `ri`, `nmi`,
`nmri`.

## 0.3.17.1

- Fix images roundtripping through Markdown
Expand Down
55 changes: 43 additions & 12 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,15 +714,45 @@ See [Subfigures](#subfigures)

- `eqnInlineTemplate`, default `$$e$$$$equationNumberTeX$${$$i$$}`

A template to typeset math when `tableEqns` is `false`. Similar to `eqnIndexTemplate`, formatting is mostly ignored, due to it being typeset
inside a display math environment. However, most LaTeX should work (but backslashes need to be doubled). The following template variables are known:

- `ri`, "raw" index, before applying `eqnIndexTemplate`
- `i`, index after applying `eqnIndexTemplate`
- `e`, the equation itself
A template to typeset math when `tableEqns` is `false`. Similar to
`eqnIndexTemplate`, formatting is mostly ignored, due to it being typeset
inside a math environment. However, most LaTeX should work (but backslashes
need to be doubled). The following template variables are known:

- `e`, the equation itself,
- `t`, the same as `e`, for backwards compatibility,
- `i`, index after applying `eqnIndexTemplate`,
- `nmi`, same as `i`, but see `eqnDisplayTemplate`,
- `ri`, "raw" index, before applying `eqnIndexTemplate`,
- `nmri`, here, same as `ri`, but see `eqnDisplayTemplate`.

`eqnInlineTemplate` is ignored if `tableEqns` is `true`.

- `eqnInlineTableTemplate`, default `$$e$$`

A counterpart of `eqnInlineTemplate` for when `tableEqns` is `true`. Behaves
the same. The logic is split like this mostly for backwards compatibility, but it also allows specifying unambiguous defaults.

`eqnInlineTableTemplate` is ignored if `tableEqns` is `false`.

- `eqnDisplayTemplate`, default `$$e$$`

A template to typeset the math element produced by applying
`eqnInlineTemplate` or `eqnInlineTableTemplate`.

The output of this template must be a sequence of inline elements. If you
want to produce block elements, see `eqnBlockTemplate`.

The same template variables from `eqnInlineTemplate` are available, with the
following changes:

- `e` (and `t`) is now the formatted equation (as per `eqnInlineTemplate` or
`eqnInlineTableTemplate`) wrapped in a math environment (display or inline
depending on `eqnBlockInlineMath`),
- `i` and `ri` are now wrapped in a math environment (same type as `e`).

`eqnDisplayTemplate` is ignored if `tableEqns` is `true`.

- `eqnBlockTemplate`, default

```markdown
Expand All @@ -734,18 +764,19 @@ See [Subfigures](#subfigures)
+----------------------------------------------------------------+-----+
```
When used with `tableEqns`, a block to use to format equations. A table
by default, but could be literally any block. `$$t$$` stands in for the
equation itself, and `$$i$$` stands in for the equation number.
When used with `tableEqns`, a block to use to format equations. A table by
default, but could be literally any block or a sequence of blocks. The
behaviour is similar to `eqnDisplayTemplate`, but the elements produced are
block elements (as opposed to inline).

Note that the default contains a raw block to fix vertical alignment
in docx output. If you're not targeting docx, it will be ignored by pandoc.

`eqnBlockTemplate` is ignored if `tableEqns` is `false` (the default).

- `eqnBlockInlineMath`, default `False`: if you need to use
inline math while rendering equation block template. Useful, e.g., if you're
using raw ooxml and tabstops to align equations in docx. For example,
- `eqnBlockInlineMath`, default `False`: if you need to use inline math while
rendering equation templates. Useful, e.g., if you're using raw ooxml and
tabstops to align equations in docx. For example,

```yaml
tableEqns: true
Expand Down
7 changes: 4 additions & 3 deletions lib-internal/Text/Pandoc/CrossRef/References/Blocks.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-}

{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts, ScopedTypeVariables, LambdaCase #-}
{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts, ScopedTypeVariables
, LambdaCase, NamedFieldPuns #-}
module Text.Pandoc.CrossRef.References.Blocks
( replaceAll
) where
Expand Down Expand Up @@ -107,8 +108,8 @@ replaceInlineMany (Span spanAttr@(label,clss,attrs) [Math DisplayMath eq]:xs) =
, Span spanAttr [RawInline (Format "latex") eq]
, RawInline (Format "latex") $ "\\end{equation}"]
else do
(eq', idxStr) <- replaceEqn spanAttr eq
pure [Span (label,clss,setLabel opts idxStr attrs) [Math DisplayMath eq']]
ReplaceEqn{replaceEqnEq, replaceEqnIdx} <- replaceEqn eqnDisplayTemplate spanAttr eq
pure [Span (label,clss,setLabel opts replaceEqnIdx attrs) replaceEqnEq]
else noReplaceRecurse
replaceInlineMany _ = noReplaceRecurse

Expand Down
48 changes: 32 additions & 16 deletions lib-internal/Text/Pandoc/CrossRef/References/Blocks/Math.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-}

{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts #-}
{-# LANGUAGE Rank2Types, OverloadedStrings, FlexibleContexts, RecordWildCards #-}

module Text.Pandoc.CrossRef.References.Blocks.Math where

Expand All @@ -39,29 +39,45 @@ runBlockMath (label, cls, attrs) eq = do
opts <- ask
if tableEqns opts && not (isLatexFormat opts)
then do
(eq', idxStr) <- replaceEqn (label, cls, attrs) eq
let mathfmt = if eqnBlockInlineMath opts then InlineMath else DisplayMath
replaceNoRecurse $ Div (label,cls,setLabel opts idxStr attrs) $
applyTemplate [Math mathfmt $ stringify idxStr] [Math mathfmt eq']
$ eqnBlockTemplate opts
ReplaceEqn{..} <- replaceEqn eqnBlockTemplate (label, cls, attrs) eq
replaceNoRecurse $ Div (label,cls,setLabel opts replaceEqnIdx attrs) replaceEqnEq
else noReplaceRecurse

replaceEqn :: Attr -> T.Text -> WS (T.Text, [Inline])
replaceEqn (label, _, attrs) eq = do
data ReplaceEqn a = ReplaceEqn
{ replaceEqnEq :: [a]
, replaceEqnIdx :: [Inline]
}

replaceEqn :: MkTemplate a t => (Options -> t) -> Attr -> T.Text -> WS (ReplaceEqn a)
replaceEqn eqTemplate (label, _, attrs) eq = do
opts <- ask
let label' | T.null label = Left "eq"
| otherwise = Right label
idxStrRaw <- replaceAttr label' attrs [] SPfxEqn
let idxStr = applyTemplate' (M.fromDistinctAscList [("i", idxStrRaw)]) $ eqnIndexTemplate opts
eqTxt = applyTemplate' eqTxtVars $ eqnInlineTemplate opts :: [Inline]
eqTxtVars = M.fromDistinctAscList
[ ("e", [Str eq])
, ("i", idxStr)
, ("ri", idxStrRaw)
eqTxt :: [Inline]
eqTxt = applyTemplate' eqTxtVars $
if tableEqns opts
then eqnInlineTableTemplate opts
else eqnInlineTemplate opts
wrapMath x = [Math mathfmt $ stringify x]
commonVars eqn = M.fromList $
[ ("e", eqn)
, ("t", eqn) -- backwards compatibility for eqnBlockTemplate
, ("i", wrapMath idxStr)
, ("ri", wrapMath idxStrRaw)
, ("nmi", idxStr)
, ("nmri", idxStrRaw)
]
eq' | tableEqns opts = eq
| otherwise = stringify eqTxt
return (eq', idxStr)
eqTxtVars = commonVars [Str eq]
eqInline = applyTemplate' eqInlineVars $ eqTemplate opts
mathfmt = if eqnBlockInlineMath opts then InlineMath else DisplayMath
eqInlineVars = commonVars $ wrapMath eqTxt
pure $ ReplaceEqn
{ replaceEqnEq = eqInline
, replaceEqnIdx = idxStr
}


splitMath :: [Block] -> [Block]
splitMath (Para ils:xs)
Expand Down
2 changes: 2 additions & 0 deletions lib-internal/Text/Pandoc/CrossRef/Util/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ data Options = Options { cref :: Bool
, eqnBlockInlineMath :: Bool
, eqnIndexTemplate :: Template
, eqnInlineTemplate :: Template
, eqnInlineTableTemplate :: Template
, eqnDisplayTemplate :: Template
, refIndexTemplate :: Text -> Template
, subfigureRefIndexTemplate :: Template
, secHeaderTemplate :: Template
Expand Down
2 changes: 2 additions & 0 deletions lib-internal/Text/Pandoc/CrossRef/Util/Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ defaultMeta =
<> linkReferences False
<> nameInLink False
<> equationNumberTeX ("\\qquad" :: T.Text)
<> eqnDisplayTemplate (var "e")
<> eqnInlineTableTemplate (var "e")
where
var = displayMath
wordVerticalAlign = rawBlock "openxml" "<w:tcPr><w:vAlign w:val=\"center\"/></w:tcPr>"
1 change: 1 addition & 0 deletions lib-internal/Text/Pandoc/CrossRef/Util/Template.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
module Text.Pandoc.CrossRef.Util.Template
( Template
, BlockTemplate
, MkTemplate
, makeTemplate
, makeIndexedTemplate
, applyTemplate
Expand Down
12 changes: 9 additions & 3 deletions pandoc-crossref.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 2.0

-- This file has been generated from package.yaml by hpack version 0.36.0.
-- This file has been generated from package.yaml by hpack version 0.34.4.
--
-- see: https://github.com/sol/hpack

Expand Down Expand Up @@ -36,6 +36,12 @@ data-files:
test/m2m/eqnBlockTemplate/expect.md
test/m2m/eqnBlockTemplate/expect.tex
test/m2m/eqnBlockTemplate/input.md
test/m2m/eqnDisplayTemplate/expect.md
test/m2m/eqnDisplayTemplate/expect.tex
test/m2m/eqnDisplayTemplate/input.md
test/m2m/eqnInlineTableTemplate/expect.md
test/m2m/eqnInlineTableTemplate/expect.tex
test/m2m/eqnInlineTableTemplate/input.md
test/m2m/eqnInlineTemplate/expect.md
test/m2m/eqnInlineTemplate/expect.tex
test/m2m/eqnInlineTemplate/input.md
Expand Down Expand Up @@ -223,9 +229,9 @@ test-suite test-integrative
, pandoc-crossref
, pandoc-types ==1.23.*
, text >=1.2.2 && <2.2
default-language: Haskell2010
if flag(enable_flaky_tests)
cpp-options: -DFLAKY
default-language: Haskell2010

test-suite test-pandoc-crossref
type: exitcode-stdio-1.0
Expand All @@ -250,9 +256,9 @@ test-suite test-pandoc-crossref
, pandoc-crossref-internal
, pandoc-types ==1.23.*
, text >=1.2.2 && <2.2
default-language: Haskell2010
if flag(enable_flaky_tests)
cpp-options: -DFLAKY
default-language: Haskell2010

benchmark simple
type: exitcode-stdio-1.0
Expand Down
5 changes: 4 additions & 1 deletion test/m2m/eqnBlockTemplate/expect.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
::: {#eq:1}
$$\int_0^x e^x dx$$ $$(1)$$
[$$\int_0^x e^x dx$$]{.math-eq}
[$$\int_0^x e^x dx$$]{.math-eq-backwards-compat}
[$$(1)$$]{.math-eq-index-math} [(1)]{.math-eq-index-no-math}
[$$1$$]{.math-eq-index-raw-math} [1]{.math-eq-index-raw-no-math}
:::
8 changes: 7 additions & 1 deletion test/m2m/eqnBlockTemplate/input.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
---
eqnBlockTemplate: |
$$t$$ $$i$$
<span class="math-eq">$$e$$</span>
<span class="math-eq-backwards-compat">$$t$$</span>
<span class="math-eq-index-math">$$i$$</span>
<span class="math-eq-index-no-math">$$nmi$$</span>
<span class="math-eq-index-raw-math">$$ri$$</span>
<span class="math-eq-index-raw-no-math">$$nmri$$</span>
tableEqns: true
eqnDisplayTemplate: foo # ensure it's ignored
---

$$\int_0^x e^x dx$${#eq:1}
6 changes: 6 additions & 0 deletions test/m2m/eqnDisplayTemplate/expect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[[ [$$e^{i\pi} = -1\qquad{(1)}$$]{.math-eq}
[$$(1)$$]{.math-eq-index-math} [(1)]{.math-eq-index-no-math}
[$$1$$]{.math-eq-index-raw-math} [1]{.math-eq-index-raw-no-math}
]{.math-eq-container}]{#eq:euler}

eq. 1
3 changes: 3 additions & 0 deletions test/m2m/eqnDisplayTemplate/expect.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\begin{equation}\phantomsection\label{eq:euler}{e^{i\pi} = -1}\end{equation}

eq.~\ref{eq:euler}
14 changes: 14 additions & 0 deletions test/m2m/eqnDisplayTemplate/input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
eqnDisplayTemplate: |
<span class="math-eq-container">
<span class="math-eq">$$e$$</span>
<span class="math-eq-index-math">$$i$$</span>
<span class="math-eq-index-no-math">$$nmi$$</span>
<span class="math-eq-index-raw-math">$$ri$$</span>
<span class="math-eq-index-raw-no-math">$$nmri$$</span>
</span>
---

$$e^{i\pi} = -1$${#eq:euler}

@eq:euler
8 changes: 8 additions & 0 deletions test/m2m/eqnInlineTableTemplate/expect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
::: {#eq:euler}
+:-------------------------------------------------------------:+-----:+
| $$ e^{i\pi} = -1 (1) (1) 1 1 $$ | $$( |
| | 1)$$ |
+---------------------------------------------------------------+------+
:::

eq. 1
3 changes: 3 additions & 0 deletions test/m2m/eqnInlineTableTemplate/expect.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
\begin{equation}\phantomsection\label{eq:euler}{e^{i\pi} = -1}\end{equation}

eq.~\ref{eq:euler}
15 changes: 15 additions & 0 deletions test/m2m/eqnInlineTableTemplate/input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
eqnInlineTableTemplate: |
<span class="math-eq-container">
<span class="math-eq">$$e$$</span>
<span class="math-eq-index-math">$$i$$</span>
<span class="math-eq-index-no-math">$$nmi$$</span>
<span class="math-eq-index-raw-math">$$ri$$</span>
<span class="math-eq-index-raw-no-math">$$nmri$$</span>
</span>
tableEqns: true
---

$$e^{i\pi} = -1$${#eq:euler}

@eq:euler

0 comments on commit f15f77c

Please sign in to comment.