Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial support for Mermaid #74

Merged
merged 2 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions example-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,7 @@ sageplot:
d2:
executable: d2
command_line_arguments:

mermaid:
executable: mmdc
command_line_arguments:
1 change: 1 addition & 0 deletions pandoc-plot.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ library
Text.Pandoc.Filter.Plot.Renderers.SageMath
Text.Pandoc.Filter.Plot.Renderers.D2
Text.Pandoc.Filter.Plot.Renderers.Asymptote
Text.Pandoc.Filter.Plot.Renderers.Mermaid
Text.Pandoc.Filter.Plot.Monad
Text.Pandoc.Filter.Plot.Monad.Logging
Text.Pandoc.Filter.Plot.Monad.Types
Expand Down
21 changes: 18 additions & 3 deletions src/Text/Pandoc/Filter/Plot/Configuration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ defaultConfiguration =
sagemathPreamble = mempty,
d2Preamble = mempty,
asyPreamble = mempty,
mermaidPreamble = mempty,
-- Executables
matplotlibExe = python,
matlabExe = "matlab",
Expand All @@ -82,6 +83,7 @@ defaultConfiguration =
sagemathExe = "sage",
d2Exe = "d2",
asyExe = "asy",
mermaidExe = "mmdc",
-- Command line arguments
matplotlibCmdArgs = mempty,
matlabCmdArgs = mempty,
Expand All @@ -98,6 +100,7 @@ defaultConfiguration =
sagemathCmdArgs = mempty,
d2CmdArgs = mempty,
asyCmdArgs = mempty,
mermaidCmdArgs = mempty,
-- Extras
matplotlibTightBBox = False,
matplotlibTransparent = False
Expand Down Expand Up @@ -159,7 +162,8 @@ data ConfigPrecursor = ConfigPrecursor
_plantumlPrec :: !PlantUMLPrecursor,
_sagemathPrec :: !SageMathPrecursor,
_d2Prec :: !D2Precursor,
_asyPrec :: !AsyPrecursor
_asyPrec :: !AsyPrecursor,
_mermaidPrec :: !MermaidPrecursor
}

defaultConfigPrecursor :: ConfigPrecursor
Expand Down Expand Up @@ -188,7 +192,8 @@ defaultConfigPrecursor =
_plantumlPrec = PlantUMLPrecursor Nothing (plantumlExe defaultConfiguration) (plantumlCmdArgs defaultConfiguration),
_sagemathPrec = SageMathPrecursor Nothing (sagemathExe defaultConfiguration) (sagemathCmdArgs defaultConfiguration),
_d2Prec = D2Precursor Nothing (d2Exe defaultConfiguration) (d2CmdArgs defaultConfiguration),
_asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration)
_asyPrec = AsyPrecursor Nothing (asyExe defaultConfiguration) (asyCmdArgs defaultConfiguration),
_mermaidPrec = MermaidPrecursor Nothing (mermaidExe defaultConfiguration) (mermaidCmdArgs defaultConfiguration)
}

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

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

data MermaidPrecursor = MermaidPrecursor {_mermaidPreamble :: !(Maybe FilePath), _mermaidExe :: !FilePath, _mermaidCmdArgs :: !Text}

instance FromJSON LoggingPrecursor where
parseJSON (Object v) =
LoggingPrecursor
Expand Down Expand Up @@ -303,12 +310,16 @@ instance FromJSON SageMathPrecursor where

instance FromJSON D2Precursor where
parseJSON (Object v) = D2Precursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= d2Exe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= d2CmdArgs defaultConfiguration
parseJSON _ = fail $ mconcat ["Could not parse ", show SageMath, " configuration."]
parseJSON _ = fail $ mconcat ["Could not parse ", show D2, " configuration."]

instance FromJSON AsyPrecursor where
parseJSON (Object v) = AsyPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= asyExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= asyCmdArgs defaultConfiguration
parseJSON _ = fail $ mconcat ["Could not parse ", show Asymptote, " configuration."]

instance FromJSON MermaidPrecursor where
parseJSON (Object v) = MermaidPrecursor <$> v .:? asKey PreambleK <*> v .:? asKey ExecutableK .!= mermaidExe defaultConfiguration <*> v .:? asKey CommandLineArgsK .!= mermaidCmdArgs defaultConfiguration
parseJSON _ = fail $ mconcat ["Could not parse ", show Mermaid, " configuration."]

toolkitAsKey :: Toolkit -> Key
toolkitAsKey = fromString . unpack . cls

Expand Down Expand Up @@ -340,6 +351,7 @@ instance FromJSON ConfigPrecursor where
_sagemathPrec <- v .:? toolkitAsKey SageMath .!= _sagemathPrec defaultConfigPrecursor
_d2Prec <- v .:? toolkitAsKey D2 .!= _d2Prec defaultConfigPrecursor
_asyPrec <- v .:? toolkitAsKey Asymptote .!= _asyPrec defaultConfigPrecursor
_mermaidPrec <- v .:? toolkitAsKey Mermaid .!= _mermaidPrec defaultConfigPrecursor

