diff options
author | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-10-10 22:14:45 +0200 |
---|---|---|
committer | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-10-10 22:14:45 +0200 |
commit | 7af368e7fc96b3bc6dfc56e90fb0f7d4de6cc926 (patch) | |
tree | c2102212221e89aab0f5efb3828ff83d34b40169 | |
parent | Add dependency info. (diff) | |
download | vimwiki-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.hs | 312 | ||||
-rw-r--r-- | hs/src/Handlingar/Common.hs | 187 | ||||
-rw-r--r-- | hs/src/Handlingar/TexOutput.hs | 153 | ||||
-rw-r--r-- | hs/vimwiki.cabal | 2 |
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, |