markdown-kate (empty) → 0.1.2.1
raw patch · 71 files changed
+3881/−0 lines, 71 filesdep +attoparsecdep +attoparsec-conduitdep +basesetup-changed
Dependencies added: attoparsec, attoparsec-conduit, base, blaze-html, conduit, containers, data-default, highlighting-kate, hspec, markdown, system-fileio, system-filepath, text, transformers, xss-sanitize
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- Text/Markdown.hs +158/−0
- Text/Markdown/Block.hs +324/−0
- Text/Markdown/Inline.hs +232/−0
- Text/Markdown/Types.hs +119/−0
- markdown-kate.cabal +57/−0
- test/Block.hs +86/−0
- test/Inline.hs +75/−0
- test/Tests/Amps and angle encoding.html +17/−0
- test/Tests/Amps and angle encoding.text +21/−0
- test/Tests/Auto links.html +18/−0
- test/Tests/Auto links.text +13/−0
- test/Tests/Backslash escapes.html +118/−0
- test/Tests/Backslash escapes.text +120/−0
- test/Tests/Blockquotes with code blocks.html +15/−0
- test/Tests/Blockquotes with code blocks.text +11/−0
- test/Tests/Code Blocks.html +18/−0
- test/Tests/Code Blocks.text +14/−0
- test/Tests/Code Spans.html +5/−0
- test/Tests/Code Spans.text +5/−0
- test/Tests/Hard-wrapped paragraphs with list-like lines.html +8/−0
- test/Tests/Hard-wrapped paragraphs with list-like lines.text +8/−0
- test/Tests/Horizontal rules.html +71/−0
- test/Tests/Horizontal rules.text +67/−0
- test/Tests/Images.html +21/−0
- test/Tests/Images.text +26/−0
- test/Tests/Inline HTML (Advanced).html +30/−0
- test/Tests/Inline HTML (Advanced).text +30/−0
- test/Tests/Inline HTML (Simple).html +72/−0
- test/Tests/Inline HTML (Simple).text +69/−0
- test/Tests/Inline HTML comments.html +13/−0
- test/Tests/Inline HTML comments.text +13/−0
- test/Tests/Links, inline style.html +23/−0
- test/Tests/Links, inline style.text +24/−0
- test/Tests/Links, reference style.html +52/−0
- test/Tests/Links, reference style.text +71/−0
- test/Tests/Links, shortcut references.html +9/−0
- test/Tests/Links, shortcut references.text +20/−0
- test/Tests/Literal quotes in titles.html +3/−0
- test/Tests/Literal quotes in titles.text +7/−0
- test/Tests/Markdown Documentation - Basics.html +314/−0
- test/Tests/Markdown Documentation - Syntax.html +942/−0
- test/Tests/Nested blockquotes.html +9/−0
- test/Tests/Nested blockquotes.text +5/−0
- test/Tests/Ordered and unordered lists.html +148/−0
- test/Tests/Strong and em together.html +7/−0
- test/Tests/Strong and em together.text +7/−0
- test/Tests/Tabs.html +25/−0
- test/Tests/Tabs.text +21/−0
- test/Tests/Tidyness.html +8/−0
- test/Tests/Tidyness.text +5/−0
- test/examples/closing-tags.html +1/−0
- test/examples/closing-tags.md +1/−0
- test/examples/entities.html +1/−0
- test/examples/entities.md +1/−0
- test/examples/fence-whitespace.html +1/−0
- test/examples/fence-whitespace.md +4/−0
- test/examples/lazy.html +3/−0
- test/examples/lazy.md +6/−0
- test/examples/list-blocks.html +1/−0
- test/examples/list-blocks.md +12/−0
- test/examples/lists-code.html +2/−0
- test/examples/lists-code.md +7/−0
- test/examples/multiline-paragraphs.html +5/−0
- test/examples/multiline-paragraphs.md +9/−0
- test/examples/sublists.html +1/−0
- test/examples/sublists.md +4/−0
- test/examples/tilde-code.html +4/−0
- test/examples/tilde-code.md +6/−0
- test/main.hs +226/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Michael Snoyman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Michael Snoyman nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Text/Markdown.hs view
@@ -0,0 +1,158 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+module Text.Markdown+ ( -- * Functions+ markdown+ -- * Settings+ , MarkdownSettings+ , msXssProtect+ , msStandaloneHtml+ , msFencedHandlers+ -- * Newtype+ , Markdown (..)+ -- * Fenced handlers+ , FencedHandler (..)+ , codeFencedHandler+ , htmlFencedHandler+ -- * Convenience re-exports+ , def+ ) where++import Text.Markdown.Inline+import Text.Markdown.Block+import Text.Markdown.Types+import Text.Highlighting.Kate+import Prelude hiding (sequence, takeWhile)+import Data.Default (Default (..))+import Data.Text (Text, unpack)+import qualified Data.Text.Lazy as TL+import Text.Blaze.Html (ToMarkup (..), Html)+import Text.Blaze.Html.Renderer.Text (renderHtml)+import Data.Conduit+import qualified Data.Conduit.List as CL+import Data.Monoid (Monoid (mappend, mempty, mconcat))+import Data.Functor.Identity (runIdentity)+import qualified Text.Blaze.Html5 as H+import qualified Text.Blaze.Html5.Attributes as HA+import Text.HTML.SanitizeXSS (sanitizeBalance)+import qualified Data.Map as Map+import Data.String (IsString)++-- | A newtype wrapper providing a @ToHtml@ instance.+newtype Markdown = Markdown TL.Text+ deriving(Monoid, IsString)++instance ToMarkup Markdown where+ toMarkup (Markdown t) = markdown def t++-- | Convert the given textual markdown content to HTML.+--+-- >>> :set -XOverloadedStrings+-- >>> import Text.Blaze.Html.Renderer.Text+-- >>> renderHtml $ markdown def "# Hello World!"+-- "<h1>Hello World!</h1>"+--+-- >>> renderHtml $ markdown def { msXssProtect = False } "<script>alert('evil')</script>"+-- "<script>alert('evil')</script>"+markdown :: MarkdownSettings -> TL.Text -> Html+markdown ms tl =+ sanitize+ $ runIdentity+ $ CL.sourceList blocksH+ $= toHtmlB ms+ $$ CL.fold mappend mempty+ where+ sanitize+ | msXssProtect ms = preEscapedToMarkup . sanitizeBalance . TL.toStrict . renderHtml+ | otherwise = id+ fixBlock :: Block Text -> Block Html+ fixBlock = fmap $ toHtmlI ms . toInline refs++ blocksH :: [Block Html]+ blocksH = map fixBlock blocks++ blocks :: [Block Text]+ blocks = runIdentity+ $ CL.sourceList (TL.toChunks tl)+ $$ toBlocks ms+ =$ CL.consume++ refs =+ Map.unions $ map toRef blocks+ where+ toRef (BlockReference x y) = Map.singleton x y+ toRef _ = Map.empty++data MState = NoState | InList ListType++toHtmlB :: Monad m => MarkdownSettings -> Conduit (Block Html) m Html+toHtmlB ms =+ loop NoState+ where+ loop state = await >>= maybe+ (closeState state)+ (\x -> do+ state' <- getState state x+ yield $ go x+ loop state')++ closeState NoState = return ()+ closeState (InList Unordered) = yield $ escape "</ul>"+ closeState (InList Ordered) = yield $ escape "</ol>"++ getState NoState (BlockList ltype _) = do+ yield $ escape $+ case ltype of+ Unordered -> "<ul>"+ Ordered -> "<ol>"+ return $ InList ltype+ getState NoState _ = return NoState+ getState state@(InList lt1) b@(BlockList lt2 _)+ | lt1 == lt2 = return state+ | otherwise = closeState state >> getState NoState b+ getState state@(InList _) _ = closeState state >> return NoState++ go (BlockPara h) = H.p h+ go (BlockPlainText h) = h+ go (BlockList _ (Left h)) = H.li h+ go (BlockList _ (Right bs)) = H.li $ blocksToHtml bs+ go (BlockHtml t) = escape t+ go (BlockCode Nothing t) = H.pre $ H.code $ toMarkup t+ go (BlockCode (Just lang) t) = H.figure $ toHighlighted (unpack lang) (unpack t)+ go (BlockQuote bs) = H.blockquote $ blocksToHtml bs+ go BlockRule = H.hr+ go (BlockHeading level h) =+ wrap level h+ where+ wrap 1 = H.h1+ wrap 2 = H.h2+ wrap 3 = H.h3+ wrap 4 = H.h4+ wrap 5 = H.h5+ wrap _ = H.h6+ go BlockReference{} = return ()++ toHighlighted l t' = toMarkup $ formatHtmlBlock (defaultFormatOpts { numberLines = True }) $ highlightAs l t'+ blocksToHtml bs = runIdentity $ mapM_ yield bs $$ toHtmlB ms =$ CL.fold mappend mempty++escape :: Text -> Html+escape = preEscapedToMarkup++toHtmlI :: MarkdownSettings -> [Inline] -> Html+toHtmlI ms is0+ | msXssProtect ms = escape $ sanitizeBalance $ TL.toStrict $ renderHtml final+ | otherwise = final+ where+ final = gos is0+ gos = mconcat . map go++ go (InlineText t) = toMarkup t+ go (InlineItalic is) = H.i $ gos is+ go (InlineBold is) = H.b $ gos is+ go (InlineCode t) = H.code $ toMarkup t+ go (InlineLink url Nothing content) = H.a H.! HA.href (H.toValue url) $ gos content+ go (InlineLink url (Just title) content) = H.a H.! HA.href (H.toValue url) H.! HA.title (H.toValue title) $ gos content+ go (InlineImage url Nothing content) = H.img H.! HA.src (H.toValue url) H.! HA.alt (H.toValue content)+ go (InlineImage url (Just title) content) = H.img H.! HA.src (H.toValue url) H.! HA.alt (H.toValue content) H.! HA.title (H.toValue title)+ go (InlineHtml t) = escape t
+ Text/Markdown/Block.hs view
@@ -0,0 +1,324 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE CPP #-}+{-# OPTIONS_HADDOCK hide #-}+module Text.Markdown.Block+ ( Block (..)+ , ListType (..)+ , toBlocks+ ) where++import Prelude+#if MIN_VERSION_conduit(1, 0, 0)+import Data.Conduit+#else+import Data.Conduit hiding ((=$=))+import Data.Conduit.Internal (pipeL)+#endif+import qualified Data.Conduit.Text as CT+import qualified Data.Conduit.List as CL+import Data.Text (Text)+import qualified Data.Text as T+import Data.Functor.Identity (runIdentity)+import Data.Char (isDigit)+import Text.Markdown.Types+import qualified Data.Set as Set+import qualified Data.Map as Map++#if !MIN_VERSION_conduit(1, 0, 0)+(=$=) :: Monad m => Pipe a a b x m y -> Pipe b b c y m z -> Pipe a a c x m z+(=$=) = pipeL+#endif++toBlocks :: Monad m => MarkdownSettings -> Conduit Text m (Block Text)+toBlocks ms =+ mapOutput fixWS CT.lines =$= toBlocksLines ms+ where+ fixWS = T.pack . go 0 . T.unpack++ go _ [] = []+ go i ('\r':cs) = go i cs+ go i ('\t':cs) =+ (replicate j ' ') ++ go (i + j) cs+ where+ j = 4 - (i `mod` 4)+ go i (c:cs) = c : go (i + 1) cs++toBlocksLines :: Monad m => MarkdownSettings -> Conduit Text m (Block Text)+toBlocksLines ms = awaitForever (start ms) =$= tightenLists++tightenLists :: Monad m => Conduit (Either Blank (Block Text)) m (Block Text)+tightenLists =+ go Nothing+ where+ go mTightList =+ await >>= maybe (return ()) go'+ where+ go' (Left Blank) = go mTightList+ go' (Right (BlockList ltNew contents)) =+ case mTightList of+ Just (ltOld, isTight) | ltOld == ltNew -> do+ yield $ BlockList ltNew $ (if isTight then tighten else untighten) contents+ go mTightList+ _ -> do+ isTight <- checkTight ltNew False+ yield $ BlockList ltNew $ (if isTight then tighten else untighten) contents+ go $ Just (ltNew, isTight)+ go' (Right b) = yield b >> go Nothing++ tighten (Right [BlockPara t]) = Left t+ tighten (Right []) = Left T.empty+ tighten x = x++ untighten (Left t) = Right [BlockPara t]+ untighten x = x++ checkTight lt sawBlank = do+ await >>= maybe (return $ not sawBlank) go'+ where+ go' (Left Blank) = checkTight lt True+ go' b@(Right (BlockList ltNext _)) | ltNext == lt = do+ leftover b+ return $ not sawBlank+ go' b = leftover b >> return False++data Blank = Blank++data LineType = LineList ListType Text+ | LineCode Text+ | LineFenced Text FencedHandler -- ^ terminator, language+ | LineBlockQuote Text+ | LineHeading Int Text+ | LineBlank+ | LineText Text+ | LineRule+ | LineHtml Text+ | LineReference Text Text -- ^ name, destination++lineType :: MarkdownSettings -> Text -> LineType+lineType ms t+ | T.null $ T.strip t = LineBlank+ | Just (term, fh) <- getFenced (Map.toList $ msFencedHandlers ms) t = LineFenced term fh+ | Just t' <- T.stripPrefix "> " t = LineBlockQuote t'+ | Just (level, t') <- stripHeading t = LineHeading level t'+ | Just t' <- T.stripPrefix " " t = LineCode t'+ | isRule t = LineRule+ | isHtmlStart t = LineHtml t+ | Just (ltype, t') <- listStart t = LineList ltype t'+ | Just (name, dest) <- getReference t = LineReference name dest+ | otherwise = LineText t+ where+ getFenced [] _ = Nothing+ getFenced ((x, fh):xs) t'+ | Just rest <- T.stripPrefix x t' = Just (x, fh $ T.strip rest)+ | otherwise = getFenced xs t'++ isRule :: Text -> Bool+ isRule =+ go . T.strip+ where+ go "* * *" = True+ go "***" = True+ go "*****" = True+ go "- - -" = True+ go "---" = True+ go "___" = True+ go "_ _ _" = True+ go t' = T.length (T.takeWhile (== '-') t') >= 5++ stripHeading :: Text -> Maybe (Int, Text)+ stripHeading t'+ | T.null x = Nothing+ | otherwise = Just (T.length x, T.strip $ T.dropWhileEnd (== '#') y)+ where+ (x, y) = T.span (== '#') t'++ getReference :: Text -> Maybe (Text, Text)+ getReference a = do+ b <- T.stripPrefix "[" $ T.dropWhile (== ' ') a+ let (name, c) = T.break (== ']') b+ d <- T.stripPrefix "]:" c+ Just (name, T.strip d)++start :: Monad m => MarkdownSettings -> Text -> Conduit Text m (Either Blank (Block Text))+start ms t =+ go $ lineType ms t+ where+ go LineBlank = yield $ Left Blank+ go (LineFenced term fh) = do+ (finished, ls) <- takeTillConsume (== term)+ case finished of+ Just _ -> do+ let block =+ case fh of+ FHRaw fh' -> fh' $ T.intercalate "\n" ls+ FHParsed fh' -> fh' $ runIdentity $ mapM_ yield ls $$ toBlocksLines ms =$ CL.consume+ mapM_ (yield . Right) block+ Nothing -> mapM_ leftover (reverse $ T.cons ' ' t : ls)+ go (LineBlockQuote t') = do+ ls <- takeQuotes =$= CL.consume+ let blocks = runIdentity $ mapM_ yield (t' : ls) $$ toBlocksLines ms =$ CL.consume+ yield $ Right $ BlockQuote blocks+ go (LineHeading level t') = yield $ Right $ BlockHeading level t'+ go (LineCode t') = do+ ls <- getIndented 4 =$= CL.consume+ yield $ Right $ BlockCode Nothing $ T.intercalate "\n" $ t' : ls+ go LineRule = yield $ Right BlockRule+ go (LineHtml t') = do+ if t' `Set.member` msStandaloneHtml ms+ then yield $ Right $ BlockHtml t'+ else do+ ls <- takeTill (T.null . T.strip) =$= CL.consume+ yield $ Right $ BlockHtml $ T.intercalate "\n" $ t' : ls+ go (LineList ltype t') = do+ t2 <- CL.peek+ case fmap (lineType ms) t2 of+ -- If the next line is a non-indented text line, then we have a+ -- lazy list.+ Just (LineText t2') | T.null (T.takeWhile (== ' ') t2') -> do+ CL.drop 1+ -- Get all of the non-indented lines.+ let loop front = do+ x <- await+ case x of+ Nothing -> return $ front []+ Just y ->+ case lineType ms y of+ LineText z -> loop (front . (z:))+ _ -> leftover y >> return (front [])+ ls <- loop (\rest -> T.dropWhile (== ' ') t' : t2' : rest)+ yield $ Right $ BlockList ltype $ Right [BlockPara $ T.intercalate "\n" ls]+ -- If the next line is an indented list, then we have a sublist. I+ -- disagree with this interpretation of Markdown, but it's the way+ -- that Github implements things, so we will too.+ _ | Just t2' <- t2+ , Just t2'' <- T.stripPrefix " " t2'+ , LineList _ltype' _t2''' <- lineType ms t2'' -> do+ ls <- getIndented 4 =$= CL.consume+ let blocks = runIdentity $ mapM_ yield ls $$ toBlocksLines ms =$ CL.consume+ let addPlainText+ | T.null $ T.strip t' = id+ | otherwise = (BlockPlainText (T.strip t'):)+ yield $ Right $ BlockList ltype $ Right $ addPlainText blocks+ _ -> do+ let t'' = T.dropWhile (== ' ') t'+ let leader = T.length t - T.length t''+ ls <- getIndented leader =$= CL.consume+ let blocks = runIdentity $ mapM_ yield (t'' : ls) $$ toBlocksLines ms =$ CL.consume+ yield $ Right $ BlockList ltype $ Right blocks+ go (LineReference x y) = yield $ Right $ BlockReference x y+ go (LineText t') = do+ -- Check for underline headings+ let getUnderline :: Text -> Maybe Int+ getUnderline s+ | T.length s < 2 = Nothing+ | T.all (== '=') s = Just 1+ | T.all (== '-') s = Just 2+ | otherwise = Nothing+ t2 <- CL.peek+ case t2 >>= getUnderline of+ Just level -> do+ CL.drop 1+ yield $ Right $ BlockHeading level t'+ Nothing -> do+ let listStartIndent x =+ case listStart x of+ Just (_, y) -> T.take 2 y == " "+ Nothing -> False+ isNonPara LineBlank = True+ isNonPara LineFenced{} = True+ isNonPara _ = False+ (mfinal, ls) <- takeTillConsume (\x -> isNonPara (lineType ms x) || listStartIndent x)+ maybe (return ()) leftover mfinal+ yield $ Right $ BlockPara $ T.intercalate "\n" $ t' : ls++isHtmlStart :: T.Text -> Bool+isHtmlStart t =+ case T.stripPrefix "<" t of+ Nothing -> False+ Just t' ->+ let (name, rest) = T.break (\c -> c `elem` " >") t'+ in T.all isValidTagName name &&+ not (T.null name) &&+ (not ("/" `T.isPrefixOf` rest) || ("/>" `T.isPrefixOf` rest))+ where+ isValidTagName :: Char -> Bool+ isValidTagName c =+ ('A' <= c && c <= 'Z') ||+ ('a' <= c && c <= 'z') ||+ ('0' <= c && c <= '9') ||+ (c == '-') ||+ (c == '_') ||+ (c == '/') ||+ (c == '!')++takeTill :: Monad m => (i -> Bool) -> Conduit i m i+takeTill f =+ loop+ where+ loop = await >>= maybe (return ()) (\x -> if f x then return () else yield x >> loop)++--takeTillConsume :: Monad m => (i -> Bool) -> Consumer i m (Maybe i, [i])+takeTillConsume f =+ loop id+ where+ loop front = await >>= maybe+ (return (Nothing, front []))+ (\x ->+ if f x+ then return (Just x, front [])+ else loop (front . (x:))+ )++listStart :: Text -> Maybe (ListType, Text)+listStart t0+ | Just t' <- T.stripPrefix "* " t = Just (Unordered, t')+ | Just t' <- T.stripPrefix "+ " t = Just (Unordered, t')+ | Just t' <- T.stripPrefix "- " t = Just (Unordered, t')+ | Just t' <- stripNumber t, Just t'' <- stripSeparator t' = Just (Ordered, t'')+ | otherwise = Nothing+ where+ t = T.stripStart t0++stripNumber :: Text -> Maybe Text+stripNumber x+ | T.null y = Nothing+ | otherwise = Just z+ where+ (y, z) = T.span isDigit x++stripSeparator :: Text -> Maybe Text+stripSeparator x =+ case T.uncons x of+ Nothing -> Nothing+ Just ('.', y) -> Just y+ Just (')', y) -> Just y+ _ -> Nothing++getIndented :: Monad m => Int -> Conduit Text m Text+getIndented leader =+ go []+ where+ go blanks = await >>= maybe (mapM_ leftover blanks) (go' blanks)++ go' blanks t+ | T.null $ T.strip t = go (T.drop leader t : blanks)+ | T.length x == leader && T.null (T.strip x) = do+ mapM_ yield $ reverse blanks+ yield y+ go []+ | otherwise = mapM_ leftover (t:blanks)+ where+ (x, y) = T.splitAt leader t++takeQuotes :: Monad m => Conduit Text m Text+takeQuotes =+ await >>= maybe (return ()) go+ where+ go "" = return ()+ go ">" = yield "" >> takeQuotes+ go t+ | Just t' <- T.stripPrefix "> " t = yield t' >> takeQuotes+ | otherwise = yield t >> takeQuotes
+ Text/Markdown/Inline.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_HADDOCK hide #-}+module Text.Markdown.Inline+ ( Inline (..)+ , inlineParser+ , toInline+ ) where++import Prelude hiding (takeWhile)+import Data.Text (Text)+import qualified Data.Text as T+import Data.Attoparsec.Text+import Control.Applicative+import Data.Monoid (Monoid, mappend)+import qualified Data.Map as Map++type RefMap = Map.Map Text Text++toInline :: RefMap -> Text -> [Inline]+toInline refmap t =+ case parseOnly (inlineParser refmap) t of+ Left s -> [InlineText $ T.pack s]+ Right is -> is++(<>) :: Monoid m => m -> m -> m+(<>) = mappend++data Inline = InlineText Text+ | InlineItalic [Inline]+ | InlineBold [Inline]+ | InlineCode Text+ | InlineHtml Text+ | InlineLink Text (Maybe Text) [Inline] -- ^ URL, title, content+ | InlineImage Text (Maybe Text) Text -- ^ URL, title, content+ deriving (Show, Eq)++inlineParser :: RefMap -> Parser [Inline]+inlineParser = fmap combine . many . inlineAny++combine :: [Inline] -> [Inline]+combine [] = []+combine (InlineText x:InlineText y:rest) = combine (InlineText (x <> y):rest)+combine (InlineText x:rest) = InlineText x : combine rest+combine (InlineItalic x:InlineItalic y:rest) = combine (InlineItalic (x <> y):rest)+combine (InlineItalic x:rest) = InlineItalic (combine x) : combine rest+combine (InlineBold x:InlineBold y:rest) = combine (InlineBold (x <> y):rest)+combine (InlineBold x:rest) = InlineBold (combine x) : combine rest+combine (InlineCode x:InlineCode y:rest) = combine (InlineCode (x <> y):rest)+combine (InlineCode x:rest) = InlineCode x : combine rest+combine (InlineLink u t c:rest) = InlineLink u t (combine c) : combine rest+combine (InlineImage u t c:rest) = InlineImage u t c : combine rest+combine (InlineHtml t:rest) = InlineHtml t : combine rest++specials :: [Char]+specials = "*_`\\[]!<&"++inlineAny :: RefMap -> Parser Inline+inlineAny refs =+ inline refs <|> special+ where+ special = InlineText . T.singleton <$> satisfy (`elem` specials)++inline :: RefMap -> Parser Inline+inline refs =+ text+ <|> escape+ <|> paired "**" InlineBold <|> paired "__" InlineBold+ <|> paired "*" InlineItalic <|> paired "_" InlineItalic+ <|> doubleCode <|> code+ <|> link+ <|> image+ <|> autoLink+ <|> html+ <|> entity+ where+ inlinesTill :: Text -> Parser [Inline]+ inlinesTill end =+ go id+ where+ go front =+ (string end *> pure (front []))+ <|> (do+ x <- inlineAny refs+ go $ front . (x:))++ text = InlineText <$> takeWhile1 (`notElem` specials)++ paired t wrap = wrap <$> do+ _ <- string t+ is <- inlinesTill t+ if null is then fail "wrapped around something missing" else return is++ doubleCode = InlineCode . T.pack <$> (string "`` " *> manyTill anyChar (string " ``"))+ code = InlineCode <$> (char '`' *> takeWhile1 (/= '`') <* char '`')++ escape = InlineText . T.singleton <$> (char '\\' *> satisfy (`elem` "\\`*_{}[]()#+-.!>"))++ takeBalancedBrackets =+ T.pack <$> go (0 :: Int)+ where+ go i = do+ c <- anyChar+ case c of+ '[' -> (c:) <$> go (i + 1)+ ']'+ | i == 0 -> return []+ | otherwise -> (c:) <$> go (i - 1)+ _ -> (c:) <$> go i++ parseUrl = fixUrl . T.pack <$> parseUrl' (0 :: Int)++ parseUrl' level+ | level > 0 = do+ c <- anyChar+ let level'+ | c == ')' = level - 1+ | otherwise = level+ c' <-+ if c == '\\'+ then anyChar+ else return c+ cs <- parseUrl' level'+ return $ c' : cs+ | otherwise = (do+ c <- hrefChar+ if c == '('+ then (c:) <$> parseUrl' 1+ else (c:) <$> parseUrl' 0) <|> return []++ parseUrlTitle defRef = parseUrlTitleInline <|> parseUrlTitleRef defRef++ parseUrlTitleInside endTitle = do+ url <- parseUrl+ mtitle <- (Just <$> title) <|> (skipSpace >> endTitle >> pure Nothing)+ return (url, mtitle)+ where+ title = do+ _ <- space+ skipSpace+ _ <- char '"'+ t <- T.stripEnd . T.pack <$> go+ return $+ if not (T.null t) && T.last t == '"'+ then T.init t+ else t+ where+ go = (char '\\' *> anyChar >>= \c -> (c:) <$> go)+ <|> (endTitle *> return [])+ <|> (anyChar >>= \c -> (c:) <$> go)++ parseUrlTitleInline = char '(' *> parseUrlTitleInside (char ')')++ parseUrlTitleRef defRef = do+ ref' <- (skipSpace *> char '[' *> takeWhile (/= ']') <* char ']') <|> return ""+ let ref = if T.null ref' then defRef else ref'+ case Map.lookup (T.unwords $ T.words ref) refs of+ Nothing -> fail "ref not found"+ Just t -> either fail return $ parseOnly (parseUrlTitleInside endOfInput) t++ link = do+ _ <- char '['+ rawContent <- takeBalancedBrackets+ content <- either fail return $ parseOnly (inlineParser refs) rawContent+ (url, mtitle) <- parseUrlTitle rawContent+ return $ InlineLink url mtitle content++ image = do+ _ <- string "!["+ content <- takeBalancedBrackets+ (url, mtitle) <- parseUrlTitle content+ return $ InlineImage url mtitle content++ fixUrl t+ | T.length t > 2 && T.head t == '<' && T.last t == '>' = T.init $ T.tail t+ | otherwise = t++ autoLink = do+ _ <- char '<'+ a <- string "http:" <|> string "https:"+ b <- takeWhile1 (/= '>')+ _ <- char '>'+ let url = a `T.append` b+ return $ InlineLink url Nothing [InlineText url]++ html = do+ c <- char '<'+ t <- takeWhile1 (\x -> ('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z') || x == '/')+ if T.null t+ then fail "invalid tag"+ else do+ t2 <- takeWhile (/= '>')+ c2 <- char '>'+ return $ InlineHtml $ T.concat+ [ T.singleton c+ , t+ , t2+ , T.singleton c2+ ]++ entity =+ rawent "<"+ <|> rawent ">"+ <|> rawent "&"+ <|> rawent """+ <|> rawent "'"+ <|> decEnt+ <|> hexEnt++ rawent t = InlineHtml <$> string t++ decEnt = do+ s <- string "&#"+ t <- takeWhile1 $ \x -> ('0' <= x && x <= '9')+ c <- char ';'+ return $ InlineHtml $ T.concat+ [ s+ , t+ , T.singleton c+ ]++ hexEnt = do+ s <- string "&#x" <|> string "&#X"+ t <- takeWhile1 $ \x -> ('0' <= x && x <= '9') || ('A' <= x && x <= 'F') || ('a' <= x && x <= 'f')+ c <- char ';'+ return $ InlineHtml $ T.concat+ [ s+ , t+ , T.singleton c+ ]++hrefChar :: Parser Char+hrefChar = (char '\\' *> anyChar) <|> satisfy (notInClass " )")
+ Text/Markdown/Types.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE OverloadedStrings #-}+module Text.Markdown.Types where++import Data.Text (Text)+import qualified Data.Text as T+import Data.Default (Default (def))+import Data.Set (Set, empty)+import Data.Map (Map, singleton)+import Data.Monoid (mappend)++-- | A settings type providing various configuration options.+--+-- See <http://www.yesodweb.com/book/settings-types> for more information on+-- settings types. In general, you can use @def@.+data MarkdownSettings = MarkdownSettings+ { msXssProtect :: Bool+ -- ^ Whether to automatically apply XSS protection to embedded HTML. Default: @True@.+ , msStandaloneHtml :: Set Text+ -- ^ HTML snippets which stand on their own. We do not require a blank line following these pieces of HTML.+ --+ -- Default: empty set.+ --+ -- Since: 0.1.2+ , msFencedHandlers :: Map Text (Text -> FencedHandler)+ -- ^ Handlers for the special \"fenced\" format. This is most commonly+ -- used for fenced code, e.g.:+ --+ -- > ```haskell+ -- > main = putStrLn "Hello"+ -- > ```+ --+ -- This is an extension of Markdown, but a fairly commonly used one.+ --+ -- This setting allows you to create new kinds of fencing. Fencing goes+ -- into two categories: parsed and raw. Code fencing would be in the raw+ -- category, where the contents are not treated as Markdown. Parsed will+ -- treat the contents as Markdown and allow you to perform some kind of+ -- modifcation to it.+ --+ -- For example, to create a new @\@\@\@@ fencing which wraps up the+ -- contents in an @article@ tag, you could use:+ --+ -- > def { msFencedHandlers = htmlFencedHandler "@@@" (const "<article>") (const "</article")+ -- > `Map.union` msFencedHandlers def+ -- > }+ --+ -- Default: code fencing for @```@ and @~~~@.+ --+ -- Since: 0.1.2+ }++-- | See 'msFencedHandlers.+--+-- Since 0.1.2+data FencedHandler = FHRaw (Text -> [Block Text])+ -- ^ Wrap up the given raw content.+ | FHParsed ([Block Text] -> [Block Text])+ -- ^ Wrap up the given parsed content.++instance Default MarkdownSettings where+ def = MarkdownSettings+ { msXssProtect = True+ , msStandaloneHtml = empty+ , msFencedHandlers = codeFencedHandler "```" `mappend` codeFencedHandler "~~~"+ }++-- | Helper for creating a 'FHRaw'.+--+-- Since 0.1.2+codeFencedHandler :: Text -- ^ Delimiter+ -> Map Text (Text -> FencedHandler)+codeFencedHandler key = singleton key $ \lang -> FHRaw $+ return . BlockCode (if T.null lang then Nothing else Just lang)++-- | Helper for creating a 'FHParsed'.+--+-- Note that the start and end parameters take a @Text@ parameter; this is the+-- text following the delimiter. For example, with the markdown:+--+-- > @@@ foo+--+-- @foo@ would be passed to start and end.+--+-- Since 0.1.2+htmlFencedHandler :: Text -- ^ Delimiter+ -> (Text -> Text) -- ^ start HTML+ -> (Text -> Text) -- ^ end HTML+ -> Map Text (Text -> FencedHandler)+htmlFencedHandler key start end = singleton key $ \lang -> FHParsed $ \blocks ->+ BlockHtml (start lang)+ : blocks+ ++ [BlockHtml $ end lang]++data ListType = Ordered | Unordered+ deriving (Show, Eq)++data Block inline+ = BlockPara inline+ | BlockList ListType (Either inline [Block inline])+ | BlockCode (Maybe Text) Text+ | BlockQuote [Block inline]+ | BlockHtml Text+ | BlockRule+ | BlockHeading Int inline+ | BlockReference Text Text+ | BlockPlainText inline+ deriving (Show, Eq)++instance Functor Block where+ fmap f (BlockPara i) = BlockPara (f i)+ fmap f (BlockList lt (Left i)) = BlockList lt $ Left $ f i+ fmap f (BlockList lt (Right bs)) = BlockList lt $ Right $ map (fmap f) bs+ fmap _ (BlockCode a b) = BlockCode a b+ fmap f (BlockQuote bs) = BlockQuote $ map (fmap f) bs+ fmap _ (BlockHtml t) = BlockHtml t+ fmap _ BlockRule = BlockRule+ fmap f (BlockHeading level i) = BlockHeading level (f i)+ fmap _ (BlockReference x y) = BlockReference x y+ fmap f (BlockPlainText x) = BlockPlainText (f x)
+ markdown-kate.cabal view
@@ -0,0 +1,57 @@+Name: markdown-kate+Version: 0.1.2.1+Synopsis: Convert Markdown to HTML, with XSS protection+Description: This library leverages existing high-performance libraries (attoparsec, blaze-html, text, and conduit), and should integrate well with existing codebases.+Homepage: https://github.com/joelteon/markdown-kate+License: BSD3+License-file: LICENSE+Author: Michael Snoyman+Maintainer: joel@outright.com+Category: Web+Build-type: Simple+Extra-source-files: test/examples/*.html+ , test/examples/*.md+ , test/Tests/*.html+ , test/Tests/*.text+Cabal-version: >=1.8++Library+ Exposed-modules: Text.Markdown+ Text.Markdown.Block+ Text.Markdown.Inline+ other-modules: Text.Markdown.Types+ Build-depends: base >= 4 && < 5+ , blaze-html >= 0.4+ , attoparsec >= 0.10+ , attoparsec-conduit >= 0.5+ , transformers >= 0.2.2+ , conduit >= 0.5.2.1+ , text+ , data-default >= 0.3+ , xss-sanitize >= 0.3.3+ , containers+ , highlighting-kate+ ghc-options: -Wall++test-suite test+ hs-source-dirs: test+ main-is: main.hs+ other-modules: Block+ Inline+ type: exitcode-stdio-1.0++ ghc-options: -Wall+ build-depends: markdown+ , base >= 4 && < 5+ , hspec >= 1.3+ , blaze-html+ , text+ , system-fileio+ , system-filepath+ , transformers+ , conduit+ , containers++source-repository head+ type: git+ location: git://github.com/joelteon/markdown-kate.git
+ test/Block.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE OverloadedStrings #-}+module Block+ ( blockSpecs+ ) where+import Test.Hspec+import Data.Text (Text)+import Data.Conduit+import qualified Data.Conduit.List as CL+import Text.Markdown (def)+import Text.Markdown.Block+import Data.Functor.Identity (runIdentity)++check :: Text -> [Block Text] -> Expectation+check md blocks = runIdentity (yield md $$ toBlocks def =$ CL.consume) `shouldBe` blocks++blockSpecs :: Spec+blockSpecs = do+ describe "tilde code" $ do+ it "simple" $ check+ "~~~haskell\nfoo\n\nbar\n~~~"+ [BlockCode (Just "haskell") "foo\n\nbar"]+ it "no lang" $ check+ "~~~\nfoo\n\nbar\n~~~"+ [BlockCode Nothing "foo\n\nbar"]+ it "no close" $ check+ "~~~\nfoo\n\nbar\n"+ [BlockPara " ~~~\nfoo", BlockPara "bar"]+ describe "list" $ do+ it "simple" $ check+ "* foo\n\n* bar\n\n"+ [ BlockList Unordered (Right [BlockPara "foo"])+ , BlockList Unordered (Right [BlockPara "bar"])+ ]+ it "nested" $ check+ "* foo\n* \n 1. bar\n 2. baz"+ [ BlockList Unordered (Left "foo")+ , BlockList Unordered (Right+ [ BlockList Ordered $ Left "bar"+ , BlockList Ordered $ Left "baz"+ ])+ ]+ it "with blank" $ check+ "* foo\n\n bar\n\n* baz"+ [ BlockList Unordered $ Right+ [ BlockPara "foo"+ , BlockPara "bar"+ ]+ , BlockList Unordered $ Right+ [ BlockPara "baz"+ ]+ ]+ describe "blockquote" $ do+ it "simple" $ check+ "> foo\n>\n> * bar"+ [ BlockQuote+ [ BlockPara "foo"+ , BlockList Unordered $ Left "bar"+ ]+ ]+ it "blank" $ check+ "> foo\n\n> * bar"+ [ BlockQuote [BlockPara "foo"]+ , BlockQuote [BlockList Unordered $ Left "bar"]+ ]+ describe "indented code" $ do+ it "simple" $ check+ " foo\n bar\n"+ [ BlockCode Nothing "foo\nbar"+ ]+ it "blank" $ check+ " foo\n\n bar\n"+ [ BlockCode Nothing "foo\n\nbar"+ ]+ it "extra space" $ check+ " foo\n\n bar\n"+ [ BlockCode Nothing "foo\n\n bar"+ ]+ describe "html" $ do+ it "simple" $ check+ "<p>Hello world!</p>"+ [ BlockHtml "<p>Hello world!</p>"+ ]+ it "multiline" $ check+ "<p>Hello world!\n</p>"+ [ BlockHtml "<p>Hello world!\n</p>"+ ]
+ test/Inline.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE OverloadedStrings #-}+module Inline+ ( inlineSpecs+ ) where++import Test.Hspec+import Text.Markdown.Inline+import Data.Text (Text)+import Data.Monoid (mempty)++check :: Text -> [Inline] -> Expectation+check md ins = toInline mempty md `shouldBe` ins++inlineSpecs :: Spec+inlineSpecs = do+ describe "raw text" $ do+ it "simple"+ $ check "raw text" [InlineText "raw text"]+ it "multiline"+ $ check "raw\ntext" [InlineText "raw\ntext"]+ describe "italic" $ do+ it "asterisk"+ $ check "raw *text*" [InlineText "raw ", InlineItalic [InlineText "text"]]+ it "underline"+ $ check "raw _text_" [InlineText "raw ", InlineItalic [InlineText "text"]]+ it "multiline"+ $ check "*raw\ntext*" [InlineItalic [InlineText "raw\ntext"]]+ it "mismatched"+ $ check "*foo* *bar" [InlineItalic [InlineText "foo"], InlineText " *bar"]+ describe "bold" $ do+ it "asterisk"+ $ check "raw **text**" [InlineText "raw ", InlineBold [InlineText "text"]]+ it "underline"+ $ check "raw __text__" [InlineText "raw ", InlineBold [InlineText "text"]]+ it "multiline"+ $ check "**raw\ntext**" [InlineBold [InlineText "raw\ntext"]]+ it "mismatched"+ $ check "**foo** *bar" [InlineBold [InlineText "foo"], InlineText " *bar"]+ describe "nested" $ do+ it "bold inside italic"+ $ check "*i __ib__ i*" [InlineItalic [InlineText "i ", InlineBold [InlineText "ib"], InlineText " i"]]+ it "bold inside italic swap"+ $ check "_i **ib** i_" [InlineItalic [InlineText "i ", InlineBold [InlineText "ib"], InlineText " i"]]+ it "italic inside bold"+ $ check "**b _ib_ b**" [InlineBold [InlineText "b ", InlineItalic [InlineText "ib"], InlineText " b"]]+ it "italic inside bold swap"+ $ check "__b *ib* b__" [InlineBold [InlineText "b ", InlineItalic [InlineText "ib"], InlineText " b"]]+ describe "code" $ do+ it "takes all characters"+ $ check "`foo*__*bar` baz`"+ [ InlineCode "foo*__*bar"+ , InlineText " baz`"+ ]+ describe "escaping" $ do+ it "asterisk"+ $ check "\\*foo*\\\\" [InlineText "*foo*\\"]+ describe "links" $ do+ it "simple" $ check "[bar](foo)" [InlineLink "foo" Nothing [InlineText "bar"]]+ it "title" $ check+ "[bar](foo \"baz\")"+ [InlineLink "foo" (Just "baz") [InlineText "bar"]]+ {-+ it "escaped href" $ check+ "<p><a href=\"foo)\" title=\"baz\">bar</a></p>"+ "[bar](foo\\) \"baz\")"+ it "escaped title" $ check+ "<p><a href=\"foo)\" title=\"baz"\">bar</a></p>"+ "[bar](foo\\) \"baz\\\"\")"+ it "inside a paragraph" $ check+ "<p>Hello <a href=\"foo\">bar</a> World</p>"+ "Hello [bar](foo) World"+ it "not a link" $ check+ "<p>Not a [ link</p>"+ "Not a [ link"+ -}
+ test/Tests/Amps and angle encoding.html view
@@ -0,0 +1,17 @@+<p>AT&T has an ampersand in their name.</p>++<p>AT&T is another way to write it.</p>++<p>This & that.</p>++<p>4 < 5.</p>++<p>6 > 5.</p>++<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>++<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>++<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>++<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
+ test/Tests/Amps and angle encoding.text view
@@ -0,0 +1,21 @@+AT&T has an ampersand in their name.++AT&T is another way to write it.++This & that.++4 < 5.++6 > 5.++Here's a [link] [1] with an ampersand in the URL.++Here's a link with an amersand in the link text: [AT&T] [2].++Here's an inline [link](/script?foo=1&bar=2).++Here's an inline [link](</script?foo=1&bar=2>).+++[1]: http://example.com/?foo=1&bar=2+[2]: http://att.com/ "AT&T"
+ test/Tests/Auto links.html view
@@ -0,0 +1,18 @@+<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>++<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>++<ul>+<li>In a list?</li>+<li><a href="http://example.com/">http://example.com/</a></li>+<li>It should.</li>+</ul>++<blockquote>+<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>+</blockquote>++<p>Auto-links should not occur here: <code><http://example.com/></code></p>++<pre><code>or here: <http://example.com/>+</code></pre>
+ test/Tests/Auto links.text view
@@ -0,0 +1,13 @@+Link: <http://example.com/>.++With an ampersand: <http://example.com/?foo=1&bar=2>++* In a list?+* <http://example.com/>+* It should.++> Blockquoted: <http://example.com/>++Auto-links should not occur here: `<http://example.com/>`++ or here: <http://example.com/>
+ test/Tests/Backslash escapes.html view
@@ -0,0 +1,118 @@+<p>These should all get escaped:</p>++<p>Backslash: \</p>++<p>Backtick: `</p>++<p>Asterisk: *</p>++<p>Underscore: _</p>++<p>Left brace: {</p>++<p>Right brace: }</p>++<p>Left bracket: [</p>++<p>Right bracket: ]</p>++<p>Left paren: (</p>++<p>Right paren: )</p>++<p>Greater-than: ></p>++<p>Hash: #</p>++<p>Period: .</p>++<p>Bang: !</p>++<p>Plus: +</p>++<p>Minus: -</p>++<p>These should not, because they occur within a code block:</p>++<pre><code>Backslash: \\++Backtick: \`++Asterisk: \*++Underscore: \_++Left brace: \{++Right brace: \}++Left bracket: \[++Right bracket: \]++Left paren: \(++Right paren: \)++Greater-than: \>++Hash: \#++Period: \.++Bang: \!++Plus: \+++Minus: \-+</code></pre>++<p>Nor should these, which occur in code spans:</p>++<p>Backslash: <code>\\</code></p>++<p>Backtick: <code>\`</code></p>++<p>Asterisk: <code>\*</code></p>++<p>Underscore: <code>\_</code></p>++<p>Left brace: <code>\{</code></p>++<p>Right brace: <code>\}</code></p>++<p>Left bracket: <code>\[</code></p>++<p>Right bracket: <code>\]</code></p>++<p>Left paren: <code>\(</code></p>++<p>Right paren: <code>\)</code></p>++<p>Greater-than: <code>\></code></p>++<p>Hash: <code>\#</code></p>++<p>Period: <code>\.</code></p>++<p>Bang: <code>\!</code></p>++<p>Plus: <code>\+</code></p>++<p>Minus: <code>\-</code></p>+++<p>These should get escaped, even though they're matching pairs for+other Markdown constructs:</p>++<p>*asterisks*</p>++<p>_underscores_</p>++<p>`backticks`</p>++<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>++<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>++<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
+ test/Tests/Backslash escapes.text view
@@ -0,0 +1,120 @@+These should all get escaped:++Backslash: \\++Backtick: \`++Asterisk: \*++Underscore: \_++Left brace: \{++Right brace: \}++Left bracket: \[++Right bracket: \]++Left paren: \(++Right paren: \)++Greater-than: \>++Hash: \#++Period: \.++Bang: \!++Plus: \+++Minus: \-++++These should not, because they occur within a code block:++ Backslash: \\++ Backtick: \`++ Asterisk: \*++ Underscore: \_++ Left brace: \{++ Right brace: \}++ Left bracket: \[++ Right bracket: \]++ Left paren: \(++ Right paren: \)++ Greater-than: \>++ Hash: \#++ Period: \.++ Bang: \!++ Plus: \+++ Minus: \-+++Nor should these, which occur in code spans:++Backslash: `\\`++Backtick: `` \` ``++Asterisk: `\*`++Underscore: `\_`++Left brace: `\{`++Right brace: `\}`++Left bracket: `\[`++Right bracket: `\]`++Left paren: `\(`++Right paren: `\)`++Greater-than: `\>`++Hash: `\#`++Period: `\.`++Bang: `\!`++Plus: `\+`++Minus: `\-`+++These should get escaped, even though they're matching pairs for+other Markdown constructs:++\*asterisks\*++\_underscores\_++\`backticks\`++This is a code span with a literal backslash-backtick sequence: `` \` ``++This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.++This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
+ test/Tests/Blockquotes with code blocks.html view
@@ -0,0 +1,15 @@+<blockquote>+<p>Example:</p>++<pre><code>sub status {+ print "working";+}+</code></pre>++<p>Or:</p>++<pre><code>sub status {+ return "working";+}+</code></pre>+</blockquote>
+ test/Tests/Blockquotes with code blocks.text view
@@ -0,0 +1,11 @@+> Example:+> +> sub status {+> print "working";+> }+> +> Or:+> +> sub status {+> return "working";+> }
+ test/Tests/Code Blocks.html view
@@ -0,0 +1,18 @@+<pre><code>code block on the first line+</code></pre>++<p>Regular text.</p>++<pre><code>code block indented by spaces+</code></pre>++<p>Regular text.</p>++<pre><code>the lines in this block +all contain trailing spaces +</code></pre>++<p>Regular Text.</p>++<pre><code>code block on the last line+</code></pre>
+ test/Tests/Code Blocks.text view
@@ -0,0 +1,14 @@+ code block on the first line+ +Regular text.++ code block indented by spaces++Regular text.++ the lines in this block + all contain trailing spaces ++Regular Text.++ code block on the last line
+ test/Tests/Code Spans.html view
@@ -0,0 +1,5 @@+<p><code><test a="</code> content of attribute <code>"></code></p>++<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>++<p>Here's how you put <code>`backticks`</code> in a code span.</p>
+ test/Tests/Code Spans.text view
@@ -0,0 +1,5 @@+`<test a="` content of attribute `">`++Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>++Here's how you put `` `backticks` `` in a code span.
+ test/Tests/Hard-wrapped paragraphs with list-like lines.html view
@@ -0,0 +1,8 @@+<p>In Markdown 1.0.0 and earlier. Version+8. This line turns into a list item.+Because a hard-wrapped line in the+middle of a paragraph looked like a+list item.</p>++<p>Here's one with a bullet.+* criminey.</p>
+ test/Tests/Hard-wrapped paragraphs with list-like lines.text view
@@ -0,0 +1,8 @@+In Markdown 1.0.0 and earlier. Version+8. This line turns into a list item.+Because a hard-wrapped line in the+middle of a paragraph looked like a+list item.++Here's one with a bullet.+* criminey.
+ test/Tests/Horizontal rules.html view
@@ -0,0 +1,71 @@+<p>Dashes:</p>++<hr>++<hr>++<hr>++<hr>++<pre><code>---+</code></pre>++<hr>++<hr>++<hr>++<hr>++<pre><code>- - -+</code></pre>++<p>Asterisks:</p>++<hr>++<hr>++<hr>++<hr>++<pre><code>***+</code></pre>++<hr>++<hr>++<hr>++<hr>++<pre><code>* * *+</code></pre>++<p>Underscores:</p>++<hr>++<hr>++<hr>++<hr>++<pre><code>___+</code></pre>++<hr>++<hr>++<hr>++<hr>++<pre><code>_ _ _+</code></pre>
+ test/Tests/Horizontal rules.text view
@@ -0,0 +1,67 @@+Dashes:++---++ ---+ + ---++ ---++ ---++- - -++ - - -+ + - - -++ - - -++ - - -+++Asterisks:++***++ ***+ + ***++ ***++ ***++* * *++ * * *+ + * * *++ * * *++ * * *+++Underscores:++___++ ___+ + ___++ ___++ ___++_ _ _++ _ _ _+ + _ _ _++ _ _ _++ _ _ _
+ test/Tests/Images.html view
@@ -0,0 +1,21 @@+<p><img src="/path/to/img.jpg" alt="Alt text"></p>++<p><img src="/path/to/img.jpg" alt="Alt text" title="Optional title"></p>++<p>Inline within a paragraph: <a href="/url/">alt text</a>.</p>++<p><img src="/url/" alt="alt text" title="title preceded by two spaces"></p>++<p><img src="/url/" alt="alt text" title="title has spaces afterward"></p>++<p><img src="/url/" alt="alt text"></p>++<p><img src="/url/" alt="alt text" title="with a title">.</p>++<p><img src="" alt="Empty"></p>++<p><img src="http://example.com/(parens).jpg" alt="this is a stupid URL"></p>++<p><img src="/url/" alt="alt text"></p>++<p><img src="/url/" alt="alt text" title="Title here"></p>
+ test/Tests/Images.text view
@@ -0,0 +1,26 @@+++++Inline within a paragraph: [alt text](/url/).++++++++.++![Empty]()++.jpg)+++![alt text][foo]++ [foo]: /url/++![alt text][bar]++ [bar]: /url/ "Title here"
+ test/Tests/Inline HTML (Advanced).html view
@@ -0,0 +1,30 @@+<p>Simple block on one line:</p>++<div>foo</div>++<p>And nested without indentation:</p>++<div>+<div>+<div>+foo+</div>+<div style=">"/>+</div>+<div>bar</div>+</div>++<p>And with attributes:</p>++<div>+ <div id="foo">+ </div>+</div>++<p>This was broken in 1.0.2b7:</p>++<div class="inlinepage">+<div class="toggleableend">+foo+</div>+</div>
+ test/Tests/Inline HTML (Advanced).text view
@@ -0,0 +1,30 @@+Simple block on one line:++<div>foo</div>++And nested without indentation:++<div>+<div>+<div>+foo+</div>+<div style=">"/>+</div>+<div>bar</div>+</div>++And with attributes:++<div>+ <div id="foo">+ </div>+</div>++This was broken in 1.0.2b7:++<div class="inlinepage">+<div class="toggleableend">+foo+</div>+</div>
+ test/Tests/Inline HTML (Simple).html view
@@ -0,0 +1,72 @@+<p>Here's a simple block:</p>++<div>+ foo+</div>++<p>This should be a code block, though:</p>++<pre><code><div>+ foo+</div>+</code></pre>++<p>As should this:</p>++<pre><code><div>foo</div>+</code></pre>++<p>Now, nested:</p>++<div>+ <div>+ <div>+ foo+ </div>+ </div>+</div>++<p>This should just be an HTML comment:</p>++<!-- Comment -->++<p>Multiline:</p>++<!--+Blah+Blah+-->++<p>Code block:</p>++<pre><code><!-- Comment -->+</code></pre>++<p>Just plain comment, with trailing spaces on the line:</p>++<!-- foo --> ++<p>Code:</p>++<pre><code><hr />+</code></pre>++<p>Hr's:</p>++<hr>++<hr/>++<hr />++<hr> ++<hr/> ++<hr /> ++<hr class="foo" id="bar" />++<hr class="foo" id="bar"/>++<hr class="foo" id="bar" >
+ test/Tests/Inline HTML (Simple).text view
@@ -0,0 +1,69 @@+Here's a simple block:++<div>+ foo+</div>++This should be a code block, though:++ <div>+ foo+ </div>++As should this:++ <div>foo</div>++Now, nested:++<div>+ <div>+ <div>+ foo+ </div>+ </div>+</div>++This should just be an HTML comment:++<!-- Comment -->++Multiline:++<!--+Blah+Blah+-->++Code block:++ <!-- Comment -->++Just plain comment, with trailing spaces on the line:++<!-- foo --> ++Code:++ <hr />+ +Hr's:++<hr>++<hr/>++<hr />++<hr> ++<hr/> ++<hr /> ++<hr class="foo" id="bar" />++<hr class="foo" id="bar"/>++<hr class="foo" id="bar" >+
+ test/Tests/Inline HTML comments.html view
@@ -0,0 +1,13 @@+<p>Paragraph one.</p>++<!-- This is a simple comment -->++<!--+ This is another comment.+-->++<p>Paragraph two.</p>++<!-- one comment block -- -- with two comments -->++<p>The end.</p>
+ test/Tests/Inline HTML comments.text view
@@ -0,0 +1,13 @@+Paragraph one.++<!-- This is a simple comment -->++<!--+ This is another comment.+-->++Paragraph two.++<!-- one comment block -- -- with two comments -->++The end.
+ test/Tests/Links, inline style.html view
@@ -0,0 +1,23 @@+<p>Just a <a href="/url/">URL</a>.</p>++<p><a href="/url/" title="title">URL and title</a>.</p>++<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>++<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>++<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p>++<p><a href="/url/">URL wrapped in angle brackets</a>.</p>++<p><a href="/url/" title="Here's the title">URL w/ angle brackets + title</a>.</p>++<p><a href="">Empty</a>.</p>++<p><a href="http://en.wikipedia.org/wiki/WIMP_(computing)">With parens in the URL</a></p>++<p>(With outer parens and <a href="/foo(bar)">parens in url</a>)</p>++<p><a href="/foo(bar)" title="and a title">With parens in the URL</a></p>++<p>(With outer parens and <a href="/foo(bar)" title="and a title">parens in url</a>)</p>
+ test/Tests/Links, inline style.text view
@@ -0,0 +1,24 @@+Just a [URL](/url/).++[URL and title](/url/ "title").++[URL and title](/url/ "title preceded by two spaces").++[URL and title](/url/ "title preceded by a tab").++[URL and title](/url/ "title has spaces afterward" ).++[URL wrapped in angle brackets](</url/>).++[URL w/ angle brackets + title](</url/> "Here's the title").++[Empty]().++[With parens in the URL](http://en.wikipedia.org/wiki/WIMP_(computing))++(With outer parens and [parens in url](/foo(bar)))+++[With parens in the URL](/foo(bar) "and a title")++(With outer parens and [parens in url](/foo(bar) "and a title"))
+ test/Tests/Links, reference style.html view
@@ -0,0 +1,52 @@+<p>Foo <a href="/url/" title="Title">bar</a>.</p>++<p>Foo <a href="/url/" title="Title">bar</a>.</p>++<p>Foo <a href="/url/" title="Title">bar</a>.</p>++<p>With <a href="/url/">embedded [brackets]</a>.</p>++<p>Indented <a href="/url">once</a>.</p>++<p>Indented <a href="/url">twice</a>.</p>++<p>Indented <a href="/url">thrice</a>.</p>++<p>Indented [four][] times.</p>++<pre><code>[four]: /url+</code></pre>++<hr>++<p><a href="foo">this</a> should work</p>++<p>So should <a href="foo">this</a>.</p>++<p>And <a href="foo">this</a>.</p>++<p>And <a href="foo">this</a>.</p>++<p>And <a href="foo">this</a>.</p>++<p>But not [that] [].</p>++<p>Nor [that][].</p>++<p>Nor [that].</p>++<p>[Something in brackets like <a href="foo">this</a> should work]</p>++<p>[Same with <a href="foo">this</a>.]</p>++<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p>++<p>Backslashing should suppress [this] and [this].</p>++<hr>++<p>Here's one where the <a href="/url/">link+breaks</a> across lines.</p>++<p>Here's another where the <a href="/url/">link +breaks</a> across lines, but with a line-ending space.</p>
+ test/Tests/Links, reference style.text view
@@ -0,0 +1,71 @@+Foo [bar] [1].++Foo [bar][1].++Foo [bar]+[1].++[1]: /url/ "Title"+++With [embedded [brackets]] [b].+++Indented [once][].++Indented [twice][].++Indented [thrice][].++Indented [four][] times.++ [once]: /url++ [twice]: /url++ [thrice]: /url++ [four]: /url+++[b]: /url/++* * *++[this] [this] should work++So should [this][this].++And [this] [].++And [this][].++And [this].++But not [that] [].++Nor [that][].++Nor [that].++[Something in brackets like [this][] should work]++[Same with [this].]++In this case, [this](/somethingelse/) points to something else.++Backslashing should suppress \[this] and [this\].++[this]: foo+++* * *++Here's one where the [link+breaks] across lines.++Here's another where the [link +breaks] across lines, but with a line-ending space.+++[link breaks]: /url/
+ test/Tests/Links, shortcut references.html view
@@ -0,0 +1,9 @@+<p>This is the <a href="/simple">simple case</a>.</p>++<p>This one has a <a href="/foo">line+break</a>.</p>++<p>This one has a <a href="/foo">line +break</a> with a line-ending space.</p>++<p><a href="/that">this</a> and the <a href="/other">other</a></p>
+ test/Tests/Links, shortcut references.text view
@@ -0,0 +1,20 @@+This is the [simple case].++[simple case]: /simple++++This one has a [line+break].++This one has a [line +break] with a line-ending space.++[line break]: /foo+++[this] [that] and the [other]++[this]: /this+[that]: /that+[other]: /other
+ test/Tests/Literal quotes in titles.html view
@@ -0,0 +1,3 @@+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>++<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
+ test/Tests/Literal quotes in titles.text view
@@ -0,0 +1,7 @@+Foo [bar][].++Foo [bar](/url/ "Title with "quotes" inside").+++ [bar]: /url/ "Title with "quotes" inside"+
+ test/Tests/Markdown Documentation - Basics.html view
@@ -0,0 +1,314 @@+<h1>Markdown: Basics</h1>++<ul id="ProjectSubmenu">+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>+ <li><a class="selected" title="Markdown Basics">Basics</a></li>+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>+</ul>++<h2>Getting the Gist of Markdown's Formatting Syntax</h2>++<p>This page offers a brief overview of what it's like to use Markdown.+The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for+every feature, but Markdown should be very easy to pick up simply by+looking at a few examples of it in action. The examples on this page+are written in a before/after style, showing example syntax and the+HTML output produced by Markdown.</p>++<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a+web application that allows you type your own Markdown-formatted text+and translate it to XHTML.</p>++<p><strong>Note:</strong> This document is itself written using Markdown; you+can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p>++<h2>Paragraphs, Headers, Blockquotes</h2>++<p>A paragraph is simply one or more consecutive lines of text, separated+by one or more blank lines. (A blank line is any line that looks like a+blank line -- a line containing nothing spaces or tabs is considered+blank.) Normal paragraphs should not be intended with spaces or tabs.</p>++<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.+Setext-style headers for <code><h1></code> and <code><h2></code> are created by+"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.+To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the+beginning of the line -- the number of hashes equals the resulting+HTML header level.</p>++<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p>++<p>Markdown:</p>++<pre><code>A First Level Header+====================++A Second Level Header+---------------------++Now is the time for all good men to come to+the aid of their country. This is just a+regular paragraph.++The quick brown fox jumped over the lazy+dog's back.++### Header 3++> This is a blockquote.+> +> This is the second paragraph in the blockquote.+>+> ## This is an H2 in a blockquote+</code></pre>++<p>Output:</p>++<pre><code><h1>A First Level Header</h1>++<h2>A Second Level Header</h2>++<p>Now is the time for all good men to come to+the aid of their country. This is just a+regular paragraph.</p>++<p>The quick brown fox jumped over the lazy+dog's back.</p>++<h3>Header 3</h3>++<blockquote>+ <p>This is a blockquote.</p>++ <p>This is the second paragraph in the blockquote.</p>++ <h2>This is an H2 in a blockquote</h2>+</blockquote>+</code></pre>++<h3>Phrase Emphasis</h3>++<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p>++<p>Markdown:</p>++<pre><code>Some of these words *are emphasized*.+Some of these words _are emphasized also_.++Use two asterisks for **strong emphasis**.+Or, if you prefer, __use two underscores instead__.+</code></pre>++<p>Output:</p>++<pre><code><p>Some of these words <em>are emphasized</em>.+Some of these words <em>are emphasized also</em>.</p>++<p>Use two asterisks for <strong>strong emphasis</strong>.+Or, if you prefer, <strong>use two underscores instead</strong>.</p>+</code></pre>++<h2>Lists</h2>++<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,+<code>+</code>, and <code>-</code>) as list markers. These three markers are+interchangable; this:</p>++<pre><code>* Candy.+* Gum.+* Booze.+</code></pre>++<p>this:</p>++<pre><code>+ Candy.++ Gum.++ Booze.+</code></pre>++<p>and this:</p>++<pre><code>- Candy.+- Gum.+- Booze.+</code></pre>++<p>all produce the same output:</p>++<pre><code><ul>+<li>Candy.</li>+<li>Gum.</li>+<li>Booze.</li>+</ul>+</code></pre>++<p>Ordered (numbered) lists use regular numbers, followed by periods, as+list markers:</p>++<pre><code>1. Red+2. Green+3. Blue+</code></pre>++<p>Output:</p>++<pre><code><ol>+<li>Red</li>+<li>Green</li>+<li>Blue</li>+</ol>+</code></pre>++<p>If you put blank lines between items, you'll get <code><p></code> tags for the+list item text. You can create multi-paragraph list items by indenting+the paragraphs by 4 spaces or 1 tab:</p>++<pre><code>* A list item.++ With multiple paragraphs.++* Another item in the list.+</code></pre>++<p>Output:</p>++<pre><code><ul>+<li><p>A list item.</p>+<p>With multiple paragraphs.</p></li>+<li><p>Another item in the list.</p></li>+</ul>+</code></pre>++<h3>Links</h3>++<p>Markdown supports two styles for creating links: <em>inline</em> and+<em>reference</em>. With both styles, you use square brackets to delimit the+text you want to turn into a link.</p>++<p>Inline-style links use parentheses immediately after the link text.+For example:</p>++<pre><code>This is an [example link](http://example.com/).+</code></pre>++<p>Output:</p>++<pre><code><p>This is an <a href="http://example.com/">+example link</a>.</p>+</code></pre>++<p>Optionally, you may include a title attribute in the parentheses:</p>++<pre><code>This is an [example link](http://example.com/ "With a Title").+</code></pre>++<p>Output:</p>++<pre><code><p>This is an <a href="http://example.com/" title="With a Title">+example link</a>.</p>+</code></pre>++<p>Reference-style links allow you to refer to your links by names, which+you define elsewhere in your document:</p>++<pre><code>I get 10 times more traffic from [Google][1] than from+[Yahoo][2] or [MSN][3].++[1]: http://google.com/ "Google"+[2]: http://search.yahoo.com/ "Yahoo Search"+[3]: http://search.msn.com/ "MSN Search"+</code></pre>++<p>Output:</p>++<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"+title="Google">Google</a> than from <a href="http://search.yahoo.com/"+title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"+title="MSN Search">MSN</a>.</p>+</code></pre>++<p>The title attribute is optional. Link names may contain letters,+numbers and spaces, but are <em>not</em> case sensitive:</p>++<pre><code>I start my morning with a cup of coffee and+[The New York Times][NY Times].++[ny times]: http://www.nytimes.com/+</code></pre>++<p>Output:</p>++<pre><code><p>I start my morning with a cup of coffee and+<a href="http://www.nytimes.com/">The New York Times</a>.</p>+</code></pre>++<h3>Images</h3>++<p>Image syntax is very much like link syntax.</p>++<p>Inline (titles are optional):</p>++<pre><code>+</code></pre>++<p>Reference-style:</p>++<pre><code>![alt text][id]++[id]: /path/to/img.jpg "Title"+</code></pre>++<p>Both of the above examples produce the same output:</p>++<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" />+</code></pre>++<h3>Code</h3>++<p>In a regular paragraph, you can create code span by wrapping text in+backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or+<code>></code>) will automatically be translated into HTML entities. This makes+it easy to use Markdown to write about HTML example code:</p>++<pre><code>I strongly recommend against using any `<blink>` tags.++I wish SmartyPants used named entities like `&mdash;`+instead of decimal-encoded entites like `&#8212;`.+</code></pre>++<p>Output:</p>++<pre><code><p>I strongly recommend against using any+<code>&lt;blink&gt;</code> tags.</p>++<p>I wish SmartyPants used named entities like+<code>&amp;mdash;</code> instead of decimal-encoded+entites like <code>&amp;#8212;</code>.</p>+</code></pre>++<p>To specify an entire block of pre-formatted code, indent every line of+the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,+and <code>></code> characters will be escaped automatically.</p>++<p>Markdown:</p>++<pre><code>If you want your page to validate under XHTML 1.0 Strict,+you've got to put paragraph tags in your blockquotes:++ <blockquote>+ <p>For example.</p>+ </blockquote>+</code></pre>++<p>Output:</p>++<pre><code><p>If you want your page to validate under XHTML 1.0 Strict,+you've got to put paragraph tags in your blockquotes:</p>++<pre><code>&lt;blockquote&gt;+ &lt;p&gt;For example.&lt;/p&gt;+&lt;/blockquote&gt;+</code></pre>+</code></pre>
+ test/Tests/Markdown Documentation - Syntax.html view
@@ -0,0 +1,942 @@+<h1>Markdown: Syntax</h1>++<ul id="ProjectSubmenu">+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>+</ul>++<ul>+<li><a href="#overview">Overview</a>+<ul>+<li><a href="#philosophy">Philosophy</a></li>+<li><a href="#html">Inline HTML</a></li>+<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>+</ul></li>+<li><a href="#block">Block Elements</a>+<ul>+<li><a href="#p">Paragraphs and Line Breaks</a></li>+<li><a href="#header">Headers</a></li>+<li><a href="#blockquote">Blockquotes</a></li>+<li><a href="#list">Lists</a></li>+<li><a href="#precode">Code Blocks</a></li>+<li><a href="#hr">Horizontal Rules</a></li>+</ul></li>+<li><a href="#span">Span Elements</a>+<ul>+<li><a href="#link">Links</a></li>+<li><a href="#em">Emphasis</a></li>+<li><a href="#code">Code</a></li>+<li><a href="#img">Images</a></li>+</ul></li>+<li><a href="#misc">Miscellaneous</a>+<ul>+<li><a href="#backslash">Backslash Escapes</a></li>+<li><a href="#autolink">Automatic Links</a></li>+</ul></li>+</ul>++<p><strong>Note:</strong> This document is itself written using Markdown; you+can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>++<hr />++<h2 id="overview">Overview</h2>++<h3 id="philosophy">Philosophy</h3>++<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>++<p>Readability, however, is emphasized above all else. A Markdown-formatted+document should be publishable as-is, as plain text, without looking+like it's been marked up with tags or formatting instructions. While+Markdown's syntax has been influenced by several existing text-to-HTML+filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,+<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of+inspiration for Markdown's syntax is the format of plain text email.</p>++<p>To this end, Markdown's syntax is comprised entirely of punctuation+characters, which punctuation characters have been carefully chosen so+as to look like what they mean. E.g., asterisks around a word actually+look like *emphasis*. Markdown lists look like, well, lists. Even+blockquotes look like quoted passages of text, assuming you've ever+used email.</p>++<h3 id="html">Inline HTML</h3>++<p>Markdown's syntax is intended for one purpose: to be used as a+format for <em>writing</em> for the web.</p>++<p>Markdown is not a replacement for HTML, or even close to it. Its+syntax is very small, corresponding only to a very small subset of+HTML tags. The idea is <em>not</em> to create a syntax that makes it easier+to insert HTML tags. In my opinion, HTML tags are already easy to+insert. The idea for Markdown is to make it easy to read, write, and+edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>+format. Thus, Markdown's formatting syntax only addresses issues that+can be conveyed in plain text.</p>++<p>For any markup that is not covered by Markdown's syntax, you simply+use HTML itself. There's no need to preface it or delimit it to+indicate that you're switching from Markdown to HTML; you just use+the tags.</p>++<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,+<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding+content by blank lines, and the start and end tags of the block should+not be indented with tabs or spaces. Markdown is smart enough not+to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p>++<p>For example, to add an HTML table to a Markdown article:</p>++<pre><code>This is a regular paragraph.++<table>+ <tr>+ <td>Foo</td>+ </tr>+</table>++This is another regular paragraph.+</code></pre>++<p>Note that Markdown formatting syntax is not processed within block-level+HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an+HTML block.</p>++<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be+used anywhere in a Markdown paragraph, list item, or header. If you+want, you can even use HTML tags instead of Markdown formatting; e.g. if+you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's+link or image syntax, go right ahead.</p>++<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within+span-level tags.</p>++<h3 id="autoescape">Automatic Escaping for Special Characters</h3>++<p>In HTML, there are two characters that demand special treatment: <code><</code>+and <code>&</code>. Left angle brackets are used to start tags; ampersands are+used to denote HTML entities. If you want to use them as literal+characters, you must escape them as entities, e.g. <code>&lt;</code>, and+<code>&amp;</code>.</p>++<p>Ampersands in particular are bedeviling for web writers. If you want to+write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to+escape ampersands within URLs. Thus, if you want to link to:</p>++<pre><code>http://images.google.com/images?num=30&q=larry+bird+</code></pre>++<p>you need to encode the URL as:</p>++<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird+</code></pre>++<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to+forget, and is probably the single most common source of HTML validation+errors in otherwise well-marked-up web sites.</p>++<p>Markdown allows you to use these characters naturally, taking care of+all the necessary escaping for you. If you use an ampersand as part of+an HTML entity, it remains unchanged; otherwise it will be translated+into <code>&amp;</code>.</p>++<p>So, if you want to include a copyright symbol in your article, you can write:</p>++<pre><code>&copy;+</code></pre>++<p>and Markdown will leave it alone. But if you write:</p>++<pre><code>AT&T+</code></pre>++<p>Markdown will translate it to:</p>++<pre><code>AT&amp;T+</code></pre>++<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use+angle brackets as delimiters for HTML tags, Markdown will treat them as+such. But if you write:</p>++<pre><code>4 < 5+</code></pre>++<p>Markdown will translate it to:</p>++<pre><code>4 &lt; 5+</code></pre>++<p>However, inside Markdown code spans and blocks, angle brackets and+ampersands are <em>always</em> encoded automatically. This makes it easy to use+Markdown to write about HTML code. (As opposed to raw HTML, which is a+terrible format for writing about HTML syntax, because every single <code><</code>+and <code>&</code> in your example code needs to be escaped.)</p>++<hr />++<h2 id="block">Block Elements</h2>++<h3 id="p">Paragraphs and Line Breaks</h3>++<p>A paragraph is simply one or more consecutive lines of text, separated+by one or more blank lines. (A blank line is any line that looks like a+blank line -- a line containing nothing but spaces or tabs is considered+blank.) Normal paragraphs should not be intended with spaces or tabs.</p>++<p>The implication of the "one or more consecutive lines of text" rule is+that Markdown supports "hard-wrapped" text paragraphs. This differs+significantly from most other text-to-HTML formatters (including Movable+Type's "Convert Line Breaks" option) which translate every line break+character in a paragraph into a <code><br /></code> tag.</p>++<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you+end a line with two or more spaces, then type return.</p>++<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic+"every line break is a <code><br /></code>" rule wouldn't work for Markdown.+Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>+work best -- and look better -- when you format them with hard breaks.</p>++<h3 id="header">Headers</h3>++<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>++<p>Setext-style headers are "underlined" using equal signs (for first-level+headers) and dashes (for second-level headers). For example:</p>++<pre><code>This is an H1+=============++This is an H2+-------------+</code></pre>++<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>++<p>Atx-style headers use 1-6 hash characters at the start of the line,+corresponding to header levels 1-6. For example:</p>++<pre><code># This is an H1++## This is an H2++###### This is an H6+</code></pre>++<p>Optionally, you may "close" atx-style headers. This is purely+cosmetic -- you can use this if you think it looks better. The+closing hashes don't even need to match the number of hashes+used to open the header. (The number of opening hashes+determines the header level.) :</p>++<pre><code># This is an H1 #++## This is an H2 ##++### This is an H3 ######+</code></pre>++<h3 id="blockquote">Blockquotes</h3>++<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're+familiar with quoting passages of text in an email message, then you+know how to create a blockquote in Markdown. It looks best if you hard+wrap the text and put a <code>></code> before every line:</p>++<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.+> +> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse+> id sem consectetuer libero luctus adipiscing.+</code></pre>++<p>Markdown allows you to be lazy and only put the <code>></code> before the first+line of a hard-wrapped paragraph:</p>++<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.++> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse+id sem consectetuer libero luctus adipiscing.+</code></pre>++<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by+adding additional levels of <code>></code>:</p>++<pre><code>> This is the first level of quoting.+>+> > This is nested blockquote.+>+> Back to the first level.+</code></pre>++<p>Blockquotes can contain other Markdown elements, including headers, lists,+and code blocks:</p>++<pre><code>> ## This is a header.+> +> 1. This is the first list item.+> 2. This is the second list item.+> +> Here's some example code:+> +> return shell_exec("echo $input | $markdown_script");+</code></pre>++<p>Any decent text editor should make email-style quoting easy. For+example, with BBEdit, you can make a selection and choose Increase+Quote Level from the Text menu.</p>++<h3 id="list">Lists</h3>++<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>++<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably+-- as list markers:</p>++<pre><code>* Red+* Green+* Blue+</code></pre>++<p>is equivalent to:</p>++<pre><code>+ Red++ Green++ Blue+</code></pre>++<p>and:</p>++<pre><code>- Red+- Green+- Blue+</code></pre>++<p>Ordered lists use numbers followed by periods:</p>++<pre><code>1. Bird+2. McHale+3. Parish+</code></pre>++<p>It's important to note that the actual numbers you use to mark the+list have no effect on the HTML output Markdown produces. The HTML+Markdown produces from the above list is:</p>++<pre><code><ol>+<li>Bird</li>+<li>McHale</li>+<li>Parish</li>+</ol>+</code></pre>++<p>If you instead wrote the list in Markdown like this:</p>++<pre><code>1. Bird+1. McHale+1. Parish+</code></pre>++<p>or even:</p>++<pre><code>3. Bird+1. McHale+8. Parish+</code></pre>++<p>you'd get the exact same HTML output. The point is, if you want to,+you can use ordinal numbers in your ordered Markdown lists, so that+the numbers in your source match the numbers in your published HTML.+But if you want to be lazy, you don't have to.</p>++<p>If you do use lazy list numbering, however, you should still start the+list with the number 1. At some point in the future, Markdown may support+starting ordered lists at an arbitrary number.</p>++<p>List markers typically start at the left margin, but may be indented by+up to three spaces. List markers must be followed by one or more spaces+or a tab.</p>++<p>To make lists look nice, you can wrap items with hanging indents:</p>++<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,+ viverra nec, fringilla in, laoreet vitae, risus.+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.+ Suspendisse id sem consectetuer libero luctus adipiscing.+</code></pre>++<p>But if you want to be lazy, you don't have to:</p>++<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,+viverra nec, fringilla in, laoreet vitae, risus.+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.+Suspendisse id sem consectetuer libero luctus adipiscing.+</code></pre>++<p>If list items are separated by blank lines, Markdown will wrap the+items in <code><p></code> tags in the HTML output. For example, this input:</p>++<pre><code>* Bird+* Magic+</code></pre>++<p>will turn into:</p>++<pre><code><ul>+<li>Bird</li>+<li>Magic</li>+</ul>+</code></pre>++<p>But this:</p>++<pre><code>* Bird++* Magic+</code></pre>++<p>will turn into:</p>++<pre><code><ul>+<li><p>Bird</p></li>+<li><p>Magic</p></li>+</ul>+</code></pre>++<p>List items may consist of multiple paragraphs. Each subsequent+paragraph in a list item must be intended by either 4 spaces+or one tab:</p>++<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit+ mi posuere lectus.++ Vestibulum enim wisi, viverra nec, fringilla in, laoreet+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum+ sit amet velit.++2. Suspendisse id sem consectetuer libero luctus adipiscing.+</code></pre>++<p>It looks nice if you indent every line of the subsequent+paragraphs, but here again, Markdown will allow you to be+lazy:</p>++<pre><code>* This is a list item with two paragraphs.++ This is the second paragraph in the list item. You're+only required to indent the first line. Lorem ipsum dolor+sit amet, consectetuer adipiscing elit.++* Another item in the same list.+</code></pre>++<p>To put a blockquote within a list item, the blockquote's <code>></code>+delimiters need to be indented:</p>++<pre><code>* A list item with a blockquote:++ > This is a blockquote+ > inside a list item.+</code></pre>++<p>To put a code block within a list item, the code block needs+to be indented <em>twice</em> -- 8 spaces or two tabs:</p>++<pre><code>* A list item with a code block:++ <code goes here>+</code></pre>++<p>It's worth noting that it's possible to trigger an ordered list by+accident, by writing something like this:</p>++<pre><code>1986. What a great season.+</code></pre>++<p>In other words, a <em>number-period-space</em> sequence at the beginning of a+line. To avoid this, you can backslash-escape the period:</p>++<pre><code>1986\. What a great season.+</code></pre>++<h3 id="precode">Code Blocks</h3>++<p>Pre-formatted code blocks are used for writing about programming or+markup source code. Rather than forming normal paragraphs, the lines+of a code block are interpreted literally. Markdown wraps a code block+in both <code><pre></code> and <code><code></code> tags.</p>++<p>To produce a code block in Markdown, simply indent every line of the+block by at least 4 spaces or 1 tab. For example, given this input:</p>++<pre><code>This is a normal paragraph:++ This is a code block.+</code></pre>++<p>Markdown will generate:</p>++<pre><code><p>This is a normal paragraph:</p>++<pre><code>This is a code block.+</code></pre>+</code></pre>++<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each+line of the code block. For example, this:</p>++<pre><code>Here is an example of AppleScript:++ tell application "Foo"+ beep+ end tell+</code></pre>++<p>will turn into:</p>++<pre><code><p>Here is an example of AppleScript:</p>++<pre><code>tell application "Foo"+ beep+end tell+</code></pre>+</code></pre>++<p>A code block continues until it reaches a line that is not indented+(or the end of the article).</p>++<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)+are automatically converted into HTML entities. This makes it very+easy to include example HTML source code using Markdown -- just paste+it and indent it, and Markdown will handle the hassle of encoding the+ampersands and angle brackets. For example, this:</p>++<pre><code> <div class="footer">+ &copy; 2004 Foo Corporation+ </div>+</code></pre>++<p>will turn into:</p>++<pre><code><pre><code>&lt;div class="footer"&gt;+ &amp;copy; 2004 Foo Corporation+&lt;/div&gt;+</code></pre>+</code></pre>++<p>Regular Markdown syntax is not processed within code blocks. E.g.,+asterisks are just literal asterisks within a code block. This means+it's also easy to use Markdown to write about Markdown's own syntax.</p>++<h3 id="hr">Horizontal Rules</h3>++<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or+more hyphens, asterisks, or underscores on a line by themselves. If you+wish, you may use spaces between the hyphens or asterisks. Each of the+following lines will produce a horizontal rule:</p>++<pre><code>* * *++***++*****++- - -++---------------------------------------++_ _ _+</code></pre>++<hr />++<h2 id="span">Span Elements</h2>++<h3 id="link">Links</h3>++<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>++<p>In both styles, the link text is delimited by [square brackets].</p>++<p>To create an inline link, use a set of regular parentheses immediately+after the link text's closing square bracket. Inside the parentheses,+put the URL where you want the link to point, along with an <em>optional</em>+title for the link, surrounded in quotes. For example:</p>++<pre><code>This is [an example](http://example.com/ "Title") inline link.++[This link](http://example.net/) has no title attribute.+</code></pre>++<p>Will produce:</p>++<pre><code><p>This is <a href="http://example.com/" title="Title">+an example</a> inline link.</p>++<p><a href="http://example.net/">This link</a> has no+title attribute.</p>+</code></pre>++<p>If you're referring to a local resource on the same server, you can+use relative paths:</p>++<pre><code>See my [About](/about/) page for details.+</code></pre>++<p>Reference-style links use a second set of square brackets, inside+which you place a label of your choosing to identify the link:</p>++<pre><code>This is [an example][id] reference-style link.+</code></pre>++<p>You can optionally use a space to separate the sets of brackets:</p>++<pre><code>This is [an example] [id] reference-style link.+</code></pre>++<p>Then, anywhere in the document, you define your link label like this,+on a line by itself:</p>++<pre><code>[id]: http://example.com/ "Optional Title Here"+</code></pre>++<p>That is:</p>++<ul>+<li>Square brackets containing the link identifier (optionally+indented from the left margin using up to three spaces);</li>+<li>followed by a colon;</li>+<li>followed by one or more spaces (or tabs);</li>+<li>followed by the URL for the link;</li>+<li>optionally followed by a title attribute for the link, enclosed+in double or single quotes.</li>+</ul>++<p>The link URL may, optionally, be surrounded by angle brackets:</p>++<pre><code>[id]: <http://example.com/> "Optional Title Here"+</code></pre>++<p>You can put the title attribute on the next line and use extra spaces+or tabs for padding, which tends to look better with longer URLs:</p>++<pre><code>[id]: http://example.com/longish/path/to/resource/here+ "Optional Title Here"+</code></pre>++<p>Link definitions are only used for creating links during Markdown+processing, and are stripped from your document in the HTML output.</p>++<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p>++<pre><code>[link text][a]+[link text][A]+</code></pre>++<p>are equivalent.</p>++<p>The <em>implicit link name</em> shortcut allows you to omit the name of the+link, in which case the link text itself is used as the name.+Just use an empty set of square brackets -- e.g., to link the word+"Google" to the google.com web site, you could simply write:</p>++<pre><code>[Google][]+</code></pre>++<p>And then define the link:</p>++<pre><code>[Google]: http://google.com/+</code></pre>++<p>Because link names may contain spaces, this shortcut even works for+multiple words in the link text:</p>++<pre><code>Visit [Daring Fireball][] for more information.+</code></pre>++<p>And then define the link:</p>++<pre><code>[Daring Fireball]: http://daringfireball.net/+</code></pre>++<p>Link definitions can be placed anywhere in your Markdown document. I+tend to put them immediately after each paragraph in which they're+used, but if you want, you can put them all at the end of your+document, sort of like footnotes.</p>++<p>Here's an example of reference links in action:</p>++<pre><code>I get 10 times more traffic from [Google] [1] than from+[Yahoo] [2] or [MSN] [3].++ [1]: http://google.com/ "Google"+ [2]: http://search.yahoo.com/ "Yahoo Search"+ [3]: http://search.msn.com/ "MSN Search"+</code></pre>++<p>Using the implicit link name shortcut, you could instead write:</p>++<pre><code>I get 10 times more traffic from [Google][] than from+[Yahoo][] or [MSN][].++ [google]: http://google.com/ "Google"+ [yahoo]: http://search.yahoo.com/ "Yahoo Search"+ [msn]: http://search.msn.com/ "MSN Search"+</code></pre>++<p>Both of the above examples will produce the following HTML output:</p>++<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"+title="Google">Google</a> than from+<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>+or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>+</code></pre>++<p>For comparison, here is the same paragraph written using+Markdown's inline link style:</p>++<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google")+than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or+[MSN](http://search.msn.com/ "MSN Search").+</code></pre>++<p>The point of reference-style links is not that they're easier to+write. The point is that with reference-style links, your document+source is vastly more readable. Compare the above examples: using+reference-style links, the paragraph itself is only 81 characters+long; with inline-style links, it's 176 characters; and as raw HTML,+it's 234 characters. In the raw HTML, there's more markup than there+is text.</p>++<p>With Markdown's reference-style links, a source document much more+closely resembles the final output, as rendered in a browser. By+allowing you to move the markup-related metadata out of the paragraph,+you can add links without interrupting the narrative flow of your+prose.</p>++<h3 id="em">Emphasis</h3>++<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an+HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML+<code><strong></code> tag. E.g., this input:</p>++<pre><code>*single asterisks*++_single underscores_++**double asterisks**++__double underscores__+</code></pre>++<p>will produce:</p>++<pre><code><em>single asterisks</em>++<em>single underscores</em>++<strong>double asterisks</strong>++<strong>double underscores</strong>+</code></pre>++<p>You can use whichever style you prefer; the lone restriction is that+the same character must be used to open and close an emphasis span.</p>++<p>Emphasis can be used in the middle of a word:</p>++<pre><code>un*fucking*believable+</code></pre>++<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a+literal asterisk or underscore.</p>++<p>To produce a literal asterisk or underscore at a position where it+would otherwise be used as an emphasis delimiter, you can backslash+escape it:</p>++<pre><code>\*this text is surrounded by literal asterisks\*+</code></pre>++<h3 id="code">Code</h3>++<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).+Unlike a pre-formatted code block, a code span indicates code within a+normal paragraph. For example:</p>++<pre><code>Use the `printf()` function.+</code></pre>++<p>will produce:</p>++<pre><code><p>Use the <code>printf()</code> function.</p>+</code></pre>++<p>To include a literal backtick character within a code span, you can use+multiple backticks as the opening and closing delimiters:</p>++<pre><code>``There is a literal backtick (`) here.``+</code></pre>++<p>which will produce this:</p>++<pre><code><p><code>There is a literal backtick (`) here.</code></p>+</code></pre>++<p>The backtick delimiters surrounding a code span may include spaces --+one after the opening, one before the closing. This allows you to place+literal backtick characters at the beginning or end of a code span:</p>++<pre><code>A single backtick in a code span: `` ` ``++A backtick-delimited string in a code span: `` `foo` ``+</code></pre>++<p>will produce:</p>++<pre><code><p>A single backtick in a code span: <code>`</code></p>++<p>A backtick-delimited string in a code span: <code>`foo`</code></p>+</code></pre>++<p>With a code span, ampersands and angle brackets are encoded as HTML+entities automatically, which makes it easy to include example HTML+tags. Markdown will turn this:</p>++<pre><code>Please don't use any `<blink>` tags.+</code></pre>++<p>into:</p>++<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>+</code></pre>++<p>You can write this:</p>++<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`.+</code></pre>++<p>to produce:</p>++<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded+equivalent of <code>&amp;mdash;</code>.</p>+</code></pre>++<h3 id="img">Images</h3>++<p>Admittedly, it's fairly difficult to devise a "natural" syntax for+placing images into a plain text document format.</p>++<p>Markdown uses an image syntax that is intended to resemble the syntax+for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>++<p>Inline image syntax looks like this:</p>++<pre><code>+++</code></pre>++<p>That is:</p>++<ul>+<li>An exclamation mark: <code>!</code>;</li>+<li>followed by a set of square brackets, containing the <code>alt</code>+attribute text for the image;</li>+<li>followed by a set of parentheses, containing the URL or path to+the image, and an optional <code>title</code> attribute enclosed in double+or single quotes.</li>+</ul>++<p>Reference-style image syntax looks like this:</p>++<pre><code>![Alt text][id]+</code></pre>++<p>Where "id" is the name of a defined image reference. Image references+are defined using syntax identical to link references:</p>++<pre><code>[id]: url/to/image "Optional title attribute"+</code></pre>++<p>As of this writing, Markdown has no syntax for specifying the+dimensions of an image; if this is important to you, you can simply+use regular HTML <code><img></code> tags.</p>++<hr />++<h2 id="misc">Miscellaneous</h2>++<h3 id="autolink">Automatic Links</h3>++<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>++<pre><code><http://example.com/>+</code></pre>++<p>Markdown will turn this into:</p>++<pre><code><a href="http://example.com/">http://example.com/</a>+</code></pre>++<p>Automatic links for email addresses work similarly, except that+Markdown will also perform a bit of randomized decimal and hex+entity-encoding to help obscure your address from address-harvesting+spambots. For example, Markdown will turn this:</p>++<pre><code><address@example.com>+</code></pre>++<p>into something like this:</p>++<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;+&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;+&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;+&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>+</code></pre>++<p>which will render in a browser as a clickable link to "address@example.com".</p>++<p>(This sort of entity-encoding trick will indeed fool many, if not+most, address-harvesting bots, but it definitely won't fool all of+them. It's better than nothing, but an address published in this way+will probably eventually start receiving spam.)</p>++<h3 id="backslash">Backslash Escapes</h3>++<p>Markdown allows you to use backslash escapes to generate literal+characters which would otherwise have special meaning in Markdown's+formatting syntax. For example, if you wanted to surround a word with+literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes+before the asterisks, like this:</p>++<pre><code>\*literal asterisks\*+</code></pre>++<p>Markdown provides backslash escapes for the following characters:</p>++<pre><code>\ backslash+` backtick+* asterisk+_ underscore+{} curly braces+[] square brackets+() parentheses+# hash mark++ plus sign+- minus sign (hyphen)+. dot+! exclamation mark+</code></pre>
+ test/Tests/Nested blockquotes.html view
@@ -0,0 +1,9 @@+<blockquote>+<p>foo</p>++<blockquote>+<p>bar</p>+</blockquote>++<p>foo</p>+</blockquote>
+ test/Tests/Nested blockquotes.text view
@@ -0,0 +1,5 @@+> foo+>+> > bar+>+> foo
+ test/Tests/Ordered and unordered lists.html view
@@ -0,0 +1,148 @@+<h2>Unordered</h2>++<p>Asterisks tight:</p>++<ul>+<li>asterisk 1</li>+<li>asterisk 2</li>+<li>asterisk 3</li>+</ul>++<p>Asterisks loose:</p>++<ul>+<li><p>asterisk 1</p></li>+<li><p>asterisk 2</p></li>+<li><p>asterisk 3</p></li>+</ul>++<hr>++<p>Pluses tight:</p>++<ul>+<li>Plus 1</li>+<li>Plus 2</li>+<li>Plus 3</li>+</ul>++<p>Pluses loose:</p>++<ul>+<li><p>Plus 1</p></li>+<li><p>Plus 2</p></li>+<li><p>Plus 3</p></li>+</ul>++<hr>++<p>Minuses tight:</p>++<ul>+<li>Minus 1</li>+<li>Minus 2</li>+<li>Minus 3</li>+</ul>++<p>Minuses loose:</p>++<ul>+<li><p>Minus 1</p></li>+<li><p>Minus 2</p></li>+<li><p>Minus 3</p></li>+</ul>++<h2>Ordered</h2>++<p>Tight:</p>++<ol>+<li>First</li>+<li>Second</li>+<li>Third</li>+</ol>++<p>and:</p>++<ol>+<li>One</li>+<li>Two</li>+<li>Three</li>+</ol>++<p>Loose using tabs:</p>++<ol>+<li><p>First</p></li>+<li><p>Second</p></li>+<li><p>Third</p></li>+</ol>++<p>and using spaces:</p>++<ol>+<li><p>One</p></li>+<li><p>Two</p></li>+<li><p>Three</p></li>+</ol>++<p>Multiple paragraphs:</p>++<ol>+<li><p>Item 1, graf one.</p>++<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's+back.</p></li>+<li><p>Item 2.</p></li>+<li><p>Item 3.</p></li>+</ol>++<h2>Nested</h2>++<ul>+<li><p>Tab</p>+<ul>+<li><p>Tab</p>+<ul>+<li>Tab</li>+</ul></li>+</ul></li>+</ul>++<p>Here's another:</p>++<ol>+<li>First</li>+<li>Second:+<ul>+<li>Fee</li>+<li>Fie</li>+<li>Foe</li>+</ul></li>+<li>Third</li>+</ol>++<p>Same thing but with paragraphs:</p>++<ol>+<li><p>First</p></li>+<li><p>Second:</p>++<ul>+<li>Fee</li>+<li>Fie</li>+<li>Foe</li>+</ul></li>+<li><p>Third</p></li>+</ol>+++<p>This was an error in Markdown 1.0.1:</p>++<ul>+<li><p>this</p>++<ul><li>sub</li></ul>++<p>that</p></li>+</ul>
+ test/Tests/Strong and em together.html view
@@ -0,0 +1,7 @@+<p><b><i>This is strong and em.</i></b></p>++<p>So is <b><i>this</i></b> word.</p>++<p><b><i>This is strong and em.</i></b></p>++<p>So is <b><i>this</i></b> word.</p>
+ test/Tests/Strong and em together.text view
@@ -0,0 +1,7 @@+***This is strong and em.***++So is ***this*** word.++___This is strong and em.___++So is ___this___ word.
+ test/Tests/Tabs.html view
@@ -0,0 +1,25 @@+<ul>+<li><p>this is a list item+indented with tabs</p></li>+<li><p>this is a list item+indented with spaces</p></li>+</ul>++<p>Code:</p>++<pre><code>this code block is indented by one tab+</code></pre>++<p>And:</p>++<pre><code> this code block is indented by two tabs+</code></pre>++<p>And:</p>++<pre><code>+ this is an example list item+ indented with tabs+++ this is an example list item+ indented with spaces+</code></pre>
+ test/Tests/Tabs.text view
@@ -0,0 +1,21 @@++ this is a list item+ indented with tabs+++ this is a list item+ indented with spaces++Code:++ this code block is indented by one tab++And:++ this code block is indented by two tabs++And:++ + this is an example list item+ indented with tabs+ + + this is an example list item+ indented with spaces
+ test/Tests/Tidyness.html view
@@ -0,0 +1,8 @@+<blockquote>+<p>A list within a blockquote:</p>+<ul>+<li>asterisk 1</li>+<li>asterisk 2</li>+<li>asterisk 3</li>+</ul>+</blockquote>
+ test/Tests/Tidyness.text view
@@ -0,0 +1,5 @@+> A list within a blockquote:+> +> * asterisk 1+> * asterisk 2+> * asterisk 3
+ test/examples/closing-tags.html view
@@ -0,0 +1,1 @@+<ul><li><p>foo</p></li></ul>
+ test/examples/closing-tags.md view
@@ -0,0 +1,1 @@+* <p>foo</p>
+ test/examples/entities.html view
@@ -0,0 +1,1 @@+<p>1 < 2 & 2 > 1, also 1 < 2 & 2 > 1 ý &#xP;</p>
+ test/examples/entities.md view
@@ -0,0 +1,1 @@+1 < 2 & 2 > 1, also 1 < 2 & 2 > 1   ý &#xP;
+ test/examples/fence-whitespace.html view
@@ -0,0 +1,1 @@+<p>foo</p><pre><code>bar</code></pre>
+ test/examples/fence-whitespace.md view
@@ -0,0 +1,4 @@+foo+```+bar+```
+ test/examples/lazy.html view
@@ -0,0 +1,3 @@+<blockquote><p>this is+lazy</p></blockquote><ol><li>This is+a list</li><li>Another item</li></ol>
+ test/examples/lazy.md view
@@ -0,0 +1,6 @@+> this is+lazy++1. This is+a list+2. Another item
+ test/examples/list-blocks.html view
@@ -0,0 +1,1 @@+<ul><li><p>This is a paragraph.</p><p>Another paragraph.</p></li><li><p>Non-paragraph.</p></li><li><p>Item.</p><ul><li>Sublist item.</li><li><ol><li>Item 1</li><li>Item 2</li></ol></li></ul></li></ul>
+ test/examples/list-blocks.md view
@@ -0,0 +1,12 @@+* This is a paragraph.++ Another paragraph.++* Non-paragraph.++* Item.++ * Sublist item.+ * + 1. Item 1+ 2. Item 2
+ test/examples/lists-code.html view
@@ -0,0 +1,2 @@+<ol><li>hello+world</li><li><p>hello</p><pre><code class="haskell">data Foo</code></pre></li></ol>
+ test/examples/lists-code.md view
@@ -0,0 +1,7 @@+1. hello+ world+2. hello++ ```haskell+ data Foo+ ```
+ test/examples/multiline-paragraphs.html view
@@ -0,0 +1,5 @@+<p>This is a multiline+paragraph.</p><ul><li><p>Multiline paragraph+in a list.</p></li><li><p>The purpose of classy prelude is <i>not</i> to encourage writing polymorphic+code based on the typeclasses provided. Though it's certainly possible to+write code such as:</p></li></ul>
+ test/examples/multiline-paragraphs.md view
@@ -0,0 +1,9 @@+This is a multiline+paragraph.++* Multiline paragraph+ in a list.++* The purpose of classy prelude is *not* to encourage writing polymorphic+ code based on the typeclasses provided. Though it's certainly possible to+ write code such as:
+ test/examples/sublists.html view
@@ -0,0 +1,1 @@+<ol><li>No encounters</li><li>Encounters<ol><li>First kind</li><li>Second kind</li></ol></li></ol>
+ test/examples/sublists.md view
@@ -0,0 +1,4 @@+1. No encounters+2. Encounters+ 1. First kind+ 2. Second kind
+ test/examples/tilde-code.html view
@@ -0,0 +1,4 @@+<pre><code class="haskell">foo+bar++baz</code></pre>
+ test/examples/tilde-code.md view
@@ -0,0 +1,6 @@+~~~haskell+foo+bar++baz+~~~
+ test/main.hs view
@@ -0,0 +1,226 @@+{-# LANGUAGE OverloadedStrings #-}+import Test.Hspec+import Text.Markdown+import Data.Text.Lazy (Text, unpack, snoc, fromStrict)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import Text.Blaze.Html.Renderer.Text (renderHtml)+import Control.Monad (forM_)+import qualified Data.Set as Set+import qualified Data.Map as Map++import qualified Filesystem.Path.CurrentOS as F+import qualified Filesystem as F++import Block+import Inline++check :: Text -> Text -> Expectation+check html md = renderHtml (markdown def md) `shouldBe` html++checkSet :: MarkdownSettings -> Text -> Text -> Expectation+checkSet set html md = renderHtml (markdown set md) `shouldBe` html++check' :: Text -> Text -> Expectation+check' html md = renderHtml (markdown def { msXssProtect = False } md) `shouldBe` html++checkNoNL :: Text -> Text -> Expectation+checkNoNL html md =+ f (renderHtml $ markdown def { msXssProtect = False } md) `shouldBe` f html+ where+ f = TL.filter (/= '\n')++-- FIXME add quickcheck: all input is valid++main :: IO ()+main = do+ examples <- getExamples+ gruber <- getGruber+ hspec $ do+ describe "block" blockSpecs+ describe "inline" inlineSpecs+ describe "paragraphs" $ do+ it "simple"+ $ check "<p>Hello World!</p>" "Hello World!"+ it "multiline"+ $ check "<p>Hello\nWorld!</p>" "Hello\nWorld!"+ it "multiple"+ $ check "<p>Hello</p><p>World!</p>" "Hello\n\nWorld!"+ describe "italics" $ do+ it "simple"+ $ check "<p><i>foo</i></p>" "*foo*"+ it "hanging"+ $ check "<p><i>foo</i> *</p>" "*foo* *"+ it "two"+ $ check "<p><i>foo</i> <i>bar</i></p>" "*foo* *bar*"+ describe "italics under" $ do+ it "simple"+ $ check "<p><i>foo</i></p>" "_foo_"+ it "hanging"+ $ check "<p><i>foo</i> _</p>" "_foo_ _"+ it "two"+ $ check "<p><i>foo</i> <i>bar</i></p>" "_foo_ _bar_"+ describe "bold" $ do+ it "simple"+ $ check "<p><b>foo</b></p>" "**foo**"+ it "hanging"+ $ check "<p><b>foo</b> **</p>" "**foo** **"+ it "two"+ $ check "<p><b>foo</b> <b>bar</b></p>" "**foo** **bar**"+ describe "bold under" $ do+ it "simple"+ $ check "<p><b>foo</b></p>" "__foo__"+ it "hanging"+ $ check "<p><b>foo</b> __</p>" "__foo__ __"+ it "two"+ $ check "<p><b>foo</b> <b>bar</b></p>" "__foo__ __bar__"+ describe "html" $ do+ it "simple"+ $ check "<div>Hello</div>" "<div>Hello</div>"+ it "dangerous"+ $ check "<div>Hello</div>" "<div onclick='alert(foo)'>Hello</div>"+ it "dangerous and allowed"+ $ check' "<div onclick='alert(foo)'>Hello</div>" "<div onclick='alert(foo)'>Hello</div>"++ let ml = "<div>foo\nbar\nbaz</div>"+ it "multiline" $ check ml ml++ let close = "<div>foo\nbar\nbaz"+ it "autoclose" $ check ml close++ let close2 = "<div>foo\nbar\nbaz\n\nparagraph"+ it "autoclose 2"+ $ check "<div>foo\nbar\nbaz<p>paragraph</p></div>" close2+ describe "inline code" $ do+ it "simple"+ $ check "<p>foo <code>bar</code> baz</p>" "foo `bar` baz"+ describe "code block" $ do+ it "simple"+ $ check+ "<pre><code>foo\n bar\nbaz</code></pre>"+ " foo\n bar\n baz"+ describe "escaping" $ do+ it "everything"+ $ check+ "<p>*foo_bar<i>baz</i>\\`bin</p>"+ "\\*foo\\_bar_baz_\\\\\\`bin"+ describe "bullets" $ do+ it "simple"+ $ check+ "<ul><li>foo</li><li>bar</li><li>baz</li></ul>"+ "* foo\n* bar\n* baz\n"+ describe "numbers" $ do+ it "simple"+ $ check+ "<ol><li>foo</li><li>bar</li><li>baz</li></ol>"+ "5. foo\n2. bar\n1. baz\n"+ describe "headings" $ do+ it "hashes"+ $ check+ "<h1>foo</h1><h2>bar</h2><h3>baz</h3>"+ "# foo\n\n## bar\n\n###baz"+ it "trailing hashes"+ $ check+ "<h1>foo</h1>"+ "# foo ####"+ it "underline"+ $ check+ "<h1>foo</h1><h2>bar</h2>"+ "foo\n=============\n\nbar\n----------------\n"+ describe "blockquotes" $ do+ it "simple"+ $ check+ "<blockquote><p>foo</p><pre><code>bar</code></pre></blockquote>"+ "> foo\n>\n> bar"+ describe "links" $ do+ it "simple" $ check "<p><a href=\"foo\">bar</a></p>" "[bar](foo)"+ it "title" $ check+ "<p><a href=\"foo\" title=\"baz\">bar</a></p>"+ "[bar](foo \"baz\")"+ it "escaped href" $ check+ "<p><a href=\"foo)\" title=\"baz\">bar</a></p>"+ "[bar](foo\\) \"baz\")"+ it "escaped title" $ check+ "<p><a href=\"foo)\" title=\"baz"\">bar</a></p>"+ "[bar](foo\\) \"baz\\\"\")"+ it "inside a paragraph" $ check+ "<p>Hello <a href=\"foo\">bar</a> World</p>"+ "Hello [bar](foo) World"+ it "not a link" $ check+ "<p>Not a [ link</p>"+ "Not a [ link"++ {-+ describe "github links" $ do+ it "simple" $ check "<p><a href=\"foo\">bar</a></p>" "[[bar|foo]]"+ it "no link text" $ check "<p><a href=\"foo\">foo</a></p>" "[[foo]]"+ it "escaping" $ check "<p><a href=\"foo-baz-bin\">bar</a></p>" "[[bar|foo/baz bin]]"+ it "inside a list" $ check "<ul><li><a href=\"foo\">foo</a></li></ul>" "* [[foo]]"+ -}++ describe "images" $ do+ it "simple" $ check + "<p><img src=\"http://link.to/image.jpg\" alt=\"foo\"></p>"+ ""+ it "title" $ check+ "<p><img src=\"http://link.to/image.jpg\" alt=\"foo\" title=\"bar\"></p>"+ ""+ it "inside a paragraph" $ check+ "<p>Hello <img src=\"http://link.to/image.jpg\" alt=\"foo\"> World</p>"+ "Hello  World"+ it "not an image" $ check+ "<p>Not an ![ image</p>"+ "Not an ![ image"++ describe "rules" $ do+ let options = concatMap (\t -> [t, snoc t '\n'])+ [ "* * *"+ , "***"+ , "*****"+ , "- - -"+ , "---------------------------------------"+ , "----------------------------------"+ ]+ forM_ options $ \o -> it (unpack o) $ check "<hr>" o++ describe "html" $ do+ it "inline" $ check "<p>foo<br>bar</p>" "foo<br>bar"+ it "inline xss" $ check "<p>foo<br>bar</p>" "foo<br onclick='evil'>bar"+ it "block" $ check "<div>hello world</div>" "<div>hello world</div>"+ it "block xss" $ check "alert('evil')" "<script>alert('evil')</script>"+ it "should be escaped" $ check "<p>1 < 2</p>" "1 < 2"+ it "standalone" $ checkSet+ def { msStandaloneHtml = Set.fromList ["<hidden>", "</hidden>"], msXssProtect = False }+ "<hidden><pre><code class=\"haskell\">foo\nbar</code></pre></hidden>"+ "<hidden>\n```haskell\nfoo\nbar\n```\n</hidden>\n"+ describe "fencing" $ do+ it "custom fencing" $ checkSet+ def+ { msFencedHandlers = Map.union+ (htmlFencedHandler "@@@" (\clazz -> T.concat ["<article class=\"", clazz, "\">"]) (const "</article>"))+ (msFencedHandlers def)+ }+ "<article class=\"someclass\"><p>foo</p><blockquote><p>bar</p></blockquote></article>"+ "@@@ someclass\nfoo\n\n> bar\n@@@"+ describe "examples" $ sequence_ examples+ describe "John Gruber's test suite" $ sequence_ gruber++getExamples :: IO [Spec]+getExamples = do+ files <- F.listDirectory "test/examples"+ mapM go $ filter (flip F.hasExtension "md") files+ where+ go fp = do+ input <- F.readTextFile fp+ output <- F.readTextFile $ F.replaceExtension fp "html"+ return $ it (F.encodeString $ F.basename fp) $ check (fromStrict $ T.strip output) (fromStrict input)++getGruber :: IO [Spec]+getGruber = do+ files <- F.listDirectory "test/Tests"+ mapM go $ filter (flip F.hasExtension "text") files+ where+ go fp = do+ input <- F.readTextFile fp+ output <- F.readTextFile $ F.replaceExtension fp "html"+ return $ it (F.encodeString $ F.basename fp) $ checkNoNL (fromStrict $ T.strip output) (fromStrict input)