Skip to content

Commit 095ea7b

Browse files
Add initial support for Mermaid
Requires mermaid-cli to be installed and `mmdc` command to be available.
1 parent 21a1508 commit 095ea7b

File tree

9 files changed

+92
-2
lines changed

9 files changed

+92
-2
lines changed

example-config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,7 @@ sageplot:
146146
d2:
147147
executable: d2
148148
command_line_arguments:
149+
150+
mermaid:
151+
executable: mmdc
152+
command_line_arguments:

pandoc-plot.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ library
8585
Text.Pandoc.Filter.Plot.Renderers.SageMath
8686
Text.Pandoc.Filter.Plot.Renderers.D2
8787
Text.Pandoc.Filter.Plot.Renderers.Asymptote
88+
Text.Pandoc.Filter.Plot.Renderers.Mermaid
8889
Text.Pandoc.Filter.Plot.Monad
8990
Text.Pandoc.Filter.Plot.Monad.Logging
9091
Text.Pandoc.Filter.Plot.Monad.Types

src/Text/Pandoc/Filter/Plot/Configuration.hs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ defaultConfiguration =
6666
sagemathPreamble = mempty,
6767
d2Preamble = mempty,
6868
asyPreamble = mempty,
69+
mermaidPreamble = mempty,
6970
-- Executables
7071
matplotlibExe = python,
7172
matlabExe = "matlab",
@@ -82,6 +83,7 @@ defaultConfiguration =
8283
sagemathExe = "sage",
8384
d2Exe = "d2",
8485
asyExe = "asy",
86+
mermaidExe = "mmdc",
8587
-- Command line arguments
8688
matplotlibCmdArgs = mempty,
8789
matlabCmdArgs = mempty,
@@ -98,6 +100,7 @@ defaultConfiguration =
98100
sagemathCmdArgs = mempty,
99101
d2CmdArgs = mempty,
100102
asyCmdArgs = mempty,
103+
mermaidCmdArgs = mempty,
101104
-- Extras
102105
matplotlibTightBBox = False,
103106
matplotlibTransparent = False
@@ -159,7 +162,8 @@ data ConfigPrecursor = ConfigPrecursor
159162
_plantumlPrec :: !PlantUMLPrecursor,
160163
_sagemathPrec :: !SageMathPrecursor,
161164
_d2Prec :: !D2Precursor,
162-
_asyPrec :: !AsyPrecursor
165+
_asyPrec :: !AsyPrecursor,
166+
_mermaidPrec :: !MermaidPrecursor
163167
}
164168

165169
defaultConfigPrecursor :: ConfigPrecursor
@@ -188,7 +192,8 @@ defaultConfigPrecursor =
188192
_plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),
189193
_sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration),
190194
_d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration),
191-
_asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration)
195+
_asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration),
196+
_mermaidPrec = MermaidPrecursor Nothing (mermaidExe defaultConfiguration) (mermaidCmdArgs defaultConfiguration)
192197
}
193198

