aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README24
-rw-r--r--changelog2
-rw-r--r--pandoc.cabal4
-rw-r--r--pandoc.hs26
-rw-r--r--src/Text/Pandoc/Options.hs12
-rw-r--r--src/Text/Pandoc/PDF.hs16
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs32
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs15
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs10
-rw-r--r--src/Text/Pandoc/Readers/Org.hs58
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs6
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs3
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs20
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs18
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs108
-rw-r--r--tests/Tests/Readers/LaTeX.hs39
-rw-r--r--tests/Tests/Readers/Org.hs24
-rw-r--r--tests/Tests/Writers/Markdown.hs91
-rw-r--r--tests/markdown-reader-more.native5
-rw-r--r--tests/markdown-reader-more.txt5
-rw-r--r--tests/pipe-tables.txt4
-rw-r--r--tests/writer.asciidoc7
-rw-r--r--tests/writer.markdown4
-rw-r--r--tests/writer.opml4
-rw-r--r--tests/writer.plain4
-rw-r--r--trypandoc/index.html4
26 files changed, 439 insertions, 106 deletions
diff --git a/README b/README
index 160fc539e..41bf0e4db 100644
--- a/README
+++ b/README
@@ -655,6 +655,11 @@ Options affecting specific writers
The default is `pdflatex`. If the engine is not in your PATH,
the full path of the engine may be specified here.
+`--latex-engine-opt=`*STRING*
+: Use the given string as a command-line argument to the `latex-engine`.
+ If used multiple times, the arguments are provided with spaces between
+ them. Note that no check for duplicate options is done.
+
Citation rendering
------------------
@@ -1822,8 +1827,8 @@ Pipe tables look like this:
The syntax is [the same as in PHP markdown extra]. The beginning and
ending pipe characters are optional, but pipes are required between all
columns. The colons indicate column alignment as shown. The header
-can be omitted, but the horizontal line must still be included, as
-it defines column alignments.
+cannot be omitted. To simulate a headerless table, include a header
+with blank cells.
Since the pipes indicate column boundaries, columns need not be vertically
aligned, as they are in the above example. So, this is a perfectly
@@ -2434,9 +2439,9 @@ Note that link labels are not case sensitive. So, this will work:
[Foo]: /bar/baz
In an *implicit* reference link, the second pair of brackets is
-empty, or omitted entirely:
+empty:
- See [my website][], or [my website].
+ See [my website][].
[my website]: http://foo.bar.baz
@@ -2450,6 +2455,15 @@ not in most other implementations:
>
> [quote]: /foo
+#### Extension: `shortcut_reference_links` ####
+
+In a *shortcut* reference link, the second pair of brackets may
+be omitted entirely:
+
+ See [my website].
+
+ [my website]: http://foo.bar.baz
+
### Internal links ###
To link to another section of the same document, use the automatically
@@ -2796,7 +2810,7 @@ variants are supported:
`fenced_code_blocks`, `definition_lists`, `intraword_underscores`,
`header_attributes`, `abbreviations`.
-`markdown_github` (Github-flavored Markdown)
+`markdown_github` (GitHub-flavored Markdown)
: `pipe_tables`, `raw_html`, `tex_math_single_backslash`,
`fenced_code_blocks`, `auto_identifiers`,
`ascii_identifiers`, `backtick_code_blocks`, `autolink_bare_uris`,
diff --git a/changelog b/changelog
index 5b516c856..f1549f3be 100644
--- a/changelog
+++ b/changelog
@@ -3975,7 +3975,7 @@ pandoc (1.9)
These constructions are now supported now by `rst2latex.py`.
- * Github syntax for fenced code blocks is supported in pandoc's
+ * GitHub syntax for fenced code blocks is supported in pandoc's
markdown. You can now write
```ruby
diff --git a/pandoc.cabal b/pandoc.cabal
index 32bbfbd26..9c613736d 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -242,8 +242,8 @@ Library
highlighting-kate >= 0.5.11.1 && < 0.6,
data-default >= 0.4 && < 0.6,
temporary >= 1.1 && < 1.3,
- blaze-html >= 0.5 && < 0.8,
- blaze-markup >= 0.5.1 && < 0.7,
+ blaze-html >= 0.5 && < 0.9,
+ blaze-markup >= 0.5.1 && < 0.8,
yaml >= 0.8.8.2 && < 0.9,
scientific >= 0.2 && < 0.4,
vector >= 0.10 && < 0.11,
diff --git a/pandoc.hs b/pandoc.hs
index 2290f750a..804576665 100644
--- a/pandoc.hs
+++ b/pandoc.hs
@@ -49,7 +49,7 @@ import System.Exit ( exitWith, ExitCode (..) )
import System.FilePath
import System.Console.GetOpt
import Data.Char ( toLower )
-import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort )
+import Data.List ( delete, intercalate, isPrefixOf, isSuffixOf, sort )
import System.Directory ( getAppUserDataDirectory, findExecutable,
doesFileExist, Permissions(..), getPermissions )
import System.IO ( stdout, stderr )
@@ -198,6 +198,7 @@ data Opt = Opt
, optCiteMethod :: CiteMethod -- ^ Method to output cites
, optListings :: Bool -- ^ Use listings package for code blocks
, optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
+ , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
, optSlideLevel :: Maybe Int -- ^ Header level that creates slides
, optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
, optAscii :: Bool -- ^ Use ascii characters only in html
@@ -259,6 +260,7 @@ defaultOpts = Opt
, optCiteMethod = Citeproc
, optListings = False
, optLaTeXEngine = "pdflatex"
+ , optLaTeXEngineArgs = []
, optSlideLevel = Nothing
, optSetextHeaders = True
, optAscii = False
@@ -734,6 +736,14 @@ options =
"PROGRAM")
"" -- "Name of latex program to use in generating PDF"
+ , Option "" ["latex-engine-opt"]
+ (ReqArg
+ (\arg opt -> do
+ let oldArgs = optLaTeXEngineArgs opt
+ return opt { optLaTeXEngineArgs = arg : oldArgs })
+ "STRING")
+ "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
+
, Option "" ["bibliography"]
(ReqArg
(\arg opt -> return opt{ optMetadata = addMetadata
@@ -905,13 +915,15 @@ readMetaValue s = case decode (UTF8.fromString s) of
usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
usageMessage programName = usageInfo
(programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
- (wrapWords 16 78 $ readers'names) ++ "\nOutput formats: " ++
+ (wrapWords 16 78 $ readers'names) ++
+ '\n' : replicate 16 ' ' ++
+ "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
(wrapWords 16 78 $ writers'names) ++
'\n' : replicate 16 ' ' ++
- "[*for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
+ "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
where
- writers'names = sort $ "pdf*" : map fst writers
- readers'names = sort $ map fst readers
+ writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
+ readers'names = sort $ "json*" : delete "json" (map fst readers)
-- Determine default reader based on source file extensions
defaultReaderName :: String -> [FilePath] -> String
@@ -1080,6 +1092,7 @@ main = do
, optCiteMethod = citeMethod
, optListings = listings
, optLaTeXEngine = latexEngine
+ , optLaTeXEngineArgs = latexEngineArgs
, optSlideLevel = slideLevel
, optSetextHeaders = setextHeaders
, optAscii = ascii
@@ -1312,7 +1325,8 @@ main = do
writerReferenceODT = referenceODT,
writerReferenceDocx = referenceDocx,
writerMediaBag = media,
- writerVerbose = verbose
+ writerVerbose = verbose,
+ writerLaTeXArgs = latexEngineArgs
}
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index 24e31fbb6..bde7454e2 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -74,7 +74,7 @@ data Extension =
| Ext_latex_macros -- ^ Parse LaTeX macro definitions (for math only)
| Ext_fenced_code_blocks -- ^ Parse fenced code blocks
| Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks
- | Ext_backtick_code_blocks -- ^ Github style ``` code blocks
+ | Ext_backtick_code_blocks -- ^ GitHub style ``` code blocks
| Ext_inline_code_attributes -- ^ Allow attributes on inline code
| Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
| Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
@@ -109,6 +109,7 @@ data Extension =
| Ext_implicit_header_references -- ^ Implicit reference links for headers
| Ext_line_blocks -- ^ RST style line blocks
| Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
+ | Ext_shortcut_reference_links -- ^ Shortcut reference links
deriving (Show, Read, Enum, Eq, Ord, Bounded)
pandocExtensions :: Set Extension
@@ -151,6 +152,7 @@ pandocExtensions = Set.fromList
, Ext_header_attributes
, Ext_implicit_header_references
, Ext_line_blocks
+ , Ext_shortcut_reference_links
]
phpMarkdownExtraExtensions :: Set Extension
@@ -164,6 +166,7 @@ phpMarkdownExtraExtensions = Set.fromList
, Ext_intraword_underscores
, Ext_header_attributes
, Ext_abbreviations
+ , Ext_shortcut_reference_links
]
githubMarkdownExtensions :: Set Extension
@@ -180,6 +183,7 @@ githubMarkdownExtensions = Set.fromList
, Ext_strikeout
, Ext_hard_line_breaks
, Ext_lists_without_preceding_blankline
+ , Ext_shortcut_reference_links
]
multimarkdownExtensions :: Set Extension
@@ -202,7 +206,9 @@ multimarkdownExtensions = Set.fromList
strictExtensions :: Set Extension
strictExtensions = Set.fromList
- [ Ext_raw_html ]
+ [ Ext_raw_html
+ , Ext_shortcut_reference_links
+ ]
data ReaderOptions = ReaderOptions{
readerExtensions :: Set Extension -- ^ Syntax extensions
@@ -324,6 +330,7 @@ data WriterOptions = WriterOptions
, writerReferenceDocx :: Maybe FilePath -- ^ Path to reference DOCX if specified
, writerMediaBag :: MediaBag -- ^ Media collected by docx or epub reader
, writerVerbose :: Bool -- ^ Verbose debugging output
+ , writerLaTeXArgs :: [String] -- ^ Flags to pass to latex-engine
} deriving Show
instance Default WriterOptions where
@@ -368,6 +375,7 @@ instance Default WriterOptions where
, writerReferenceDocx = Nothing
, writerMediaBag = mempty
, writerVerbose = False
+ , writerLaTeXArgs = []
}
-- | Returns True if the given extension is enabled.
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index ea6699ac4..59a6ebede 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -71,7 +71,8 @@ makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex)
makePDF program writer opts doc = withTempDir "tex2pdf." $ \tmpdir -> do
doc' <- handleImages opts tmpdir doc
let source = writer opts doc'
- tex2pdf' (writerVerbose opts) tmpdir program source
+ args = writerLaTeXArgs opts
+ tex2pdf' (writerVerbose opts) args tmpdir program source
handleImages :: WriterOptions
-> FilePath -- ^ temp dir to store images
@@ -132,15 +133,16 @@ convertImage tmpdir fname =
doNothing = return (Right fname)
tex2pdf' :: Bool -- ^ Verbose output
+ -> [String] -- ^ Arguments to the latex-engine
-> FilePath -- ^ temp directory for output
-> String -- ^ tex program
-> String -- ^ tex source
-> IO (Either ByteString ByteString)
-tex2pdf' verbose tmpDir program source = do
+tex2pdf' verbose args tmpDir program source = do
let numruns = if "\\tableofcontents" `isInfixOf` source
then 3 -- to get page numbers
else 2 -- 1 run won't give you PDF bookmarks
- (exit, log', mbPdf) <- runTeXProgram verbose program 1 numruns tmpDir source
+ (exit, log', mbPdf) <- runTeXProgram verbose program args 1 numruns tmpDir source
case (exit, mbPdf) of
(ExitFailure _, _) -> do
let logmsg = extractMsg log'
@@ -173,9 +175,9 @@ extractMsg log' = do
-- Run a TeX program on an input bytestring and return (exit code,
-- contents of stdout, contents of produced PDF if any). Rerun
-- a fixed number of times to resolve references.
-runTeXProgram :: Bool -> String -> Int -> Int -> FilePath -> String
+runTeXProgram :: Bool -> String -> [String] -> Int -> Int -> FilePath -> String
-> IO (ExitCode, ByteString, Maybe ByteString)
-runTeXProgram verbose program runNumber numRuns tmpDir source = do
+runTeXProgram verbose program args runNumber numRuns tmpDir source = do
let file = tmpDir </> "input.tex"
exists <- doesFileExist file
unless exists $ UTF8.writeFile file source
@@ -188,7 +190,7 @@ runTeXProgram verbose program runNumber numRuns tmpDir source = do
let file' = file
#endif
let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
- "-output-directory", tmpDir', file']
+ "-output-directory", tmpDir', file'] ++ args
env' <- getEnvironment
let sep = searchPathSeparator:[]
let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
@@ -212,7 +214,7 @@ runTeXProgram verbose program runNumber numRuns tmpDir source = do
B.hPutStr stderr err
putStr "\n"
if runNumber <= numRuns
- then runTeXProgram verbose program (runNumber + 1) numRuns tmpDir source
+ then runTeXProgram verbose program args (runNumber + 1) numRuns tmpDir source
else do
let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
pdfExists <- doesFileExist pdfFile
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index 942b9f3b3..31ac37bf1 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -271,7 +271,9 @@ ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
blockCommands :: M.Map String (LP Blocks)
blockCommands = M.fromList $
[ ("par", mempty <$ skipopts)
- , ("title", mempty <$ (skipopts *> tok >>= addMeta "title"))
+ , ("title", mempty <$ (skipopts *>
+ (grouped inline >>= addMeta "title")
+ <|> (grouped block >>= addMeta "title")))
, ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
, ("author", mempty <$ (skipopts *> authors))
-- -- in letter class, temp. store address & sig as title, author
@@ -341,7 +343,7 @@ setCaption :: LP Blocks
setCaption = do
ils <- tok
mblabel <- option Nothing $
- try $ spaces >> controlSeq "label" >> (Just <$> tok)
+ try $ spaces' >> controlSeq "label" >> (Just <$> tok)
let ils' = case mblabel of
Just lab -> ils <> spanWith
("",[],[("data-label", stringify lab)]) mempty
@@ -369,7 +371,7 @@ section (ident, classes, kvs) lvl = do
let lvl' = if hasChapters then lvl + 1 else lvl
skipopts
contents <- grouped inline
- lab <- option ident $ try (spaces >> controlSeq "label" >> spaces >> braced)
+ lab <- option ident $ try (spaces' >> controlSeq "label" >> spaces' >> braced)
attr' <- registerHeader (lab, classes, kvs) contents
return $ headerWith attr' lvl' contents
@@ -495,7 +497,7 @@ inlineCommands = M.fromList $
, ("v", option (str "v") $ try $ tok >>= accent hacek)
, ("u", option (str "u") $ try $ tok >>= accent breve)
, ("i", lit "i")
- , ("\\", linebreak <$ (optional (bracketed inline) *> optional sp))
+ , ("\\", linebreak <$ (optional (bracketed inline) *> spaces'))
, (",", pure mempty)
, ("@", pure mempty)
, (" ", lit "\160")
@@ -508,7 +510,7 @@ inlineCommands = M.fromList $
, ("thanks", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
, ("footnote", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
, ("verb", doverb)
- , ("lstinline", doverb)
+ , ("lstinline", skipopts *> doverb)
, ("Verb", doverb)
, ("texttt", (code . stringify . toList) <$> tok)
, ("url", (unescapeURL <$> braced) >>= \url ->
@@ -1275,7 +1277,7 @@ complexNatbibCitation mode = try $ do
parseAligns :: LP [Alignment]
parseAligns = try $ do
char '{'
- let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ try (string "@{}")
+ let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
maybeBar
let cAlign = AlignCenter <$ char 'c'
let lAlign = AlignLeft <$ char 'l'
@@ -1289,13 +1291,13 @@ parseAligns = try $ do
return aligns'
hline :: LP ()
-hline = () <$ (try $ spaces >> controlSeq "hline")
+hline = () <$ (try $ spaces' *> controlSeq "hline" <* spaces')
lbreak :: LP ()
-lbreak = () <$ (try $ spaces *> controlSeq "\\")
+lbreak = () <$ (try $ spaces' *> controlSeq "\\" <* spaces')
amp :: LP ()
-amp = () <$ (try $ spaces *> char '&')
+amp = () <$ (try $ spaces' *> char '&')
parseTableRow :: Int -- ^ number of columns
-> LP [Blocks]
@@ -1308,20 +1310,22 @@ parseTableRow cols = try $ do
guard $ cells' /= [mempty]
-- note: a & b in a three-column table leaves an empty 3rd cell:
let cells'' = cells' ++ replicate (cols - numcells) mempty
- spaces
+ spaces'
return cells''
+spaces' :: LP ()
+spaces' = spaces *> skipMany (comment *> spaces)
+
simpTable :: Bool -> LP Blocks
simpTable hasWidthParameter = try $ do
- when hasWidthParameter $ () <$ (spaces >> tok)
- spaces
+ when hasWidthParameter $ () <$ (spaces' >> tok)
+ skipopts
aligns <- parseAligns
let cols = length aligns
optional hline
header' <- option [] $ try (parseTableRow cols <* lbreak <* hline)
rows <- sepEndBy (parseTableRow cols) (lbreak <* optional hline)
- spaces
- skipMany (comment *> spaces)
+ spaces'
let header'' = if null header'
then replicate cols mempty
else header'
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 187b479c3..a36c2acde 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -448,18 +448,18 @@ block = do
res <- choice [ mempty <$ blanklines
, codeBlockFenced
, yamlMetaBlock
- , guardEnabled Ext_latex_macros *> (macro >>= return . return)
-- note: bulletList needs to be before header because of
-- the possibility of empty list items: -
, bulletList
, header
, lhsCodeBlock
- , rawTeXBlock
, divHtml
, htmlBlock
, table
- , lineBlock
, codeBlockIndented
+ , guardEnabled Ext_latex_macros *> (macro >>= return . return)
+ , rawTeXBlock
+ , lineBlock
, blockQuote
, hrule
, orderedList
@@ -1287,11 +1287,9 @@ pipeBreak = try $ do
pipeTable :: MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
pipeTable = try $ do
- (heads,aligns) <- try ( pipeBreak >>= \als ->
- return (return $ replicate (length als) mempty, als))
- <|> ( pipeTableRow >>= \row -> pipeBreak >>= \als ->
-
- return (row, als) )
+ (heads,aligns) <- pipeTableRow >>= \row ->
+ pipeBreak >>= \als ->
+ return (row, als)
lines' <- sequence <$> many1 pipeTableRow
let widths = replicate (length aligns) 0.0
return $ (aligns, widths, heads, lines')
@@ -1679,6 +1677,7 @@ referenceLink constructor (lab, raw) = do
lookAhead (try (spnl >> normalCite >> return (mempty, "")))
<|>
try (spnl >> reference)
+ when (raw' == "") $ guardEnabled Ext_shortcut_reference_links
let labIsRef = raw' == "" || raw' == "[]"
let key = toKey $ if labIsRef then raw else raw'
parsedRaw <- parseFromString (mconcat <$> many inline) raw'
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index e43b8a86c..d1ba35ba0 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -593,11 +593,17 @@ imageOption =
<|> try (many1 (oneOf "x0123456789") <* string "px")
<|> try (oneOfStrings ["link=","alt=","page=","class="] <* many (noneOf "|]"))
+collapseUnderscores :: String -> String
+collapseUnderscores [] = []
+collapseUnderscores ('_':'_':xs) = collapseUnderscores ('_':xs)
+collapseUnderscores (x:xs) = x : collapseUnderscores xs
+
+addUnderscores :: String -> String
+addUnderscores = collapseUnderscores . intercalate "_" . words
+
internalLink :: MWParser Inlines
internalLink = try $ do
sym "[["
- let addUnderscores x = let (pref,suff) = break (=='#') x
- in pref ++ intercalate "_" (words suff)
pagename <- unwords . words <$> many (noneOf "|]")
label <- option (B.text pagename) $ char '|' *>
( (mconcat <$> many1 (notFollowedBy (char ']') *> inline))
diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs
index f16aed48d..4a523657c 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances #-}
{-
Copyright (C) 2014 Albert Krewinkel <tarleb@moltkeplatz.de>
@@ -49,7 +49,7 @@ import Control.Applicative ( Applicative, pure
, (<$>), (<$), (<*>), (<*), (*>) )
import Control.Arrow (first)
import Control.Monad (foldM, guard, liftM, liftM2, mplus, mzero, when)
-import Control.Monad.Reader (Reader, runReader, ask, asks)
+import Control.Monad.Reader (Reader, runReader, ask, asks, local)
import Data.Char (isAlphaNum, toLower)
import Data.Default
import Data.List (intersperse, isPrefixOf, isSuffixOf)
@@ -62,9 +62,11 @@ import Network.HTTP (urlEncode)
readOrg :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
-> Pandoc
-readOrg opts s = readWith parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
+readOrg opts s = flip runReader def $ readWithM parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
-type OrgParser = Parser [Char] OrgParserState
+data OrgParserLocal = OrgParserLocal { orgLocalQuoteContext :: QuoteContext }
+
+type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
parseOrg :: OrgParser Pandoc
parseOrg = do
@@ -125,6 +127,9 @@ data OrgParserState = OrgParserState
, orgStateNotes' :: OrgNoteTable
}
+instance Default OrgParserLocal where
+ def = OrgParserLocal NoQuote
+
instance HasReaderOptions OrgParserState where
extractReaderOptions = orgStateOptions
@@ -138,6 +143,10 @@ instance HasLastStrPosition OrgParserState where
getLastStrPos = orgStateLastStrPos
setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
+instance HasQuoteContext st (Reader OrgParserLocal) where
+ getQuoteContext = asks orgLocalQuoteContext
+ withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
+
instance Default OrgParserState where
def = defaultOrgParserState
@@ -964,6 +973,7 @@ inline =
, subscript
, superscript
, inlineLaTeX
+ , smart
, symbol
] <* (guard =<< newlinesCountWithinLimits)
<?> "inline"
@@ -1270,12 +1280,16 @@ displayMath :: OrgParser (F Inlines)
displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
, rawMathBetween "$$" "$$"
]
+
+updatePositions :: Char
+ -> OrgParser (Char)
+updatePositions c = do
+ when (c `elem` emphasisPreChars) updateLastPreCharPos
+ when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
+ return c
+
symbol :: OrgParser (F Inlines)
symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
- where updatePositions c = do
- when (c `elem` emphasisPreChars) updateLastPreCharPos
- when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
- return c
emphasisBetween :: Char
-> OrgParser (F Inlines)
@@ -1486,3 +1500,31 @@ inlineLaTeXCommand = try $ do
count len anyChar
return cs
_ -> mzero
+
+smart :: OrgParser (F Inlines)
+smart = do
+ getOption readerSmart >>= guard
+ doubleQuoted <|> singleQuoted <|>
+ choice (map (return <$>) [orgApostrophe, dash, ellipses])
+ where orgApostrophe =
+ (char '\'' <|> char '\8217') <* updateLastPreCharPos
+ <* updateLastForbiddenCharPos
+ *> return (B.str "\x2019")
+
+singleQuoted :: OrgParser (F Inlines)
+singleQuoted = try $ do
+ singleQuoteStart
+ withQuoteContext InSingleQuote $
+ fmap B.singleQuoted . trimInlinesF . mconcat <$>
+ many1Till inline singleQuoteEnd
+
+-- doubleQuoted will handle regular double-quoted sections, as well
+-- as dialogues with an open double-quote without a close double-quote
+-- in the same paragraph.
+doubleQuoted :: OrgParser (F Inlines)
+doubleQuoted = try $ do
+ doubleQuoteStart
+ contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
+ (withQuoteContext InDoubleQuote $ (doubleQuoteEnd <* updateLastForbiddenCharPos) >> return
+ (fmap B.doubleQuoted . trimInlinesF $ contents))
+ <|> (return $ return (B.str "\8220") <> contents)
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index e5b8c5167..1c33b004a 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -126,7 +126,7 @@ blockToAsciiDoc :: WriterOptions -- ^ Options
blockToAsciiDoc _ Null = return empty
blockToAsciiDoc opts (Plain inlines) = do
contents <- inlineListToAsciiDoc opts inlines
- return $ contents <> cr
+ return $ contents <> blankline
blockToAsciiDoc opts (Para [Image alt (src,'f':'i':'g':':':tit)]) = do
blockToAsciiDoc opts (Para [Image alt (src,tit)])
blockToAsciiDoc opts (Para inlines) = do
@@ -272,7 +272,7 @@ bulletListItemToAsciiDoc opts blocks = do
contents <- foldM addBlock empty blocks
modify $ \s -> s{ bulletListLevel = lev }
let marker = text (replicate lev '*')
- return $ marker <> space <> contents <> cr
+ return $ marker <> text " " <> contents <> cr
-- | Convert ordered list item (a list of blocks) to asciidoc.
orderedListItemToAsciiDoc :: WriterOptions -- ^ options
@@ -292,7 +292,7 @@ orderedListItemToAsciiDoc opts marker blocks = do
modify $ \s -> s{ orderedListLevel = lev + 1 }
contents <- foldM addBlock empty blocks
modify $ \s -> s{ orderedListLevel = lev }
- return $ text marker <> space <> contents <> cr
+ return $ text marker <> text " " <> contents <> cr
-- | Convert definition list item (label, list of blocks) to asciidoc.
definitionListItemToAsciiDoc :: WriterOptions
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index b10317506..19f8f2f11 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -114,7 +114,8 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) =
n | n == 0 -> "chapter"
| n >= 1 && n <= 5 -> "sect" ++ show n
| otherwise -> "simplesect"
- in inTags True tag [("id", writerIdentifierPrefix opts ++ id')] $
+ in inTags True tag [("id", writerIdentifierPrefix opts ++ id') |
+ not (null id')] $
inTagsSimple "title" (inlinesToDocbook opts title) $$
vcat (map (elementToDocbook opts (lvl + 1)) elements')
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index ef00ea036..53dc931cc 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -446,19 +446,25 @@ blockToHtml opts (Para lst) = do
contents <- inlineListToHtml opts lst
return $ H.p contents
blockToHtml opts (Div attr@(_,classes,_) bs) = do
- contents <- blockListToHtml opts bs
+ let speakerNotes = "notes" `elem` classes
+ -- we don't want incremental output inside speaker notes, see #1394
+ let opts' = if speakerNotes then opts{ writerIncremental = False } else opts
+ contents <- blockListToHtml opts' bs
let contents' = nl opts >> contents >> nl opts
return $
- if "notes" `elem` classes
- then let opts' = opts{ writerIncremental = False } in
- -- we don't want incremental output inside speaker notes
- case writerSlideVariant opts of
+ if speakerNotes
+ then case writerSlideVariant opts of
RevealJsSlides -> addAttrs opts' attr $ H5.aside $ contents'
NoSlides -> addAttrs opts' attr $ H.div $ contents'
_ -> mempty
else addAttrs opts attr $ H.div $ contents'
-blockToHtml _ (RawBlock f str)
+blockToHtml opts (RawBlock f str)
| f == Format "html" = return $ preEscapedString str
+ | f == Format "latex" =
+ case writerHTMLMathMethod opts of
+ MathJax _ -> do modify (\st -> st{ stMath = True })
+ return $ toHtml str
+ _ -> return mempty
| otherwise = return mempty
blockToHtml opts (HorizontalRule) = return $ if writerHtml5 opts then H5.hr else H.hr
blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
@@ -769,6 +775,8 @@ inlineToHtml opts inline =
case writerHTMLMathMethod opts of
LaTeXMathML _ -> do modify (\st -> st {stMath = True})
return $ toHtml str
+ MathJax _ -> do modify (\st -> st {stMath = True})
+ return $ toHtml str
_ -> return mempty
| f == Format "html" -> return $ preEscapedString str
| otherwise -> return mempty
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 64e36ca0b..58456e3ab 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -42,6 +42,7 @@ import Data.List ( (\\), isSuffixOf, isInfixOf, stripPrefix,
isPrefixOf, intercalate, intersperse )
import Data.Char ( toLower, isPunctuation, isAscii, isLetter, isDigit, ord )
import Data.Maybe ( fromMaybe )
+import Data.Aeson.Types ( (.:), parseMaybe, withObject )
import Control.Applicative ((<|>))
import Control.Monad.State
import Text.Pandoc.Pretty
@@ -102,8 +103,16 @@ pandocToLaTeX options (Pandoc meta blocks) = do
modify $ \s -> s{ stInternalLinks = query isInternalLink blocks' }
let template = writerTemplate options
-- set stBook depending on documentclass
+ let colwidth = if writerWrapText options
+ then Just $ writerColumns options
+ else Nothing
+ metadata <- metaToJSON options
+ (fmap (render colwidth) . blockListToLaTeX)
+ (fmap (render colwidth) . inlineListToLaTeX)
+ meta
let bookClasses = ["memoir","book","report","scrreprt","scrbook"]
- case lookup "documentclass" (writerVariables options) of
+ case lookup "documentclass" (writerVariables options) `mplus`
+ parseMaybe (withObject "object" (.: "documentclass")) metadata of
Just x | x `elem` bookClasses -> modify $ \s -> s{stBook = True}
| otherwise -> return ()
Nothing | any (\x -> "\\documentclass" `isPrefixOf` x &&
@@ -114,13 +123,6 @@ pandocToLaTeX options (Pandoc meta blocks) = do
-- \enquote{...} for smart quotes:
when ("{csquotes}" `isInfixOf` template) $
modify $ \s -> s{stCsquotes = True}
- let colwidth = if writerWrapText options
- then Just $ writerColumns options
- else Nothing
- metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToLaTeX)
- (fmap (render colwidth) . inlineListToLaTeX)
- meta
let (blocks'', lastHeader) = if writerCiteMethod options == Citeproc then
(blocks', [])
else case last blocks' of
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index d71f0daf8..ebf7e20e2 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -57,12 +57,15 @@ import qualified Data.Text as T
type Notes = [[Block]]
type Refs = [([Inline], Target)]
-data WriterState = WriterState { stNotes :: Notes
- , stRefs :: Refs
- , stIds :: [String]
- , stPlain :: Bool }
+data WriterState = WriterState { stNotes :: Notes
+ , stRefs :: Refs
+ , stRefShortcutable :: Bool
+ , stInList :: Bool
+ , stIds :: [String]
+ , stPlain :: Bool }
instance Default WriterState
- where def = WriterState{ stNotes = [], stRefs = [], stIds = [], stPlain = False }
+ where def = WriterState{ stNotes = [], stRefs = [], stRefShortcutable = True,
+ stInList = False, stIds = [], stPlain = False }
-- | Convert Pandoc to Markdown.
writeMarkdown :: WriterOptions -> Pandoc -> String
@@ -453,7 +456,7 @@ blockToMarkdown opts t@(Table caption aligns widths headers rows) = do
$ Pandoc nullMeta [t]
return $ nst $ tbl $$ blankline $$ caption'' $$ blankline
blockToMarkdown opts (BulletList items) = do
- contents <- mapM (bulletListItemToMarkdown opts) items
+ contents <- inList $ mapM (bulletListItemToMarkdown opts) items
return $ cat contents <> blankline
blockToMarkdown opts (OrderedList (start,sty,delim) items) = do
let start' = if isEnabled Ext_startnum opts then start else 1
@@ -464,13 +467,22 @@ blockToMarkdown opts (OrderedList (start,sty,delim) items) = do
let markers' = map (\m -> if length m < 3
then m ++ replicate (3 - length m) ' '
else m) markers
- contents <- mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
+ contents <- inList $
+ mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
zip markers' items
return $ cat contents <> blankline
blockToMarkdown opts (DefinitionList items) = do
- contents <- mapM (definitionListItemToMarkdown opts) items
+ contents <- inList $ mapM (definitionListItemToMarkdown opts) items
return $ cat contents <> blankline
+inList :: State WriterState a -> State WriterState a
+inList p = do
+ oldInList <- gets stInList
+ modify $ \st -> st{ stInList = True }
+ res <- p
+ modify $ \st -> st{ stInList = oldInList }
+ return res
+
addMarkdownAttribute :: String -> String
addMarkdownAttribute s =
case span isTagText $ reverse $ parseTags s of
@@ -497,7 +509,12 @@ pipeTable headless aligns rawHeaders rawRows = do
AlignCenter -> ':':replicate w '-' ++ ":"
AlignRight -> replicate (w + 1) '-' ++ ":"
AlignDefault -> replicate (w + 2) '-'
- let header = if headless then empty else torow rawHeaders
+ -- note: pipe tables can't completely lack a
+ -- header; for a headerless table, we need a header of empty cells.
+ -- see jgm/pandoc#1996.
+ let header = if headless
+ then torow (replicate (length aligns) empty)
+ else torow rawHeaders
let border = nowrap $ text "|" <> hcat (intersperse (text "|") $
map toborder $ zip aligns widths) <> text "|"
let body = vcat $ map torow rawRows
@@ -677,12 +694,53 @@ getReference label (src, tit) = do
-- | Convert list of Pandoc inline elements to markdown.
inlineListToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
-inlineListToMarkdown opts lst =
- mapM (inlineToMarkdown opts) (avoidBadWraps lst) >>= return . cat
- where avoidBadWraps [] = []
- avoidBadWraps (Space:Str (c:cs):xs)
- | c `elem` ("-*+>" :: String) = Str (' ':c:cs) : avoidBadWraps xs
- avoidBadWraps (x:xs) = x : avoidBadWraps xs
+inlineListToMarkdown opts lst = do
+ inlist <- gets stInList
+ go (if inlist then avoidBadWrapsInList lst else lst)
+ where go [] = return empty
+ go (i:is) = case i of
+ (Link _ _) -> case is of
+ -- If a link is followed by another link or '[' we don't shortcut
+ (Link _ _):_ -> unshortcutable
+ Space:(Link _ _):_ -> unshortcutable
+ Space:(Str('[':_)):_ -> unshortcutable
+ Space:(RawInline _ ('[':_)):_ -> unshortcutable
+ Space:(Cite _ _):_ -> unshortcutable
+ (Cite _ _):_ -> unshortcutable
+ Str ('[':_):_ -> unshortcutable
+ (RawInline _ ('[':_)):_ -> unshortcutable
+ (RawInline _ (' ':'[':_)):_ -> unshortcutable
+ _ -> shortcutable
+ _ -> shortcutable
+ where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
+ unshortcutable = do
+ iMark <- withState (\s -> s { stRefShortcutable = False })
+ (inlineToMarkdown opts i)
+ modify (\s -> s {stRefShortcutable = True })
+ fmap (iMark <>) (go is)
+
+avoidBadWrapsInList :: [Inline] -> [Inline]
+avoidBadWrapsInList [] = []
+avoidBadWrapsInList (Space:Str ('>':cs):xs) =
+ Str (' ':'>':cs) : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str [c]:[])
+ | c `elem` "-*+" = Str [' ', c] : []
+avoidBadWrapsInList (Space:Str [c]:Space:xs)
+ | c `elem` "-*+" = Str [' ', c] : Space : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str cs:Space:xs)
+ | isOrderedListMarker cs = Str (' ':cs) : Space : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str cs:[])
+ | isOrderedListMarker cs = Str (' ':cs) : []
+avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
+
+isOrderedListMarker :: String -> Bool
+isOrderedListMarker xs = (last xs `elem` ".)") &&
+ isRight (runParserT (anyOrderedListMarker >> eof)
+ defaultParserState "" xs)
+
+isRight :: Either a b -> Bool
+isRight (Right _) = True
+isRight (Left _) = False
escapeSpaces :: Inline -> Inline
escapeSpaces (Str s) = Str $ substitute " " "\\ " s
@@ -692,8 +750,10 @@ escapeSpaces x = x
-- | Convert Pandoc inline element to markdown.
inlineToMarkdown :: WriterOptions -> Inline -> State WriterState Doc
inlineToMarkdown opts (Span attrs ils) = do
+ plain <- gets stPlain
contents <- inlineListToMarkdown opts ils
- return $ if isEnabled Ext_raw_html opts
+ return $ if not plain &&
+ (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
then tagWithAttrs "span" attrs <> contents <> text "</span>"
else contents
inlineToMarkdown opts (Emph lst) = do
@@ -726,13 +786,14 @@ inlineToMarkdown opts (Subscript lst) = do
else "<sub>" <> contents <> "</sub>"
inlineToMarkdown opts (SmallCaps lst) = do
plain <- gets stPlain
- if plain
- then inlineListToMarkdown opts $ capitalize lst
- else do
+ if not plain &&
+ (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
+ then do
contents <- inlineListToMarkdown opts lst
return $ tagWithAttrs "span"
- ("",[],[("style","font-variant:small-caps;")])
+ ("",[],[("style","font-variant:small-caps;")])
<> contents <> text "</span>"
+ else inlineListToMarkdown opts $ capitalize lst
inlineToMarkdown opts (Quoted SingleQuote lst) = do
contents <- inlineListToMarkdown opts lst
return $ "‘" <> contents <> "’"
@@ -838,6 +899,9 @@ inlineToMarkdown opts (Link txt (src, tit)) = do
[Str s] | escapeURI s == srcSuffix -> True
_ -> False
let useRefLinks = writerReferenceLinks opts && not useAuto
+ shortcutable <- gets stRefShortcutable
+ let useShortcutRefLinks = shortcutable &&
+ isEnabled Ext_shortcut_reference_links opts
ref <- if useRefLinks then getReference txt (src, tit) else return []
reftext <- inlineListToMarkdown opts ref
return $ if useAuto
@@ -847,7 +911,9 @@ inlineToMarkdown opts (Link txt (src, tit)) = do
else if useRefLinks
then let first = "[" <> linktext <> "]"
second = if txt == ref
- then "[]"
+ then if useShortcutRefLinks
+ then ""
+ else "[]"
else "[" <> reftext <> "]"
in first <> second
else if plain
diff --git a/tests/Tests/Readers/LaTeX.hs b/tests/Tests/Readers/LaTeX.hs
index 8ff23ebc1..47916b0c0 100644
--- a/tests/Tests/Readers/LaTeX.hs
+++ b/tests/Tests/Readers/LaTeX.hs
@@ -7,6 +7,7 @@ import Tests.Helpers
import Tests.Arbitrary()
import Text.Pandoc.Builder
import Text.Pandoc
+import Data.Monoid (mempty)
latex :: String -> Pandoc
latex = readLaTeX def
@@ -16,6 +17,10 @@ infix 4 =:
=> String -> (String, c) -> Test
(=:) = test latex
+simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
+simpleTable' aligns = table "" (zip aligns (repeat 0.0))
+ (map (const mempty) aligns)
+
tests :: [Test]
tests = [ testGroup "basic"
[ "simple" =:
@@ -62,6 +67,40 @@ tests = [ testGroup "basic"
"\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock ""
]
+ , testGroup "tables"
+ [ "Single cell table" =:
+ "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?>
+ simpleTable' [AlignLeft] [[plain "Test"]]
+ , "Multi cell table" =:
+ "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Multi line table" =:
+ unlines [ "\\begin{tabular}{|c|}"
+ , "One\\\\"
+ , "Two\\\\"
+ , "Three\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignCenter]
+ [[plain "One"], [plain "Two"], [plain "Three"]]
+ , "Empty table" =:
+ "\\begin{tabular}{}\\end{tabular}" =?>
+ simpleTable' [] []
+ , "Table with fixed column width" =:
+ "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]]
+ , "Table with empty column separators" =:
+ "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with custom column separators" =:
+ unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
+ , "One&Two\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with vertical alignment argument" =:
+ "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
+ ]
+
, testGroup "citations"
[ natbibCitations
, biblatexCitations
diff --git a/tests/Tests/Readers/Org.hs b/tests/Tests/Readers/Org.hs
index 39c40cd45..c373d52cc 100644
--- a/tests/Tests/Readers/Org.hs
+++ b/tests/Tests/Readers/Org.hs
@@ -12,6 +12,9 @@ import Data.Monoid (mempty, mappend, mconcat)
org :: String -> Pandoc
org = readOrg def
+orgSmart :: String -> Pandoc
+orgSmart = readOrg def { readerSmart = True }
+
infix 4 =:
(=:) :: ToString c
=> String -> (String, c) -> Test
@@ -1152,4 +1155,25 @@ tests =
]
in codeBlockWith ( "", classes, params) "code body\n"
]
+ , testGroup "Smart punctuation"
+ [ test orgSmart "quote before ellipses"
+ ("'...hi'"
+ =?> para (singleQuoted "…hi"))
+
+ , test orgSmart "apostrophe before emph"
+ ("D'oh! A l'/aide/!"
+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
+
+ , test orgSmart "apostrophe in French"
+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
+
+ , test orgSmart "Quotes cannot occur at the end of emphasized text"
+ ("/say \"yes\"/" =?>
+ para ("/say" <> space <> doubleQuoted "yes" <> "/"))
+
+ , test orgSmart "Dashes are allowed at the borders of emphasis'"
+ ("/foo---/" =?>
+ para (emph "foo—"))
+ ]
]
diff --git a/tests/Tests/Writers/Markdown.hs b/tests/Tests/Writers/Markdown.hs
index c2a8f5903..dce40ddcb 100644
--- a/tests/Tests/Writers/Markdown.hs
+++ b/tests/Tests/Writers/Markdown.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Tests.Writers.Markdown (tests) where
import Test.Framework
@@ -35,4 +36,92 @@ tests = [ "indented code after list"
=: bulletList [ plain "foo" <> bulletList [ plain "bar" ],
plain "baz" ]
=?> "- foo\n - bar\n- baz\n"
- ]
+ ] ++ [shortcutLinkRefsTests]
+
+shortcutLinkRefsTests :: Test
+shortcutLinkRefsTests =
+ let infix 4 =:
+ (=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> Test
+ (=:) = test (writeMarkdown (def {writerReferenceLinks = True}) . toPandoc)
+ in testGroup "Shortcut reference links"
+ [ "Simple link (shortcutable)"
+ =: (para (link "/url" "title" "foo"))
+ =?> "[foo]\n\n [foo]: /url \"title\""
+ , "Followed by another link (unshortcutable)"
+ =: (para ((link "/url1" "title1" "first")
+ <> (link "/url2" "title2" "second")))
+ =?> unlines [ "[first][][second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Followed by space and another link (unshortcutable)"
+ =: (para ((link "/url1" "title1" "first") <> " "
+ <> (link "/url2" "title2" "second")))
+ =?> unlines [ "[first][] [second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: (para ((link "/url1" "" "foo") <> (link "/url2" "" "foo")
+ <> (link "/url3" "" "foo")))
+ =?> unlines [ "[foo][][foo][1][foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: (para ((link "/url1" "" "foo") <> " " <> (link "/url2" "" "foo")
+ <> " " <> (link "/url3" "" "foo")))
+ =?> unlines [ "[foo][] [foo][1] [foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is followed by text in brackets"
+ =: (para ((link "/url" "" "link") <> "[text in brackets]"))
+ =?> unlines [ "[link][][text in brackets]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and text in brackets"
+ =: (para ((link "/url" "" "link") <> " [text in brackets]"))
+ =?> unlines [ "[link][] [text in brackets]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline"
+ =: (para ((link "/url" "" "link") <> rawInline "markdown" "[rawText]"))
+ =?> unlines [ "[link][][rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and RawInline"
+ =: (para ((link "/url" "" "link") <> space <> rawInline "markdown" "[rawText]"))
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline with space"
+ =: (para ((link "/url" "" "link") <> rawInline "markdown" " [rawText]"))
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by citation"
+ =: (para ((link "/url" "" "link") <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
+ =?> unlines [ "[link][][@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and citation"
+ =: (para ((link "/url" "" "link") <> space <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
+ =?> unlines [ "[link][] [@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ ]
diff --git a/tests/markdown-reader-more.native b/tests/markdown-reader-more.native
index 3f4bb5740..96204898e 100644
--- a/tests/markdown-reader-more.native
+++ b/tests/markdown-reader-more.native
@@ -156,4 +156,7 @@
,Para [Str "MapReduce",Space,Str "is",Space,Str "a",Space,Str "paradigm",Space,Str "popularized",Space,Str "by",Space,Link [Str "Google"] ("http://google.com",""),Space,Cite [Citation {citationId = "mapreduce", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@mapreduce]"],Space,Str "as",Space,Str "its",Space,Str "most",Space,Str "vocal",Space,Str "proponent."]
,Header 2 ("empty-reference-links",[],[]) [Str "Empty",Space,Str "reference",Space,Str "links"]
,Para [Str "bar"]
-,Para [Link [Str "foo2"] ("","")]]
+,Para [Link [Str "foo2"] ("","")]
+,Header 2 ("wrapping-shouldnt-introduce-new-list-items",[],[]) [Str "Wrapping",Space,Str "shouldn\8217t",Space,Str "introduce",Space,Str "new",Space,Str "list",Space,Str "items"]
+,BulletList
+ [[Plain [Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "2015."]]]]
diff --git a/tests/markdown-reader-more.txt b/tests/markdown-reader-more.txt
index d7439f6cb..99e9ec7e8 100644
--- a/tests/markdown-reader-more.txt
+++ b/tests/markdown-reader-more.txt
@@ -276,3 +276,8 @@ most vocal proponent.
bar
[foo2]
+
+## Wrapping shouldn't introduce new list items
+
+- blah blah blah blah blah blah blah blah blah blah blah blah blah blah 2015.
+
diff --git a/tests/pipe-tables.txt b/tests/pipe-tables.txt
index ee8d54d9f..83debd595 100644
--- a/tests/pipe-tables.txt
+++ b/tests/pipe-tables.txt
@@ -1,7 +1,7 @@
Simplest table without caption:
| Default1 | Default2 | Default3 |
-|----------|----------|----------|
+ |----------|----------|----------|
|12|12|12|
|123|123|123|
|1|1|1|
@@ -27,6 +27,7 @@ Simple table without caption:
Headerless table without caption:
+| | | |
|------:|:-----|:------:|
|12|12|12|
|123|123|123|
@@ -48,5 +49,6 @@ One-column:
Header-less one-column:
+| |
|:-:|
|hi|
diff --git a/tests/writer.asciidoc b/tests/writer.asciidoc
index 4b063fe68..aebc529f0 100644
--- a/tests/writer.asciidoc
+++ b/tests/writer.asciidoc
@@ -375,15 +375,19 @@ HTML Blocks
Simple block on one line:
foo
+
And nested without indentation:
foo
bar
+
Interpreted markdown in a table:
This is _emphasized_
+
And this is *strong*
+
Here’s a simple block:
foo
@@ -405,6 +409,7 @@ As should this:
Now, nested:
foo
+
This should just be an HTML comment:
Multiline:
@@ -485,7 +490,7 @@ Ellipses…and…and….
LaTeX
-----
-*
+*
* latexmath:[$2+2=4$]
* latexmath:[$x \in y$]
* latexmath:[$\alpha \wedge \omega$]
diff --git a/tests/writer.markdown b/tests/writer.markdown
index ad97b15ef..7276b31c7 100644
--- a/tests/writer.markdown
+++ b/tests/writer.markdown
@@ -549,8 +549,8 @@ LaTeX
These shouldn’t be math:
- To get the famous equation, write `$e = mc^2$`.
-- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is
- emphasized.)
+- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot”
+ is emphasized.)
- Shoes (\$20) and socks (\$5).
- Escaped `$`: \$73 *this should be emphasized* 23\$.
diff --git a/tests/writer.opml b/tests/writer.opml
index 840c3c6e1..8f79e842c 100644
--- a/tests/writer.opml
+++ b/tests/writer.opml
@@ -33,7 +33,7 @@
<outline text="Lists">
<outline text="Unordered" _note="Asterisks tight:&#10;&#10;- asterisk 1&#10;- asterisk 2&#10;- asterisk 3&#10;&#10;Asterisks loose:&#10;&#10;- asterisk 1&#10;&#10;- asterisk 2&#10;&#10;- asterisk 3&#10;&#10;Pluses tight:&#10;&#10;- Plus 1&#10;- Plus 2&#10;- Plus 3&#10;&#10;Pluses loose:&#10;&#10;- Plus 1&#10;&#10;- Plus 2&#10;&#10;- Plus 3&#10;&#10;Minuses tight:&#10;&#10;- Minus 1&#10;- Minus 2&#10;- Minus 3&#10;&#10;Minuses loose:&#10;&#10;- Minus 1&#10;&#10;- Minus 2&#10;&#10;- Minus 3&#10;&#10;">
</outline>
- <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy dog’s&#10; back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.&#10;&#10;">
+ <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy&#10; dog’s back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.&#10;&#10;">
</outline>
<outline text="Nested" _note="- Tab&#10; - Tab&#10; - Tab&#10;&#10;Here’s another:&#10;&#10;1. First&#10;2. Second:&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third&#10;&#10;Same thing but with paragraphs:&#10;&#10;1. First&#10;&#10;2. Second:&#10;&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third&#10;&#10;">
</outline>
@@ -50,7 +50,7 @@
</outline>
<outline text="Smart quotes, ellipses, dashes" _note="“Hello,” said the spider. “‘Shelob’ is my name.”&#10;&#10;‘A’, ‘B’, and ‘C’ are letters.&#10;&#10;‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’&#10;&#10;‘He said, “I want to go.”’ Were you alive in the 70’s?&#10;&#10;Here is some quoted ‘`code`’ and a “[quoted&#10;link](http://example.com/?foo=1&amp;bar=2)”.&#10;&#10;Some dashes: one—two — three—four — five.&#10;&#10;Dashes between numbers: 5–7, 255–66, 1987–1999.&#10;&#10;Ellipses…and…and….&#10;&#10;------------------------------------------------------------------------">
</outline>
-<outline text="LaTeX" _note="- \cite[22-23]{smith.1899}&#10;- $2+2=4$&#10;- $x \in y$&#10;- $\alpha \wedge \omega$&#10;- $223$&#10;- $p$-Tree&#10;- Here’s some display math:&#10; $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it:&#10; $\alpha + \omega \times x^2$.&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes (\$20) and socks (\$5).&#10;- Escaped `$`: \$73 *this should be emphasized* 23\$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;\begin{tabular}{|l|l|}\hline&#10;Animal &amp; Number \\ \hline&#10;Dog &amp; 2 \\&#10;Cat &amp; 1 \\ \hline&#10;\end{tabular}&#10;&#10;------------------------------------------------------------------------">
+<outline text="LaTeX" _note="- \cite[22-23]{smith.1899}&#10;- $2+2=4$&#10;- $x \in y$&#10;- $\alpha \wedge \omega$&#10;- $223$&#10;- $p$-Tree&#10;- Here’s some display math:&#10; $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it:&#10; $\alpha + \omega \times x^2$.&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot”&#10; is emphasized.)&#10;- Shoes (\$20) and socks (\$5).&#10;- Escaped `$`: \$73 *this should be emphasized* 23\$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;\begin{tabular}{|l|l|}\hline&#10;Animal &amp; Number \\ \hline&#10;Dog &amp; 2 \\&#10;Cat &amp; 1 \\ \hline&#10;\end{tabular}&#10;&#10;------------------------------------------------------------------------">
</outline>
<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 \&lt; 5.&#10;&#10;6 \&gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: [&#10;&#10;Right bracket: ]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: \&gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
</outline>
diff --git a/tests/writer.plain b/tests/writer.plain
index fab0489ac..0332a747b 100644
--- a/tests/writer.plain
+++ b/tests/writer.plain
@@ -499,8 +499,8 @@ LATEX
These shouldn’t be math:
- To get the famous equation, write $e = mc^2$.
-- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” is
- emphasized.)
+- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot”
+ is emphasized.)
- Shoes ($20) and socks ($5).
- Escaped $: $73 _this should be emphasized_ 23$.
diff --git a/trypandoc/index.html b/trypandoc/index.html
index 2c9c55ef2..6d781971e 100644
--- a/trypandoc/index.html
+++ b/trypandoc/index.html
@@ -73,7 +73,7 @@ $(document).ready(function() {
<option value="markdown" selected>Markdown</option>
<option value="markdown_strict">Markdown/strict</option>
<option value="markdown_phpextra">PHP Markdown Extra</option>
- <option value="markdown_github">Github Markdown</option>
+ <option value="markdown_github">GitHub Markdown</option>
<option value="markdown_mmd">MultiMarkdown</option>
<option value="rst">reStructuredText</option>
<option value="textile">Textile</option>
@@ -99,7 +99,7 @@ $(document).ready(function() {
<option value="markdown">Markdown</option>
<option value="markdown_strict">Markdown/strict</option>
<option value="markdown_phpextra">PHP Markdown Extra</option>
- <option value="markdown_github">Github Markdown</option>
+ <option value="markdown_github">GitHub Markdown</option>
<option value="markdown_mmd">MultiMarkdown</option>
<option value="rst">reStructuredText</option>
<option value="asciidoc">AsciiDoc</option>