From d1ded4b0260b32550ac45329d7c43a82a7e7e911 Mon Sep 17 00:00:00 2001
From: John MacFarlane <fiddlosopher@gmail.com>
Date: Sat, 28 Jan 2012 12:25:24 -0800
Subject: [PATCH] Support github syntax for fenced code blocks.

You can now write

    ```ruby
    x = 2
    ```

instead of

    ~~~ {.ruby}
    x = 2
    ~~~~
---
 README                              | 42 +++++++++++++++++++----------
 src/Text/Pandoc/Readers/Markdown.hs | 24 ++++++++++-------
 2 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/README b/README
index 23b43d2c0..c25b5bf11 100644
--- a/README
+++ b/README
@@ -876,9 +876,9 @@ Note: blank lines in the verbatim text need not begin with four spaces.
 
 In addition to standard indented code blocks, Pandoc supports
 *delimited* code blocks.  These begin with a row of three or more
-tildes (`~`) and end with a row of tildes that must be at least
-as long as the starting row.  Everything between the tilde-lines
-is treated as code.  No indentation is necessary:
+tildes (`~`) or backticks (`` ` ``) and end with a row of tildes or
+backticks that must be at least as long as the starting row. Everything
+between these lines is treated as code. No indentation is necessary:
 
     ~~~~~~~
     if (a > 3) {
@@ -889,8 +889,8 @@ is treated as code.  No indentation is necessary:
 Like regular code blocks, delimited code blocks must be separated
 from surrounding text by blank lines.
 
-If the code itself contains a row of tildes, just use a longer
-row of tildes at the start and end:
+If the code itself contains a row of tildes or backticks, just use a longer
+row of tildes or backticks at the start and end:
 
     ~~~~~~~~~~~~~~~~
     ~~~~~~~~~~
@@ -898,28 +898,42 @@ row of tildes at the start and end:
     ~~~~~~~~~~
     ~~~~~~~~~~~~~~~~
 
-Optionally, you may specify the language of the code block using
+Optionally, you may attach attributes to the code block using
 this syntax:
 
-    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.haskell .numberLines}
+    ~~~~ {#mycode .haskell .numberLines startFrom="100"}
     qsort []     = []
     qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++
                    qsort (filter (>= x) xs)
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Some output formats can use this information to do syntax highlighting.
-Currently, the only output formats that uses this information are HTML
-and LaTeX. If highlighting is supported for your output format and language,
-then the code block above will appear highlighted, with numbered lines. (To
-see which languages are supported, do `pandoc --version`.) Otherwise, the code
-block above will appear as follows:
+Here `mycode` is an identifier, `haskell` and `numberLines` are classes, and
+`startFrom` is an attribute with value `100`. Some output formats can use this
+information to do syntax highlighting. Currently, the only output formats
+that uses this information are HTML and LaTeX. If highlighting is supported
+for your output format and language, then the code block above will appear
+highlighted, with numbered lines. (To see which languages are supported, do
+`pandoc --version`.) Otherwise, the code block above will appear as follows:
 
-    <pre class="haskell">
+    <pre id="mycode" class="haskell numberLines" startFrom="100">
       <code>
       ...
       </code>
     </pre>
 
+A shortcut form can also be used for specifying the language of
+the code block:
+
+    ```haskell
+    qsort [] = []
+    ```
+
+This is equivalent to:
+
+    ``` {.haskell}
+    qsort [] = []
+    ```
+
 To prevent all highlighting, use the `--no-highlight` flag.
 To set the highlighting style, use `--highlight-style`.
 
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 1fd99a3ab..fb04e88fe 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -371,17 +371,21 @@ hrule = try $ do
 indentedLine :: GenParser Char ParserState [Char]
 indentedLine = indentSpaces >> manyTill anyChar newline >>= return . (++ "\n")
 
-codeBlockDelimiter :: Maybe Int
-                   -> GenParser Char st (Int, ([Char], [[Char]], [([Char], [Char])]))
-codeBlockDelimiter len = try $ do
+blockDelimiter :: (Char -> Bool)
+               -> Maybe Int
+               -> GenParser Char st (Int, (String, [String], [(String, String)]), Char)
+blockDelimiter f len = try $ do
+  c <- lookAhead (satisfy f)
   size <- case len of
-              Just l  -> count l (char '~') >> many (char '~') >> return l
-              Nothing -> count 3 (char '~') >> many (char '~') >>= 
-                         return . (+ 3) . length 
+              Just l  -> count l (char c) >> many (char c) >> return l
+              Nothing -> count 3 (char c) >> many (char c) >>=
+                         return . (+ 3) . length
   many spaceChar
-  attr <- option ([],[],[]) attributes
+  attr <- option ([],[],[])
+          $ (try $ many spaceChar >> attributes)   -- ~~~ {.ruby}
+         <|> (many1 alphaNum >>= \x -> return ([],[x],[])) -- github variant ```ruby
   blankline
-  return (size, attr) 
+  return (size, attr, c)
 
 attributes :: GenParser Char st ([Char], [[Char]], [([Char], [Char])])
 attributes = try $ do
@@ -425,8 +429,8 @@ keyValAttr = try $ do
 
 codeBlockDelimited :: GenParser Char st Block
 codeBlockDelimited = try $ do
-  (size, attr) <- codeBlockDelimiter Nothing
-  contents <- manyTill anyLine (codeBlockDelimiter (Just size))
+  (size, attr, c) <- blockDelimiter (\c -> c == '~' || c == '`') Nothing
+  contents <- manyTill anyLine (blockDelimiter (== c) (Just size))
   blanklines
   return $ CodeBlock attr $ intercalate "\n" contents