Skip to content

add support for CJK & gnuplot/ditaa/mermaid/plantuml graph #3

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

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions simplex.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ Executable simplex
, mtl >= 2.0.1
, time >= 1.4
, random >= 1.0


, text >= 1.0
, MissingH >= 1.5.0
20 changes: 19 additions & 1 deletion src/Simplex/CmdLineOpts.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import Data.Maybe
data Flag = Help | Verbose | Print | NoClean
| Pdflatex String | Pdfcrop String
| Graphviz String | Gnuplot String
| Ditaa String | PlantUML String
| Mermaid String | Java String
| Watch Int | DryRun | Type String
| Density Int | Quality Int | Crop
| Convert String | Force | Version
Expand All @@ -38,7 +40,11 @@ data Opts = Opts {
optPdflatex :: String,
optPdfcrop :: String,
optGraphviz :: String,
optJava :: String,
optGnuplot :: String,
optDitaa :: String,
optPlantUML :: String,
optMermaid :: String,
optConvert :: String
}

Expand All @@ -62,6 +68,10 @@ defOpts = Opts {
optPdfcrop = "pdfcrop",
optGraphviz = "dot",
optGnuplot = "gnuplot",
optJava = "java",
optDitaa = "ditaa.jar",
optPlantUML = "plantuml.jar",
optMermaid = "mmdc",
optConvert = "convert"
}

