summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-10-10 22:14:45 +0200
committerHugo Hörnquist <hugo@lysator.liu.se>2023-10-10 22:14:45 +0200
commit7af368e7fc96b3bc6dfc56e90fb0f7d4de6cc926 (patch)
treec2102212221e89aab0f5efb3828ff83d34b40169
parentAdd dependency info. (diff)
downloadvimwiki-scripts-7af368e7fc96b3bc6dfc56e90fb0f7d4de6cc926.tar.gz
vimwiki-scripts-7af368e7fc96b3bc6dfc56e90fb0f7d4de6cc926.tar.xz
Split Handlingar into multiple files.
This is the first step to allow multiple render backends.
-rw-r--r--hs/src/Handlingar.hs312
-rw-r--r--hs/src/Handlingar/Common.hs187
-rw-r--r--hs/src/Handlingar/TexOutput.hs153
-rw-r--r--hs/vimwiki.cabal2
4 files changed, 349 insertions, 305 deletions
diff --git a/hs/src/Handlingar.hs b/hs/src/Handlingar.hs
index 4da8541..cb126b7 100644
--- a/hs/src/Handlingar.hs
+++ b/hs/src/Handlingar.hs
@@ -9,55 +9,13 @@ import Prelude hiding
, writeFile
)
-import Control.Monad.State.Lazy
-import Data.ByteString (ByteString)
-import Data.Default (def)
-import Data.Map ((!))
-import Data.Maybe (fromMaybe)
-import Data.Set (Set)
-import Data.String (IsString(fromString))
-import Data.Text (Text, pack, unpack, strip)
-import Data.Text.Encoding (decodeLatin1, decodeUtf8)
-import Data.Text.Encoding.Base64 (encodeBase64)
import Data.Text.IO (putStrLn, writeFile)
-import Mail (getMail, MailPart(..), getBytes, getFile)
-import Network.URI (URI, parseURI, uriScheme, uriPath)
-import Network.URI.Encode (encodeWith, decode)
-import System.Directory (makeAbsolute, createDirectoryIfMissing, copyFile)
-import System.FilePath (dropFileName, takeExtension, (<.>), takeBaseName)
-import System.IO (Handle)
+import System.FilePath (dropFileName)
import System.Posix.Directory (changeWorkingDirectory, getWorkingDirectory)
-import System.Process
- ( createProcess
- , cleanupProcess
- , shell
- , CreateProcess(cwd)
- , waitForProcess
- )
-import Tex (toTex, TeX (..))
-import Text.DocTemplates (toVal, Val(SimpleVal, ListVal), Context(Context))
-import Text.Pandoc
- ( runIOorExplode
- , readVimwiki
- , readHtml
- , WriterOptions( writerTemplate
- , writerListings
- , writerVariables)
- , PandocMonad
- , PandocIO
- , writePlain
- )
-import Text.Pandoc.Builder
-import Text.Pandoc.Extract (AppendixItem, getHeadingData, extractKV)
-import Text.Pandoc.Items (comment, dlist)
-import Text.Pandoc.Templates (compileDefaultTemplate)
-import Text.Pandoc.Walk (walk, walkM)
-import Text.Pandoc.Writers.LaTeX (writeLaTeX)
-import Util (joinBy, splitBy, uncurry3, (<&>))
-import qualified Data.Map.Lazy as Map
-import qualified Data.Set as Set
+import Text.Pandoc (runIOorExplode)
import qualified Data.Text.IO as T
-import Text.URI.Decode (urlDecode)
+
+import Handlingar.TexOutput (handleTex)
-- TODO pandoc possibly contains a better way to handle attachements,
-- something about media bag
@@ -71,229 +29,9 @@ import Text.URI.Decode (urlDecode)
-- - Mail, where mail attachements are copied verbatim
-- other attachements become mail attachments
--- Takes a list of Pandoc Blocks starting with a heading. If the first
--- element after the heading is a Definition list, then parse that to
--- kv-pairs, and return it also.
-handleBlocks :: PandocMonad m => [Block] -> m (Text, [(Text, Text)], [Block])
-handleBlocks (head:DefinitionList definitions:blocks) = do
- heading <- writePlain def (Pandoc nullMeta [head])
- kvs <- mapM extractKV definitions
- return (strip heading, kvs, blocks)
-handleBlocks (head:blocks) = do
- heading <- writePlain def (Pandoc nullMeta [head])
- return (strip heading, [], blocks)
-handleBlocks blocks = return ("Heading missing", [], blocks)
-
-buildPrimary :: PandocMonad m
- => Pandoc
- -> m (Pandoc, [AppendixItem])
-buildPrimary (Pandoc meta blocks) = do
- -- Pandoc meta blocks <- reader def text
- -- let Just blocks = getHeadingData heading blocks
- (heading, kvs, wantedBlocks') <- handleBlocks blocks
- let (pandoc, appendices) = replaceLinks $ Pandoc meta wantedBlocks'
-
- let pandoc' = foldl (flip . uncurry $ setMeta) pandoc
- $ ("title", heading) : kvs
- return (pandoc', appendices)
-
-
-rewriteLink :: Inline -> State [AppendixItem] Inline
-rewriteLink (Link _ is (target, "wikilink")) = do
- let appendixRef = encodeBase64 target
- let txt = [ Str "(bilaga"
- , RawInline (Format "latex")
- ("~\\ref{bilaga:" <> appendixRef <> "}")
- , Str ")"
- ]
- let lnk = Link ("", [], [ ("reference-type", "ref")
- , ("reference", "bilaga:" <> appendixRef) ])
- (is <> [Superscript txt])
- ( "#bilaga:" <> appendixRef, "" )
- modify ((is, appendixRef, target):)
- return lnk
-rewriteLink x = return x
-
-shorten :: Block -> Block
-shorten (BlockQuote _) = BlockQuote [ Para [ Code ("", [], []) "[...]" ] ]
-shorten x = x
-
-replaceLinks :: Pandoc -> (Pandoc, [AppendixItem])
-replaceLinks = flip runState [] . walkM rewriteLink
-
-handleBilagaHeading :: [Inline] -> Text -> Block
-handleBilagaHeading is ref = Header 1 ("bilaga:" <> ref, [], []) is
-
-
-uriChars :: Set Char
-uriChars = Set.fromList $ ":/?#" -- Allows us to modifiy existing URL
- <> "-._~" -- URL safe
- <> ['A'..'Z'] <> ['a'..'z'] <> ['0'..'9']
-
-getVimwikiPage :: FilePath -> PandocIO [Block]
-getVimwikiPage path = do
- text <- liftIO $ T.readFile path
- Pandoc _ blocks <- readVimwiki def text
- return blocks
-
-handleFile :: FilePath -> String -> PandocIO (Maybe [Block])
-handleFile fname ".txt" = do
- text <- liftIO $ T.readFile fname
- return . Just $ [CodeBlock ("", [], []) text]
-handleFile fname ".pdf" = do
- aname <- liftIO $ makeAbsolute fname
- let pagecmd = [ TexCmd "thispagestyle" [] ["fancy"]
- , TexCmd "lhead" [] ["Bilaga \\Alph{section}.\\arabic{subsection}"]]
- let arg = [ "frame"
- , "pages={-}"
- , "width=\\textwidth"
- , "pagecommand=" <> mconcat (fmap toTex pagecmd)]
- let lines = [ TexCmd "phantomsection" [] []
- , TexCmd "stepcounter" [] ["subsection"]
- , TexCmd "includepdf" [joinBy "," arg] [pack . decode $ aname] ]
- let inline = RawInline
- (Format "latex")
- (mconcat $ fmap toTex lines)
- return . Just $ [ Plain [ inline ] ]
-handleFile fname ".tex" = do
- aname <- liftIO $ makeAbsolute fname
- let dest = "/tmp/vimwiki-script/" ++ (takeBaseName aname)
- liftIO $ createDirectoryIfMissing True dest
- liftIO (copyFile aname $ dest ++ "/doc.tex")
- (_, _, _, handle) <- liftIO $ createProcess ((shell "latexmk -pdf doc") { cwd = Just dest })
- liftIO $ waitForProcess handle
- handleFile (dest ++ "/doc.pdf") ".pdf"
- -- return . Just $ [ Plain [ Str . pack $ "TEX compiled " ++ dest ] ]
--- handleFile fname _ = return . Just $ [Para [Str . pack $ fname]]
-handleFile fname _ = do
- text <- liftIO $ T.readFile fname
- return . Just $ [CodeBlock ("", [], []) text]
-
-findAlternative :: [MailPart] -> Maybe MailPart
-findAlternative [] = Nothing
-findAlternative (m@MailPart { contentType = contentType }:xs) = case contentType of
- "text/html" -> Just m
- "text/plain" -> Just m
- _ -> findAlternative xs
-
-
--- TODO where are these strings defined
--- Strict Bytestring
-decoder :: String -> (ByteString -> Text)
-decoder "iso-8859-1" = decodeLatin1
-decoder "utf-8" = decodeUtf8
--- decoder _ = decodeUtf8Lenient
-decoder _ = decodeLatin1
-
-
--- https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
--- TODO differentiate between inline images (through cid:<> urls), and
--- unrelated attachements
-handleMailBody :: (Handle, Handle) -> MailPart -> PandocIO [Block]
-handleMailBody ports mail =
- case splitBy '/' $ contentType mail of
- ("multipart", "alternative") -> do
- case findAlternative $ reverse $ parts mail of
- Just part -> handleMailBody ports part
- Nothing -> return [ Para [ Str "Couldn't find any suitable alternative" ] ]
- -- mixed, but any unknown should be treated as mixed
- ("multipart", _) -> concat <$> mapM (handleMailBody ports) (parts mail)
- ("text", "plain") -> do
- bytes <- liftIO $ getBytes (partId mail) ports
- let content = decoder (fromMaybe "ASCII" $ charset mail) bytes
- return [ CodeBlock ("", [], []) content ]
- ("text", "html") -> do
- bytes <- liftIO $ getBytes (partId mail) ports
- let content = decoder (fromMaybe "ASCII" $ charset mail) bytes
- pdoc <- readHtml def content
- -- TODO renumber links
- let Pandoc _ blocks = walk shorten pdoc
- return blocks
- ("image", _) -> do
- tmpFile <- liftIO $ getFile (partId mail) ports
- let img = [ Plain
- [ Image ("", [], [])
- [Str "Image Caption?"]
- (pack tmpFile, "") ]]
- let figure = [ Figure ("", [], []) -- TODO figure ref
- -- (Caption Nothing [Plain [Str . filename mail]])
- (Caption Nothing [Plain [Str . pack . show $ filename mail]])
- img
- ]
- return img
- -- TODO
- -- ("application", "pdf") -> do
- _ -> return [ Header 2 ("", [], []) [ Str "Attachment omitted" ]
- , dlist [ ("Content-Type", contentType mail)
- , ("Filename", show . filename $ mail) ]
- ]
-
--- TODO Titlecase the headers
--- TODO from and to should monospace the
--- address (but not the name)
-formatMail :: MailPart -> (Handle, Handle) -> PandocIO [Block]
-formatMail mail ports = do
- let keys = ["from", "to", "subject", "date"]
- let f key = ( [Str $ key <> ":"]
- , [[Plain [ Str . pack $ headers mail ! unpack key ]]]
- )
- let kvs = map f keys
-
- body <- handleMailBody ports mail
-
- return $ DefinitionList kvs : body
-
-
-handleMailLink :: URI -> PandocIO [Block]
-handleMailLink uri = do
- let id = decode . uriPath $ uri
- -- liftIO $ print id
- mail' <- liftIO $ getMail id
- -- TODO #short
- body <- case mail' of
- Left err -> return [ Para [ Str "From "
- , Code ("", [], []) "getMail:" ]
- , Para [Str . pack $ err]
- , Para [Code ("", [], []) (pack id) ]]
- Right (mail, proc@(Just stdin, Just stdout, _, _)) -> do
- -- TODO "short" `in` uriFrag
- bs <- formatMail mail (stdout, stdin)
- liftIO $ cleanupProcess proc
- return bs
- -- TODO error
- _ -> return []
-
- return $ comment ("msg id: " <> pack id) <> body
-
--- See also: Html rebuildLinks
-handleBilaga :: [Block] -> Text -> PandocIO (Maybe [Block])
-handleBilaga currentPage url = case parseURI . encodeWith (`elem` uriChars) . unpack $ url of
- Just uri -> case uriScheme uri of
- ('w':'n':'.':wikiname) -> return . Just $ [Para [Str $ "Interwiki" <> pack wikiname]]
- "file:" -> do
- let (Just fname) = urlDecode $ uriPath uri
- liftIO $ do
- print $ "raw = " ++ uriPath uri
- print $ "fname = " ++ fname
- handleFile fname $ takeExtension fname
- "mail:" -> Just <$> handleMailLink uri
- _ -> return $ Just [Para [Str . pack . show $ uri]]
- Nothing -> case break (== '#') (unpack url) of
- ("", '#':frag) -> return $ getHeadingData (pack frag) currentPage
- (page, '#':frag) -> getVimwikiPage (page <.> "wiki") <&> getHeadingData (pack frag)
- (page, "") -> Just <$> getVimwikiPage (page <.> "wiki")
- _ -> return $ Just [Para [Str "ERROR"]]
-
-f :: [Block] -> [Inline] -> Text -> Text -> PandocIO [Block]
-f bs is a b = do
- let bg = handleBilagaHeading is a
- mxs <- handleBilaga bs b
- case mxs of
- Just xs -> return $ bg : xs
- Nothing -> return []
-
-- renumber :: Int -> [Blocks] -> [Blocks]
+
main :: [String] -> IO ()
main args = do
case args of
@@ -306,45 +44,9 @@ main args = do
-- let workdir = dropFileName file
- tex <- runIOorExplode $ do
- texTemplate <- compileDefaultTemplate "latex"
- Pandoc m' og_bs <- readVimwiki def text
- let Just better_blocks = getHeadingData (pack heading) og_bs
- -- TODO limit to only relevant heading
- (Pandoc meta bs, appendices) <- buildPrimary (Pandoc m' better_blocks)
- -- apx <- mconcat $ mapM handleBilaga $ reverse appendicies
- -- TODO this bs should be the initial source, NOT
- -- the result of buildPrimary
- fragments <- mapM (uncurry3 (f og_bs)) $ reverse appendices
- let apx = mconcat fragments
- let trail = [ RawBlock (Format "latex") "\\appendix" ] <> apx
- let content = Pandoc meta $ bs <> trail
-
- let opts = [ ("boxlinks", toVal True)
- , ("colorlinks", toVal True)
- , ("papersize", SimpleVal "a4")
- , ("numbersections", toVal True)
- , ("lang", SimpleVal "swedish")
- , ("header-includes", ListVal $ fmap (SimpleVal . fromString . unpack . toTex) [
- TexPackage "pdfpages" -- including PDF's
- , TexPackage "fancyhdr" -- page headers on included pdf pages
- , TempletizedTexPackage ["most"] "tcolorbox" -- for blockquotes
- , LstSet [ ("breaklines", "true")
- , ("basicstyle", "\\scriptsize") ]
- , TexCmd "newtcolorbox" [] ["myquote", joinBy "," [ "breakable"
- , "colback=red!5!white"
- , "colframe=red!75!black" ]]
- , TexCmd "renewenvironment" [] ("quote" : fmap toTex [
- TexCmd "begin" [] ["myquote"]
- , TexCmd "end" [] ["myquote"]
- ])
- ])
- ]
- writeLaTeX (def { writerTemplate = Just texTemplate
- , writerListings = True
- , writerVariables = Context $ Map.fromList opts }) content
-
+ tex <- runIOorExplode $ handleTex text heading
changeWorkingDirectory cwd
writeFile "out.tex" tex
putStrLn "Wrote result to out.tex"
+
_ -> error "Usage: ./main handlingar <input-file> <heading>"
diff --git a/hs/src/Handlingar/Common.hs b/hs/src/Handlingar/Common.hs
new file mode 100644
index 0000000..dec38c6
--- /dev/null
+++ b/hs/src/Handlingar/Common.hs
@@ -0,0 +1,187 @@
+{-# LANGUAGE OverloadedStrings
+ , ImportQualifiedPost
+ #-}
+
+module Handlingar.Common
+( decoder
+, findAlternative
+, formatMail
+, getVimwikiPage
+, handleBilagaHeading
+, handleBlocks
+, handleMailLink
+, replaceLinks
+, rewriteLink
+, shorten
+, uriChars
+) where
+
+import Control.Monad.State.Lazy
+import Data.ByteString (ByteString)
+import Data.Default (def)
+import Data.Map ((!))
+import Data.Maybe (fromMaybe)
+import Data.Set (Set)
+import Data.Set qualified as Set
+import Data.Text (Text, pack, unpack, strip)
+import Data.Text.Encoding (decodeLatin1, decodeUtf8)
+import Data.Text.Encoding.Base64 (encodeBase64)
+import Data.Text.IO qualified as T
+import Mail (getMail, MailPart(..), getBytes, getFile)
+import Network.URI (URI, uriPath)
+import Network.URI.Encode (decode)
+import System.IO (Handle)
+import System.Process (cleanupProcess)
+import Text.Pandoc (readVimwiki, readHtml, PandocMonad, PandocIO, writePlain)
+import Text.Pandoc.Builder
+import Text.Pandoc.Extract (AppendixItem, extractKV)
+import Text.Pandoc.Items (comment, dlist)
+import Text.Pandoc.Walk (walk, walkM)
+import Util (splitBy)
+
+
+handleBilagaHeading :: [Inline] -> Text -> Block
+handleBilagaHeading is ref = Header 1 ("bilaga:" <> ref, [], []) is
+
+-- Takes a list of Pandoc Blocks starting with a heading. If the first
+-- element after the heading is a Definition list, then parse that to
+-- kv-pairs, and return it also.
+handleBlocks :: PandocMonad m => [Block] -> m (Text, [(Text, Text)], [Block])
+handleBlocks (head:DefinitionList definitions:blocks) = do
+ heading <- writePlain def (Pandoc nullMeta [head])
+ kvs <- mapM extractKV definitions
+ return (strip heading, kvs, blocks)
+handleBlocks (head:blocks) = do
+ heading <- writePlain def (Pandoc nullMeta [head])
+ return (strip heading, [], blocks)
+handleBlocks blocks = return ("Heading missing", [], blocks)
+
+
+shorten :: Block -> Block
+shorten (BlockQuote _) = BlockQuote [ Para [ Code ("", [], []) "[...]" ] ]
+shorten x = x
+
+
+rewriteLink :: Inline -> State [AppendixItem] Inline
+rewriteLink (Link _ is (target, "wikilink")) = do
+ let appendixRef = encodeBase64 target
+ let txt = [ Str "(bilaga"
+ , RawInline (Format "latex")
+ ("~\\ref{bilaga:" <> appendixRef <> "}")
+ , Str ")"
+ ]
+ let lnk = Link ("", [], [ ("reference-type", "ref")
+ , ("reference", "bilaga:" <> appendixRef) ])
+ (is <> [Superscript txt])
+ ( "#bilaga:" <> appendixRef, "" )
+ modify ((is, appendixRef, target):)
+ return lnk
+rewriteLink x = return x
+
+replaceLinks :: Pandoc -> (Pandoc, [AppendixItem])
+replaceLinks = flip runState [] . walkM rewriteLink
+
+
+uriChars :: Set Char
+uriChars = Set.fromList $ ":/?#" -- Allows us to modifiy existing URL
+ <> "-._~" -- URL safe
+ <> ['A'..'Z'] <> ['a'..'z'] <> ['0'..'9']
+
+getVimwikiPage :: FilePath -> PandocIO [Block]
+getVimwikiPage path = do
+ text <- liftIO $ T.readFile path
+ Pandoc _ blocks <- readVimwiki def text
+ return blocks
+
+findAlternative :: [MailPart] -> Maybe MailPart
+findAlternative [] = Nothing
+findAlternative (m@MailPart { contentType = contentType }:xs) = case contentType of
+ "text/html" -> Just m
+ "text/plain" -> Just m
+ _ -> findAlternative xs
+
+
+-- TODO where are these strings defined
+-- Strict Bytestring
+decoder :: String -> (ByteString -> Text)
+decoder "iso-8859-1" = decodeLatin1
+decoder "utf-8" = decodeUtf8
+-- decoder _ = decodeUtf8Lenient
+decoder _ = decodeLatin1
+
+
+handleMailBody :: (Handle, Handle) -> MailPart -> PandocIO [Block]
+handleMailBody ports mail =
+ case splitBy '/' $ contentType mail of
+ ("multipart", "alternative") -> do
+ case findAlternative $ reverse $ parts mail of
+ Just part -> handleMailBody ports part
+ Nothing -> return [ Para [ Str "Couldn't find any suitable alternative" ] ]
+ -- mixed, but any unknown should be treated as mixed
+ ("multipart", _) -> concat <$> mapM (handleMailBody ports) (parts mail)
+ ("text", "plain") -> do
+ bytes <- liftIO $ getBytes (partId mail) ports
+ let content = decoder (fromMaybe "ASCII" $ charset mail) bytes
+ return [ CodeBlock ("", [], []) content ]
+ ("text", "html") -> do
+ bytes <- liftIO $ getBytes (partId mail) ports
+ let content = decoder (fromMaybe "ASCII" $ charset mail) bytes
+ pdoc <- readHtml def content
+ -- TODO renumber links
+ let Pandoc _ blocks = walk shorten pdoc
+ return blocks
+ ("image", _) -> do
+ tmpFile <- liftIO $ getFile (partId mail) ports
+ let img = [ Plain
+ [ Image ("", [], [])
+ [Str "Image Caption?"]
+ (pack tmpFile, "") ]]
+ let figure = [ Figure ("", [], []) -- TODO figure ref
+ -- (Caption Nothing [Plain [Str . filename mail]])
+ (Caption Nothing [Plain [Str . pack . show $ filename mail]])
+ img
+ ]
+ return img
+ -- TODO
+ -- ("application", "pdf") -> do
+ _ -> return [ Header 2 ("", [], []) [ Str "Attachment omitted" ]
+ , dlist [ ("Content-Type", contentType mail)
+ , ("Filename", show . filename $ mail) ]
+ ]
+
+-- TODO Titlecase the headers
+-- TODO from and to should monospace the
+-- address (but not the name)
+formatMail :: MailPart -> (Handle, Handle) -> PandocIO [Block]
+formatMail mail ports = do
+ let keys = ["from", "to", "subject", "date"]
+ let f key = ( [Str $ key <> ":"]
+ , [[Plain [ Str . pack $ headers mail ! unpack key ]]]
+ )
+ let kvs = map f keys
+
+ body <- handleMailBody ports mail
+
+ return $ DefinitionList kvs : body
+
+
+handleMailLink :: URI -> PandocIO [Block]
+handleMailLink uri = do
+ let id = decode . uriPath $ uri
+ -- liftIO $ print id
+ mail' <- liftIO $ getMail id
+ -- TODO #short
+ body <- case mail' of
+ Left err -> return [ Para [ Str "From "
+ , Code ("", [], []) "getMail:" ]
+ , Para [Str . pack $ err]
+ , Para [Code ("", [], []) (pack id) ]]
+ Right (mail, proc@(Just stdin, Just stdout, _, _)) -> do
+ -- TODO "short" `in` uriFrag
+ bs <- formatMail mail (stdout, stdin)
+ liftIO $ cleanupProcess proc
+ return bs
+ -- TODO error
+ _ -> return []
+
+ return $ comment ("msg id: " <> pack id) <> body
diff --git a/hs/src/Handlingar/TexOutput.hs b/hs/src/Handlingar/TexOutput.hs
new file mode 100644
index 0000000..6028b5f
--- /dev/null
+++ b/hs/src/Handlingar/TexOutput.hs
@@ -0,0 +1,153 @@
+{-# LANGUAGE OverloadedStrings
+ , ImportQualifiedPost
+ #-}
+
+module Handlingar.TexOutput
+( handleTex
+) where
+
+
+import Control.Monad.State.Lazy
+import Data.Default (def)
+import Data.Map.Lazy qualified as Map
+import Data.String (IsString(fromString))
+import Data.Text (Text, pack, unpack)
+import Data.Text.IO qualified as T
+import Handlingar.Common (handleBilagaHeading, getVimwikiPage, handleMailLink, handleBlocks, replaceLinks, uriChars)
+import Network.URI (parseURI, uriScheme, uriPath)
+import Network.URI.Encode (encodeWith, decode)
+import System.Directory (makeAbsolute, createDirectoryIfMissing, copyFile)
+import System.FilePath (takeExtension, (<.>), takeBaseName)
+import System.Process (createProcess, shell, CreateProcess(cwd), waitForProcess)
+import Tex (toTex, TeX (..))
+import Text.DocTemplates (toVal, Val(SimpleVal, ListVal), Context(Context))
+import Text.Pandoc (readVimwiki, WriterOptions(writerTemplate, writerListings, writerVariables), PandocMonad, PandocIO)
+import Text.Pandoc.Builder
+import Text.Pandoc.Extract (AppendixItem, getHeadingData)
+import Text.Pandoc.Templates (compileDefaultTemplate)
+import Text.Pandoc.Writers.LaTeX (writeLaTeX)
+import Text.URI.Decode (urlDecode)
+import Util (joinBy, uncurry3, (<&>))
+
+
+buildPrimary :: PandocMonad m
+ => Pandoc
+ -> m (Pandoc, [AppendixItem])
+buildPrimary (Pandoc meta blocks) = do
+ -- Pandoc meta blocks <- reader def text
+ -- let Just blocks = getHeadingData heading blocks
+ (heading, kvs, wantedBlocks') <- handleBlocks blocks
+ let (pandoc, appendices) = replaceLinks $ Pandoc meta wantedBlocks'
+
+ let pandoc' = foldl (flip . uncurry $ setMeta) pandoc
+ $ ("title", heading) : kvs
+ return (pandoc', appendices)
+
+
+
+handleFileTex :: FilePath -> String -> PandocIO (Maybe [Block])
+handleFileTex fname ".txt" = do
+ text <- liftIO $ T.readFile fname
+ return . Just $ [CodeBlock ("", [], []) text]
+handleFileTex fname ".pdf" = do
+ aname <- liftIO $ makeAbsolute fname
+ let pagecmd = [ TexCmd "thispagestyle" [] ["fancy"]
+ , TexCmd "lhead" [] ["Bilaga \\Alph{section}.\\arabic{subsection}"]]
+ let arg = [ "frame"
+ , "pages={-}"
+ , "width=\\textwidth"
+ , "pagecommand=" <> mconcat (fmap toTex pagecmd)]
+ let lines = [ TexCmd "phantomsection" [] []
+ , TexCmd "stepcounter" [] ["subsection"]
+ , TexCmd "includepdf" [joinBy "," arg] [pack . decode $ aname] ]
+ let inline = RawInline
+ (Format "latex")
+ (mconcat $ fmap toTex lines)
+ return . Just $ [ Plain [ inline ] ]
+handleFileTex fname ".tex" = do
+ aname <- liftIO $ makeAbsolute fname
+ let dest = "/tmp/vimwiki-script/" ++ (takeBaseName aname)
+ liftIO $ createDirectoryIfMissing True dest
+ liftIO (copyFile aname $ dest ++ "/doc.tex")
+ (_, _, _, handle) <- liftIO $ createProcess ((shell "latexmk -pdf doc") { cwd = Just dest })
+ liftIO $ waitForProcess handle
+ handleFileTex (dest ++ "/doc.pdf") ".pdf"
+ -- return . Just $ [ Plain [ Str . pack $ "TEX compiled " ++ dest ] ]
+-- handleFileTex fname _ = return . Just $ [Para [Str . pack $ fname]]
+handleFileTex fname _ = do
+ text <- liftIO $ T.readFile fname
+ return . Just $ [CodeBlock ("", [], []) text]
+
+
+-- https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
+-- TODO differentiate between inline images (through cid:<> urls), and
+-- unrelated attachements
+
+-- See also: Html rebuildLinks
+handleBilagaTex :: [Block] -> Text -> PandocIO (Maybe [Block])
+handleBilagaTex currentPage url = case parseURI . encodeWith (`elem` uriChars) . unpack $ url of
+ Just uri -> case uriScheme uri of
+ ('w':'n':'.':wikiname) -> return . Just $ [Para [Str $ "Interwiki" <> pack wikiname]]
+ "file:" -> do
+ let (Just fname) = urlDecode $ uriPath uri
+ liftIO $ do
+ print $ "raw = " ++ uriPath uri
+ print $ "fname = " ++ fname
+ handleFileTex fname $ takeExtension fname
+ "mail:" -> Just <$> handleMailLink uri
+ _ -> return $ Just [Para [Str . pack . show $ uri]]
+ Nothing -> case break (== '#') (unpack url) of
+ ("", '#':frag) -> return $ getHeadingData (pack frag) currentPage
+ (page, '#':frag) -> getVimwikiPage (page <.> "wiki") <&> getHeadingData (pack frag)
+ (page, "") -> Just <$> getVimwikiPage (page <.> "wiki")
+ _ -> return $ Just [Para [Str "ERROR"]]
+
+
+f :: [Block] -> [Inline] -> Text -> Text -> PandocIO [Block]
+f bs is a b = do
+ let bg = handleBilagaHeading is a
+ mxs <- handleBilagaTex bs b
+ case mxs of
+ Just xs -> return $ bg : xs
+ Nothing -> return []
+
+
+handleTex :: Text -> String -> PandocIO Text
+handleTex source_text heading = do
+ texTemplate <- compileDefaultTemplate "latex"
+ Pandoc m' og_bs <- readVimwiki def source_text
+ let Just better_blocks = getHeadingData (pack heading) og_bs
+ -- TODO limit to only relevant heading
+ (Pandoc meta bs, appendices) <- buildPrimary (Pandoc m' better_blocks)
+ -- apx <- mconcat $ mapM handleBilagaTex $ reverse appendicies
+ -- TODO this bs should be the initial source, NOT
+ -- the result of buildPrimary
+ fragments <- mapM (uncurry3 (f og_bs)) $ reverse appendices
+ let apx = mconcat fragments
+ let trail = [ RawBlock (Format "latex") "\\appendix" ] <> apx
+ let content = Pandoc meta $ bs <> trail
+
+ let opts = [ ("boxlinks", toVal True)
+ , ("colorlinks", toVal True)
+ , ("papersize", SimpleVal "a4")
+ , ("numbersections", toVal True)
+ , ("lang", SimpleVal "swedish")
+ , ("header-includes", ListVal $ fmap (SimpleVal . fromString . unpack . toTex) [
+ TexPackage "pdfpages" -- including PDF's
+ , TexPackage "fancyhdr" -- page headers on included pdf pages
+ , TempletizedTexPackage ["most"] "tcolorbox" -- for blockquotes
+ , LstSet [ ("breaklines", "true")
+ , ("basicstyle", "\\scriptsize") ]
+ , TexCmd "newtcolorbox" [] ["myquote", joinBy "," [ "breakable"
+ , "colback=red!5!white"
+ , "colframe=red!75!black" ]]
+ , TexCmd "renewenvironment" [] ("quote" : fmap toTex [
+ TexCmd "begin" [] ["myquote"]
+ , TexCmd "end" [] ["myquote"]
+ ])
+ ])
+ ]
+ writeLaTeX (def { writerTemplate = Just texTemplate
+ , writerListings = True
+ , writerVariables = Context $ Map.fromList opts }) content
+
diff --git a/hs/vimwiki.cabal b/hs/vimwiki.cabal
index 2322521..27442ab 100644
--- a/hs/vimwiki.cabal
+++ b/hs/vimwiki.cabal
@@ -33,6 +33,8 @@ executable Main
Html,
Mail,
Handlingar,
+ Handlingar.Common,
+ Handlingar.TexOutput,
Vimwiki.Man,
System.Home,
Util,