194199
data LoggingPrecursor = LoggingPrecursor
@@ -233,6 +238,8 @@ data D2Precursor = D2Precursor {_d2Preamble :: !(Maybe FilePath), _d2Exe :: !Fil
233238

234239
data AsyPrecursor = AsyPrecursor {_asyPreamble :: !(Maybe FilePath), _asyExe :: !FilePath, _asyCmdArgs :: !Text}
235240

241+
data MermaidPrecursor = MermaidPrecursor {_mermaidPreamble :: !(Maybe FilePath), _mermaidExe :: !FilePath, _mermaidCmdArgs :: !Text}
242+
236243
instance FromJSON LoggingPrecursor where
237244
parseJSON (Object v) =
238245
LoggingPrecursor
@@ -309,6 +316,10 @@ instance FromJSON AsyPrecursor where
309316
parseJSON (Object v) = AsyPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= asyExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= asyCmdArgs defaultConfiguration
310317
parseJSON _ = fail $ mconcat ["Could not parse ", show Asymptote, " configuration."]
311318

319+
instance FromJSON MermaidPrecursor where
320+
parseJSON (Object v) = MermaidPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= mermaidExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= mermaidCmdArgs defaultConfiguration
321+
parseJSON _ = fail $ mconcat ["Could not parse ", show Mermaid, " configuration."]
322+
312323
toolkitAsKey :: Toolkit -> Key
313324
toolkitAsKey = fromString . unpack . cls
314325

@@ -340,6 +351,7 @@ instance FromJSON ConfigPrecursor where
340351
_sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor
341352
_d2Prec <- v .:? toolkitAsKey D2 .!= _d2Prec defaultConfigPrecursor
342353
_asyPrec <- v .:? toolkitAsKey Asymptote .!= _asyPrec defaultConfigPrecursor
354+
_mermaidPrec <- v .:? toolkitAsKey Mermaid .!= _mermaidPrec defaultConfigPrecursor
343355

344356
return $ ConfigPrecursor {..}
345357
parseJSON _ = fail "Could not parse configuration."
@@ -376,6 +388,7 @@ renderConfig ConfigPrecursor {..} = do
376388
sagemathExe = _sagemathExe _sagemathPrec
377389
d2Exe = _d2Exe _d2Prec
378390
asyExe = _asyExe _asyPrec
391+
mermaidExe = _mermaidExe _mermaidPrec
379392

380393
matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec
381394
matlabCmdArgs = _matlabCmdArgs _matlabPrec
@@ -392,6 +405,7 @@ renderConfig ConfigPrecursor {..} = do
392405
sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec
393406
d2CmdArgs = _d2CmdArgs _d2Prec
394407
asyCmdArgs = _asyCmdArgs _asyPrec
408+
mermaidCmdArgs = _mermaidCmdArgs _mermaidPrec
395409

396410
matplotlibPreamble <- readPreamble (_matplotlibPreamble _matplotlibPrec)
397411
matlabPreamble <- readPreamble (_matlabPreamble _matlabPrec)
@@ -408,6 +422,7 @@ renderConfig ConfigPrecursor {..} = do
408422
sagemathPreamble <- readPreamble (_sagemathPreamble _sagemathPrec)
409423
d2Preamble <- readPreamble (_d2Preamble _d2Prec)
410424
asyPreamble <- readPreamble (_asyPreamble _asyPrec)
425+
mermaidPreamble <- readPreamble (_mermaidPreamble _mermaidPrec)
411426

412427
return Configuration {..}
413428
where

src/Text/Pandoc/Filter/Plot/Monad.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ executable tk = exeSelector tk <&> exeFromPath
284284
exeSelector SageMath = asksConfig sagemathExe
285285
exeSelector D2 = asksConfig d2Exe
286286
exeSelector Asymptote = asksConfig asyExe
287+
exeSelector Mermaid = asksConfig mermaidExe
287288

288289
-- | The @Configuration@ type holds the default values to use
289290
-- when running pandoc-plot. These values can be overridden in code blocks.
@@ -356,6 +357,8 @@ data Configuration = Configuration
356357
d2Preamble :: !Script,
357358
-- | The default preamble script for the Asymptote toolkit.
358359
asyPreamble :: !Script,
360+
-- | The default preamble script for the Mermaid toolkit.
361+
mermaidPreamble :: !Script,
359362
-- | The executable to use to generate figures using the matplotlib toolkit.
360363
matplotlibExe :: !FilePath,
361364
-- | The executable to use to generate figures using the MATLAB toolkit.
@@ -386,6 +389,8 @@ data Configuration = Configuration
386389
d2Exe :: !FilePath,
387390
-- | The executable to use to generate figures using Asymptote
388391
asyExe :: !FilePath,
392+
-- | The executable to use to generate figures using Mermaid
393+
mermaidExe :: !FilePath,
389394
-- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit
390395
matplotlibCmdArgs :: !Text,
391396
-- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.
@@ -416,6 +421,8 @@ data Configuration = Configuration
416421
d2CmdArgs :: !Text,
417422
-- | Command-line arguments to pass to the interpreter for the Asymptote toolkit.
418423
asyCmdArgs :: !Text,
424+
-- | Command-line arguments to pass to the interpreter for the Mermaid toolkit.
425+
mermaidCmdArgs :: !Text,
419426
-- | Whether or not to make Matplotlib figures tight by default.
420427
matplotlibTightBBox :: !Bool,
421428
-- | Whether or not to make Matplotlib figures transparent by default.

src/Text/Pandoc/Filter/Plot/Monad/Types.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ data Toolkit
6363
| SageMath
6464
| D2
6565
| Asymptote
66+
| Mermaid
6667
deriving (Bounded, Eq, Enum, Generic, Ord)
6768

6869
-- | This instance should only be used to display toolkit names
@@ -82,6 +83,7 @@ instance Show Toolkit where
8283
show SageMath = "SageMath"
8384
show D2 = "D2"
8485
show Asymptote = "Asymptote"
86+
show Mermaid = "Mermaid"
8587

8688
-- | Class name which will trigger the filter
8789
cls :: Toolkit -> Text
@@ -100,6 +102,7 @@ cls PlantUML = "plantuml"
100102
cls SageMath = "sageplot"
101103
cls D2 = "d2"
102104
cls Asymptote = "asy"
105+
cls Mermaid = "mermaid"
103106

104107
-- | Executable program, and sometimes the directory where it can be found.
105108
data Executable

src/Text/Pandoc/Filter/Plot/Renderers.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ import Text.Pandoc.Filter.Plot.Renderers.Asymptote
9999
( asymptote,
100100
asymptoteSupportedSaveFormats,
101101
)
102+
import Text.Pandoc.Filter.Plot.Renderers.Mermaid
103+
( mermaid,
104+
mermaidSupportedSaveFormats,
105+
)
102106
-- | Get the renderer associated with a toolkit.
103107
-- If the renderer has not been used before,
104108
-- initialize it and store where it is. It will be re-used.
@@ -118,6 +122,7 @@ renderer PlantUML = plantuml
118122
renderer SageMath = sagemath
119123
renderer D2 = d2
120124
renderer Asymptote = asymptote
125+
renderer Mermaid = mermaid
121126

122127
-- | Save formats supported by this renderer.
123128
supportedSaveFormats :: Toolkit -> [SaveFormat]
@@ -136,6 +141,7 @@ supportedSaveFormats PlantUML = plantumlSupportedSaveFormats
136141
supportedSaveFormats SageMath = sagemathSupportedSaveFormats
137142
supportedSaveFormats D2 = d2SupportedSaveFormats
138143
supportedSaveFormats Asymptote = asymptoteSupportedSaveFormats
144+
supportedSaveFormats Mermaid = mermaidSupportedSaveFormats
139145

140146
-- | The function that maps from configuration to the preamble.
141147
preambleSelector :: Toolkit -> (Configuration -> Script)
@@ -154,6 +160,7 @@ preambleSelector PlantUML = plantumlPreamble
154160
preambleSelector SageMath = sagemathPreamble
155161
preambleSelector D2 = d2Preamble
156162
preambleSelector Asymptote = asyPreamble
163+
preambleSelector Mermaid = mermaidPreamble
157164

158165
-- | Parse code block headers for extra attributes that are specific
159166
-- to this renderer. By default, no extra attributes are parsed.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE QuasiQuotes #-}
3+
{-# LANGUAGE RecordWildCards #-}
4+
{-# LANGUAGE NoImplicitPrelude #-}
5+
6+
-- |
7+
-- Module : $header$
8+
-- Copyright : (c) Sanchayan Maity, 2024 - present
9+
-- License : GNU GPL, version 2 or above
10+
-- Maintainer : sanchayan@sanchayanmaity.net
11+
-- Stability : internal
12+
-- Portability : portable
13+
--
14+
-- Rendering Mermaid plots code blocks
15+
module Text.Pandoc.Filter.Plot.Renderers.Mermaid
16+
( mermaid,
17+
mermaidSupportedSaveFormats,
18+
)
19+
where
20+
21+
import Data.Char (toLower)
22+
import Text.Pandoc.Filter.Plot.Renderers.Prelude
23+
24+
mermaid :: PlotM Renderer
25+
mermaid = do
26+
cmdargs <- asksConfig mermaidCmdArgs
27+
return
28+
$ Renderer
29+
{ rendererToolkit = Mermaid,
30+
rendererCapture = mermaidCapture,
31+
rendererCommand = mermaidCommand cmdargs,
32+
rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -V|],
33+
rendererSupportedSaveFormats = mermaidSupportedSaveFormats,
34+
rendererChecks = mempty,
35+
rendererLanguage = "mermaid",
36+
rendererComment = mempty,
37+
rendererScriptExtension = ".mermaid"
38+
}
39+
40+
mermaidSupportedSaveFormats :: [SaveFormat]
41+
mermaidSupportedSaveFormats = [PDF, PNG, SVG]
42+
43+
mermaidCommand :: Text -> OutputSpec -> Text
44+
mermaidCommand cmdargs OutputSpec {..} =
45+
let fmt = fmap toLower . show . saveFormat $ oFigureSpec
46+
in [st|#{pathToExe oExecutable} #{cmdargs} -q -e #{fmt} -i "#{oScriptPath}" -o "#{oFigurePath}"|]
47+
48+
-- Mermaid export is entirely based on command-line arguments
49+
-- so there is no need to modify the script itself.
50+
mermaidCapture :: FigureSpec -> FilePath -> Script
51+
mermaidCapture FigureSpec {..} _ = script

tests/Common.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ testFileInclusion tk =
123123
include SageMath = "tests/includes/sagemath.sage"
124124
include D2 = "tests/includes/d2-dd.d2"
125125
include Asymptote = "tests/includes/asymptote.asy"
126+
include Mermaid = "tests/includes/mermaid.mermaid"
126127

127128
-------------------------------------------------------------------------------
128129
-- Tests that the files are saved in all the advertised formats
@@ -423,6 +424,7 @@ trivialContent PlantUML = "@startuml\nAlice -> Bob: test\n@enduml"
423424
trivialContent SageMath = "G = plot(sin, 1, 10)"
424425
trivialContent D2 = "x -> y -> z"
425426
trivialContent Asymptote = "draw((0,0)--(1,0));"
427+
trivialContent Mermaid = "graph LR\n\tA --> B"
426428

427429
addCaption :: String -> Block -> Block
428430
addCaption caption (CodeBlock (id', cls, attrs) script) =

tests/includes/mermaid.mermaid

Whitespace-only changes.

0 commit comments

Comments
 (0)