Expand All @@ -74,12 +84,16 @@ cmdOpts = [
Option "p" ["print"] (NoArg Print) "Print processed tex to stdout.",
Option "c" ["crop"] (NoArg Crop) "Crops the document so that no margins are left.",
Option "f" ["force"] (NoArg Force) "Forces the creation of output files.",
Option "tT" ["type"] (ReqArg Type "") "Specify type of output (pdf, png, tex)",
Option "tT" ["type"] (ReqArg Type "") "Specify type of output (pdf, png, tex, html)",
Option "x" ["pdflatex"] (ReqArg Pdflatex "") "Path to `pdflatex' executable",
Option "k" ["pdfcrop"] (ReqArg Pdfcrop "") "Path to `pdfcrop'",
Option "z" ["graphviz"] (ReqArg Graphviz "") "Path to `dot' (graphviz)",
Option "g" ["gnuplot"] (ReqArg Gnuplot "") "Path to `gnuplot'",
Option "m" ["convert"] (ReqArg Convert "") "Path to `convert' (ImageMagick)",
Option "" ["java"] (ReqArg Java "") "Path to `java'",
Option "" ["mmdc"] (ReqArg Mermaid "") "Path to `mmdc'",
Option "" ["ditaa"] (ReqArg Ditaa "") "Path to ditaai.jar",
Option "" ["plantuml"] (ReqArg PlantUML "") "Path to plantuml.jar",
Option "w" ["watch"] (OptArg (Watch . read . fromMaybe "2000") "") "Watch files or folder (optionally amount of time in ms)",
Option "3" ["three-times"] (NoArg ThreeTimes) "Execute `pdflatex' three times instead of the default two times.",
Option "s" ["symbols"] (OptArg (ListSymbols . fromMaybe "\\%s\n") "") "Show a list of symboles known to simplex.",
Expand Down Expand Up @@ -115,6 +129,10 @@ parseArgs = do
Pdflatex c -> opts { optPdflatex = c }
Pdfcrop c -> opts { optPdfcrop = c }
Graphviz c -> opts { optGraphviz = c }
Java c -> opts { optJava = c }
Mermaid c -> opts { optMermaid = c }
Ditaa c -> opts { optDitaa = c }
PlantUML c -> opts { optPlantUML = c }
Gnuplot c -> opts { optGnuplot = c }
Convert c -> opts { optConvert = c }
parseOpts opts _ = opts
Expand Down
20 changes: 15 additions & 5 deletions src/Simplex/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ data State = SStart | SNewline | SControl | SControlAfter | SSymbol | SSpace | S
isBlock (TBlock _) = True
isBlock _ = False

convertAlias :: String -> String
convertAlias s =
case s of
".chapter" -> "!!"
".part" -> "!!!"
".section" -> "="
".subsection" -> "=="
".subsubsection" -> "==="
_ -> s

parse :: [Token] -> Document
parse = parse' $ Document [] []

Expand Down Expand Up @@ -314,7 +324,7 @@ lex' l c m SStart s@(x:xs)
| otherwise = lex' l (c+1) [x] SControl xs

lex' l c m SNewline s@(x:xs)
| x == '\n' = mkBlock m : lex' (l+1) 0 m SStart xs
| x == '\n' = mkBlock m : lex' (l+1) 0 [] SStart xs
| x == ' ' = lex' l (c+1) m SSpace xs
| x == '\t' = lex' l (c+1) ('\n':m) SSymbol xs
| isAlpha x = mkBlock m : lex' l (c+1) [x] SCommand xs
Expand All @@ -327,10 +337,10 @@ lex' l c m SCommand s@(x:xs)
| otherwise = lex' l (c+1) (x:m) SCommand xs

lex' l c m SControl s@(x:xs)
| x == ' ' && c < 4 = TControl (reverse m) : lex' l (c+1) [] SControlAfter xs
| x == ' ' = TControl (reverse m) : lex' l (c+1) [] SSymbol xs
| x == '\t' = TControl (reverse m) : lex' l (c+1) [] SSymbol xs
| x == '\n' = TControl (reverse m) : lex' (l+1) 0 [] SNewline xs
| x == ' ' && c < 4 = TControl (convertAlias (reverse m)) : lex' l (c+1) [] SControlAfter xs
| x == ' ' = TControl (convertAlias (reverse m)) : lex' l (c+1) [] SSymbol xs
| x == '\t' = TControl (convertAlias (reverse m)) : lex' l (c+1) [] SSymbol xs
| x == '\n' = TControl (convertAlias (reverse m)) : lex' (l+1) 0 [] SNewline xs
| otherwise = lex' l (c+1) (x:m) SControl xs

lex' l c m SControlAfter s@(x:xs)
Expand Down
110 changes: 94 additions & 16 deletions src/Simplex/Specials.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,60 @@ processSpecials o s (Document b m) = do
processSpecials' :: Opts -> Spec -> [Block] -> IO (Spec, [Block])

processSpecials' opts spec (BVerbatim "digraph" b : xs) = do
(spec', pdf) <- mkGraph "dot" "digraph" opts spec b
(spec', g) <- mkGraph "dot" "digraph" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null pdf
return (spec'', (if null g
then BVerbatim "error" "Graphviz .digraph failed"
else BCommand "image" [pdf]) : rest)
else BCommand "image" [g]) : rest)

processSpecials' opts spec (BVerbatim "graph" b : xs) = do
(spec', pdf) <- mkGraph "neato" "graph" opts spec b
(spec', g) <- mkGraph "neato" "graph" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null pdf
return (spec'', (if null g
then BVerbatim "error" "Graphviz .graph failed"
else BCommand "image" [pdf]) : rest)
else BCommand "image" [g]) : rest)

processSpecials' opts spec (BVerbatim "neato" b : xs) = do
(spec', pdf) <- mkGraph "neato" "" opts spec b
(spec', g) <- mkGraph "neato" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null pdf
return (spec'', (if null g
then BVerbatim "error" "Graphviz .neato failed"
else BCommand "image" [pdf]) : rest)
else BCommand "image" [g]) : rest)

processSpecials' opts spec (BVerbatim "dot" b : xs) = do
(spec', pdf) <- mkGraph "dot" "" opts spec b
(spec', g) <- mkGraph "dot" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null pdf
return (spec'', (if null g
then BVerbatim "error" "Graphviz .dot failed"
else BCommand "image" [pdf]) : rest)
else BCommand "image" [g]) : rest)

processSpecials' opts spec (BVerbatim "gnuplot" b : xs) = do
(spec', g) <- mkGraph "gnuplot" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null g
then BVerbatim "error" "Gnuplot .gp failed"
else BCommand "image" [g]) : rest)

processSpecials' opts spec (BVerbatim "mermaid" b : xs) = do
(spec', g) <- mkGraph "mermaid" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null g
then BVerbatim "error" "Mermaid .mmd failed"
else BCommand "image" [g]) : rest )

processSpecials' opts spec (BVerbatim "ditaa" b : xs) = do
(spec', png) <- mkGraph "ditaa" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null png
then BVerbatim "error" "ditaa .ditaa failed"
else BCommand "image" [png]) : rest )

