???
This commit is contained in:
parent
b9b7eb98f1
commit
85ce3ee34a
1 changed files with 99 additions and 4 deletions
103
src/Djot.hs
103
src/Djot.hs
|
|
@ -11,6 +11,7 @@ module Djot
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Applicative (many, optional, some, (<|>))
|
import Control.Applicative (many, optional, some, (<|>))
|
||||||
|
import Control.Monad (guard)
|
||||||
import Data.Foldable (for_)
|
import Data.Foldable (for_)
|
||||||
import Data.Functor (void, (<$>))
|
import Data.Functor (void, (<$>))
|
||||||
import Data.List (elemIndex)
|
import Data.List (elemIndex)
|
||||||
|
|
@ -19,8 +20,8 @@ import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import IR
|
import IR
|
||||||
import Logger (Logger (logCallStack, logDebug, logError))
|
import Logger (Logger (logCallStack, logDebug, logError))
|
||||||
import Text.Megaparsec (MonadParsec (lookAhead, notFollowedBy, parseError, try), ParseErrorBundle (ParseErrorBundle, bundleErrors), SourcePos (sourceColumn), anySingle, choice, errorOffset, getInput, getOffset, manyTill, parse, satisfy, sepBy, setErrorOffset, someTill)
|
import Text.Megaparsec (MonadParsec (lookAhead, notFollowedBy, parseError, try), ParseErrorBundle (ParseErrorBundle, bundleErrors), SourcePos (sourceColumn), anySingle, choice, errorOffset, getInput, getOffset, manyTill, oneOf, parse, satisfy, sepBy, setErrorOffset, someTill)
|
||||||
import Text.Megaparsec.Char (char, lowerChar, newline, numberChar, space, string, tab, upperChar)
|
import Text.Megaparsec.Char (char, digitChar, lowerChar, newline, numberChar, space, spaceChar, string, tab, upperChar)
|
||||||
import Utilities.Parsing
|
import Utilities.Parsing
|
||||||
|
|
||||||
(.>) :: (a -> b) -> (b -> c) -> a -> c
|
(.>) :: (a -> b) -> (b -> c) -> a -> c
|
||||||
|
|
@ -115,7 +116,11 @@ listBlock attrs = do
|
||||||
error "todo"
|
error "todo"
|
||||||
-- any listMarker
|
-- any listMarker
|
||||||
-- can probably just use listMarker' via choice or smth like that
|
-- can probably just use listMarker' via choice or smth like that
|
||||||
listMarker = error "todo"
|
listMarker = do
|
||||||
|
indent <- length <$> many (notFollowedBy newline *> spaceChar)
|
||||||
|
(lt, markerLen) <- choice [unorderedMarker, orderedMarker]
|
||||||
|
void (char ' ') <|> lookAhead (void newline)
|
||||||
|
pure (lt, indent + markerLen + 1)
|
||||||
-- listItem which must be of list_type
|
-- listItem which must be of list_type
|
||||||
listItem' list_type = do
|
listItem' list_type = do
|
||||||
listMarker' list_type
|
listMarker' list_type
|
||||||
|
|
@ -123,14 +128,104 @@ listBlock attrs = do
|
||||||
content <- some $ listLine $ notFollowedBy $ listMarker' list_type
|
content <- some $ listLine $ notFollowedBy $ listMarker' list_type
|
||||||
|
|
||||||
error "todo"
|
error "todo"
|
||||||
|
unorderedMarker = do
|
||||||
|
c <- oneOf ['-', '+', '*']
|
||||||
|
pure (Unordered {style = Just (T.singleton c)}, 1)
|
||||||
|
|
||||||
|
orderedMarker =
|
||||||
|
choice
|
||||||
|
[ parenEnclosed,
|
||||||
|
periodOrParen
|
||||||
|
]
|
||||||
|
|
||||||
|
parenEnclosed = do
|
||||||
|
void $ char '('
|
||||||
|
(content, lt) <- orderedContent
|
||||||
|
void $ char ')'
|
||||||
|
let markerLen = T.length content + 2 -- ( + content + )
|
||||||
|
pure (lt, markerLen)
|
||||||
|
|
||||||
|
periodOrParen = do
|
||||||
|
(content, baseType) <- orderedContent
|
||||||
|
suffix <- oneOf ['.', ')']
|
||||||
|
let markerLen = T.length content + 1
|
||||||
|
style = orderedStyle baseType
|
||||||
|
lt =
|
||||||
|
Ordered
|
||||||
|
{ start_number = orderedStart baseType content,
|
||||||
|
style = style
|
||||||
|
}
|
||||||
|
pure (lt, markerLen)
|
||||||
|
orderedStart _ (DecimalContent d) = Just (read d)
|
||||||
|
orderedStart _ _ = Nothing -- roman/alpha start not tracked numerically
|
||||||
|
orderedStyle DecimalContent {} = Nothing -- default, omit attribute
|
||||||
|
orderedStyle UpperRomanContent {} = Just "I"
|
||||||
|
orderedStyle LowerRomanContent {} = Just "i"
|
||||||
|
orderedStyle UpperAlphaContent {} = Just "A"
|
||||||
|
orderedStyle LowerAlphaContent {} = Just "a"
|
||||||
|
orderedStyle UpperRomanMulti {} = Just "I"
|
||||||
|
orderedStyle LowerRomanMulti {} = Just "i"
|
||||||
|
orderedStyle UpperAlphaMulti {} = Just "A"
|
||||||
|
orderedStyle LowerAlphaMulti {} = Just "a"
|
||||||
|
ol_digit_handle = do
|
||||||
|
digits <- some digitChar
|
||||||
|
pure (T.pack digits, DecimalContent digits)
|
||||||
|
isRomanUpper c = c `elem` ("IVXLCDM" :: String)
|
||||||
|
isRomanLower c = c `elem` ("ivxlcdm" :: String)
|
||||||
|
ol_upper_handle = do
|
||||||
|
c <- upperChar
|
||||||
|
let t = T.singleton c
|
||||||
|
if isRomanUpper c
|
||||||
|
then pure (t, UpperRomanContent c)
|
||||||
|
else pure (t, UpperAlphaContent c)
|
||||||
|
orderedContent = do
|
||||||
|
choice
|
||||||
|
[ ol_digit_handle,
|
||||||
|
ol_upper_handle,
|
||||||
|
do
|
||||||
|
c <- lowerChar
|
||||||
|
let t = T.singleton c
|
||||||
|
if isRomanLower c
|
||||||
|
then pure (t, LowerRomanContent c) -- assume roman for ambiguous
|
||||||
|
else pure (t, LowerAlphaContent c),
|
||||||
|
do
|
||||||
|
-- multi-char lower: roman or alpha (xix, viii, etc.)
|
||||||
|
cs <- some lowerChar
|
||||||
|
let t = T.pack cs
|
||||||
|
if all isRomanLower cs
|
||||||
|
then pure (t, LowerRomanMulti cs)
|
||||||
|
else pure (t, LowerAlphaMulti cs)
|
||||||
|
]
|
||||||
-- listMarker which must be of list_type
|
-- listMarker which must be of list_type
|
||||||
listMarker' list_type = error "todo"
|
listMarker' expected = do
|
||||||
|
indent <- length <$> many (many (notFollowedBy newline *> spaceChar))
|
||||||
|
(lt, markerLen) <- case expected of
|
||||||
|
Unordered {style} -> do
|
||||||
|
(lt, ml) <- unorderedMarker
|
||||||
|
guard $ matchesUnordered style lt
|
||||||
|
pure (lt, ml)
|
||||||
|
Ordered {style} -> do
|
||||||
|
(lt, ml) <- orderedMarker
|
||||||
|
guard $ matchesOrdered style lt
|
||||||
|
pure (lt, ml)
|
||||||
|
void (char ' ') <|> lookAhead (void newline)
|
||||||
|
pure (lt, indent + markerLen + 1)
|
||||||
-- list line which must parse check before the rest of the line
|
-- list line which must parse check before the rest of the line
|
||||||
listLine check = do
|
listLine check = do
|
||||||
check
|
check
|
||||||
manyTill anySingle newline
|
manyTill anySingle newline
|
||||||
|
|
||||||
|
data OrderedContent
|
||||||
|
= DecimalContent String
|
||||||
|
| UpperRomanContent Char
|
||||||
|
| LowerRomanContent Char
|
||||||
|
| UpperAlphaContent Char
|
||||||
|
| LowerAlphaContent Char
|
||||||
|
| UpperRomanMulti String
|
||||||
|
| LowerRomanMulti String
|
||||||
|
| UpperAlphaMulti String
|
||||||
|
| LowerAlphaMulti String
|
||||||
|
|
||||||
taskListBlock :: (Logger m, Characters s) => Attrs -> Parser s m Element
|
taskListBlock :: (Logger m, Characters s) => Attrs -> Parser s m Element
|
||||||
taskListBlock attrs = do
|
taskListBlock attrs = do
|
||||||
error "todo"
|
error "todo"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue