module Wiki where -------------------------------------------------------------------------------- -- List of imported modules and functions import Data.Maybe (fromJust) import Text.Html import Network.Shed.Httpd import Network.URI -------------------------------------------------------------------------------- -- | String formatting alternatives for inline text. data Inline = Bold String | Unformatted String deriving (Eq, Show) -- | A list of (un)formatted strings. type Text = [Inline] -- | Text formatting alternatives for blocks of text (between newlines). data Block = Bullet Text | Paragraph Text deriving (Eq, Show) -- | A list of (un)formatted blocks. type Page = [Block] -------------------------------------------------------------------------------- -- | Split a string into its lexical components to simplify manipulation. inlinify :: String -> [String] inlinify [] = [] inlinify str = case split [] str of (ln, wd, next) -> appCons reverse ln . appCons id wd $ inlinify next where split ln ('*':'*':cs) = (ln, "**", cs) split ln (c:cs) = split (c : ln) cs split ln "" = (ln, "", "") -- | Apply a function to a list and cons the result to another list. appCons :: ([a] -> b) -> [a] -> [b] -> [b] appCons _ [] = id appCons f xs = (f xs :) -- | Split lines into their lexical components to simplify manipulation. blockify :: [String] -> [String] blockify [] = [] blockify lns = case split [] lns of (paras, ln, next) -> appCons (unwords . reverse) paras . appCons id ln $ blockify next where split paras (l@('*':' ':_):ls) = (paras, l, ls) split paras ("":ls) = (paras, [], ls) split paras (l:ls) = split (l : paras) ls split paras [] = (paras, [], []) -- | Merge two |Maybe| values with priority on the first one. mplus :: Maybe a -> Maybe a -> Maybe a mplus Nothing y = y mplus x _ = x -------------------------------------------------------------------------------- -- Ex. 3 -- Ex. 4 readInline :: [String] -> Maybe (Inline, [String]) readInline inp = readBold inp `mplus` readUnformattedInline inp readUnformattedInline :: [String] -> Maybe (Inline, [String]) readUnformattedInline [] = Nothing readUnformattedInline (c:cs) = Just (Unformatted c, cs) readBold :: [String] -> Maybe (Inline, [String]) readBold inp = case inp of "**":txt:"**":rest -> Just (Bold txt, rest) _ -> Nothing -------------------------------------------------------------------------------- -- Ex. 5 readText :: String -> Text readText = undefined -------------------------------------------------------------------------------- -- Ex. 6 readBlock :: String -> Block readBlock inp = fromJust $ readBullet inp `mplus` readUnformattedBlock inp readUnformattedBlock :: String -> Maybe Block readUnformattedBlock = Just . Paragraph . readText readBullet :: String -> Maybe Block readBullet inp = case inp of '*':' ':txt -> Just . Bullet $ readText txt _ -> Nothing -------------------------------------------------------------------------------- -- Ex. 7 readPage :: String -> Page readPage = undefined -------------------------------------------------------------------------------- -- Ex. 9 -- | Example use of Text.HTML: make a paragraph with |"Hello, World!"| in bold. exampleHtml :: Html exampleHtml = thehtml << body << p << bold << "Hello, World!" inlineToHtml :: Inline -> Html inlineToHtml = undefined textToHtml :: Text -> Html textToHtml = undefined -------------------------------------------------------------------------------- -- Ex. 10 -- | Example unordered list with list items in HTML. exampleList :: Html exampleList = ulist << [li << "item 1", li << "item 2"] blockToHtml :: Block -> Html blockToHtml = undefined pageToHtml :: Page -> Html pageToHtml = undefined -- | Convert a wiki-formatted string to a renderable HTML string. wikify :: String -> String wikify = renderHtml . (body <<) . pageToHtml . readPage -------------------------------------------------------------------------------- simpleServer :: Request -> IO Response simpleServer = return . Response responseOK [contentText] . show initMyServer :: (Request -> IO Response) -> IO Server initMyServer = initServer myPort myPort :: Int myPort = 7734 contentText, contentHtml :: (String, String) contentText = contentType "text/plain" contentHtml = contentType "text/html" responseOK, responseNotFound :: Int responseOK = 200 responseNotFound = 404 methodGET, methodPOST :: String methodGET = "GET" methodPOST = "POST" -------------------------------------------------------------------------------- -- Ex. 12 fileServer :: Request -> IO Response fileServer = undefined -------------------------------------------------------------------------------- -- Ex. 13 -- | Example form with a single text field. exampleForm :: Html exampleForm = form ! [action $ "http://localhost:" ++ show myPort ++ "/post", method methodPOST] << [ input ! [thetype "text"] , input ! [thetype "submit", value "Submit"] ] wikiFormServer :: Request -> IO Response wikiFormServer = undefined