processSpecials' opts spec (BVerbatim "plantuml" b : xs) = do
(spec', g) <- mkGraph "plantuml" "" opts spec b
(spec'', rest) <- processSpecials' opts spec' xs
return (spec'', (if null g
then BVerbatim "error" "plantuml .plantuml failed"
else BCommand "image" [g]) : rest )

processSpecials' opts spec (x : xs) = do
(spec', rest) <- processSpecials' opts spec xs
Expand All @@ -78,10 +106,60 @@ randomString n = do

mkGraph e g opts spec c = do
file <- randomString 10

let spec' = spec { sRemoveFiles = (file ++ ".pdf") : (file ++ ".dot") : sRemoveFiles spec }
case e of
"dot" -> mkGraphDot e file g opts spec c
"neato" -> mkGraphDot e file g opts spec c
"gnuplot" -> mkGraphGnuPlot e file g opts spec c
"mermaid" -> mkGraphMermaid e file g opts spec c
"ditaa" -> mkGraphDitaa e file g opts spec c
"plantuml" -> mkGraphPlantUML e file g opts spec c
_ -> return (spec, [])


mkGraphDot e file g opts spec c = do
let spec' = if (optType opts == "html")
then spec { sRemoveFiles = (file ++ ".dot") : sRemoveFiles spec }
else spec { sRemoveFiles = (file ++ ".jpeg") : (file ++ ".dot") : sRemoveFiles spec}
writeFile (file ++ ".dot") (if null g then c else g ++ " G {\n" ++ c ++ "\n}\n")

r <- exec (optVerbose opts) (optGraphviz opts) ["-Tpdf", "-K" ++ e, file ++ ".dot", "-o" ++ file ++ ".pdf"]
return (spec', (either (const "") (const $ file ++ ".pdf") r))
r <- exec (optVerbose opts) (optGraphviz opts) ["-Tjpeg", "-K" ++ e, file ++ ".dot", "-o" ++ file ++ ".jpeg"]
return (spec', (either (const "") (const $ file ++ ".jpeg") r))

mkGraphGnuPlot e file g opts spec c = do
let spec' = if (optType opts == "html" )
then spec { sRemoveFiles = (file ++ ".gp") : sRemoveFiles spec }
else spec { sRemoveFiles = (file ++ ".jpeg") : (file ++ ".gp") : sRemoveFiles spec }
writeFile (file ++ ".gp") ("set terminal jpeg\n" ++ "set output \"" ++ file ++ ".jpeg" ++ "\"\n" ++c ++ "\n")

r <- exec (optVerbose opts) (optGnuplot opts) [file ++ ".gp"]
return (spec', (either (const "") (const $ file ++ ".jpeg") r))

mkGraphMermaid e file g opts spec c = do
let spec' = if (optType opts == "html")
then spec { sRemoveFiles = (file ++ ".mmd") : sRemoveFiles spec}
else spec { sRemoveFiles = (file ++ ".png") : (file ++ ".mmd") : sRemoveFiles spec}
writeFile (file ++ ".mmd") (c ++ "\n")

r <- exec (optVerbose opts) (optMermaid opts) ["-i", file ++ ".mmd" , "-o", file ++ ".png"]

return (spec', (either (const "") (const $ file ++ ".png") r))

mkGraphDitaa e file g opts spec c = do
let spec' = if (optType opts == "html")
then spec { sRemoveFiles = (file ++ ".ditaa") : sRemoveFiles spec}
else spec { sRemoveFiles = (file ++ ".png") : (file ++ ".ditaa") : sRemoveFiles spec}
writeFile (file ++ ".ditaa") (c ++ "\n")

r <- exec (optVerbose opts) (optJava opts) ["-jar", (optDitaa opts),file ++ ".ditaa", file ++ ".png"]

return (spec', (either (const "") (const $ file ++ ".png") r))

mkGraphPlantUML e file g opts spec c = do
let spec' = if (optType opts == "html")
then spec { sRemoveFiles = (file ++ ".plantuml") : sRemoveFiles spec }
else spec { sRemoveFiles = (file ++ ".png") : (file ++ ".plantuml") : sRemoveFiles spec }
writeFile (file ++ ".plantuml") ("@startuml\n" ++ c ++ "\n@enduml\n")

r <- exec (optVerbose opts) (optJava opts) ["-jar", (optPlantUML opts), file ++ ".plantuml"]

return (spec', (either (const "") (const $ file ++ ".png") r))
57 changes: 48 additions & 9 deletions src/Simplex/ToTeX.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{-# LANGUAGE Haskell2010 #-}

module Simplex.ToTeX (toTeX) where
module Simplex.ToTeX (toTeX, docProps) where

import Simplex.Parser
import Simplex.Config
Expand Down Expand Up @@ -115,13 +115,45 @@ packages = [("inputenc", "\\usepackage[utf8]{inputenc}\n"),

]

docProps doc@(Document blocks props) = props

toTeX cfg doc@(Document blocks props) = concat $ preamble $ toTeX' cfg' $ blocks
where
cfg' = config cfg doc
preamble xs =
documentClass cfg' props

: "\\usepackage{iftex}\n"
: "\\ifPDFTeX"
: "\\usepackage{lmodern} % pdflatex or dvi latex\n"
: "\\usepackage[T1]{fontenc}\n"
: "\\usepackage[utf8]{inputenc}\n"
: "\\else\n"
: "\\usepackage{fontspec} % XeLaTeX or LuaLaTeX\n"
: "\\fi\n"
: maybe
""
(\x -> "\\usepackage[heading = true ]{ctex}\n")
(lookup "cjk" props)
: "\\usepackage[\n"
: "latexmk\n"
: "]{lwarp}\n"
: maybe
""
(\x -> "\\setcounter{FileDepth}{" ++ x ++ "}\n")
(lookup "filedepth" props)
: maybe
""
(\x -> "\\setcounter{SideTOCDepth}{" ++ x ++ "}\n")
(lookup "sidetocdepth" props)
: maybe
""
(\x -> "\\boolfalse{FileSectionNames}\n")
(lookup "nofilesectionnames" props)
: maybe
""
(\x -> "\\CSSFilename{" ++ x ++ "}\n")
(lookup "css" props)
: maybe
""
(\x -> "\\usepackage[" ++ x ++ "]{babel}\n")
Expand All @@ -130,28 +162,31 @@ toTeX cfg doc@(Document blocks props) = concat $ preamble $ toTeX' cfg' $ blocks
: "\\usepackage{fancyhdr}\n"
: "\\usepackage{tabularx}\n"

: "\\usepackage{eurosym}\n"
: "\\DeclareUnicodeCharacter{20AC}{\\euro{}}\n"
: "%% \\usepackage{eurosym}\n"
: maybe
"%% \\DeclareUnicodeCharacter{20AC}{\\euro{}}\n"
(\x -> "")
(lookup "cjk" props)

: "\\usepackage{amsmath}\n"
: "\\usepackage{amsfonts}\n"
: "\\usepackage{amssymb}\n"

: "\\usepackage{stmaryrd}\n"
: "\\usepackage{wasysym}\n"
: "%% \\usepackage{wasysym}\n"

: "\\let\\EUR\\undefined\n"
: "\\usepackage{marvosym}\n"
: "%% \\let\\EUR\\undefined\n"
: "%% \\usepackage{marvosym}\n"

: "\\usepackage{verbatim}\n"
: "\\usepackage{listings}\n"
: "\\usepackage{multicol}\n"

: "\\usepackage[usenames,dvipsnames]{color}\n"
: "\\usepackage[table]{xcolor}\n"
: "\\usepackage{multirow}\n"
: "%% \\usepackage[table]{xcolor}\n"
: "%% \\usepackage{multirow}\n"

: "\\usepackage{lastpage}\n"
: "%% \\usepackage{lastpage}\n"
: "\\usepackage{graphicx}\n"
: maybe
"\\usepackage[section]{placeins}\n"
Expand Down Expand Up @@ -251,6 +286,10 @@ toTeX cfg doc@(Document blocks props) = concat $ preamble $ toTeX' cfg' $ blocks
(\x -> "\\setcounter{tocdepth}{" ++ x ++ "}\n")
(lookup "tocdepth" props)

: maybe
"\\newcommand{\\setkomavar}[2]{} %% FIXME: later\n"
(\x -> "")
(lookup "letter" props)
: maybe
""
(\x -> "\\setkomavar{fromaddress}{" ++ escapeTeX' "}\n" x)
Expand Down
1 change: 1 addition & 0 deletions src/Simplex/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ skipOneSpace s = s

removeIfExists :: String -> IO ()
removeIfExists file = do
print $ "removing file " ++ file
exists <- doesFileExist file
when exists (removeFile file)

Expand Down
Loading