{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
module Cheapskate.Util (
joinLines
, tabFilter
, isWhitespace
, isEscapable
, normalizeReference
, Scanner
, scanIndentSpace
, scanNonindentSpace
, scanSpacesToColumn
, scanChar
, scanBlankline
, scanSpaces
, scanSpnl
, nfb
, nfbChar
, upToCountChars
) where
import Data.Text (Text)
import qualified Data.Text as T
import Data.Char
#if ! MIN_VERSION_base(4,8,0)
import Control.Applicative
#endif
import Cheapskate.ParserCombinators
joinLines :: [Text] -> Text
joinLines :: [Text] -> Text
joinLines = Text -> [Text] -> Text
T.intercalate Text
"\n"
tabFilter :: Text -> Text
tabFilter :: Text -> Text
tabFilter = [Text] -> Text
T.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> [Text]
pad forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> [Text]
T.split (forall a. Eq a => a -> a -> Bool
== Char
'\t')
where pad :: [Text] -> [Text]
pad [] = []
pad [Text
t] = [Text
t]
pad (Text
t:[Text]
ts) = let tl :: Int
tl = Text -> Int
T.length Text
t
n :: Int
n = Int
tl forall a. Num a => a -> a -> a
+ Int
4 forall a. Num a => a -> a -> a
- (Int
tl forall a. Integral a => a -> a -> a
`mod` Int
4)
in Int -> Char -> Text -> Text
T.justifyLeft Int
n Char
' ' Text
t forall a. a -> [a] -> [a]
: [Text] -> [Text]
pad [Text]
ts
isWhitespace :: Char -> Bool
isWhitespace :: Char -> Bool
isWhitespace Char
' ' = Bool
True
isWhitespace Char
'\t' = Bool
True
isWhitespace Char
'\n' = Bool
True
isWhitespace Char
'\r' = Bool
True
isWhitespace Char
_ = Bool
False
isEscapable :: Char -> Bool
isEscapable :: Char -> Bool
isEscapable Char
c = Char -> Bool
isAscii Char
c Bool -> Bool -> Bool
&& (Char -> Bool
isSymbol Char
c Bool -> Bool -> Bool
|| Char -> Bool
isPunctuation Char
c)
normalizeReference :: Text -> Text
normalizeReference :: Text -> Text
normalizeReference = Text -> Text
T.toCaseFold forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
T.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> Text -> [Text]
T.split Char -> Bool
isWhitespace
type Scanner = Parser ()
scanIndentSpace :: Scanner
scanIndentSpace :: Scanner
scanIndentSpace = () forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ forall (m :: * -> *) a. Monad m => Int -> m a -> m [a]
count Int
4 ((Char -> Bool) -> Scanner
skip (forall a. Eq a => a -> a -> Bool
==Char
' '))
scanSpacesToColumn :: Int -> Scanner
scanSpacesToColumn :: Int -> Scanner
scanSpacesToColumn Int
col = do
Int
currentCol <- Position -> Int
column forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser Position
getPosition
case Int
col forall a. Num a => a -> a -> a
- Int
currentCol of
Int
n | Int
n forall a. Ord a => a -> a -> Bool
>= Int
1 -> () forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ (forall (m :: * -> *) a. Monad m => Int -> m a -> m [a]
count Int
n ((Char -> Bool) -> Scanner
skip (forall a. Eq a => a -> a -> Bool
==Char
' ')))
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
scanNonindentSpace :: Scanner
scanNonindentSpace :: Scanner
scanNonindentSpace = () forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Int -> (Char -> Bool) -> Parser Text
upToCountChars Int
3 (forall a. Eq a => a -> a -> Bool
==Char
' ')
scanChar :: Char -> Scanner
scanChar :: Char -> Scanner
scanChar Char
c = (Char -> Bool) -> Scanner
skip (forall a. Eq a => a -> a -> Bool
== Char
c) forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return ()
scanBlankline :: Scanner
scanBlankline :: Scanner
scanBlankline = Scanner
scanSpaces forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Scanner
endOfInput
scanSpaces :: Scanner
scanSpaces :: Scanner
scanSpaces = (Char -> Bool) -> Scanner
skipWhile (forall a. Eq a => a -> a -> Bool
==Char
' ')
scanSpnl :: Scanner
scanSpnl :: Scanner
scanSpnl = Scanner
scanSpaces forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall (f :: * -> *) a. Alternative f => a -> f a -> f a
option () (Char -> Parser Char
char Char
'\n' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Scanner
scanSpaces)
nfb :: Parser a -> Scanner
nfb :: forall a. Parser a -> Scanner
nfb = forall a. Parser a -> Scanner
notFollowedBy
nfbChar :: Char -> Scanner
nfbChar :: Char -> Scanner
nfbChar Char
c = forall a. Parser a -> Scanner
nfb ((Char -> Bool) -> Scanner
skip (forall a. Eq a => a -> a -> Bool
==Char
c))
upToCountChars :: Int -> (Char -> Bool) -> Parser Text
upToCountChars :: Int -> (Char -> Bool) -> Parser Text
upToCountChars Int
cnt Char -> Bool
f =
forall s. s -> (s -> Char -> Maybe s) -> Parser Text
scan Int
0 (\Int
n Char
c -> if Int
n forall a. Ord a => a -> a -> Bool
< Int
cnt Bool -> Bool -> Bool
&& Char -> Bool
f Char
c then forall a. a -> Maybe a
Just (Int
nforall a. Num a => a -> a -> a
+Int
1) else forall a. Maybe a
Nothing)