module Data.OrgMode.Parse.Attoparsec.Headings
( module Data.OrgMode.Parse.Internal
, heading
, headingLevel
, headingPriority
, headingTitle
, headingKeyword
)
where
import Control.Applicative ((*>), (<*), (<|>))
import Data.Attoparsec.Text as T
import Data.Attoparsec.Types as TP (Parser)
import Data.Char (isUpper)
import Data.Maybe (catMaybes, isJust)
import Data.Text as Text (Text, concat, length,
null, pack)
import Prelude hiding (concat, null, takeWhile)
import Data.OrgMode.Parse.Internal
heading :: TP.Parser Text Heading
heading = do
lvl <- headingLevel
st <- option Nothing headingState
pr <- option Nothing headingPriority
(tl, k) <- headingTitle
keys <- attemptKeys k
endOfLine
return $ Heading lvl pr st tl (catMaybes (k:keys))
where
attemptKeys (Just _) = many' (headingKeyword)
attemptKeys Nothing = return []
headingLevel :: TP.Parser Text Int
headingLevel = return . Text.length =<< takeWhile1 (== '*')
headingPriority :: TP.Parser Text (Maybe Priority)
headingPriority = do
pr <- start *> (takeWhile $ inClass "ABC") <* end
if null pr
then fail "Priority must be one of [#A], [#B], or [#C]"
else return . Just $ toPriority pr
where
start = char '[' *> char '#'
end = char ']' <* space
headingState :: TP.Parser Text (Maybe State)
headingState = do
st <- space *> takeWhile isUpper <* space
if null st
then return Nothing
else return . Just $ State st
headingTitle :: TP.Parser Text (Text, Maybe Keyword)
headingTitle = takeTitleKeys <|> takeTitleEnd
takeTitleEnd :: TP.Parser Text (Text, Maybe Keyword)
takeTitleEnd = do
t <- takeTill isEndOfLine
return (t, Nothing)
takeTitleKeys :: TP.Parser Text (Text, Maybe Keyword)
takeTitleKeys = do
t <- takeWhile $ notInClass ":\n\r"
cl <- char ':'
k <- headingKeyword'
if isJust k
then char ':' *> return (t, k)
else do
(t', k') <- takeTitleKeys
return (concat [t, pack [cl], t'], k')
headingKeyword' :: TP.Parser Text (Maybe Keyword)
headingKeyword' = do
key <- takeWhile $ notInClass " :\n\r"
if null key
then return Nothing
else return . Just $ Keyword key
headingKeyword :: TP.Parser Text (Maybe Keyword)
headingKeyword = do
key <- (takeWhile1 $ notInClass ":\n\r") <* char ':'
if null key
then return Nothing
else return . Just $ Keyword key