{-# LANGUAGE CPP #-}
module Network.Gitit.Page ( stringToPage
, pageToString
, readCategories
)
where
import Network.Gitit.Types
import Network.Gitit.Util (trim, splitCategories, parsePageType)
import Text.ParserCombinators.Parsec
import Data.Char (toLower)
import Data.List (intercalate)
import Data.Maybe (fromMaybe)
import Data.ByteString.UTF8 (toString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import System.IO (withFile, Handle, IOMode(..))
import qualified Control.Exception as E
import System.IO.Error (isEOFError)
parseMetadata :: String -> ([(String, String)], String)
parseMetadata :: [Char] -> ([([Char], [Char])], [Char])
parseMetadata [Char]
raw =
case Parsec [Char] () ([([Char], [Char])], [Char])
-> [Char]
-> [Char]
-> Either ParseError ([([Char], [Char])], [Char])
forall s t a.
Stream s Identity t =>
Parsec s () a -> [Char] -> s -> Either ParseError a
parse Parsec [Char] () ([([Char], [Char])], [Char])
forall st. GenParser Char st ([([Char], [Char])], [Char])
pMetadataBlock [Char]
"" [Char]
raw of
Left ParseError
_ -> ([], [Char]
raw)
Right ([([Char], [Char])]
ls, [Char]
rest) -> ([([Char], [Char])]
ls, [Char]
rest)
pMetadataBlock :: GenParser Char st ([(String, String)], String)
pMetadataBlock :: forall st. GenParser Char st ([([Char], [Char])], [Char])
pMetadataBlock = GenParser Char st ([([Char], [Char])], [Char])
-> GenParser Char st ([([Char], [Char])], [Char])
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st ([([Char], [Char])], [Char])
-> GenParser Char st ([([Char], [Char])], [Char]))
-> GenParser Char st ([([Char], [Char])], [Char])
-> GenParser Char st ([([Char], [Char])], [Char])
forall a b. (a -> b) -> a -> b
$ do
[Char]
_ <- [Char] -> ParsecT [Char] st Identity [Char]
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m [Char]
string [Char]
"---"
Char
_ <- GenParser Char st Char
forall st. GenParser Char st Char
pBlankline
[([Char], [Char])]
ls <- ParsecT [Char] st Identity ([Char], [Char])
-> GenParser Char st Char
-> ParsecT [Char] st Identity [([Char], [Char])]
forall s (m :: * -> *) t u a end.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
manyTill ParsecT [Char] st Identity ([Char], [Char])
forall st. GenParser Char st ([Char], [Char])
pMetadataLine GenParser Char st Char
forall st. GenParser Char st Char
pMetaEnd
GenParser Char st Char -> ParsecT [Char] st Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany GenParser Char st Char
forall st. GenParser Char st Char
pBlankline
[Char]
rest <- ParsecT [Char] st Identity [Char]
forall (m :: * -> *) s u. Monad m => ParsecT s u m s
getInput
([([Char], [Char])], [Char])
-> GenParser Char st ([([Char], [Char])], [Char])
forall a. a -> ParsecT [Char] st Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ([([Char], [Char])]
ls, [Char]
rest)
pMetaEnd :: GenParser Char st Char
pMetaEnd :: forall st. GenParser Char st Char
pMetaEnd = GenParser Char st Char -> GenParser Char st Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st Char -> GenParser Char st Char)
-> GenParser Char st Char -> GenParser Char st Char
forall a b. (a -> b) -> a -> b
$ do
[Char] -> ParsecT [Char] st Identity [Char]
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m [Char]
string [Char]
"..." ParsecT [Char] st Identity [Char]
-> ParsecT [Char] st Identity [Char]
-> ParsecT [Char] st Identity [Char]
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> [Char] -> ParsecT [Char] st Identity [Char]
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m [Char]
string [Char]
"---"
GenParser Char st Char
forall st. GenParser Char st Char
pBlankline
pBlankline :: GenParser Char st Char
pBlankline :: forall st. GenParser Char st Char
pBlankline = GenParser Char st Char -> GenParser Char st Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st Char -> GenParser Char st Char)
-> GenParser Char st Char -> GenParser Char st Char
forall a b. (a -> b) -> a -> b
$ GenParser Char st Char -> ParsecT [Char] st Identity [Char]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many ([Char] -> GenParser Char st Char
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m Char
oneOf [Char]
" \t") ParsecT [Char] st Identity [Char]
-> GenParser Char st Char -> GenParser Char st Char
forall a b.
ParsecT [Char] st Identity a
-> ParsecT [Char] st Identity b -> ParsecT [Char] st Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> GenParser Char st Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline
pMetadataLine :: GenParser Char st (String, String)
pMetadataLine :: forall st. GenParser Char st ([Char], [Char])
pMetadataLine = GenParser Char st ([Char], [Char])
-> GenParser Char st ([Char], [Char])
forall tok st a. GenParser tok st a -> GenParser tok st a
try (GenParser Char st ([Char], [Char])
-> GenParser Char st ([Char], [Char]))
-> GenParser Char st ([Char], [Char])
-> GenParser Char st ([Char], [Char])
forall a b. (a -> b) -> a -> b
$ do
Char
first <- ParsecT [Char] st Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter
[Char]
rest <- ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity [Char]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT [Char] st Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
letter ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> [Char] -> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m Char
oneOf [Char]
"-_")
let ident :: [Char]
ident = Char
firstChar -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
rest
ParsecT [Char] st Identity Char -> ParsecT [Char] st Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany ([Char] -> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m Char
oneOf [Char]
" \t")
Char
_ <- Char -> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char Char
':'
[Char]
rawval <- ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity [Char]
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity [Char])
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m Char
noneOf [Char]
"\n\r"
ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (ParsecT [Char] st Identity Char -> ParsecT [Char] st Identity Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char)
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
forall a b. (a -> b) -> a -> b
$ ParsecT [Char] st Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity () -> ParsecT [Char] st Identity ()
forall a b.
ParsecT [Char] st Identity a
-> ParsecT [Char] st Identity b -> ParsecT [Char] st Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ParsecT [Char] st Identity Char -> ParsecT [Char] st Identity ()
forall s (m :: * -> *) t a u.
(Stream s m t, Show a) =>
ParsecT s u m a -> ParsecT s u m ()
notFollowedBy ParsecT [Char] st Identity Char
forall st. GenParser Char st Char
pBlankline ParsecT [Char] st Identity ()
-> ParsecT [Char] st Identity () -> ParsecT [Char] st Identity ()
forall a b.
ParsecT [Char] st Identity a
-> ParsecT [Char] st Identity b -> ParsecT [Char] st Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
ParsecT [Char] st Identity Char -> ParsecT [Char] st Identity ()
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m ()
skipMany1 ([Char] -> ParsecT [Char] st Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
[Char] -> ParsecT s u m Char
oneOf [Char]
" \t") ParsecT [Char] st Identity ()
-> ParsecT [Char] st Identity Char
-> ParsecT [Char] st Identity Char
forall a b.
ParsecT [Char] st Identity a
-> ParsecT [Char] st Identity b -> ParsecT [Char] st Identity b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT [Char] st Identity Char
forall a. a -> ParsecT [Char] st Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return Char
' ')
Char
_ <- ParsecT [Char] st Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
newline
([Char], [Char]) -> GenParser Char st ([Char], [Char])
forall a. a -> ParsecT [Char] st Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char]
ident, [Char] -> [Char]
trim [Char]
rawval)
stringToPage :: Config -> String -> String -> Page
stringToPage :: Config -> [Char] -> [Char] -> Page
stringToPage Config
conf [Char]
pagename [Char]
raw =
let ([([Char], [Char])]
ls, [Char]
rest) = [Char] -> ([([Char], [Char])], [Char])
parseMetadata [Char]
raw
page' :: Page
page' = Page { pageName :: [Char]
pageName = [Char]
pagename
, pageFormat :: PageType
pageFormat = Config -> PageType
defaultPageType Config
conf
, pageLHS :: Bool
pageLHS = Config -> Bool
defaultLHS Config
conf
, pageTOC :: Bool
pageTOC = Config -> Bool
tableOfContents Config
conf
, pageTitle :: [Char]
pageTitle = [Char]
pagename
, pageCategories :: [[Char]]
pageCategories = []
, pageText :: [Char]
pageText = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\r') [Char]
rest
, pageMeta :: [([Char], [Char])]
pageMeta = [([Char], [Char])]
ls }
in (([Char], [Char]) -> Page -> Page)
-> Page -> [([Char], [Char])] -> Page
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ([Char], [Char]) -> Page -> Page
adjustPage Page
page' [([Char], [Char])]
ls
adjustPage :: (String, String) -> Page -> Page
adjustPage :: ([Char], [Char]) -> Page -> Page
adjustPage ([Char]
"title", [Char]
val) Page
page' = Page
page' { pageTitle = val }
adjustPage ([Char]
"format", [Char]
val) Page
page' = Page
page' { pageFormat = pt, pageLHS = lhs }
where (PageType
pt, Bool
lhs) = [Char] -> (PageType, Bool)
parsePageType [Char]
val
adjustPage ([Char]
"toc", [Char]
val) Page
page' = Page
page' {
pageTOC = map toLower val `elem` ["yes","true"] }
adjustPage ([Char]
"categories", [Char]
val) Page
page' =
Page
page' { pageCategories = splitCategories val ++ pageCategories page' }
adjustPage ([Char]
_, [Char]
_) Page
page' = Page
page'
pageToString :: Config -> Page -> String
pageToString :: Config -> Page -> [Char]
pageToString Config
conf Page
page' =
let pagename :: [Char]
pagename = Page -> [Char]
pageName Page
page'
pagetitle :: [Char]
pagetitle = Page -> [Char]
pageTitle Page
page'
pageformat :: PageType
pageformat = Page -> PageType
pageFormat Page
page'
pagelhs :: Bool
pagelhs = Page -> Bool
pageLHS Page
page'
pagetoc :: Bool
pagetoc = Page -> Bool
pageTOC Page
page'
pagecats :: [[Char]]
pagecats = Page -> [[Char]]
pageCategories Page
page'
metadata :: [([Char], [Char])]
metadata = (([Char], [Char]) -> Bool)
-> [([Char], [Char])] -> [([Char], [Char])]
forall a. (a -> Bool) -> [a] -> [a]
filter
(\([Char]
k, [Char]
_) -> Bool -> Bool
not ([Char]
k [Char] -> [[Char]] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`
[[Char]
"title", [Char]
"format", [Char]
"toc", [Char]
"categories"]))
(Page -> [([Char], [Char])]
pageMeta Page
page')
metadata' :: [Char]
metadata' = (if [Char]
pagename [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char]
pagetitle
then [Char]
"title: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
pagetitle [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\n"
else [Char]
"") [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
(if PageType
pageformat PageType -> PageType -> Bool
forall a. Eq a => a -> a -> Bool
/= Config -> PageType
defaultPageType Config
conf Bool -> Bool -> Bool
||
Bool
pagelhs Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Config -> Bool
defaultLHS Config
conf
then [Char]
"format: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
(Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower (PageType -> [Char]
forall a. Show a => a -> [Char]
show PageType
pageformat) [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
if Bool
pagelhs then [Char]
"+lhs\n" else [Char]
"\n"
else [Char]
"") [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
(if Bool
pagetoc Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Config -> Bool
tableOfContents Config
conf
then [Char]
"toc: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
(if Bool
pagetoc then [Char]
"yes" else [Char]
"no") [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\n"
else [Char]
"") [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
(if Bool -> Bool
not ([[Char]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Char]]
pagecats)
then [Char]
"categories: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [[Char]] -> [Char]
forall a. [a] -> [[a]] -> [a]
intercalate [Char]
", " [[Char]]
pagecats [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\n"
else [Char]
"") [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
([[Char]] -> [Char]
unlines ((([Char], [Char]) -> [Char]) -> [([Char], [Char])] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map (\([Char]
k, [Char]
v) -> [Char]
k [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
": " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
v) [([Char], [Char])]
metadata))
in (if [Char] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
metadata' then [Char]
"" else [Char]
"---\n" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
metadata' [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"...\n\n")
[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Page -> [Char]
pageText Page
page'
readCategories :: FilePath -> IO [String]
readCategories :: [Char] -> IO [[Char]]
readCategories [Char]
f =
[Char] -> IOMode -> (Handle -> IO [[Char]]) -> IO [[Char]]
forall r. [Char] -> IOMode -> (Handle -> IO r) -> IO r
withFile [Char]
f IOMode
ReadMode ((Handle -> IO [[Char]]) -> IO [[Char]])
-> (Handle -> IO [[Char]]) -> IO [[Char]]
forall a b. (a -> b) -> a -> b
$ \Handle
h ->
IO [[Char]] -> (IOError -> IO [[Char]]) -> IO [[Char]]
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
E.catch (do ByteString
fl <- Handle -> IO ByteString
B.hGetLine Handle
h
if ByteString -> Bool
dashline ByteString
fl
then do
[[Char]]
rest <- Handle -> (ByteString -> Bool) -> IO [[Char]]
hGetLinesTill Handle
h ByteString -> Bool
dotOrDashline
let ([([Char], [Char])]
md,[Char]
_) = [Char] -> ([([Char], [Char])], [Char])
parseMetadata ([Char] -> ([([Char], [Char])], [Char]))
-> [Char] -> ([([Char], [Char])], [Char])
forall a b. (a -> b) -> a -> b
$ [[Char]] -> [Char]
unlines ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
"---"[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[[Char]]
rest
[[Char]] -> IO [[Char]]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([[Char]] -> IO [[Char]]) -> [[Char]] -> IO [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]]
splitCategories ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char] -> Maybe [Char] -> [Char]
forall a. a -> Maybe a -> a
fromMaybe [Char]
""
(Maybe [Char] -> [Char]) -> Maybe [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [([Char], [Char])] -> Maybe [Char]
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [Char]
"categories" [([Char], [Char])]
md
else [[Char]] -> IO [[Char]]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [])
(\IOError
e -> if IOError -> Bool
isEOFError IOError
e then [[Char]] -> IO [[Char]]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [] else IOError -> IO [[Char]]
forall e a. Exception e => e -> IO a
E.throwIO IOError
e)
dashline :: B.ByteString -> Bool
dashline :: ByteString -> Bool
dashline ByteString
x =
case ByteString -> [Char]
BC.unpack ByteString
x of
(Char
'-':Char
'-':Char
'-':[Char]
xs) | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') [Char]
xs -> Bool
True
[Char]
_ -> Bool
False
dotOrDashline :: B.ByteString -> Bool
dotOrDashline :: ByteString -> Bool
dotOrDashline ByteString
x =
case ByteString -> [Char]
BC.unpack ByteString
x of
(Char
'-':Char
'-':Char
'-':[Char]
xs) | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') [Char]
xs -> Bool
True
(Char
'.':Char
'.':Char
'.':[Char]
xs) | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') [Char]
xs -> Bool
True
[Char]
_ -> Bool
False
hGetLinesTill :: Handle -> (B.ByteString -> Bool) -> IO [String]
hGetLinesTill :: Handle -> (ByteString -> Bool) -> IO [[Char]]
hGetLinesTill Handle
h ByteString -> Bool
end = do
ByteString
next <- Handle -> IO ByteString
B.hGetLine Handle
h
if ByteString -> Bool
end ByteString
next
then [[Char]] -> IO [[Char]]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [ByteString -> [Char]
toString ByteString
next]
else do
[[Char]]
rest <- Handle -> (ByteString -> Bool) -> IO [[Char]]
hGetLinesTill Handle
h ByteString -> Bool
end
[[Char]] -> IO [[Char]]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> [Char]
toString ByteString
next[Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
:[[Char]]
rest)