@@ -0,0 +1,110 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-
3+Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.Readers.Org.Meta
22+ Copyright : Copyright (C) 2014-2016 Albert Krewinkel
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
26+
27+Parsers for Org-mode meta declarations.
28+-}
29+module Text.Pandoc.Readers.Org.Meta
30+ ( metaLine
31+ ) where
32+
33+import Text.Pandoc.Readers.Org.BlockStarts
34+import Text.Pandoc.Readers.Org.ExportSettings ( exportSettings )
35+import Text.Pandoc.Readers.Org.Inlines
36+import Text.Pandoc.Readers.Org.ParserState
37+import Text.Pandoc.Readers.Org.Parsing
38+
39+import qualified Text.Pandoc.Builder as B
40+import Text.Pandoc.Builder ( Blocks, Inlines )
41+import Text.Pandoc.Definition
42+import Text.Pandoc.Compat.Monoid ((<>))
43+
44+import Control.Monad ( mzero )
45+import Data.Char ( toLower )
46+import Data.List ( intersperse )
47+import qualified Data.Map as M
48+import Network.HTTP ( urlEncode )
49+
50+-- | Parse and handle a single line containing meta information
51+-- The order, in which blocks are tried, makes sure that we're not looking at
52+-- the beginning of a block, so we don't need to check for it
53+metaLine :: OrgParser Blocks
54+metaLine = mempty <$ metaLineStart <* (optionLine <|> declarationLine)
55+
56+declarationLine :: OrgParser ()
57+declarationLine = try $ do
58+ key <- metaKey
59+ value <- metaInlines
60+ updateState $ \st ->
61+ let meta' = B.setMeta key <$> value <*> pure nullMeta
62+ in st { orgStateMeta = orgStateMeta st <> meta' }
63+
64+metaInlines :: OrgParser (F MetaValue)
65+metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
66+
67+metaKey :: OrgParser String
68+metaKey = map toLower <$> many1 (noneOf ": \n\r")
69+ <* char ':'
70+ <* skipSpaces
71+
72+optionLine :: OrgParser ()
73+optionLine = try $ do
74+ key <- metaKey
75+ case key of
76+ "link" -> parseLinkFormat >>= uncurry addLinkFormat
77+ "options" -> exportSettings
78+ _ -> mzero
79+
80+addLinkFormat :: String
81+ -> (String -> String)
82+ -> OrgParser ()
83+addLinkFormat key formatter = updateState $ \s ->
84+ let fs = orgStateLinkFormatters s
85+ in s{ orgStateLinkFormatters = M.insert key formatter fs }
86+
87+parseLinkFormat :: OrgParser ((String, String -> String))
88+parseLinkFormat = try $ do
89+ linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
90+ linkSubst <- parseFormat
91+ return (linkType, linkSubst)
92+
93+-- | An ad-hoc, single-argument-only implementation of a printf-style format
94+-- parser.
95+parseFormat :: OrgParser (String -> String)
96+parseFormat = try $ do
97+ replacePlain <|> replaceUrl <|> justAppend
98+ where
99+ -- inefficient, but who cares
100+ replacePlain = try $ (\x -> concat . flip intersperse x)
101+ <$> sequence [tillSpecifier 's', rest]
102+ replaceUrl = try $ (\x -> concat . flip intersperse x . urlEncode)
103+ <$> sequence [tillSpecifier 'h', rest]
104+ justAppend = try $ (++) <$> rest
105+
106+ rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r")
107+ tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:""))
108+
109+inlinesTillNewline :: OrgParser (F Inlines)
110+inlinesTillNewline = trimInlinesF . mconcat <$> manyTill inline newline