return $ ConfigPrecursor {..}
parseJSON _ = fail "Could not parse configuration."
Expand Down Expand Up @@ -376,6 +388,7 @@ renderConfig ConfigPrecursor {..} = do
sagemathExe = _sagemathExe _sagemathPrec
d2Exe = _d2Exe _d2Prec
asyExe = _asyExe _asyPrec
mermaidExe = _mermaidExe _mermaidPrec

matplotlibCmdArgs = _matplotlibCmdArgs _matplotlibPrec
matlabCmdArgs = _matlabCmdArgs _matlabPrec
Expand All @@ -392,6 +405,7 @@ renderConfig ConfigPrecursor {..} = do
sagemathCmdArgs = _sagemathCmdArgs _sagemathPrec
d2CmdArgs = _d2CmdArgs _d2Prec
asyCmdArgs = _asyCmdArgs _asyPrec
mermaidCmdArgs = _mermaidCmdArgs _mermaidPrec

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

return Configuration {..}
where
Expand Down
7 changes: 7 additions & 0 deletions src/Text/Pandoc/Filter/Plot/Monad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ executable tk = exeSelector tk <&> exeFromPath
exeSelector SageMath = asksConfig sagemathExe
exeSelector D2 = asksConfig d2Exe
exeSelector Asymptote = asksConfig asyExe
exeSelector Mermaid = asksConfig mermaidExe

-- | The @Configuration@ type holds the default values to use
-- when running pandoc-plot. These values can be overridden in code blocks.
Expand Down Expand Up @@ -356,6 +357,8 @@ data Configuration = Configuration
d2Preamble :: !Script,
-- | The default preamble script for the Asymptote toolkit.
asyPreamble :: !Script,
-- | The default preamble script for the Mermaid toolkit.
mermaidPreamble :: !Script,
-- | The executable to use to generate figures using the matplotlib toolkit.
matplotlibExe :: !FilePath,
-- | The executable to use to generate figures using the MATLAB toolkit.
Expand Down Expand Up @@ -386,6 +389,8 @@ data Configuration = Configuration
d2Exe :: !FilePath,
-- | The executable to use to generate figures using Asymptote
asyExe :: !FilePath,
-- | The executable to use to generate figures using Mermaid
mermaidExe :: !FilePath,
-- | Command-line arguments to pass to the Python interpreter for the Matplotlib toolkit
matplotlibCmdArgs :: !Text,
-- | Command-line arguments to pass to the interpreter for the MATLAB toolkit.
Expand Down Expand Up @@ -416,6 +421,8 @@ data Configuration = Configuration
d2CmdArgs :: !Text,
-- | Command-line arguments to pass to the interpreter for the Asymptote toolkit.
asyCmdArgs :: !Text,
-- | Command-line arguments to pass to the interpreter for the Mermaid toolkit.
mermaidCmdArgs :: !Text,
-- | Whether or not to make Matplotlib figures tight by default.
matplotlibTightBBox :: !Bool,
-- | Whether or not to make Matplotlib figures transparent by default.
Expand Down
3 changes: 3 additions & 0 deletions src/Text/Pandoc/Filter/Plot/Monad/Types.hs
SanchayanMaity marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ data Toolkit
| SageMath
| D2
| Asymptote
| Mermaid
deriving (Bounded, Eq, Enum, Generic, Ord)

-- | This instance should only be used to display toolkit names
Expand All @@ -82,6 +83,7 @@ instance Show Toolkit where
show SageMath = "SageMath"
show D2 = "D2"
show Asymptote = "Asymptote"
show Mermaid = "Mermaid"

-- | Class name which will trigger the filter
cls :: Toolkit -> Text
Expand All @@ -100,6 +102,7 @@ cls PlantUML = "plantuml"
cls SageMath = "sageplot"
cls D2 = "d2"
cls Asymptote = "asy"
cls Mermaid = "mermaid"

-- | Executable program, and sometimes the directory where it can be found.
data Executable
Expand Down
7 changes: 7 additions & 0 deletions src/Text/Pandoc/Filter/Plot/Renderers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ import Text.Pandoc.Filter.Plot.Renderers.Asymptote
( asymptote,
asymptoteSupportedSaveFormats,
)
import Text.Pandoc.Filter.Plot.Renderers.Mermaid
( mermaid,
mermaidSupportedSaveFormats,
)
-- | Get the renderer associated with a toolkit.
-- If the renderer has not been used before,
-- initialize it and store where it is. It will be re-used.
Expand All @@ -118,6 +122,7 @@ renderer PlantUML = plantuml
renderer SageMath = sagemath
renderer D2 = d2
renderer Asymptote = asymptote
renderer Mermaid = mermaid

