1{-# LANGUAGE OverloadedStrings #-} 2{- | 3 Module : Text.Pandoc.Readers.Org.ExportSettings 4 Copyright : © 2016-2021 Albert Krewinkel 5 License : GNU GPL, version 2 or above 6 7 Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> 8 9Parsers for Org-mode export options. 10-} 11module Text.Pandoc.Readers.Org.ExportSettings 12 ( exportSettings 13 ) where 14 15import Text.Pandoc.Class.PandocMonad (PandocMonad, report) 16import Text.Pandoc.Logging (LogMessage (UnknownOrgExportOption)) 17import Text.Pandoc.Readers.Org.ParserState 18import Text.Pandoc.Readers.Org.Parsing 19 20import Control.Monad (mzero, void) 21import Data.Char (toLower) 22import Data.Maybe (listToMaybe) 23import Data.Text (Text, unpack) 24 25-- | Read and handle space separated org-mode export settings. 26exportSettings :: PandocMonad m => OrgParser m () 27exportSettings = void $ sepBy skipSpaces exportSetting 28 29-- | Setter function for export settings. 30type ExportSettingSetter a = a -> ExportSettings -> ExportSettings 31 32-- | Read and process a single org-mode export option. 33exportSetting :: PandocMonad m => OrgParser m () 34exportSetting = choice 35 [ booleanSetting "^" (\val es -> es { exportSubSuperscripts = val }) 36 , booleanSetting "'" (\val es -> es { exportSmartQuotes = val }) 37 , booleanSetting "*" (\val es -> es { exportEmphasizedText = val }) 38 , booleanSetting "-" (\val es -> es { exportSpecialStrings = val }) 39 , ignoredSetting ":" 40 , ignoredSetting "<" 41 , booleanSetting "\\n" (\val es -> es { exportPreserveBreaks = val }) 42 , archivedTreeSetting "arch" (\val es -> es { exportArchivedTrees = val }) 43 , booleanSetting "author" (\val es -> es { exportWithAuthor = val }) 44 , ignoredSetting "c" 45 -- org-mode allows the special value `comment` for creator, which we'll 46 -- interpret as true as it doesn't make sense in the context of Pandoc. 47 , booleanSetting "creator" (\val es -> es { exportWithCreator = val }) 48 , complementableListSetting "d" (\val es -> es { exportDrawers = val }) 49 , ignoredSetting "date" 50 , booleanSetting "e" (\val es -> es { exportWithEntities = val }) 51 , booleanSetting "email" (\val es -> es { exportWithEmail = val }) 52 , booleanSetting "f" (\val es -> es { exportWithFootnotes = val }) 53 , integerSetting "H" (\val es -> es { exportHeadlineLevels = val }) 54 , ignoredSetting "inline" 55 , ignoredSetting "num" 56 , booleanSetting "p" (\val es -> es { exportWithPlanning = val }) 57 , ignoredSetting "pri" 58 , ignoredSetting "prop" 59 , ignoredSetting "stat" 60 , booleanSetting "tags" (\val es -> es { exportWithTags = val }) 61 , ignoredSetting "tasks" 62 , texSetting "tex" (\val es -> es { exportWithLatex = val }) 63 , ignoredSetting "timestamp" 64 , ignoredSetting "title" 65 , ignoredSetting "toc" 66 , booleanSetting "todo" (\val es -> es { exportWithTodoKeywords = val }) 67 , booleanSetting "|" (\val es -> es { exportWithTables = val }) 68 , ignoreAndWarn 69 ] <?> "export setting" 70 71-- | Generic handler for export settings. Takes a parser which converts 72-- the plain option text into a data structure. 73genericExportSetting :: Monad m 74 => OrgParser m a 75 -> Text 76 -> ExportSettingSetter a 77 -> OrgParser m () 78genericExportSetting optionParser settingIdentifier setter = try $ do 79 _ <- textStr settingIdentifier *> char ':' 80 value <- optionParser 81 updateState $ modifyExportSettings value 82 where 83 modifyExportSettings val st = 84 st { orgStateExportSettings = setter val . orgStateExportSettings $ st } 85 86-- | A boolean option, either nil (False) or non-nil (True). 87booleanSetting :: Monad m => Text -> ExportSettingSetter Bool -> OrgParser m () 88booleanSetting = genericExportSetting elispBoolean 89 90-- | An integer-valued option. 91integerSetting :: Monad m => Text -> ExportSettingSetter Int -> OrgParser m () 92integerSetting = genericExportSetting parseInt 93 where 94 parseInt = try $ 95 many1 digit >>= maybe mzero (return . fst) . listToMaybe . reads 96 97-- | Either the string "headline" or an elisp boolean and treated as an 98-- @ArchivedTreesOption@. 99archivedTreeSetting :: Monad m 100 => Text 101 -> ExportSettingSetter ArchivedTreesOption 102 -> OrgParser m () 103archivedTreeSetting = 104 genericExportSetting $ archivedTreesHeadlineSetting <|> archivedTreesBoolean 105 where 106 archivedTreesHeadlineSetting = 107 ArchivedTreesHeadlineOnly <$ optionString "headline" 108 109 archivedTreesBoolean = try $ do 110 exportBool <- elispBoolean 111 return $ 112 if exportBool 113 then ArchivedTreesExport 114 else ArchivedTreesNoExport 115 116-- | A list or a complement list (i.e. a list starting with `not`). 117complementableListSetting :: Monad m 118 => Text 119 -> ExportSettingSetter (Either [Text] [Text]) 120 -> OrgParser m () 121complementableListSetting = genericExportSetting $ choice 122 [ Left <$> complementTextList 123 , Right <$> stringList 124 , (\b -> if b then Left [] else Right []) <$> elispBoolean 125 ] 126 where 127 -- Read a plain list of strings. 128 stringList :: Monad m => OrgParser m [Text] 129 stringList = try $ 130 char '(' 131 *> sepBy elispText spaces 132 <* char ')' 133 134 -- Read an emacs lisp list specifying a complement set. 135 complementTextList :: Monad m => OrgParser m [Text] 136 complementTextList = try $ 137 string "(not " 138 *> sepBy elispText spaces 139 <* char ')' 140 141 elispText :: Monad m => OrgParser m Text 142 elispText = try $ 143 char '"' 144 *> manyTillChar alphaNum (char '"') 145 146-- | Parses either @t@, @nil@, or @verbatim@ into a 'TeXExport' value. 147texSetting :: Monad m 148 => Text 149 -> ExportSettingSetter TeXExport 150 -> OrgParser m () 151texSetting = genericExportSetting $ texVerbatim <|> texBoolean 152 where 153 texVerbatim = TeXVerbatim <$ optionString "verbatim" 154 155 texBoolean = try $ do 156 exportBool <- elispBoolean 157 return $ 158 if exportBool 159 then TeXExport 160 else TeXIgnore 161 162-- | Read but ignore the export setting. 163ignoredSetting :: Monad m => Text -> OrgParser m () 164ignoredSetting s = try (() <$ textStr s <* char ':' <* many1 nonspaceChar) 165 166-- | Read any setting string, but ignore it and emit a warning. 167ignoreAndWarn :: PandocMonad m => OrgParser m () 168ignoreAndWarn = try $ do 169 opt <- many1Char nonspaceChar 170 report (UnknownOrgExportOption opt) 171 return () 172 173-- | Read an elisp boolean. Only NIL is treated as false, non-NIL values are 174-- interpreted as true. 175elispBoolean :: Monad m => OrgParser m Bool 176elispBoolean = try $ do 177 value <- many1 nonspaceChar 178 return $ case map toLower value of 179 "nil" -> False 180 "{}" -> False 181 "()" -> False 182 _ -> True 183 184-- | Try to parse a literal string as the option value. Returns the 185-- string on success. 186optionString :: Monad m => Text -> OrgParser m Text 187optionString s = try $ do 188 _ <- string (unpack s) 189 lookAhead (newline <|> spaceChar) 190 return s 191