-- | Save formats supported by this renderer.
supportedSaveFormats :: Toolkit -> [SaveFormat]
Expand All @@ -136,6 +141,7 @@ supportedSaveFormats PlantUML = plantumlSupportedSaveFormats
supportedSaveFormats SageMath = sagemathSupportedSaveFormats
supportedSaveFormats D2 = d2SupportedSaveFormats
supportedSaveFormats Asymptote = asymptoteSupportedSaveFormats
supportedSaveFormats Mermaid = mermaidSupportedSaveFormats

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

-- | Parse code block headers for extra attributes that are specific
-- to this renderer. By default, no extra attributes are parsed.
Expand Down
51 changes: 51 additions & 0 deletions src/Text/Pandoc/Filter/Plot/Renderers/Mermaid.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- |
-- Module : $header$
-- Copyright : (c) Sanchayan Maity, 2024 - present
-- License : GNU GPL, version 2 or above
-- Maintainer : [email protected]
-- Stability : internal
-- Portability : portable
--
-- Rendering Mermaid plots code blocks
module Text.Pandoc.Filter.Plot.Renderers.Mermaid
( mermaid,
mermaidSupportedSaveFormats,
)
where

import Data.Char (toLower)
import Text.Pandoc.Filter.Plot.Renderers.Prelude

mermaid :: PlotM Renderer
mermaid = do
cmdargs <- asksConfig mermaidCmdArgs
return
$ Renderer
{ rendererToolkit = Mermaid,
rendererCapture = mermaidCapture,
rendererCommand = mermaidCommand cmdargs,
rendererAvailability = CommandSuccess $ \exe -> [st|#{pathToExe exe} -V|],
rendererSupportedSaveFormats = mermaidSupportedSaveFormats,
rendererChecks = mempty,
rendererLanguage = "mermaid",
rendererComment = mempty,
rendererScriptExtension = ".mermaid"
}

mermaidSupportedSaveFormats :: [SaveFormat]
mermaidSupportedSaveFormats = [PDF, PNG, SVG]

mermaidCommand :: Text -> OutputSpec -> Text
mermaidCommand cmdargs OutputSpec {..} =
let fmt = fmap toLower . show . saveFormat $ oFigureSpec
in [st|#{pathToExe oExecutable} #{cmdargs} -q -e #{fmt} -i "#{oScriptPath}" -o "#{oFigurePath}"|]

-- Mermaid export is entirely based on command-line arguments
-- so there is no need to modify the script itself.
mermaidCapture :: FigureSpec -> FilePath -> Script
mermaidCapture FigureSpec {..} _ = script
2 changes: 2 additions & 0 deletions tests/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
)
_ <- runPlotM Nothing defaultTestConfig $ make cb
inclusion <- readFile (include tk)
sourcePath <- head . filter (isExtensionOf ".src.html") <$> listDirectory tempDir

Check warning on line 107 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest, 9.8.2)

In the use of ‘head’

Check warning on line 107 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest, 9.8.2)

In the use of ‘head’

Check warning on line 107 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest, 9.8.2)

In the use of ‘head’
src <- readFile (tempDir </> sourcePath)
assertIsInfix inclusion src
where
Expand All @@ -123,6 +123,7 @@
include SageMath = "tests/includes/sagemath.sage"
include D2 = "tests/includes/d2-dd.d2"
include Asymptote = "tests/includes/asymptote.asy"
include Mermaid = "tests/includes/mermaid.mermaid"

-------------------------------------------------------------------------------
-- Tests that the files are saved in all the advertised formats
Expand Down Expand Up @@ -173,7 +174,7 @@
if null incompatibleFormats
then return ()
else do
let fmt = head incompatibleFormats

Check warning on line 177 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest, 9.8.2)

In the use of ‘head’

Check warning on line 177 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest, 9.8.2)

In the use of ‘head’

Check warning on line 177 in tests/Common.hs

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest, 9.8.2)

In the use of ‘head’
cb = addSaveFormat fmt $ codeBlock tk (trivialContent tk)

result <- runPlotM Nothing defaultTestConfig $ makeEither cb
Expand Down Expand Up @@ -423,6 +424,7 @@
trivialContent SageMath = "G = plot(sin, 1, 10)"
trivialContent D2 = "x -> y -> z"
trivialContent Asymptote = "draw((0,0)--(1,0));"
trivialContent Mermaid = "graph LR\n\tA --> B"

addCaption :: String -> Block -> Block
addCaption caption (CodeBlock (id', cls, attrs) script) =
Expand Down
Empty file added tests/includes/mermaid.mermaid
Empty file.
Loading