From e02cfcdeaccf588399579283998a7fb93a5c08f6 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Wed, 3 May 2017 12:13:25 +0200 Subject: Markdown Writer: put space before reference link definitions Fixes #3630 (#3631). Previously the attributes in link reference definitions did not have a space preceding. --- test/command/3630.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 test/command/3630.md (limited to 'test/command') diff --git a/test/command/3630.md b/test/command/3630.md new file mode 100644 index 000000000..db3a17dda --- /dev/null +++ b/test/command/3630.md @@ -0,0 +1,8 @@ +``` +% pandoc -f markdown -t markdown --reference-links +![foo](bar.png){#myId} +^D +![foo] + + [foo]: bar.png {#myId} +``` -- cgit v1.2.3 From 6e55e6837a38b83d0ed4329ab366c699d6c2551f Mon Sep 17 00:00:00 2001 From: schrieveslaach Date: Wed, 3 May 2017 12:16:48 +0200 Subject: LaTeX reader: Add support for tabularx environment (#3632) --- src/Text/Pandoc/Readers/LaTeX.hs | 7 ++- test/command/tabularx.md | 110 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 test/command/tabularx.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index a54238206..b88b6eae4 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1156,6 +1156,7 @@ environments = M.fromList , ("table", env "table" $ resetCaption *> skipopts *> blocks >>= addTableCaption) , ("tabular*", env "tabular" $ simpTable True) + , ("tabularx", env "tabularx" $ simpTable True) , ("tabular", env "tabular" $ simpTable False) , ("quote", blockQuote <$> env "quote" blocks) , ("quotation", blockQuote <$> env "quotation" blocks) @@ -1414,7 +1415,11 @@ parseAligns = try $ do let lAlign = AlignLeft <$ char 'l' let rAlign = AlignRight <$ char 'r' let parAlign = AlignLeft <$ (char 'p' >> braced) - let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign + -- algins from tabularx + let xAlign = AlignLeft <$ char 'X' + let mAlign = AlignLeft <$ (char 'm' >> braced) + let bAlign = AlignLeft <$ (char 'b' >> braced) + let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign <|> xAlign <|> mAlign <|> bAlign let alignPrefix = char '>' >> braced let alignSuffix = char '<' >> braced let alignSpec = do diff --git a/test/command/tabularx.md b/test/command/tabularx.md new file mode 100644 index 000000000..1d295c978 --- /dev/null +++ b/test/command/tabularx.md @@ -0,0 +1,110 @@ +``` +% pandoc -f latex -t native +\begin{tabularx}{\linewidth}{|c|c|c|} +\hline + Column Heading 1 + & Column Heading 2 + & Column Heading 3 \\ +\hline + Cell 1.1 + & Cell 1.2 + & Cell 1.3 \\ +\hline + Cell 2.1 + & Cell 2.2 + & Cell 2.3 \\ +\hline + Cell 3.1 + & Cell 3.2 + & Cell 3.3 \\ +\hline +\end{tabularx} +^D +[Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0] + [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]] + [[[Plain [Str "Cell",Space,Str "1.1"]] + ,[Plain [Str "Cell",Space,Str "1.2"]] + ,[Plain [Str "Cell",Space,Str "1.3"]]] + ,[[Plain [Str "Cell",Space,Str "2.1"]] + ,[Plain [Str "Cell",Space,Str "2.2"]] + ,[Plain [Str "Cell",Space,Str "2.3"]]] + ,[[Plain [Str "Cell",Space,Str "3.1"]] + ,[Plain [Str "Cell",Space,Str "3.2"]] + ,[Plain [Str "Cell",Space,Str "3.3"]]]]] +``` + +``` +% pandoc -f latex -t native +\begin{tabularx}{\linewidth}{|X|c|p{0.25\linewidth}|} +\hline + Column Heading 1 + & Column Heading 2 + & Column Heading 3 \\ +\hline + Cell 1.1 + & Cell 1.2 + & Cell 1.3 \\ +\hline + Cell 2.1 + & Cell 2.2 + & Cell 2.3 \\ +\hline + Cell 3.1 + & Cell 3.2 + & Cell 3.3 \\ +\hline +\end{tabularx} +^D +[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.0,0.0,0.0] + [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]] + [[[Plain [Str "Cell",Space,Str "1.1"]] + ,[Plain [Str "Cell",Space,Str "1.2"]] + ,[Plain [Str "Cell",Space,Str "1.3"]]] + ,[[Plain [Str "Cell",Space,Str "2.1"]] + ,[Plain [Str "Cell",Space,Str "2.2"]] + ,[Plain [Str "Cell",Space,Str "2.3"]]] + ,[[Plain [Str "Cell",Space,Str "3.1"]] + ,[Plain [Str "Cell",Space,Str "3.2"]] + ,[Plain [Str "Cell",Space,Str "3.3"]]]]] +``` + +``` +% pandoc -f latex -t native +\begin{tabularx}{\linewidth}{|b{0.25\linewidth}|c|m{0.25\linewidth}|} +\hline + Column Heading 1 + & Column Heading 2 + & Column Heading 3 \\ +\hline + Cell 1.1 + & Cell 1.2 + & Cell 1.3 \\ +\hline + Cell 2.1 + & Cell 2.2 + & Cell 2.3 \\ +\hline + Cell 3.1 + & Cell 3.2 + & Cell 3.3 \\ +\hline +\end{tabularx} +^D +[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.0,0.0,0.0] + [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]] + ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]] + [[[Plain [Str "Cell",Space,Str "1.1"]] + ,[Plain [Str "Cell",Space,Str "1.2"]] + ,[Plain [Str "Cell",Space,Str "1.3"]]] + ,[[Plain [Str "Cell",Space,Str "2.1"]] + ,[Plain [Str "Cell",Space,Str "2.2"]] + ,[Plain [Str "Cell",Space,Str "2.3"]]] + ,[[Plain [Str "Cell",Space,Str "3.1"]] + ,[Plain [Str "Cell",Space,Str "3.2"]] + ,[Plain [Str "Cell",Space,Str "3.3"]]]]] +``` -- cgit v1.2.3 From 79855ef934175c9a8890653375e05735d8b05a8d Mon Sep 17 00:00:00 2001 From: David A Roberts Date: Wed, 3 May 2017 20:19:45 +1000 Subject: Markdown writer: better escaping for links (#3628) Previously the Markdown writer would sometimes create links where there were none in the source. This is now avoided by selectively escaping bracket characters when they occur in a place where a link might be created. Closes #3619. --- src/Text/Pandoc/Writers/Markdown.hs | 11 ++++++++++- test/command/3619.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/command/3619.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 655fd8780..7c0874278 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -821,7 +821,8 @@ inlineListToMarkdown opts lst = do 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 + -- If a link is followed by another link, or '[', '(' or ':' + -- then we don't shortcut (Link _ _ _):_ -> unshortcutable Space:(Link _ _ _):_ -> unshortcutable Space:(Str('[':_)):_ -> unshortcutable @@ -831,9 +832,17 @@ inlineListToMarkdown opts lst = do SoftBreak:(Str('[':_)):_ -> unshortcutable SoftBreak:(RawInline _ ('[':_)):_ -> unshortcutable SoftBreak:(Cite _ _):_ -> unshortcutable + LineBreak:(Link _ _ _):_ -> unshortcutable + LineBreak:(Str('[':_)):_ -> unshortcutable + LineBreak:(RawInline _ ('[':_)):_ -> unshortcutable + LineBreak:(Cite _ _):_ -> unshortcutable (Cite _ _):_ -> unshortcutable Str ('[':_):_ -> unshortcutable + Str ('(':_):_ -> unshortcutable + Str (':':_):_ -> unshortcutable (RawInline _ ('[':_)):_ -> unshortcutable + (RawInline _ ('(':_)):_ -> unshortcutable + (RawInline _ (':':_)):_ -> unshortcutable (RawInline _ (' ':'[':_)):_ -> unshortcutable _ -> shortcutable _ -> shortcutable diff --git a/test/command/3619.md b/test/command/3619.md new file mode 100644 index 000000000..62962c43b --- /dev/null +++ b/test/command/3619.md @@ -0,0 +1,28 @@ +``` +% pandoc -f html -t markdown --reference-links +bar: baz +^D +[bar][]: baz + + [bar]: foo +``` + +``` +% pandoc -f html -t markdown --reference-links +bar(baz) +^D +[bar][](baz) + + [bar]: foo +``` + +``` +% pandoc -f html -t markdown_strict --reference-links +foo
bar +^D +[foo][] +[bar] + + [foo]: a + [bar]: b +``` -- cgit v1.2.3 From 57cba3f1d5aa682df4ca8aafc3bc1d2ed4ead911 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 3 May 2017 22:43:34 +0200 Subject: Org reader: support table.el tables Closes #3314 --- src/Text/Pandoc/Readers/Org/BlockStarts.hs | 5 +++++ src/Text/Pandoc/Readers/Org/Blocks.hs | 20 +++++++++++------- src/Text/Pandoc/Readers/Org/Parsing.hs | 1 + test/command/3314.md | 34 ++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 test/command/3314.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Org/BlockStarts.hs b/src/Text/Pandoc/Readers/Org/BlockStarts.hs index cc2e82d5b..f05725f16 100644 --- a/src/Text/Pandoc/Readers/Org/BlockStarts.hs +++ b/src/Text/Pandoc/Readers/Org/BlockStarts.hs @@ -61,6 +61,10 @@ headerStart = try $ tableStart :: Monad m => OrgParser m Char tableStart = try $ skipSpaces *> char '|' +gridTableStart :: Monad m => OrgParser m () +gridTableStart = try $ skipSpaces <* char '+' <* char '-' + + latexEnvStart :: Monad m => OrgParser m String latexEnvStart = try $ do skipSpaces *> string "\\begin{" @@ -126,6 +130,7 @@ endOfBlock = lookAhead . try $ do , hline , metaLineStart , commentLineStart + , gridTableStart , void noteMarker , void tableStart , void drawerStart diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index b0a19b833..89c076869 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -755,7 +755,11 @@ data OrgTable = OrgTable } table :: PandocMonad m => OrgParser m (F Blocks) -table = try $ do +table = gridTableWith blocks True <|> orgTable + +-- | A normal org table +orgTable :: PandocMonad m => OrgParser m (F Blocks) +orgTable = try $ do -- don't allow a table on the first line of a list item; org requires that -- tables start at first non-space character on the line let isFirstInListItem st = (orgStateParserContext st == ListItemState) && @@ -854,28 +858,28 @@ normalizeTable (OrgTable colProps heads rows) = rowToContent :: OrgTable -> OrgTableRow -> F OrgTable -rowToContent orgTable row = +rowToContent tbl row = case row of OrgHlineRow -> return singleRowPromotedToHeader OrgAlignRow props -> return . setProperties $ props OrgContentRow cs -> appendToBody cs where singleRowPromotedToHeader :: OrgTable - singleRowPromotedToHeader = case orgTable of + singleRowPromotedToHeader = case tbl of OrgTable{ orgTableHeader = [], orgTableRows = b:[] } -> - orgTable{ orgTableHeader = b , orgTableRows = [] } - _ -> orgTable + tbl{ orgTableHeader = b , orgTableRows = [] } + _ -> tbl setProperties :: [ColumnProperty] -> OrgTable - setProperties ps = orgTable{ orgTableColumnProperties = ps } + setProperties ps = tbl{ orgTableColumnProperties = ps } appendToBody :: F [Blocks] -> F OrgTable appendToBody frow = do newRow <- frow - let oldRows = orgTableRows orgTable + let oldRows = orgTableRows tbl -- NOTE: This is an inefficient O(n) operation. This should be changed -- if performance ever becomes a problem. - return orgTable{ orgTableRows = oldRows ++ [newRow] } + return tbl{ orgTableRows = oldRows ++ [newRow] } -- diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs index 464ef9ca6..aa3a08279 100644 --- a/src/Text/Pandoc/Readers/Org/Parsing.hs +++ b/src/Text/Pandoc/Readers/Org/Parsing.hs @@ -70,6 +70,7 @@ module Text.Pandoc.Readers.Org.Parsing , dash , ellipses , citeKey + , gridTableWith -- * Re-exports from Text.Pandoc.Parsec , runParser , runParserT diff --git a/test/command/3314.md b/test/command/3314.md new file mode 100644 index 000000000..064b04cbd --- /dev/null +++ b/test/command/3314.md @@ -0,0 +1,34 @@ +See #3315 and . + +``` +% pandoc -f org -t html5 ++-----------+-------+----------+ +| First | 12.0 | Example | +| | | row | +| | | spanning | +| | | lines | ++-----------+-------+----------+ +| Second | 5.0 | Another | ++-----------+-------+----------+ +^D + +++++ + + + + + + + + + + + + +
First12.0Example row spanning lines
Second5.0Another
+``` + -- cgit v1.2.3 From da8c153a6872a040440f8853a37f559bb3b26b02 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Sat, 6 May 2017 10:59:40 +0200 Subject: Org reader: support macros Closes: #3401 --- src/Text/Pandoc/Readers/Org/Inlines.hs | 21 +++++++++++++++++++++ src/Text/Pandoc/Readers/Org/Meta.hs | 27 ++++++++++++++++++++++++++- src/Text/Pandoc/Readers/Org/ParserState.hs | 18 ++++++++++++++++++ test/Tests/Readers/Org.hs | 18 ++++++++++++++++++ test/command/3401.md | 19 +++++++++++++++++++ 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/command/3401.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs index 64ffb8ef5..5772e4157 100644 --- a/src/Text/Pandoc/Readers/Org/Inlines.hs +++ b/src/Text/Pandoc/Readers/Org/Inlines.hs @@ -120,6 +120,7 @@ inline = , superscript , inlineLaTeX , exportSnippet + , macro , smart , symbol ] <* (guard =<< newlinesCountWithinLimits) @@ -839,6 +840,26 @@ exportSnippet = try $ do snippet <- manyTill anyChar (try $ string "@@") returnF $ B.rawInline format snippet +macro :: PandocMonad m => OrgParser m (F Inlines) +macro = try $ do + recursionDepth <- orgStateMacroDepth <$> getState + guard $ recursionDepth < 15 + string "{{{" + name <- many alphaNum + args <- ([] <$ string "}}}") + <|> char '(' *> argument `sepBy` char ',' <* eoa + expander <- lookupMacro name <$> getState + case expander of + Nothing -> mzero + Just fn -> do + updateState $ \s -> s { orgStateMacroDepth = recursionDepth + 1 } + res <- parseFromString (mconcat <$> many inline) $ fn args + updateState $ \s -> s { orgStateMacroDepth = recursionDepth } + return res + where + argument = many $ notFollowedBy eoa *> noneOf "," + eoa = string ")}}}" + smart :: PandocMonad m => OrgParser m (F Inlines) smart = do guardEnabled Ext_smart diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs index 7938fc6c6..8c362f209 100644 --- a/src/Text/Pandoc/Readers/Org/Meta.hs +++ b/src/Text/Pandoc/Readers/Org/Meta.hs @@ -46,7 +46,7 @@ import Text.Pandoc.Definition import Control.Monad (mzero, void) import Data.Char (toLower) -import Data.List (intersperse) +import Data.List (intersperse, sort) import qualified Data.Map as M import Network.HTTP (urlEncode) @@ -151,6 +151,7 @@ optionLine = try $ do "todo" -> todoSequence >>= updateState . registerTodoSequence "seq_todo" -> todoSequence >>= updateState . registerTodoSequence "typ_todo" -> todoSequence >>= updateState . registerTodoSequence + "macro" -> macroDefinition >>= updateState . registerMacro _ -> mzero addLinkFormat :: Monad m => String @@ -218,3 +219,27 @@ todoSequence = try $ do let todoMarkers = map (TodoMarker Todo) todo doneMarkers = map (TodoMarker Done) done in todoMarkers ++ doneMarkers + +macroDefinition :: Monad m => OrgParser m (String, [String] -> String) +macroDefinition = try $ do + macroName <- many1 nonspaceChar <* skipSpaces + firstPart <- expansionPart + (elemOrder, parts) <- unzip <$> many ((,) <$> placeholder <*> expansionPart) + let expander = mconcat . alternate (firstPart:parts) . reorder elemOrder + return (macroName, expander) + where + placeholder :: Monad m => OrgParser m Int + placeholder = try . fmap read $ char '$' *> many1 digit + + expansionPart :: Monad m => OrgParser m String + expansionPart = try $ many (notFollowedBy placeholder *> noneOf "\n\r") + + alternate :: [a] -> [a] -> [a] + alternate [] ys = ys + alternate xs [] = xs + alternate (x:xs) (y:ys) = x : y : alternate xs ys + + reorder :: [Int] -> [String] -> [String] + reorder perm xs = + let element n = take 1 $ drop (n - 1) xs + in concatMap element perm diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index bdd1dc951..e47565814 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -39,6 +39,9 @@ module Text.Pandoc.Readers.Org.ParserState , TodoState (..) , activeTodoMarkers , registerTodoSequence + , MacroExpander + , lookupMacro + , registerMacro , F , askF , asksF @@ -78,6 +81,8 @@ type OrgNoteTable = [OrgNoteRecord] -- | Map of functions for link transformations. The map key is refers to the -- link-type, the corresponding function transforms the given link string. type OrgLinkFormatters = M.Map String (String -> String) +-- | Macro expander function +type MacroExpander = [String] -> String -- | The states in which a todo item can be data TodoState = Todo | Done @@ -105,6 +110,8 @@ data OrgParserState = OrgParserState , orgStateLastPreCharPos :: Maybe SourcePos , orgStateLastStrPos :: Maybe SourcePos , orgStateLinkFormatters :: OrgLinkFormatters + , orgStateMacros :: M.Map String MacroExpander + , orgStateMacroDepth :: Int , orgStateMeta :: F Meta , orgStateNotes' :: OrgNoteTable , orgStateOptions :: ReaderOptions @@ -156,6 +163,8 @@ defaultOrgParserState = OrgParserState , orgStateLastPreCharPos = Nothing , orgStateLastStrPos = Nothing , orgStateLinkFormatters = M.empty + , orgStateMacros = M.empty + , orgStateMacroDepth = 0 , orgStateMeta = return nullMeta , orgStateNotes' = [] , orgStateOptions = def @@ -185,6 +194,15 @@ activeTodoSequences st = activeTodoMarkers :: OrgParserState -> TodoSequence activeTodoMarkers = concat . activeTodoSequences +lookupMacro :: String -> OrgParserState -> Maybe MacroExpander +lookupMacro macroName = M.lookup macroName . orgStateMacros + +registerMacro :: (String, MacroExpander) -> OrgParserState -> OrgParserState +registerMacro (name, expander) st = + let curMacros = orgStateMacros st + in st{ orgStateMacros = M.insert name expander curMacros } + + -- -- Export Settings diff --git a/test/Tests/Readers/Org.hs b/test/Tests/Readers/Org.hs index 7a7960396..278d91cfd 100644 --- a/test/Tests/Readers/Org.hs +++ b/test/Tests/Readers/Org.hs @@ -469,6 +469,24 @@ tests = , citationNoteNum = 0 , citationHash = 0} in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}") + + , "Macro" =: + unlines [ "#+MACRO: HELLO /Hello, $1/" + , "{{{HELLO(World)}}}" + ] =?> + para (emph "Hello, World") + + , "Macro repeting its argument" =: + unlines [ "#+MACRO: HELLO $1$1" + , "{{{HELLO(moin)}}}" + ] =?> + para "moinmoin" + + , "Macro called with too few arguments" =: + unlines [ "#+MACRO: HELLO Foo $1 $2 Bar" + , "{{{HELLO()}}}" + ] =?> + para "Foo Bar" ] , testGroup "Meta Information" $ diff --git a/test/command/3401.md b/test/command/3401.md new file mode 100644 index 000000000..99528553a --- /dev/null +++ b/test/command/3401.md @@ -0,0 +1,19 @@ +See #3401 and + +``` +% pandoc -f org -t native +#+MACRO: HELLO /Hello, $1/ +{{{HELLO(World)}}} +^D +[Para [Emph [Str "Hello,",Space,Str "World"]]] +``` + +Inverted argument order + +``` +% pandoc -f org -t native +#+MACRO: A $2,$1 +{{{A(1,2)}}} +^D +[Para [Str "2,1"]] +``` -- cgit v1.2.3 From ddf2524477e2a59b36fd37f7e5957ebb3b37c265 Mon Sep 17 00:00:00 2001 From: schrieveslaach Date: Sat, 6 May 2017 15:09:29 +0200 Subject: Fix keyval funtion: pandoc did not parse options in braces correctly.… (#3642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix keyval funtion: pandoc did not parse options in braces correctly. Additionally, dot, dash, and colon were no valid characters * Add | as possible option value * Improved code --- src/Text/Pandoc/Readers/LaTeX.hs | 2 +- test/command/lstlisting.md | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/command/lstlisting.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index b88b6eae4..1ce92a4a2 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1095,7 +1095,7 @@ parseListingsOptions options = keyval :: PandocMonad m => LP m (String, String) keyval = try $ do key <- many1 alphaNum - val <- option "" $ char '=' >> many1 (alphaNum <|> char '.' <|> char '\\') + val <- option "" $ char '=' >> braced <|> (many1 (alphaNum <|> oneOf ".:-|\\")) skipMany spaceChar optional (char ',') skipMany spaceChar diff --git a/test/command/lstlisting.md b/test/command/lstlisting.md new file mode 100644 index 000000000..d928cc702 --- /dev/null +++ b/test/command/lstlisting.md @@ -0,0 +1,25 @@ +``` +% pandoc -f latex -t native +\begin{lstlisting}[language=Java, caption={Java Example}, label=lst:Hello-World] +public class World { + public static void main(String[] args) { + System.out.println("Hello World"); + } +} +\end{lstlisting} +^D +[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"] +``` + +``` +% pandoc -f latex -t native +\begin{lstlisting}[language=Java, escapechar=|, caption={Java Example}, label=lst:Hello-World] +public class World { + public static void main(String[] args) { + System.out.println("Hello World"); + } +} +\end{lstlisting} +^D +[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("escapechar","|"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"] +``` -- cgit v1.2.3 From f20c89e24380007a47f3e28889706a6f584bc6e0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 6 May 2017 22:15:51 +0200 Subject: LaTeX reader: Better handling of comments inside math environments. This solves a problem with commented out `\end{eqnarray}` inside an eqnarray (among other things). Closes #3113. --- src/Text/Pandoc/Readers/LaTeX.hs | 73 +++++++++++++++++++++++----------------- test/command/3113.md | 13 +++++++ 2 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 test/command/3113.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 1ce92a4a2..b13fc215b 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -492,20 +492,20 @@ isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Bl inlineEnvironments :: PandocMonad m => M.Map String (LP m Inlines) inlineEnvironments = M.fromList - [ ("displaymath", mathEnv id Nothing "displaymath") - , ("math", math <$> verbEnv "math") - , ("equation", mathEnv id Nothing "equation") - , ("equation*", mathEnv id Nothing "equation*") - , ("gather", mathEnv id (Just "gathered") "gather") - , ("gather*", mathEnv id (Just "gathered") "gather*") - , ("multline", mathEnv id (Just "gathered") "multline") - , ("multline*", mathEnv id (Just "gathered") "multline*") - , ("eqnarray", mathEnv id (Just "aligned") "eqnarray") - , ("eqnarray*", mathEnv id (Just "aligned") "eqnarray*") - , ("align", mathEnv id (Just "aligned") "align") - , ("align*", mathEnv id (Just "aligned") "align*") - , ("alignat", mathEnv id (Just "aligned") "alignat") - , ("alignat*", mathEnv id (Just "aligned") "alignat*") + [ ("displaymath", mathEnvWith id Nothing "displaymath") + , ("math", math <$> mathEnv "math") + , ("equation", mathEnvWith id Nothing "equation") + , ("equation*", mathEnvWith id Nothing "equation*") + , ("gather", mathEnvWith id (Just "gathered") "gather") + , ("gather*", mathEnvWith id (Just "gathered") "gather*") + , ("multline", mathEnvWith id (Just "gathered") "multline") + , ("multline*", mathEnvWith id (Just "gathered") "multline*") + , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray") + , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*") + , ("align", mathEnvWith id (Just "aligned") "align") + , ("align*", mathEnvWith id (Just "aligned") "align*") + , ("alignat", mathEnvWith id (Just "aligned") "alignat") + , ("alignat*", mathEnvWith id (Just "aligned") "alignat*") ] inlineCommands :: PandocMonad m => M.Map String (LP m Inlines) @@ -1187,19 +1187,19 @@ environments = M.fromList , ("obeylines", parseFromString (para . trimInlines . mconcat <$> many inline) =<< intercalate "\\\\\n" . lines <$> verbEnv "obeylines") - , ("displaymath", mathEnv para Nothing "displaymath") - , ("equation", mathEnv para Nothing "equation") - , ("equation*", mathEnv para Nothing "equation*") - , ("gather", mathEnv para (Just "gathered") "gather") - , ("gather*", mathEnv para (Just "gathered") "gather*") - , ("multline", mathEnv para (Just "gathered") "multline") - , ("multline*", mathEnv para (Just "gathered") "multline*") - , ("eqnarray", mathEnv para (Just "aligned") "eqnarray") - , ("eqnarray*", mathEnv para (Just "aligned") "eqnarray*") - , ("align", mathEnv para (Just "aligned") "align") - , ("align*", mathEnv para (Just "aligned") "align*") - , ("alignat", mathEnv para (Just "aligned") "alignat") - , ("alignat*", mathEnv para (Just "aligned") "alignat*") + , ("displaymath", mathEnvWith para Nothing "displaymath") + , ("equation", mathEnvWith para Nothing "equation") + , ("equation*", mathEnvWith para Nothing "equation*") + , ("gather", mathEnvWith para (Just "gathered") "gather") + , ("gather*", mathEnvWith para (Just "gathered") "gather*") + , ("multline", mathEnvWith para (Just "gathered") "multline") + , ("multline*", mathEnvWith para (Just "gathered") "multline*") + , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray") + , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*") + , ("align", mathEnvWith para (Just "aligned") "align") + , ("align*", mathEnvWith para (Just "aligned") "align*") + , ("alignat", mathEnvWith para (Just "aligned") "alignat") + , ("alignat*", mathEnvWith para (Just "aligned") "alignat*") ] figure :: PandocMonad m => LP m Blocks @@ -1264,19 +1264,32 @@ listenv name p = try $ do updateState $ \st -> st{ stateParserContext = oldCtx } return res -mathEnv :: PandocMonad m => (Inlines -> a) -> Maybe String -> String -> LP m a -mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name) +mathEnvWith :: PandocMonad m + => (Inlines -> a) -> Maybe String -> String -> LP m a +mathEnvWith f innerEnv name = f <$> mathDisplay (inner <$> mathEnv name) where inner x = case innerEnv of Nothing -> x Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++ "\\end{" ++ y ++ "}" +mathEnv :: PandocMonad m => String -> LP m String +mathEnv name = do + skipopts + optional blankline + let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name) + charMuncher = skipMany comment *> + (many1 (noneOf "\\%") <|> try (string "\\%") + <|> try (string "\\\\") <|> count 1 anyChar) + res <- concat <$> manyTill charMuncher endEnv + return $ stripTrailingNewlines res + verbEnv :: PandocMonad m => String -> LP m String verbEnv name = do skipopts optional blankline let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name) - res <- manyTill anyChar endEnv + charMuncher = anyChar + res <- manyTill charMuncher endEnv return $ stripTrailingNewlines res fancyverbEnv :: PandocMonad m => String -> LP m Blocks diff --git a/test/command/3113.md b/test/command/3113.md new file mode 100644 index 000000000..f44e25709 --- /dev/null +++ b/test/command/3113.md @@ -0,0 +1,13 @@ +``` +% pandoc -f latex -t native +\begin{eqnarray} +A&=&B,\\ +C&=&D,\\ +%\end{eqnarray} +%\begin{eqnarray} +E&=&F +\end{eqnarray} +^D +[Para [Math DisplayMath "\\begin{aligned}\nA&=&B,\\\\\nC&=&D,\\\\\nE&=&F\\end{aligned}"]] +``` + -- cgit v1.2.3 From 82cc7fb0d462401b54bfe5172e7e49ab7b7302d9 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 6 May 2017 22:56:16 +0200 Subject: Markdown reader: improved parsing of indented raw HTML blocks. Previously we inadvertently interpreted indented HTML as code blocks. This was a regression. We now seek to determine the indentation level of the contents of an HTML block, and (optionally) skip that much indentation. As a side effect, indentation may be stripped off of raw HTML blocks, if `markdown_in_html_blocks` is used. This is better than having things interpreted as indented code blocks. Closes #1841. --- src/Text/Pandoc/Readers/Markdown.hs | 8 ++++++- test/command/1841.md | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test/command/1841.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 5515c735b..691d4d5cf 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1088,13 +1088,19 @@ rawTeXBlock = do rawHtmlBlocks :: PandocMonad m => MarkdownParser m (F Blocks) rawHtmlBlocks = do (TagOpen tagtype _, raw) <- htmlTag isBlockTag + -- we don't want ' text' to be a code block: + skipMany spaceChar + indentlevel <- (blankline >> length <$> many (char ' ')) <|> return 0 -- try to find closing tag -- we set stateInHtmlBlock so that closing tags that can be either block or -- inline will not be parsed as inline tags oldInHtmlBlock <- stateInHtmlBlock <$> getState updateState $ \st -> st{ stateInHtmlBlock = Just tagtype } let closer = htmlTag (\x -> x ~== TagClose tagtype) - contents <- mconcat <$> many (notFollowedBy' closer >> block) + let block' = do notFollowedBy' closer + atMostSpaces indentlevel + block + contents <- mconcat <$> many block' result <- (closer >>= \(_, rawcloser) -> return ( return (B.rawBlock "html" $ stripMarkdownAttribute raw) <> diff --git a/test/command/1841.md b/test/command/1841.md new file mode 100644 index 000000000..408f224bd --- /dev/null +++ b/test/command/1841.md @@ -0,0 +1,42 @@ +``` +% pandoc + + + + + +
*one* [a link](http://google.com)
+^D + + + + + +
+one + +a link +
+``` + +``` +% pandoc + + + + + +
*one*[a link](http://google.com)
+^D + + + + + +
+one + +a link +
+``` + -- cgit v1.2.3 From 4b9fb7a1280f1d923a6bcecbf42a496480020359 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 10 May 2017 23:35:45 +0200 Subject: Combine grid table parsers The grid table parsers for markdown and rst was combined into one single parser, slightly changing parsing behavior of both parsers: - The markdown parser now compactifies block content cell-wise: pure text blocks in cells are now treated as paragraphs only if the cell contains multiple paragraphs, and as plain blocks otherwise. Before, this was true only for single-column tables. - The rst parser now accepts newlines and multiple blocks in header cells. Closes: #3638 --- src/Text/Pandoc/Parsing.hs | 69 ++++++++++++++++++++++-------- src/Text/Pandoc/Readers/Markdown.hs | 84 +------------------------------------ test/command/3516.md | 4 +- test/markdown-reader-more.native | 68 +++++++++++++++--------------- test/tables-rstsubset.native | 12 +++--- 5 files changed, 94 insertions(+), 143 deletions(-) (limited to 'test/command') diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index e0c0e36d6..fa3ff898e 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -66,6 +66,7 @@ module Text.Pandoc.Parsing ( anyLine, tableWith, widthsFromIndices, gridTableWith, + gridTableWith', readWith, readWithM, testStringWith, @@ -770,6 +771,20 @@ tableWith :: (Stream s m Char, HasReaderOptions st, -> ParserT s st m end -> ParserT s st m (mf Blocks) tableWith headerParser rowParser lineParser footerParser = try $ do + (aligns, widths, heads, rows) <- tableWith' headerParser rowParser + lineParser footerParser + return $ B.table mempty (zip aligns widths) <$> heads <*> rows + +type TableComponents mf = ([Alignment], [Double], mf [Blocks], mf [[Blocks]]) + +tableWith' :: (Stream s m Char, HasReaderOptions st, + Functor mf, Applicative mf, Monad mf) + => ParserT s st m (mf [Blocks], [Alignment], [Int]) + -> ([Int] -> ParserT s st m (mf [Blocks])) + -> ParserT s st m sep + -> ParserT s st m end + -> ParserT s st m (TableComponents mf) +tableWith' headerParser rowParser lineParser footerParser = try $ do (heads, aligns, indices) <- headerParser lines' <- sequence <$> rowParser indices `sepEndBy1` lineParser footerParser @@ -777,7 +792,7 @@ tableWith headerParser rowParser lineParser footerParser = try $ do let widths = if (indices == []) then replicate (length aligns) 0.0 else widthsFromIndices numColumns indices - return $ B.table mempty (zip aligns widths) <$> heads <*> lines' + return $ (aligns, widths, heads, lines') -- Calculate relative widths of table columns, based on indices widthsFromIndices :: Int -- Number of columns on terminal @@ -812,24 +827,42 @@ widthsFromIndices numColumns' indices = -- ending with a footer (dashed line followed by blank line). gridTableWith :: (Stream [Char] m Char, HasReaderOptions st, Functor mf, Applicative mf, Monad mf) - => ParserT [Char] st m (mf Blocks) -- ^ Block list parser + => ParserT [Char] st m (mf Blocks) -- ^ Block list parser -> Bool -- ^ Headerless table -> ParserT [Char] st m (mf Blocks) gridTableWith blocks headless = tableWith (gridTableHeader headless blocks) (gridTableRow blocks) (gridTableSep '-') gridTableFooter +gridTableWith' :: (Stream [Char] m Char, HasReaderOptions st, + Functor mf, Applicative mf, Monad mf) + => ParserT [Char] st m (mf Blocks) -- ^ Block list parser + -> Bool -- ^ Headerless table + -> ParserT [Char] st m (TableComponents mf) +gridTableWith' blocks headless = + tableWith' (gridTableHeader headless blocks) (gridTableRow blocks) + (gridTableSep '-') gridTableFooter + gridTableSplitLine :: [Int] -> String -> [String] gridTableSplitLine indices line = map removeFinalBar $ tail $ splitStringByIndices (init indices) $ trimr line -gridPart :: Stream s m Char => Char -> ParserT s st m (Int, Int) +gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment) gridPart ch = do + leftColon <- option False (True <$ char ':') dashes <- many1 (char ch) + rightColon <- option False (True <$ char ':') char '+' - return (length dashes, length dashes + 1) - -gridDashedLines :: Stream s m Char => Char -> ParserT s st m [(Int,Int)] + let lengthDashes = length dashes + (if leftColon then 1 else 0) + + (if rightColon then 1 else 0) + let alignment = case (leftColon, rightColon) of + (True, True) -> AlignCenter + (True, False) -> AlignLeft + (False, True) -> AlignRight + (False, False) -> AlignDefault + return ((lengthDashes, lengthDashes + 1), alignment) + +gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)] gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline removeFinalBar :: String -> String @@ -853,18 +886,18 @@ gridTableHeader headless blocks = try $ do else many1 (notFollowedBy (gridTableSep '=') >> char '|' >> many1Till anyChar newline) - if headless - then return () - else gridTableSep '=' >> return () - let lines' = map snd dashes + underDashes <- if headless + then return dashes + else gridDashedLines '=' + guard $ length dashes == length underDashes + let lines' = map (snd . fst) underDashes let indices = scanl (+) 0 lines' - let aligns = replicate (length lines') AlignDefault - -- RST does not have a notion of alignments + let aligns = map snd underDashes let rawHeads = if headless - then replicate (length dashes) "" - else map (intercalate " ") $ transpose + then replicate (length underDashes) "" + else map (unlines . map trim) $ transpose $ map (gridTableSplitLine indices) rawContent - heads <- fmap sequence . mapM (parseFromString blocks) $ map trim rawHeads + heads <- fmap sequence $ mapM (parseFromString blocks . trim) rawHeads return (heads, aligns, indices) gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [String] @@ -882,6 +915,9 @@ gridTableRow blocks indices = do colLines <- many1 (gridTableRawLine indices) let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $ transpose colLines + compactifyCell bs = case compactify [bs] of + [] -> mempty + x:_ -> x cells <- sequence <$> mapM (parseFromString blocks) cols return $ fmap (map compactifyCell) cells @@ -893,9 +929,6 @@ removeOneLeadingSpace xs = where startsWithSpace "" = True startsWithSpace (y:_) = y == ' ' -compactifyCell :: Blocks -> Blocks -compactifyCell bs = head $ compactify [bs] - -- | Parse footer for a grid table. gridTableFooter :: Stream s m Char => ParserT s st m [Char] gridTableFooter = blanklines diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 691d4d5cf..4ff5a1845 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1291,89 +1291,7 @@ multilineTableHeader headless = try $ do -- ending with a footer (dashed line followed by blank line). gridTable :: PandocMonad m => Bool -- ^ Headerless table -> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]]) -gridTable headless = - tableWith (gridTableHeader headless) gridTableRow - (gridTableSep '-') gridTableFooter - -gridTableSplitLine :: [Int] -> String -> [String] -gridTableSplitLine indices line = map removeFinalBar $ tail $ - splitStringByIndices (init indices) $ trimr line - -gridPart :: PandocMonad m => Char -> ParserT [Char] st m ((Int, Int), Alignment) -gridPart ch = do - leftColon <- option False (True <$ char ':') - dashes <- many1 (char ch) - rightColon <- option False (True <$ char ':') - char '+' - let lengthDashes = length dashes + (if leftColon then 1 else 0) + - (if rightColon then 1 else 0) - let alignment = case (leftColon, rightColon) of - (True, True) -> AlignCenter - (True, False) -> AlignLeft - (False, True) -> AlignRight - (False, False) -> AlignDefault - return ((lengthDashes, lengthDashes + 1), alignment) - -gridDashedLines :: PandocMonad m => Char -> ParserT [Char] st m [((Int, Int), Alignment)] -gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline - -removeFinalBar :: String -> String -removeFinalBar = - reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse - --- | Separator between rows of grid table. -gridTableSep :: PandocMonad m => Char -> MarkdownParser m Char -gridTableSep ch = try $ gridDashedLines ch >> return '\n' - --- | Parse header for a grid table. -gridTableHeader :: PandocMonad m => Bool -- ^ Headerless table - -> MarkdownParser m (F [Blocks], [Alignment], [Int]) -gridTableHeader headless = try $ do - optional blanklines - dashes <- gridDashedLines '-' - rawContent <- if headless - then return [] - else many1 (try (char '|' >> anyLine)) - underDashes <- if headless - then return dashes - else gridDashedLines '=' - guard $ length dashes == length underDashes - let lines' = map (snd . fst) underDashes - let indices = scanl (+) 0 lines' - let aligns = map snd underDashes - let rawHeads = if headless - then replicate (length underDashes) "" - else map (unlines . map trim) $ transpose - $ map (gridTableSplitLine indices) rawContent - heads <- fmap sequence $ mapM (parseFromString parseBlocks . trim) rawHeads - return (heads, aligns, indices) - -gridTableRawLine :: PandocMonad m => [Int] -> MarkdownParser m [String] -gridTableRawLine indices = do - char '|' - line <- anyLine - return (gridTableSplitLine indices line) - --- | Parse row of grid table. -gridTableRow :: PandocMonad m => [Int] - -> MarkdownParser m (F [Blocks]) -gridTableRow indices = do - colLines <- many1 (gridTableRawLine indices) - let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $ - transpose colLines - fmap compactify <$> fmap sequence (mapM (parseFromString parseBlocks) cols) - -removeOneLeadingSpace :: [String] -> [String] -removeOneLeadingSpace xs = - if all startsWithSpace xs - then map (drop 1) xs - else xs - where startsWithSpace "" = True - startsWithSpace (y:_) = y == ' ' - --- | Parse footer for a grid table. -gridTableFooter :: PandocMonad m => MarkdownParser m [Char] -gridTableFooter = blanklines +gridTable headless = gridTableWith' parseBlocks headless pipeBreak :: PandocMonad m => MarkdownParser m ([Alignment], [Int]) pipeBreak = try $ do diff --git a/test/command/3516.md b/test/command/3516.md index 982043874..8c7e478d3 100644 --- a/test/command/3516.md +++ b/test/command/3516.md @@ -27,8 +27,8 @@ on Windows builds. [Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2] [[] ,[]] - [[[Para [Str "1"]] - ,[Para [Str "2"]]] + [[[Plain [Str "1"]] + ,[Plain [Str "2"]]] ,[[] ,[]]]] ``` diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native index baafb5334..1007dbac7 100644 --- a/test/markdown-reader-more.native +++ b/test/markdown-reader-more.native @@ -99,74 +99,74 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S [[Plain [Str "col",Space,Str "1"]] ,[Plain [Str "col",Space,Str "2"]] ,[Plain [Str "col",Space,Str "3"]]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Headless"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "With",Space,Str "alignments"] ,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[Plain [Str "col",Space,Str "1"]] ,[Plain [Str "col",Space,Str "2"]] ,[Plain [Str "col",Space,Str "3"]]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Headless",Space,Str "with",Space,Str "alignments"] ,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] - [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] - ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]] - ,[[Para [Str "r2",Space,Str "d"]] - ,[Para [Str "e"]] - ,[Para [Str "f"]]]] + [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]] + ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]] + ,[[Plain [Str "r2",Space,Str "d"]] + ,[Plain [Str "e"]] + ,[Plain [Str "f"]]]] ,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"] ,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555] [[] ,[] ,[]] [[[Header 1 ("col-1",[],[]) [Str "col",Space,Str "1"] - ,Para [Str "col",Space,Str "1"]] + ,Plain [Str "col",Space,Str "1"]] ,[Header 1 ("col-2",[],[]) [Str "col",Space,Str "2"] - ,Para [Str "col",Space,Str "2"]] + ,Plain [Str "col",Space,Str "2"]] ,[Header 1 ("col-3",[],[]) [Str "col",Space,Str "3"] - ,Para [Str "col",Space,Str "3"]]] + ,Plain [Str "col",Space,Str "3"]]] ,[[Para [Str "r1",Space,Str "a"] ,Para [Str "r1",Space,Str "bis"]] ,[BulletList [[Plain [Str "b"]] ,[Plain [Str "b",Space,Str "2"]] ,[Plain [Str "b",Space,Str "2"]]]] - ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]] + ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]] ,Para [Str "Empty",Space,Str "cells"] ,Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2] [[] diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native index d9bb9f2fb..8b7ccdf76 100644 --- a/test/tables-rstsubset.native +++ b/test/tables-rstsubset.native @@ -54,9 +54,9 @@ ,[Plain [Str "1"]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"] ,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] - [[Plain [Str "Centered",Space,Str "Header"]] - ,[Plain [Str "Left",Space,Str "Aligned"]] - ,[Plain [Str "Right",Space,Str "Aligned"]] + [[Plain [Str "Centered",SoftBreak,Str "Header"]] + ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] + ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] ,[Plain [Str "Default",Space,Str "aligned"]]] [[[Plain [Str "First"]] ,[Plain [Str "row"]] @@ -68,9 +68,9 @@ ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]] ,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"] ,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325] - [[Plain [Str "Centered",Space,Str "Header"]] - ,[Plain [Str "Left",Space,Str "Aligned"]] - ,[Plain [Str "Right",Space,Str "Aligned"]] + [[Plain [Str "Centered",SoftBreak,Str "Header"]] + ,[Plain [Str "Left",SoftBreak,Str "Aligned"]] + ,[Plain [Str "Right",SoftBreak,Str "Aligned"]] ,[Plain [Str "Default",Space,Str "aligned"]]] [[[Plain [Str "First"]] ,[Plain [Str "row"]] -- cgit v1.2.3 From 37189667cc2bc86d308ad771318528bd77876912 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 15 May 2017 20:36:11 +0200 Subject: Textile reader: fix bug for certain links in table cells. Closes #3667. --- src/Text/Pandoc/Readers/Textile.hs | 7 +++++-- test/command/3667.md | 13 +++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 test/command/3667.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs index df057837f..abf8be452 100644 --- a/src/Text/Pandoc/Readers/Textile.hs +++ b/src/Text/Pandoc/Readers/Textile.hs @@ -586,8 +586,9 @@ link = try $ do char ':' let stop = if bracketed then char ']' - else lookAhead $ space <|> - try (oneOf "!.,;:" *> (space <|> newline)) + else lookAhead $ space <|> eof' <|> + try (oneOf "!.,;:" *> + (space <|> newline <|> eof')) url <- many1Till nonspaceChar stop let name' = if B.toList name == [Str "$"] then B.str url else name return $ if attr == nullAttr @@ -728,3 +729,5 @@ groupedInlineMarkup = try $ do singleton :: a -> [a] singleton x = [x] +eof' :: Monad m => ParserT [Char] s m Char +eof' = '\n' <$ eof diff --git a/test/command/3667.md b/test/command/3667.md new file mode 100644 index 000000000..97de8f598 --- /dev/null +++ b/test/command/3667.md @@ -0,0 +1,13 @@ +``` +% pandoc -f textile +| "link text":http://example.com/ | +^D + + + + + + +
link text
+``` + -- cgit v1.2.3 From af4bf91c5925b5c6a7431cef8a7997c16d4c7b2b Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Sun, 14 May 2017 12:45:31 +0200 Subject: Org reader: add basic file inclusion mechanism Support for the `#+INCLUDE:` file inclusion mechanism was added. Recognized include types are *example*, *export*, *src*, and normal org file inclusion. Advanced features like line numbers and level selection are not implemented yet. Closes: #3510 --- pandoc.cabal | 3 +++ src/Text/Pandoc/Readers/Org/Blocks.hs | 36 ++++++++++++++++++++++++++---- src/Text/Pandoc/Readers/Org/ParserState.hs | 11 ++++++++- src/Text/Pandoc/Readers/Org/Parsing.hs | 1 + test/command/3510-export.latex | 1 + test/command/3510-src.hs | 1 + test/command/3510-subdoc.org | 5 +++++ test/command/3510.md | 20 +++++++++++++++++ 8 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 test/command/3510-export.latex create mode 100644 test/command/3510-src.hs create mode 100644 test/command/3510-subdoc.org create mode 100644 test/command/3510.md (limited to 'test/command') diff --git a/pandoc.cabal b/pandoc.cabal index a713e9372..bdee857b0 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -138,6 +138,9 @@ Extra-Source-Files: test/command/abbrevs test/command/sub-file-chapter-1.tex test/command/sub-file-chapter-2.tex + test/command/3510-subdoc.org + test/command/3510-export.latex + test/command/3510-src.hs test/docbook-reader.docbook test/docbook-xref.docbook test/html-reader.html diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index 788ec26dc..e77a64efe 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -1,6 +1,3 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ViewPatterns #-} {- Copyright (C) 2014-2017 Albert Krewinkel @@ -18,7 +15,9 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} - +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ViewPatterns #-} {- | Module : Text.Pandoc.Readers.Org.Options Copyright : Copyright (C) 2014-2017 Albert Krewinkel @@ -274,6 +273,7 @@ block = choice [ mempty <$ blanklines , figure , example , genericDrawer + , include , specialLine , horizontalRule , list @@ -717,6 +717,34 @@ exampleCode = B.codeBlockWith ("", ["example"], []) specialLine :: PandocMonad m => OrgParser m (F Blocks) specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine +-- | Include the content of a file. +include :: PandocMonad m => OrgParser m (F Blocks) +include = try $ do + metaLineStart <* stringAnyCase "include:" <* skipSpaces + filename <- includeTarget + blockType <- optionMaybe $ skipSpaces *> many1 alphaNum + blocksParser <- case blockType of + Just "example" -> do + return $ pure . B.codeBlock <$> parseRaw + Just "export" -> do + format <- skipSpaces *> many (noneOf "\n\r\t ") + return $ pure . B.rawBlock format <$> parseRaw + Just "src" -> do + language <- skipSpaces *> many (noneOf "\n\r\t ") + let attr = (mempty, [language], mempty) + return $ pure . B.codeBlockWith attr <$> parseRaw + _ -> return $ pure . B.fromList <$> blockList + anyLine + insertIncludedFileF blocksParser ["."] filename + where + includeTarget :: PandocMonad m => OrgParser m FilePath + includeTarget = do + char '"' + manyTill (noneOf "\n\r\t") (char '"') + + parseRaw :: PandocMonad m => OrgParser m String + parseRaw = many anyChar + rawExportLine :: PandocMonad m => OrgParser m Blocks rawExportLine = try $ do metaLineStart diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index f530d1d03..51666fc64 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -66,7 +66,8 @@ import Text.Pandoc.Logging import Text.Pandoc.Parsing (HasHeaderMap (..), HasIdentifierList (..), HasLogMessages (..), HasLastStrPosition (..), HasQuoteContext (..), - HasReaderOptions (..), ParserContext (..), + HasReaderOptions (..), HasIncludeFiles (..), + ParserContext (..), QuoteContext (..), SourcePos, Future, askF, asksF, returnF, runF, trimInlinesF) @@ -106,6 +107,7 @@ data OrgParserState = OrgParserState , orgStateExportSettings :: ExportSettings , orgStateHeaderMap :: M.Map Inlines String , orgStateIdentifiers :: Set.Set String + , orgStateIncludeFiles :: [String] , orgStateLastForbiddenCharPos :: Maybe SourcePos , orgStateLastPreCharPos :: Maybe SourcePos , orgStateLastStrPos :: Maybe SourcePos @@ -148,6 +150,12 @@ instance HasLogMessages OrgParserState where addLogMessage msg st = st{ orgLogMessages = msg : orgLogMessages st } getLogMessages st = reverse $ orgLogMessages st +instance HasIncludeFiles OrgParserState where + getIncludeFiles = orgStateIncludeFiles + addIncludeFile f st = st { orgStateIncludeFiles = f : orgStateIncludeFiles st } + dropLatestIncludeFile st = + st { orgStateIncludeFiles = drop 1 $ orgStateIncludeFiles st } + instance Default OrgParserState where def = defaultOrgParserState @@ -159,6 +167,7 @@ defaultOrgParserState = OrgParserState , orgStateExportSettings = def , orgStateHeaderMap = M.empty , orgStateIdentifiers = Set.empty + , orgStateIncludeFiles = [] , orgStateLastForbiddenCharPos = Nothing , orgStateLastPreCharPos = Nothing , orgStateLastStrPos = Nothing diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs index 50f5ebae5..c25b215df 100644 --- a/src/Text/Pandoc/Readers/Org/Parsing.hs +++ b/src/Text/Pandoc/Readers/Org/Parsing.hs @@ -71,6 +71,7 @@ module Text.Pandoc.Readers.Org.Parsing , ellipses , citeKey , gridTableWith + , insertIncludedFileF -- * Re-exports from Text.Pandoc.Parsec , runParser , runParserT diff --git a/test/command/3510-export.latex b/test/command/3510-export.latex new file mode 100644 index 000000000..6d8636322 --- /dev/null +++ b/test/command/3510-export.latex @@ -0,0 +1 @@ +\emph{Hello} \ No newline at end of file diff --git a/test/command/3510-src.hs b/test/command/3510-src.hs new file mode 100644 index 000000000..ad5744b80 --- /dev/null +++ b/test/command/3510-src.hs @@ -0,0 +1 @@ +putStrLn outString diff --git a/test/command/3510-subdoc.org b/test/command/3510-subdoc.org new file mode 100644 index 000000000..5bcc6678a --- /dev/null +++ b/test/command/3510-subdoc.org @@ -0,0 +1,5 @@ +* Subsection + +Included text + +Lorem ipsum. diff --git a/test/command/3510.md b/test/command/3510.md new file mode 100644 index 000000000..7993db848 --- /dev/null +++ b/test/command/3510.md @@ -0,0 +1,20 @@ +See +``` +% pandoc -f org -t native +Text + +#+include: "command/3510-subdoc.org" + +#+INCLUDE: "command/3510-src.hs" src haskell +#+INCLUDE: "command/3510-export.latex" export latex + +More text +^D +[Para [Str "Text"] +,Header 1 ("subsection",[],[]) [Str "Subsection"] +,Para [Str "Included",Space,Str "text"] +,Plain [Str "Lorem",Space,Str "ipsum."] +,CodeBlock ("",["haskell"],[]) "putStrLn outString\n" +,RawBlock (Format "latex") "\\emph{Hello}" +,Para [Str "More",Space,Str "text"]] +``` -- cgit v1.2.3 From 7b3aaee15ab69cdf3125a214c2124b91622af759 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 17 May 2017 16:23:33 +0200 Subject: Markdown writer: Fixed duplicated reference links with `--reference-links` and `--reference-location=section`. Also ensure that there are no empty link references `[]`. Closes #3674. --- src/Text/Pandoc/Writers/Markdown.hs | 26 +++++++++++++++----------- test/command/3674.md | 26 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 test/command/3674.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 37bb98f5f..b70716181 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -91,6 +91,7 @@ instance Default WriterEnv data WriterState = WriterState { stNotes :: Notes , stRefs :: Refs + , stKeys :: Set.Set Key , stIds :: Set.Set String , stNoteNum :: Int } @@ -98,6 +99,7 @@ data WriterState = WriterState { stNotes :: Notes instance Default WriterState where def = WriterState{ stNotes = [] , stRefs = [] + , stKeys = Set.empty , stIds = Set.empty , stNoteNum = 1 } @@ -798,19 +800,21 @@ getKey = toKey . render Nothing -- Prefer label if possible; otherwise, generate a unique key. getReference :: PandocMonad m => Attr -> Doc -> Target -> MD m Doc getReference attr label target = do - st <- get - let keys = map (\(l,_,_) -> getKey l) (stRefs st) - case find (\(_,t,a) -> t == target && a == attr) (stRefs st) of + refs <- gets stRefs + case find (\(_,t,a) -> t == target && a == attr) refs of Just (ref, _, _) -> return ref Nothing -> do - label' <- case getKey label `elem` keys of - True -> -- label is used; generate numerical label - case find (\n -> Key n `notElem` keys) $ - map show [1..(10000 :: Integer)] of - Just x -> return $ text x - Nothing -> throwError $ PandocSomeError "no unique label" - False -> return label - modify (\s -> s{ stRefs = (label', target, attr) : stRefs st }) + keys <- gets stKeys + label' <- if isEmpty label || getKey label `Set.member` keys + then case find (\n -> not (Key n `Set.member` keys)) $ + map show [1..(10000 :: Integer)] of + Just x -> return $ text x + Nothing -> + throwError $ PandocSomeError "no unique label" + else return label + modify (\s -> s{ stRefs = (label', target, attr) : stRefs s, + stKeys = Set.insert (getKey label') (stKeys s) + }) return label' -- | Convert list of Pandoc inline elements to markdown. diff --git a/test/command/3674.md b/test/command/3674.md new file mode 100644 index 000000000..09f4e0d1e --- /dev/null +++ b/test/command/3674.md @@ -0,0 +1,26 @@ +Make sure we don't get duplicate reference links, even with +`--reference-location=section`. + +``` +% pandoc --reference-links -t markdown --reference-location=section --atx-headers +# a + +![](a) + +# b + +![](b) + +^D +# a + +![][1] + + [1]: a + +# b + +![][2] + + [2]: b +``` -- cgit v1.2.3 From 818d5c2f354cd4896659493452722c030ae7c766 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 18 May 2017 13:20:32 +0200 Subject: Markdown: allow attributes in reference links to start on next line. This addresses a subsidiary issue in #3674. --- src/Text/Pandoc/Readers/Markdown.hs | 4 +++- test/command/3674.md | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 7434ef1f6..af7588562 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -392,7 +392,9 @@ referenceKey = try $ do src <- try betweenAngles <|> sourceURL tit <- option "" referenceTitle attr <- option nullAttr $ try $ - guardEnabled Ext_link_attributes >> skipSpaces >> attributes + do guardEnabled Ext_link_attributes + skipSpaces >> optional newline >> skipSpaces + attributes addKvs <- option [] $ guardEnabled Ext_mmd_link_attributes >> many (try $ spnl >> keyValAttr) blanklines diff --git a/test/command/3674.md b/test/command/3674.md index 09f4e0d1e..92ed4bed7 100644 --- a/test/command/3674.md +++ b/test/command/3674.md @@ -24,3 +24,16 @@ Make sure we don't get duplicate reference links, even with [2]: b ``` + +Subsidiary issue: allow line break between reference link +url/title and attributes: + +``` +% pandoc +[a] + +[a]: url +{.class} +^D +

a

+``` -- cgit v1.2.3 From ca77f0a95e03cace027a235ebbc1effa99ea030a Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 19 May 2017 21:01:45 +0200 Subject: RST writer: add empty comments when needed... to avoid including a blocquote in the indented content of a preceding block. Closes #3675. --- src/Text/Pandoc/Writers/RST.hs | 28 +++++++++++++++++++++++++--- test/command/3675.md | 15 +++++++++++++++ test/writer.rst | 6 ++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 test/command/3675.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index d16f013c0..5dc2ba31a 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -57,6 +57,7 @@ data WriterState = , stHasRawTeX :: Bool , stOptions :: WriterOptions , stTopLevel :: Bool + , stLastNested :: Bool } type RST = StateT WriterState @@ -67,7 +68,7 @@ writeRST opts document = do let st = WriterState { stNotes = [], stLinks = [], stImages = [], stHasMath = False, stHasRawTeX = False, stOptions = opts, - stTopLevel = True} + stTopLevel = True, stLastNested = False} evalStateT (pandocToRST document) st -- | Return RST representation of document. @@ -343,11 +344,32 @@ blockListToRST' :: PandocMonad m -> RST m Doc blockListToRST' topLevel blocks = do tl <- gets stTopLevel - modify (\s->s{stTopLevel=topLevel}) - res <- vcat `fmap` mapM blockToRST blocks + modify (\s->s{stTopLevel=topLevel, stLastNested=False}) + res <- vcat `fmap` mapM blockToRST' blocks modify (\s->s{stTopLevel=tl}) return res +blockToRST' :: PandocMonad m => Block -> RST m Doc +blockToRST' (x@BlockQuote{}) = do + lastNested <- gets stLastNested + res <- blockToRST x + modify (\s -> s{stLastNested = True}) + return $ if lastNested + then ".." $+$ res + else res +blockToRST' x = do + modify (\s -> s{stLastNested = + case x of + Para [Image _ _ (_,'f':'i':'g':':':_)] -> True + Para{} -> False + Plain{} -> False + Header{} -> False + LineBlock{} -> False + HorizontalRule -> False + _ -> True + }) + blockToRST x + blockListToRST :: PandocMonad m => [Block] -- ^ List of block elements -> RST m Doc diff --git a/test/command/3675.md b/test/command/3675.md new file mode 100644 index 000000000..b129c7a63 --- /dev/null +++ b/test/command/3675.md @@ -0,0 +1,15 @@ +```` +% pandoc -t rst +```python +print("hello") +``` +> block quote +^D +.. code:: python + + print("hello") + +.. + + block quote +```` diff --git a/test/writer.rst b/test/writer.rst index 1aeeacacb..1b2f6d1e9 100644 --- a/test/writer.rst +++ b/test/writer.rst @@ -75,6 +75,8 @@ E-mail style: This is a block quote. It is pretty short. +.. + Code in a block quote: :: @@ -92,6 +94,8 @@ E-mail style: nested + .. + nested This should not be a block quote: 2 > 1. @@ -342,6 +346,8 @@ Multiple blocks with italics: { orange code block } + .. + orange block quote Multiple definitions, tight: -- cgit v1.2.3 From 03cb05f4c614f08600bcd8e90a7fd1ca13ae33a2 Mon Sep 17 00:00:00 2001 From: Marc Schreiber Date: Thu, 20 Apr 2017 11:11:01 +0200 Subject: Improve SVG image size code. The old code made some unwise assumptions about how the svg file would look. See #3580. --- pandoc.cabal | 4 + src/Text/Pandoc/ImageSize.hs | 2 +- test/command/SVG_logo-without-xml-declaration.svg | 32 ++++++ test/command/SVG_logo.svg | 33 ++++++ test/command/corrupt.svg | 5 + test/command/inkscape-cube.svg | 119 ++++++++++++++++++++ test/command/svg.md | 129 ++++++++++++++++++++++ 7 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 test/command/SVG_logo-without-xml-declaration.svg create mode 100644 test/command/SVG_logo.svg create mode 100644 test/command/corrupt.svg create mode 100644 test/command/inkscape-cube.svg create mode 100644 test/command/svg.md (limited to 'test/command') diff --git a/pandoc.cabal b/pandoc.cabal index 61ef5c522..14a407b85 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -136,6 +136,10 @@ Extra-Source-Files: test/*.native test/command/*.md test/command/abbrevs + test/command/SVG_logo-without-xml-declaration.svg + test/command/SVG_logo.svg + test/command/corrupt.svg + test/command/inkscape-cube.svg test/command/sub-file-chapter-1.tex test/command/sub-file-chapter-2.tex test/command/3510-subdoc.org diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs index a0800e499..4d914a10c 100644 --- a/src/Text/Pandoc/ImageSize.hs +++ b/src/Text/Pandoc/ImageSize.hs @@ -116,7 +116,7 @@ imageType img = case B.take 4 img of _ -> mzero findSvgTag :: ByteString -> Bool -findSvgTag img = B.null $ snd (B.breakSubstring img " ByteString -> Either String ImageSize imageSize opts img = diff --git a/test/command/SVG_logo-without-xml-declaration.svg b/test/command/SVG_logo-without-xml-declaration.svg new file mode 100644 index 000000000..febcab6ca --- /dev/null +++ b/test/command/SVG_logo-without-xml-declaration.svg @@ -0,0 +1,32 @@ + +SVG Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/command/SVG_logo.svg b/test/command/SVG_logo.svg new file mode 100644 index 000000000..5333a5ddb --- /dev/null +++ b/test/command/SVG_logo.svg @@ -0,0 +1,33 @@ + + +SVG Logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/command/corrupt.svg b/test/command/corrupt.svg new file mode 100644 index 000000000..cfaa697f0 --- /dev/null +++ b/test/command/corrupt.svg @@ -0,0 +1,5 @@ +Lorem ipsum dolor sit amet etiam. A pede dolor neque pretium luctus pharetra vel rutrum. Orci nonummy ac. At eu est tempor +proin wisi. Nunc tincidunt proin. Suspendisse lorem commodo. Integer diam diam semper commodo dictum et tellus eu ultrices +nec erat pulvinar porttitor nulla nulla mauris orci libero eros elementum et possimus voluptate. Velit morbi et. Luctus diam +in. Lorem tincidunt sem dolor rerum mauris. Dis taciti posuere pellentesque sed rutrum. Lectus donec fusce in dictum pede. +In etiam congue. Aliquam aliquet elit arcu mauris enim. Risus at enim. diff --git a/test/command/inkscape-cube.svg b/test/command/inkscape-cube.svg new file mode 100644 index 000000000..995c3c734 --- /dev/null +++ b/test/command/inkscape-cube.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/test/command/svg.md b/test/command/svg.md new file mode 100644 index 000000000..bcf00ddae --- /dev/null +++ b/test/command/svg.md @@ -0,0 +1,129 @@ +``` +% pandoc -f latex -t icml +\includegraphics{command/corrupt.svg} +^D + + + + + + + + + + + + + + + + + + + $ID/Embedded + + + + + + + +``` + +``` +% pandoc -f latex -t icml +\includegraphics{command/SVG_logo.svg} +^D + + + + + + + + + + + + + + + + + + + $ID/Embedded + + + + + + + +``` + +``` +% pandoc -f latex -t icml +\includegraphics{command/SVG_logo-without-xml-declaration.svg} +^D + + + + + + + + + + + + + + + + + + + $ID/Embedded + + + + + + + +``` + + +``` +% pandoc -f latex -t icml +\includegraphics{command/inkscape-cube.svg} +^D + + + + + + + + + + + + + + + + + + + $ID/Embedded + + + + + + + +``` + -- cgit v1.2.3 From c0c54b79063379dc8534a88b4a9cccbe7c9a3b80 Mon Sep 17 00:00:00 2001 From: keiichiro shikano Date: Wed, 24 May 2017 03:53:04 +0900 Subject: RST Reader: parse list table directive (#3688) Closes #3432. --- src/Text/Pandoc/Readers/RST.hs | 29 ++++- test/command/3432.md | 289 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 test/command/3432.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index ac1f4f834..c835ecf52 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -58,7 +58,6 @@ import Text.Printf (printf) -- [ ] .. parsed-literal -- [ ] :widths: attribute in .. table -- [ ] .. csv-table --- [ ] .. list-table -- | Parse reStructuredText string and return Pandoc document. readRST :: PandocMonad m @@ -676,6 +675,7 @@ directive' = do (lengthToDim . filter (not . isSpace)) case label of "table" -> tableDirective top fields body' + "list-table" -> listTableDirective top fields body' "line-block" -> lineBlockDirective body' "raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body) "role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields @@ -762,6 +762,33 @@ tableDirective top _fields body = do aligns' widths' header' rows' _ -> return mempty + +-- TODO: :stub-columns:. +-- Only the first row becomes the header even if header-rows: > 1, since Pandoc doesn't support a table with multiple header rows. +-- We don't need to parse :align: as it represents the whole table align. +listTableDirective :: PandocMonad m => String -> [(String, String)] -> String -> RSTParser m Blocks +listTableDirective top fields body = do + bs <- parseFromString parseBlocks body + title <- parseFromString (trimInlines . mconcat <$> many inline) top + let rows = takeRows $ B.toList bs + headerRowsNum = fromMaybe (0 :: Int) $ lookup "header-rows" fields >>= safeRead + (headerRow,bodyRows,numOfCols) = case rows of + x:xs -> if headerRowsNum > 0 then (x, xs, length x) else ([], rows, length x) + _ -> ([],[],0) + widths = case trim <$> lookup "widths" fields of + Just "auto" -> replicate numOfCols 0 + Just specs -> normWidths $ map (fromMaybe (0 :: Double) . safeRead) $ splitBy (`elem` (" ," :: String)) specs + _ -> replicate numOfCols 0 + return $ B.table title + (zip (replicate numOfCols AlignDefault) widths) + headerRow + bodyRows + where takeRows [BulletList rows] = map takeCells rows + takeRows _ = [] + takeCells [BulletList cells] = map B.fromList cells + takeCells _ = [] + normWidths ws = map (/ max 1 (sum ws)) ws + -- TODO: -- - Only supports :format: fields with a single format for :raw: roles, -- change Text.Pandoc.Definition.Format to fix diff --git a/test/command/3432.md b/test/command/3432.md new file mode 100644 index 000000000..7264d22c3 --- /dev/null +++ b/test/command/3432.md @@ -0,0 +1,289 @@ +List-table with header-rows and widths options. + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + :widths: 15 10 30 + :header-rows: 1 + + * - Treat + - Quantity + - Description + * - Albatross + - 2.99 + - On a stick! + * - Crunchy Frog + - 1.49 + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
TreatQuantityDescription
Albatross2.99On a stick!
Crunchy Frog1.49If we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` + +List-table whose widths is "auto". + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + :header-rows: 1 + :widths: auto + + * - Treat + - Quantity + - Description + * - Albatross + - 2.99 + - On a stick! + * - Crunchy Frog + - 1.49 + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + + + + + + + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
TreatQuantityDescription
Albatross2.99On a stick!
Crunchy Frog1.49If we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` + + +List-table with header-rows which is bigger than 1. Only the first row is treated as a header. + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + :header-rows: 2 + + * - Treat + - Quantity + - Description + * - Albatross + - 2.99 + - On a stick! + * - Crunchy Frog + - 1.49 + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + + + + + + + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
TreatQuantityDescription
Albatross2.99On a stick!
Crunchy Frog1.49If we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` + +List-table without header-rows. + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + + * - Albatross + - 2.99 + - On a stick! + * - Crunchy Frog + - 1.49 + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
Albatross2.99On a stick!
Crunchy Frog1.49If we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` + +List-table with empty cells. You need a space after '-', otherwise the row will disapear. Parser for Bulletlists causes this ristriction. + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + :header-rows: 2 + + * - Treat + - Quantity + - Description + * - Albatross + - 2.99 + - + * - Crunchy Frog + - + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + + + + + + + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
TreatQuantityDescription
Albatross2.99
Crunchy FrogIf we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` + +List-table with a cell having a bulletlist + +``` +% pandoc -f rst +.. list-table:: Frozen Delights! + + * - Albatross + - 2.99 + - + On a stick! + + In a cup! + * - Crunchy Frog + - 1.49 + - If we took the bones out, it wouldn't be + crunchy, now would it? + * - Gannet Ripple + - 1.99 + - On a stick! +^D + + + + + + + + + + + + + + + + + + + +
Frozen Delights!
Albatross2.99
    +
  • On a stick!
  • +
  • In a cup!
  • +
Crunchy Frog1.49If we took the bones out, it wouldn't be crunchy, now would it?
Gannet Ripple1.99On a stick!
+``` -- cgit v1.2.3 From bc6aac7b474495c4433c31bcd4a3570057edb850 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 24 May 2017 22:41:47 +0200 Subject: Parsing: Provide parseFromString'. This is a verison of parseFromString specialied to ParserState, which resets stateLastStrPos at the end. This is almost always what we want. This fixes a bug where `_hi_` wasn't treated as emphasis in the following, because pandoc got confused about the position of the last word: - [o] _hi_ Closes #3690. --- src/Text/Pandoc/Parsing.hs | 18 ++++++++++++- src/Text/Pandoc/Readers/LaTeX.hs | 12 ++++----- src/Text/Pandoc/Readers/Markdown.hs | 40 +++++++++++++++-------------- src/Text/Pandoc/Readers/RST.hs | 50 ++++++++++++++++++------------------- src/Text/Pandoc/Readers/TWiki.hs | 8 +++--- src/Text/Pandoc/Readers/Textile.hs | 8 +++--- src/Text/Pandoc/Readers/Txt2Tags.hs | 6 ++--- test/command/3690.md | 8 ++++++ 8 files changed, 88 insertions(+), 62 deletions(-) create mode 100644 test/command/3690.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index c6be48d19..e6157dde3 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -50,6 +50,7 @@ module Text.Pandoc.Parsing ( anyLine, enclosed, stringAnyCase, parseFromString, + parseFromString', lineClump, charsInBalanced, romanNumeral, @@ -358,7 +359,10 @@ stringAnyCase (x:xs) = do return (firstChar:rest) -- | Parse contents of 'str' using 'parser' and return result. -parseFromString :: Monad m => ParserT String st m a -> String -> ParserT String st m a +parseFromString :: Monad m + => ParserT String st m a + -> String + -> ParserT String st m a parseFromString parser str = do oldPos <- getPosition oldInput <- getInput @@ -370,6 +374,18 @@ parseFromString parser str = do setPosition oldPos return result +-- | Like 'parseFromString' but specialized for 'ParserState'. +-- This resets 'stateLastStrPos', which is almost always what we want. +parseFromString' :: Monad m + => ParserT String ParserState m a + -> String + -> ParserT String ParserState m a +parseFromString' parser str = do + oldStrPos <- stateLastStrPos <$> getState + res <- parseFromString parser str + updateState $ \st -> st{ stateLastStrPos = oldStrPos } + return res + -- | Parse raw line block up to and including blank lines. lineClump :: Stream [Char] m Char => ParserT [Char] st m String lineClump = blanklines diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index af7c1d9b7..88be40e3e 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -304,8 +304,8 @@ blockCommand = try $ do rawcommand <- getRawCommand name' transformed <- applyMacros' rawcommand guard $ transformed /= rawcommand - notFollowedBy $ parseFromString inlines transformed - parseFromString blocks transformed + notFollowedBy $ parseFromString' inlines transformed + parseFromString' blocks transformed lookupListDefault raw [name',name] blockCommands inBrackets :: Inlines -> Inlines @@ -475,7 +475,7 @@ inlineCommand = try $ do transformed <- applyMacros' rawcommand exts <- getOption readerExtensions if transformed /= rawcommand - then parseFromString inlines transformed + then parseFromString' inlines transformed else if extensionEnabled Ext_raw_tex exts then return $ rawInline "latex" rawcommand else ignore rawcommand @@ -1021,7 +1021,7 @@ rawEnv name = do (bs, raw) <- withRaw $ env name blocks raw' <- applyMacros' $ beginCommand ++ raw if raw' /= beginCommand ++ raw - then parseFromString blocks raw' + then parseFromString' blocks raw' else if parseRaw then return $ rawBlock "latex" $ beginCommand ++ raw' else do @@ -1119,7 +1119,7 @@ keyvals :: PandocMonad m => LP m [(String, String)] keyvals = try $ char '[' *> manyTill keyval (char ']') alltt :: PandocMonad m => String -> LP m Blocks -alltt t = walk strToCode <$> parseFromString blocks +alltt t = walk strToCode <$> parseFromString' blocks (substitute " " "\\ " $ substitute "%" "\\%" $ intercalate "\\\\\n" $ lines t) where strToCode (Str s) = Code nullAttr s @@ -1503,7 +1503,7 @@ parseTableRow cols prefixes suffixes = try $ do guard $ length rawcells == cols let rawcells' = zipWith3 (\c p s -> p ++ trim c ++ s) rawcells prefixes suffixes - cells' <- mapM (parseFromString tableCell) rawcells' + cells' <- mapM (parseFromString' tableCell) rawcells' let numcells = length cells' guard $ numcells <= cols && numcells >= 1 guard $ cells' /= [mempty] diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index af7588562..17a7184c0 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -155,9 +155,11 @@ litChar = escapedChar' inlinesInBalancedBrackets :: PandocMonad m => MarkdownParser m (F Inlines) inlinesInBalancedBrackets = do char '[' + pos <- getPosition (_, raw) <- withRaw $ charsInBalancedBrackets 1 guard $ not $ null raw - parseFromString (trimInlinesF . mconcat <$> many inline) (init raw) + parseFromString' (setPosition pos >> + trimInlinesF . mconcat <$> many inline) (init raw) charsInBalancedBrackets :: PandocMonad m => Int -> MarkdownParser m () charsInBalancedBrackets 0 = return () @@ -189,7 +191,7 @@ rawTitleBlockLine = do titleLine :: PandocMonad m => MarkdownParser m (F Inlines) titleLine = try $ do raw <- rawTitleBlockLine - res <- parseFromString (many inline) raw + res <- parseFromString' (many inline) raw return $ trimInlinesF $ mconcat res authorsLine :: PandocMonad m => MarkdownParser m (F [Inlines]) @@ -200,12 +202,12 @@ authorsLine = try $ do (trimInlinesF . mconcat <$> many (try $ notFollowedBy sep >> inline)) sep - sequence <$> parseFromString pAuthors raw + sequence <$> parseFromString' pAuthors raw dateLine :: PandocMonad m => MarkdownParser m (F Inlines) dateLine = try $ do raw <- rawTitleBlockLine - res <- parseFromString (many inline) raw + res <- parseFromString' (many inline) raw return $ trimInlinesF $ mconcat res titleBlock :: PandocMonad m => MarkdownParser m () @@ -290,7 +292,7 @@ ignorable t = (T.pack "_") `T.isSuffixOf` t toMetaValue :: PandocMonad m => Text -> MarkdownParser m (F MetaValue) -toMetaValue x = toMeta <$> parseFromString parseBlocks (T.unpack x) +toMetaValue x = toMeta <$> parseFromString' parseBlocks (T.unpack x) where toMeta p = do p' <- p @@ -466,7 +468,7 @@ noteBlock = try $ do rest <- many $ try $ blanklines >> indentSpaces >> rawLines let raw = unlines (first:rest) ++ "\n" optional blanklines - parsed <- parseFromString parseBlocks raw + parsed <- parseFromString' parseBlocks raw let newnote = (ref, parsed) oldnotes <- stateNotes' <$> getState case lookup ref oldnotes of @@ -774,7 +776,7 @@ blockQuote :: PandocMonad m => MarkdownParser m (F Blocks) blockQuote = do raw <- emailBlockQuote -- parse the extracted block, which may contain various block elements: - contents <- parseFromString parseBlocks $ (intercalate "\n" raw) ++ "\n\n" + contents <- parseFromString' parseBlocks $ (intercalate "\n" raw) ++ "\n\n" return $ B.blockQuote <$> contents -- @@ -887,7 +889,7 @@ listItem start = try $ do setState $ state {stateParserContext = ListItemState} -- parse the extracted block, which may contain various block elements: let raw = concat (first:continuations) - contents <- parseFromString parseBlocks raw + contents <- parseFromString' parseBlocks raw updateState (\st -> st {stateParserContext = oldContext}) return contents @@ -934,8 +936,8 @@ definitionListItem :: PandocMonad m => Bool -> MarkdownParser m (F (Inlines, [Bl definitionListItem compact = try $ do rawLine' <- anyLine raw <- many1 $ defRawBlock compact - term <- parseFromString (trimInlinesF . mconcat <$> many inline) rawLine' - contents <- mapM (parseFromString parseBlocks . (++"\n")) raw + term <- parseFromString' (trimInlinesF . mconcat <$> many inline) rawLine' + contents <- mapM (parseFromString' parseBlocks . (++"\n")) raw optional blanklines return $ liftM2 (,) term (sequence contents) @@ -1127,7 +1129,7 @@ lineBlock :: PandocMonad m => MarkdownParser m (F Blocks) lineBlock = try $ do guardEnabled Ext_line_blocks lines' <- lineBlockLines >>= - mapM (parseFromString (trimInlinesF . mconcat <$> many inline)) + mapM (parseFromString' (trimInlinesF . mconcat <$> many inline)) return $ B.lineBlock <$> sequence lines' -- @@ -1170,7 +1172,7 @@ simpleTableHeader headless = try $ do then replicate (length dashes) "" else rawHeads heads <- fmap sequence - $ mapM (parseFromString (mconcat <$> many plain)) + $ mapM (parseFromString' (mconcat <$> many plain)) $ map trim rawHeads' return (heads, aligns, indices) @@ -1216,7 +1218,7 @@ tableLine :: PandocMonad m => [Int] -> MarkdownParser m (F [Blocks]) tableLine indices = rawTableLine indices >>= - fmap sequence . mapM (parseFromString (mconcat <$> many plain)) + fmap sequence . mapM (parseFromString' (mconcat <$> many plain)) -- Parse a multiline table row and return a list of blocks (columns). multilineRow :: PandocMonad m @@ -1225,7 +1227,7 @@ multilineRow :: PandocMonad m multilineRow indices = do colLines <- many1 (rawTableLine indices) let cols = map unlines $ transpose colLines - fmap sequence $ mapM (parseFromString (mconcat <$> many plain)) cols + fmap sequence $ mapM (parseFromString' (mconcat <$> many plain)) cols -- Parses a table caption: inlines beginning with 'Table:' -- and followed by blank lines. @@ -1283,7 +1285,7 @@ multilineTableHeader headless = try $ do then replicate (length dashes) "" else map (unlines . map trim) rawHeadsList heads <- fmap sequence $ - mapM (parseFromString (mconcat <$> many plain)) $ + mapM (parseFromString' (mconcat <$> many plain)) $ map trim rawHeads return (heads, aligns, indices) @@ -1340,7 +1342,7 @@ pipeTableRow = try $ do let chunk = void (code <|> math <|> rawHtmlInline <|> escapedChar <|> rawLaTeXInline') <|> void (noneOf "|\n\r") let cellContents = ((trim . snd) <$> withRaw (many chunk)) >>= - parseFromString pipeTableCell + parseFromString' pipeTableCell cells <- cellContents `sepEndBy1` (char '|') -- surrounding pipes needed for a one-column table: guard $ not (length cells == 1 && not openPipe) @@ -1747,8 +1749,8 @@ referenceLink constructor (lab, raw) = do 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' - fallback <- parseFromString (mconcat <$> many inline) $ dropBrackets raw + parsedRaw <- parseFromString' (mconcat <$> many inline) raw' + fallback <- parseFromString' (mconcat <$> many inline) $ dropBrackets raw implicitHeaderRefs <- option False $ True <$ guardEnabled Ext_implicit_header_references let makeFallback = do @@ -1954,7 +1956,7 @@ textualCite = try $ do let (spaces',raw') = span isSpace raw spc | null spaces' = mempty | otherwise = B.space - lab <- parseFromString (mconcat <$> many inline) $ dropBrackets raw' + lab <- parseFromString' (mconcat <$> many inline) $ dropBrackets raw' fallback <- referenceLink B.linkWith (lab,raw') return $ do fallback' <- fallback diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index e3780f89b..1ea142112 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -196,7 +196,7 @@ parseRST = do parseCitation :: PandocMonad m => (String, String) -> RSTParser m (Inlines, [Blocks]) parseCitation (ref, raw) = do - contents <- parseFromString parseBlocks raw + contents <- parseFromString' parseBlocks raw return $ (B.spanWith (ref, ["citation-label"], []) (B.str ref), [contents]) @@ -246,7 +246,7 @@ fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks]) fieldListItem minIndent = try $ do (name, raw) <- rawFieldListItem minIndent term <- parseInlineFromString name - contents <- parseFromString parseBlocks raw + contents <- parseFromString' parseBlocks raw optional blanklines return (term, [contents]) @@ -445,7 +445,7 @@ blockQuote :: PandocMonad m => RSTParser m Blocks blockQuote = do raw <- indentedBlock -- parse the extracted block, which may contain various block elements: - contents <- parseFromString parseBlocks $ raw ++ "\n\n" + contents <- parseFromString' parseBlocks $ raw ++ "\n\n" return $ B.blockQuote contents {- @@ -533,7 +533,7 @@ definitionListItem = try $ do term <- trimInlines . mconcat <$> many1Till inline endline raw <- indentedBlock -- parse the extracted block, which may contain various block elements: - contents <- parseFromString parseBlocks $ raw ++ "\n" + contents <- parseFromString' parseBlocks $ raw ++ "\n" return (term, [contents]) definitionList :: PandocMonad m => RSTParser m Blocks @@ -595,7 +595,7 @@ listItem start = try $ do let oldContext = stateParserContext state setState $ state {stateParserContext = ListItemState} -- parse the extracted block, which may itself contain block elements - parsed <- parseFromString parseBlocks $ concat (first:rest) ++ "\n" + parsed <- parseFromString' parseBlocks $ concat (first:rest) ++ "\n" updateState (\st -> st {stateParserContext = oldContext}) return $ case B.toList parsed of [Para xs] -> @@ -686,19 +686,19 @@ directive' = do "line-block" -> lineBlockDirective body' "raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body) "role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields - "container" -> parseFromString parseBlocks body' + "container" -> parseFromString' parseBlocks body' "replace" -> B.para <$> -- consumed by substKey parseInlineFromString (trim top) "unicode" -> B.para <$> -- consumed by substKey parseInlineFromString (trim $ unicodeTransform top) - "compound" -> parseFromString parseBlocks body' - "pull-quote" -> B.blockQuote <$> parseFromString parseBlocks body' - "epigraph" -> B.blockQuote <$> parseFromString parseBlocks body' - "highlights" -> B.blockQuote <$> parseFromString parseBlocks body' + "compound" -> parseFromString' parseBlocks body' + "pull-quote" -> B.blockQuote <$> parseFromString' parseBlocks body' + "epigraph" -> B.blockQuote <$> parseFromString' parseBlocks body' + "highlights" -> B.blockQuote <$> parseFromString' parseBlocks body' "rubric" -> B.para . B.strong <$> parseInlineFromString top _ | label `elem` ["attention","caution","danger","error","hint", "important","note","tip","warning","admonition"] -> - do bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body' + do bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body' let lab = case label of "admonition" -> mempty (l:ls) -> B.divWith ("",["admonition-title"],[]) @@ -711,11 +711,11 @@ directive' = do (trim top ++ if null subtit then "" else (": " ++ subtit)) - bod <- parseFromString parseBlocks body' + bod <- parseFromString' parseBlocks body' return $ B.divWith ("",["sidebar"],[]) $ tit <> bod "topic" -> do tit <- B.para . B.strong <$> parseInlineFromString top - bod <- parseFromString parseBlocks body' + bod <- parseFromString' parseBlocks body' return $ B.divWith ("",["topic"],[]) $ tit <> bod "default-role" -> mempty <$ updateState (\s -> s { stateRstDefaultRole = @@ -731,7 +731,7 @@ directive' = do "math" -> return $ B.para $ mconcat $ map B.displayMath $ toChunks $ top ++ "\n\n" ++ body "figure" -> do - (caption, legend) <- parseFromString extractCaption body' + (caption, legend) <- parseFromString' extractCaption body' let src = escapeURI $ trim top return $ B.para (B.imageWith (imgAttr "figclass") src "fig:" caption) <> legend @@ -750,21 +750,21 @@ directive' = do -- directive content or the first immediately following element children <- case body of "" -> block - _ -> parseFromString parseBlocks body' + _ -> parseFromString' parseBlocks body' return $ B.divWith attrs children other -> do pos <- getPosition logMessage $ SkippedContent (".. " ++ other) pos - bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body' + bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body' return $ B.divWith ("",[other],[]) bod tableDirective :: PandocMonad m => String -> [(String, String)] -> String -> RSTParser m Blocks tableDirective top _fields body = do - bs <- parseFromString parseBlocks body + bs <- parseFromString' parseBlocks body case B.toList bs of [Table _ aligns' widths' header' rows'] -> do - title <- parseFromString (trimInlines . mconcat <$> many inline) top + title <- parseFromString' (trimInlines . mconcat <$> many inline) top -- TODO widths -- align is not applicable since we can't represent whole table align return $ B.singleton $ Table (B.toList title) @@ -780,8 +780,8 @@ listTableDirective :: PandocMonad m => String -> [(String, String)] -> String -> RSTParser m Blocks listTableDirective top fields body = do - bs <- parseFromString parseBlocks body - title <- parseFromString (trimInlines . mconcat <$> many inline) top + bs <- parseFromString' parseBlocks body + title <- parseFromString' (trimInlines . mconcat <$> many inline) top let rows = takeRows $ B.toList bs headerRowsNum = fromMaybe (0 :: Int) $ lookup "header-rows" fields >>= safeRead @@ -812,7 +812,7 @@ addNewRole :: PandocMonad m => String -> [(String, String)] -> RSTParser m Blocks addNewRole roleString fields = do pos <- getPosition - (role, parentRole) <- parseFromString inheritedRole roleString + (role, parentRole) <- parseFromString' inheritedRole roleString customRoles <- stateRstCustomRoles <$> getState let getBaseRole (r, f, a) roles = case M.lookup r roles of @@ -1127,7 +1127,7 @@ simpleTableRow indices = do let cols = map unlines . transpose $ firstLine : conLines ++ [replicate (length indices) "" | not (null conLines)] - mapM (parseFromString parseBlocks) cols + mapM (parseFromString' parseBlocks) cols simpleTableSplitLine :: [Int] -> String -> [String] simpleTableSplitLine indices line = @@ -1150,7 +1150,7 @@ simpleTableHeader headless = try $ do let rawHeads = if headless then replicate (length dashes) "" else simpleTableSplitLine indices rawContent - heads <- mapM (parseFromString (mconcat <$> many plain)) $ + heads <- mapM (parseFromString' (mconcat <$> many plain)) $ map trim rawHeads return (heads, aligns, indices) @@ -1206,7 +1206,7 @@ inline = choice [ note -- can start with whitespace, so try before ws , symbol ] "inline" parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines -parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline) +parseInlineFromString = parseFromString' (trimInlines . mconcat <$> many inline) hyphens :: Monad m => RSTParser m Inlines hyphens = do @@ -1470,7 +1470,7 @@ note = try $ do -- Note references inside other notes are allowed in reST, but -- not yet in this implementation. updateState $ \st -> st{ stateNotes = [] } - contents <- parseFromString parseBlocks raw + contents <- parseFromString' parseBlocks raw let newnotes = if (ref == "*" || ref == "#") -- auto-numbered -- delete the note so the next auto-numbered note -- doesn't get the same contents: diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs index ecb609ae9..aea55b7a9 100644 --- a/src/Text/Pandoc/Readers/TWiki.hs +++ b/src/Text/Pandoc/Readers/TWiki.hs @@ -106,7 +106,7 @@ parseHtmlContentWithAttrs tag parser = do parsedContent <- try $ parseContent content return (attr, parsedContent) where - parseContent = parseFromString $ nested $ manyTill parser endOfContent + parseContent = parseFromString' $ nested $ manyTill parser endOfContent endOfContent = try $ skipMany blankline >> skipSpaces >> eof parseHtmlContent :: PandocMonad m => String -> TWParser m a -> TWParser m [a] @@ -233,7 +233,7 @@ listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat filterSpaces = reverse . dropWhile (== ' ') . reverse listContinuation = notFollowedBy (string prefix >> marker) >> string " " >> lineContent - parseContent = parseFromString $ many1 $ nestedList <|> parseInline + parseContent = parseFromString' $ many1 $ nestedList <|> parseInline parseInline = many1Till inline (lastNewline <|> newlineBeforeNestedList) >>= return . B.plain . mconcat nestedList = list prefix @@ -297,7 +297,7 @@ noautolink = do setState $ st{ stateAllowLinks = True } return $ mconcat blocks where - parseContent = parseFromString $ many $ block + parseContent = parseFromString' $ many $ block para :: PandocMonad m => TWParser m B.Blocks para = many1Till inline endOfParaElement >>= return . result . mconcat @@ -525,4 +525,4 @@ linkText = do return (url, "", content) where linkContent = (char '[') >> many1Till anyChar (char ']') >>= parseLinkContent - parseLinkContent = parseFromString $ many1 inline + parseLinkContent = parseFromString' $ many1 inline diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs index abf8be452..52f4f2493 100644 --- a/src/Text/Pandoc/Readers/Textile.hs +++ b/src/Text/Pandoc/Readers/Textile.hs @@ -315,7 +315,7 @@ definitionListItem = try $ do optional whitespace >> newline s <- many1Till anyChar (try (string "=:" >> newline)) -- this ++ "\n\n" does not look very good - ds <- parseFromString parseBlocks (s ++ "\n\n") + ds <- parseFromString' parseBlocks (s ++ "\n\n") return [ds] -- raw content @@ -367,7 +367,7 @@ tableCell = try $ do notFollowedBy blankline raw <- trim <$> many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline)) - content <- mconcat <$> parseFromString (many inline) raw + content <- mconcat <$> parseFromString' (many inline) raw return ((isHeader, alignment), B.plain content) -- | A table row is made of many table cells @@ -389,7 +389,7 @@ table = try $ do _ <- attributes char '.' rawcapt <- trim <$> anyLine - parseFromString (mconcat <$> many inline) rawcapt + parseFromString' (mconcat <$> many inline) rawcapt rawrows <- many1 $ (skipMany ignorableRow) >> tableRow skipMany ignorableRow blanklines @@ -507,7 +507,7 @@ note = try $ do notes <- stateNotes <$> getState case lookup ref notes of Nothing -> fail "note not found" - Just raw -> B.note <$> parseFromString parseBlocks raw + Just raw -> B.note <$> parseFromString' parseBlocks raw -- | Special chars markupChars :: [Char] diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs index 05c6c9a69..d8791869d 100644 --- a/src/Text/Pandoc/Readers/Txt2Tags.hs +++ b/src/Text/Pandoc/Readers/Txt2Tags.hs @@ -212,7 +212,7 @@ quote :: T2T Blocks quote = try $ do lookAhead tab rawQuote <- many1 (tab *> optional spaces *> anyLine) - contents <- parseFromString parseBlocks (intercalate "\n" rawQuote ++ "\n\n") + contents <- parseFromString' parseBlocks (intercalate "\n" rawQuote ++ "\n\n") return $ B.blockQuote contents commentLine :: T2T Inlines @@ -264,7 +264,7 @@ listItem start end = try $ do firstLine <- anyLineNewline blank <- option "" ("\n" <$ blankline) rest <- concat <$> many (listContinuation markerLength) - parseFromString end $ firstLine ++ blank ++ rest + parseFromString' end $ firstLine ++ blank ++ rest -- continuation of a list item - indented and separated by blankline or endline. -- Note: nested lists are parsed as continuations. @@ -439,7 +439,7 @@ inlineMarkup p f c special = try $ do Just middle -> do lastChar <- anyChar end <- many1 (char c) - let parser inp = parseFromString (mconcat <$> many p) inp + let parser inp = parseFromString' (mconcat <$> many p) inp let start' = case drop 2 start of "" -> mempty xs -> special xs diff --git a/test/command/3690.md b/test/command/3690.md new file mode 100644 index 000000000..213b88138 --- /dev/null +++ b/test/command/3690.md @@ -0,0 +1,8 @@ +``` +% pandoc +- [o] _hi_ +^D +
    +
  • [o] hi
  • +
+``` -- cgit v1.2.3 From b9a30ef9596b8d19554e03cd1ef8f0dc0695a486 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 24 May 2017 23:23:08 +0200 Subject: Markdown reader: fixed smart quotes after emphasis. E.g. in *foo*'s 'foo' Closes #2228. --- src/Text/Pandoc/Readers/Markdown.hs | 11 ++++++----- test/command/2228.md | 6 ++++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 test/command/2228.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 17a7184c0..3e3de0d9d 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1557,9 +1557,9 @@ ender c n = try $ do three :: PandocMonad m => Char -> MarkdownParser m (F Inlines) three c = do contents <- mconcat <$> many (notFollowedBy (ender c 1) >> inline) - (ender c 3 >> return ((B.strong . B.emph) <$> contents)) - <|> (ender c 2 >> one c (B.strong <$> contents)) - <|> (ender c 1 >> two c (B.emph <$> contents)) + (ender c 3 >> updateLastStrPos >> return ((B.strong . B.emph) <$> contents)) + <|> (ender c 2 >> updateLastStrPos >> one c (B.strong <$> contents)) + <|> (ender c 1 >> updateLastStrPos >> two c (B.emph <$> contents)) <|> return (return (B.str [c,c,c]) <> contents) -- Parse inlines til you hit two c's, and emit strong. @@ -1567,7 +1567,8 @@ three c = do two :: PandocMonad m => Char -> F Inlines -> MarkdownParser m (F Inlines) two c prefix' = do contents <- mconcat <$> many (try $ notFollowedBy (ender c 2) >> inline) - (ender c 2 >> return (B.strong <$> (prefix' <> contents))) + (ender c 2 >> updateLastStrPos >> + return (B.strong <$> (prefix' <> contents))) <|> return (return (B.str [c,c]) <> (prefix' <> contents)) -- Parse inlines til you hit a c, and emit emph. @@ -1578,7 +1579,7 @@ one c prefix' = do <|> try (string [c,c] >> notFollowedBy (ender c 1) >> two c mempty) ) - (ender c 1 >> return (B.emph <$> (prefix' <> contents))) + (ender c 1 >> updateLastStrPos >> return (B.emph <$> (prefix' <> contents))) <|> return (return (B.str [c]) <> (prefix' <> contents)) strongOrEmph :: PandocMonad m => MarkdownParser m (F Inlines) diff --git a/test/command/2228.md b/test/command/2228.md new file mode 100644 index 000000000..589a2350e --- /dev/null +++ b/test/command/2228.md @@ -0,0 +1,6 @@ +``` +% pandoc -f markdown+smart -t latex+smart +*foo*'s 'foo' +^D +\emph{foo}'s `foo' +``` -- cgit v1.2.3 From 41db9e826e5be45d087b1959d6d5dbeb8389e2a7 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 25 May 2017 09:35:25 +0200 Subject: MediaWiki reader: don't do curly quotes inside `` contexts. Even if `+smart`. See #3585. --- src/Text/Pandoc/Readers/MediaWiki.hs | 11 ++++++++++- test/command/3585.md | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/command/3585.md (limited to 'test/command') diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs index b261021e0..3f6142f00 100644 --- a/src/Text/Pandoc/Readers/MediaWiki.hs +++ b/src/Text/Pandoc/Readers/MediaWiki.hs @@ -74,6 +74,7 @@ readMediaWiki opts s = do , mwHeaderMap = M.empty , mwIdentifierList = Set.empty , mwLogMessages = [] + , mwInTT = False } (s ++ "\n") case parsed of @@ -87,6 +88,7 @@ data MWState = MWState { mwOptions :: ReaderOptions , mwHeaderMap :: M.Map Inlines String , mwIdentifierList :: Set.Set String , mwLogMessages :: [LogMessage] + , mwInTT :: Bool } type MWParser m = ParserT [Char] MWState m @@ -569,7 +571,12 @@ inlineTag = do TagOpen "sub" _ -> B.subscript <$> inlinesInTags "sub" TagOpen "sup" _ -> B.superscript <$> inlinesInTags "sup" TagOpen "code" _ -> encode <$> inlinesInTags "code" - TagOpen "tt" _ -> encode <$> inlinesInTags "tt" + TagOpen "tt" _ -> do + inTT <- mwInTT <$> getState + updateState $ \st -> st{ mwInTT = True } + result <- encode <$> inlinesInTags "tt" + updateState $ \st -> st{ mwInTT = inTT } + return result TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask" _ -> B.rawInline "html" . snd <$> htmlTag (~== tag) @@ -690,6 +697,8 @@ strong = B.strong <$> nested (inlinesBetween start end) doubleQuotes :: PandocMonad m => MWParser m Inlines doubleQuotes = do guardEnabled Ext_smart + inTT <- mwInTT <$> getState + guard (not inTT) B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote) where openDoubleQuote = sym "\"" >> lookAhead nonspaceChar closeDoubleQuote = try $ sym "\"" diff --git a/test/command/3585.md b/test/command/3585.md new file mode 100644 index 000000000..739ddeea4 --- /dev/null +++ b/test/command/3585.md @@ -0,0 +1,16 @@ +``` +% pandoc -f mediawiki+smart -t native +"Hello" + +Same but bzip2 it and nice it zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org "> /storage/c-3po/tank-storage-data-svn.dmp.bz2" +^D +[Para [Quoted DoubleQuote [Str "Hello"]] +,Para [Str "Same",Space,Str "but",Space,Str "bzip2",Space,Str "it",Space,Str "and",Space,Str "nice",Space,Str "it",Space,Code ("",[],[]) "zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org \"> /storage/c-3po/tank-storage-data-svn.dmp.bz2\""]] +``` + +``` +% pandoc -f mediawiki -t native +"Hello" +^D +[Para [Str "\"Hello\""]] +``` -- cgit v1.2.3 From e34131502af7ac16bac60a0a8081ffc45d6b1b1e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 25 May 2017 11:52:09 +0200 Subject: Update command tests to include stderr output. --- test/command/1718.md | 11 +++++++++++ test/command/3494.md | 2 +- test/command/3577.md | 2 +- test/command/512.md | 1 + test/command/parse-raw.md | 3 +++ test/command/svg.md | 3 +++ test/command/tabularx.md | 6 +++--- 7 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 test/command/1718.md (limited to 'test/command') diff --git a/test/command/1718.md b/test/command/1718.md new file mode 100644 index 000000000..401610a7a --- /dev/null +++ b/test/command/1718.md @@ -0,0 +1,11 @@ +``` +% pandoc -t native +Note[^1]. + +[^1]: the first note. + +[^2]: the second, unused, note. +^D +[warning] Note with key '2' defined at line 5 column 1 but not used. +[Para [Str "Note",Note [Para [Str "the",Space,Str "first",Space,Str "note."]],Str "."]] +``` diff --git a/test/command/3494.md b/test/command/3494.md index faa58c321..7c480fde6 100644 --- a/test/command/3494.md +++ b/test/command/3494.md @@ -1,5 +1,5 @@ ``` -% pandoc -f latex +% pandoc -f latex --quiet \begin{table}[h!] \begin{tabular}{r|l|l} diff --git a/test/command/3577.md b/test/command/3577.md index bfeb86eaa..dc88937e9 100644 --- a/test/command/3577.md +++ b/test/command/3577.md @@ -1,5 +1,5 @@ ``` -% pandoc -f latex -t html5 +% pandoc -f latex -t html5 --quiet \begin{figure}[ht] \begin{subfigure}{0.45\textwidth} \centering diff --git a/test/command/512.md b/test/command/512.md index a13c434f6..52e5dbe07 100644 --- a/test/command/512.md +++ b/test/command/512.md @@ -36,6 +36,7 @@ Loop detection: __ link1_ ^D +[warning] Circular reference 'link1' at line 1 column 15

click here

``` diff --git a/test/command/parse-raw.md b/test/command/parse-raw.md index f4e493c69..6c91c2fa9 100644 --- a/test/command/parse-raw.md +++ b/test/command/parse-raw.md @@ -9,6 +9,7 @@ % pandoc -f latex -t markdown \emph{Hi \foo{there}} ^D +[warning] Skipped '\foo{there}' at line 1 column 21 *Hi* ``` @@ -23,5 +24,7 @@ % pandoc -f html -t markdown Hi there ^D +[warning] Skipped '' at input line 1 column 8 +[warning] Skipped '' at input line 1 column 20 *Hi there* ``` diff --git a/test/command/svg.md b/test/command/svg.md index bcf00ddae..36ca2fdb7 100644 --- a/test/command/svg.md +++ b/test/command/svg.md @@ -2,6 +2,7 @@ % pandoc -f latex -t icml \includegraphics{command/corrupt.svg} ^D +[warning] Could not determine image size for 'command/corrupt.svg': could not determine image type @@ -34,6 +35,7 @@ % pandoc -f latex -t icml \includegraphics{command/SVG_logo.svg} ^D +[warning] Could not determine image size for 'command/SVG_logo.svg': could not determine SVG size @@ -66,6 +68,7 @@ % pandoc -f latex -t icml \includegraphics{command/SVG_logo-without-xml-declaration.svg} ^D +[warning] Could not determine image size for 'command/SVG_logo-without-xml-declaration.svg': could not determine SVG size diff --git a/test/command/tabularx.md b/test/command/tabularx.md index 1d295c978..9e6069542 100644 --- a/test/command/tabularx.md +++ b/test/command/tabularx.md @@ -1,5 +1,5 @@ ``` -% pandoc -f latex -t native +% pandoc -f latex -t native --quiet \begin{tabularx}{\linewidth}{|c|c|c|} \hline Column Heading 1 @@ -36,7 +36,7 @@ ``` ``` -% pandoc -f latex -t native +% pandoc -f latex -t native --quiet \begin{tabularx}{\linewidth}{|X|c|p{0.25\linewidth}|} \hline Column Heading 1 @@ -73,7 +73,7 @@ ``` ``` -% pandoc -f latex -t native +% pandoc -f latex -t native --quiet \begin{tabularx}{\linewidth}{|b{0.25\linewidth}|c|m{0.25\linewidth}|} \hline Column Heading 1 -- cgit v1.2.3 From 708973a33a0ce425bb21a5ffa06fbdab465d3fb8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 25 May 2017 12:50:43 +0200 Subject: Added `spaced_reference_links` extension. This is now the default for pandoc's Markdown. It allows whitespace between the two parts of a reference link: e.g. [a] [b] [b]: url This is now forbidden by default. Closes #2602. --- MANUAL.txt | 10 +- src/Text/Pandoc/Extensions.hs | 6 +- src/Text/Pandoc/Readers/Markdown.hs | 8 +- test/command/2602.md | 18 + test/testsuite.native | 2 - test/testsuite.txt | 11 +- test/writer.asciidoc | 4 - test/writer.context | 40 +- test/writer.docbook4 | 6 - test/writer.docbook5 | 6 - test/writer.dokuwiki | 4 - test/writer.fb2 | 1014 ++++++++++++++++++++++++++++++++++- test/writer.haddock | 4 - test/writer.html4 | 2 - test/writer.html5 | 2 - test/writer.icml | 102 ++-- test/writer.jats | 6 - test/writer.latex | 4 - test/writer.man | 4 - test/writer.markdown | 4 - test/writer.mediawiki | 4 - test/writer.ms | 10 - test/writer.muse | 4 - test/writer.native | 2 - test/writer.opendocument | 4 - test/writer.opml | 2 +- test/writer.org | 4 - test/writer.plain | 4 - test/writer.rst | 4 - test/writer.rtf | 8 - test/writer.tei | 2 - test/writer.texinfo | 4 - test/writer.textile | 4 - test/writer.zimwiki | 4 - 34 files changed, 1101 insertions(+), 216 deletions(-) create mode 100644 test/command/2602.md (limited to 'test/command') diff --git a/MANUAL.txt b/MANUAL.txt index 170af0d6f..2cd35d14d 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -3100,7 +3100,8 @@ definition, which may occur elsewhere in the document (either before or after the link). The link consists of link text in square brackets, followed by a label in -square brackets. (There can be space between the two.) The link definition +square brackets. (There cannot be space between the two unless the +`spaced_reference_links` extension is enabled.) The link definition consists of the bracketed label, followed by a colon and a space, followed by the URL, and optionally (after a space) a link title either in quotes or in parentheses. The label must not be parseable as a citation (assuming @@ -3551,6 +3552,13 @@ implied by pandoc's default `all_symbols_escapable`. Allow a list to occur right after a paragraph, with no intervening blank space. +#### Extension: `spaced_reference_links` #### + +Allow whitespace between the two components of a reference link, +for example, + + [foo] [bar]. + #### Extension: `hard_line_breaks` #### Causes all newlines within a paragraph to be interpreted as hard line diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs index 374fae2c1..58e8c414d 100644 --- a/src/Text/Pandoc/Extensions.hs +++ b/src/Text/Pandoc/Extensions.hs @@ -137,6 +137,7 @@ data Extension = | Ext_shortcut_reference_links -- ^ Shortcut reference links | Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes | Ext_old_dashes -- ^ -- = em, - before number = en + | Ext_spaced_reference_links -- ^ Allow space between two parts of ref link deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic) -- | Extensions to be used with pandoc-flavored markdown. @@ -187,7 +188,7 @@ pandocExtensions = extensionsFromList , Ext_smart ] --- | Extensions to be used with github-flavored markdown. +-- | Extensions to be used with plain text output. plainExtensions :: Extensions plainExtensions = extensionsFromList [ Ext_table_captions @@ -220,6 +221,7 @@ phpMarkdownExtraExtensions = extensionsFromList , Ext_link_attributes , Ext_abbreviations , Ext_shortcut_reference_links + , Ext_spaced_reference_links ] -- | Extensions to be used with github-flavored markdown. @@ -272,6 +274,7 @@ multimarkdownExtensions = extensionsFromList , Ext_superscript , Ext_subscript , Ext_backtick_code_blocks + , Ext_spaced_reference_links ] -- | Language extensions to be used with strict markdown. @@ -279,6 +282,7 @@ strictExtensions :: Extensions strictExtensions = extensionsFromList [ Ext_raw_html , Ext_shortcut_reference_links + , Ext_spaced_reference_links ] -- | Default extensions from format-describing string. diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 11f35deb2..4fb75b344 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1750,10 +1750,12 @@ referenceLink :: PandocMonad m referenceLink constructor (lab, raw) = do sp <- (True <$ lookAhead (char ' ')) <|> return False (_,raw') <- option (mempty, "") $ - lookAhead (try (guardEnabled Ext_citations >> - spnl >> normalCite >> return (mempty, ""))) + lookAhead (try (do guardEnabled Ext_citations + guardDisabled Ext_spaced_reference_links <|> spnl + normalCite + return (mempty, ""))) <|> - try (spnl >> reference) + try ((guardDisabled Ext_spaced_reference_links <|> spnl) >> reference) when (raw' == "") $ guardEnabled Ext_shortcut_reference_links let labIsRef = raw' == "" || raw' == "[]" let key = toKey $ if labIsRef then raw else raw' diff --git a/test/command/2602.md b/test/command/2602.md new file mode 100644 index 000000000..5ed4b581c --- /dev/null +++ b/test/command/2602.md @@ -0,0 +1,18 @@ +``` +% pandoc +[a] [b] + +[b]: url +^D +

[a] b

+``` + +``` +% pandoc -f markdown+spaced_reference_links +[a] [b] + +[b]: url +^D +

a

+``` + diff --git a/test/testsuite.native b/test/testsuite.native index fa234dfc2..0587bddb8 100644 --- a/test/testsuite.native +++ b/test/testsuite.native @@ -369,8 +369,6 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."] ,Header 2 ("reference",[],[]) [Str "Reference"] ,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."] -,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."] -,Para [Str "Foo",Space,Link ("",[],[]) [Str "bar"] ("/url/",""),Str "."] ,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."] ,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."] ,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."] diff --git a/test/testsuite.txt b/test/testsuite.txt index f6b0a7c95..9413cc81a 100644 --- a/test/testsuite.txt +++ b/test/testsuite.txt @@ -621,16 +621,11 @@ Just a [URL](/url/). ## Reference -Foo [bar] [a]. - Foo [bar][a]. -Foo [bar] -[a]. - [a]: /url/ -With [embedded [brackets]] [b]. +With [embedded [brackets]][b]. [b] by itself should be a link. @@ -659,9 +654,9 @@ Foo [biz](/url/ "Title with "quote" inside"). ## With ampersands -Here's a [link with an ampersand in the URL] [1]. +Here's a [link with an ampersand in the URL][1]. -Here's a link with an amersand in the link text: [AT&T] [2]. +Here's a link with an amersand in the link text: [AT&T][2]. Here's an [inline link](/script?foo=1&bar=2). diff --git a/test/writer.asciidoc b/test/writer.asciidoc index 2bf62e36f..639663743 100644 --- a/test/writer.asciidoc +++ b/test/writer.asciidoc @@ -600,10 +600,6 @@ Reference Foo link:/url/[bar]. -Foo link:/url/[bar]. - -Foo link:/url/[bar]. - With link:/url/[embedded [brackets]]. link:/url/[b] by itself should be a link. diff --git a/test/writer.context b/test/writer.context index eafc56f2a..9884c82c9 100644 --- a/test/writer.context +++ b/test/writer.context @@ -787,19 +787,15 @@ Just a \useURL[url4][/url/][][URL]\from[url4]. Foo \useURL[url13][/url/][][bar]\from[url13]. -Foo \useURL[url14][/url/][][bar]\from[url14]. +With \useURL[url14][/url/][][embedded {[}brackets{]}]\from[url14]. -Foo \useURL[url15][/url/][][bar]\from[url15]. +\useURL[url15][/url/][][b]\from[url15] by itself should be a link. -With \useURL[url16][/url/][][embedded {[}brackets{]}]\from[url16]. +Indented \useURL[url16][/url][][once]\from[url16]. -\useURL[url17][/url/][][b]\from[url17] by itself should be a link. +Indented \useURL[url17][/url][][twice]\from[url17]. -Indented \useURL[url18][/url][][once]\from[url18]. - -Indented \useURL[url19][/url][][twice]\from[url19]. - -Indented \useURL[url20][/url][][thrice]\from[url20]. +Indented \useURL[url18][/url][][thrice]\from[url18]. This should {[}not{]}{[}{]} be a link. @@ -807,41 +803,41 @@ This should {[}not{]}{[}{]} be a link. [not]: /url \stoptyping -Foo \useURL[url21][/url/][][bar]\from[url21]. +Foo \useURL[url19][/url/][][bar]\from[url19]. -Foo \useURL[url22][/url/][][biz]\from[url22]. +Foo \useURL[url20][/url/][][biz]\from[url20]. \subsection[with-ampersands]{With ampersands} -Here's a \useURL[url23][http://example.com/?foo=1&bar=2][][link with an -ampersand in the URL]\from[url23]. +Here's a \useURL[url21][http://example.com/?foo=1&bar=2][][link with an +ampersand in the URL]\from[url21]. Here's a link with an amersand in the link text: -\useURL[url24][http://att.com/][][AT&T]\from[url24]. +\useURL[url22][http://att.com/][][AT&T]\from[url22]. -Here's an \useURL[url25][/script?foo=1&bar=2][][inline link]\from[url25]. +Here's an \useURL[url23][/script?foo=1&bar=2][][inline link]\from[url23]. -Here's an \useURL[url26][/script?foo=1&bar=2][][inline link in pointy -braces]\from[url26]. +Here's an \useURL[url24][/script?foo=1&bar=2][][inline link in pointy +braces]\from[url24]. \subsection[autolinks]{Autolinks} -With an ampersand: \useURL[url27][http://example.com/?foo=1&bar=2]\from[url27] +With an ampersand: \useURL[url25][http://example.com/?foo=1&bar=2]\from[url25] \startitemize[packed] \item In a list? \item - \useURL[url28][http://example.com/]\from[url28] + \useURL[url26][http://example.com/]\from[url26] \item It should. \stopitemize An e-mail address: -\useURL[url29][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url29] +\useURL[url27][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url27] \startblockquote -Blockquoted: \useURL[url30][http://example.com/]\from[url30] +Blockquoted: \useURL[url28][http://example.com/]\from[url28] \stopblockquote Auto-links should not occur here: \type{} @@ -880,7 +876,7 @@ Here is a footnote reference,\footnote{Here is the footnote. It can go indent the first line of each block.\stopbuffer\footnote{\getbuffer} This should {\em not} be a footnote reference, because it contains a space.{[}^my note{]} Here is an inline note.\footnote{This is {\em easier} to type. Inline - notes may contain \useURL[url31][http://google.com][][links]\from[url31] and + notes may contain \useURL[url29][http://google.com][][links]\from[url29] and \type{]} verbatim characters, as well as {[}bracketed text{]}.} \startblockquote diff --git a/test/writer.docbook4 b/test/writer.docbook4 index eee19cdd9..163255974 100644 --- a/test/writer.docbook4 +++ b/test/writer.docbook4 @@ -1248,12 +1248,6 @@ These should not be escaped: \$ \\ \> \[ \{ Foo bar. - - Foo bar. - - - Foo bar. - With embedded [brackets]. diff --git a/test/writer.docbook5 b/test/writer.docbook5 index 07ca0f827..992cd8b63 100644 --- a/test/writer.docbook5 +++ b/test/writer.docbook5 @@ -1223,12 +1223,6 @@ These should not be escaped: \$ \\ \> \[ \{ Foo bar. - - Foo bar. - - - Foo bar. - With embedded [brackets]. diff --git a/test/writer.dokuwiki b/test/writer.dokuwiki index 79fcdde8a..4ba1b7054 100644 --- a/test/writer.dokuwiki +++ b/test/writer.dokuwiki @@ -556,10 +556,6 @@ Just a [[url/|URL]]. Foo [[url/|bar]]. -Foo [[url/|bar]]. - -Foo [[url/|bar]]. - With [[url/|embedded [brackets]]]. [[url/|b]] by itself should be a link. diff --git a/test/writer.fb2 b/test/writer.fb2 index 0412c8cf4..63d0bdfbf 100644 --- a/test/writer.fb2 +++ b/test/writer.fb2 @@ -1,3 +1,1013 @@ -Pandoc Test SuiteJohnMacFarlaneAnonymousJuly 17, 2006pandoc<p>Pandoc Test Suite</p>

John MacFarlane

Anonymous

July 17, 2006

This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.

——————————

<p>Headers</p>
<p>Level 2 with an embedded link </url></p>
<p>Level 3 with emphasis</p>
<p>Level 4</p>
<p>Level 5</p>
<p>Level 1</p>
<p>Level 2 with emphasis</p>
<p>Level 3</p>

with no blank line

<p>Level 2</p>

with no blank line

——————————

<p>Paragraphs</p>

Here’s a regular paragraph.

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.

There should be a hard line breakhere.

——————————

<p>Block Quotes</p>

E-mail style:

This is a block quote. It is pretty short.

Code in a block quote:

sub status {

print "working";

}

A list:

 1. item one

 2. item two

Nested block quotes:

nested

nested

This should not be a block quote: 2 > 1.

And a following paragraph.

——————————

<p>Code Blocks</p>

Code:

---- (should be four hyphens)

sub status {

print "working";

}

this code block is indented by one tab

And:

this code block is indented by two tabs

These should not be escaped: \$ \\ \> \[ \{

——————————

<p>Lists</p>
<p>Unordered</p>

Asterisks tight:

• asterisk 1

• asterisk 2

• asterisk 3

Asterisks loose:

• asterisk 1

• asterisk 2

• asterisk 3

Pluses tight:

• Plus 1

• Plus 2

• Plus 3

Pluses loose:

• Plus 1

• Plus 2

• Plus 3

Minuses tight:

• Minus 1

• Minus 2

• Minus 3

Minuses loose:

• Minus 1

• Minus 2

• Minus 3

<p>Ordered</p>

Tight:

 1. First

 2. Second

 3. Third

and:

 1. One

 2. Two

 3. Three

Loose using tabs:

 1. First

 2. Second

 3. Third

and using spaces:

 1. One

 2. Two

 3. Three

Multiple paragraphs:

 1. Item 1, graf one.Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.

 2. Item 2.

 3. Item 3.

<p>Nested</p>

• Tab

◦ Tab

* Tab

Here’s another:

 1. First

 2. Second:

   • Fee

   • Fie

   • Foe

 3. Third

Same thing but with paragraphs:

 1. First

 2. Second:

   • Fee

   • Fie

   • Foe

 3. Third

<p>Tabs and spaces</p>

• this is a list item indented with tabs

• this is a list item indented with spaces

◦ this is an example list item indented with tabs

◦ this is an example list item indented with spaces

<p>Fancy list markers</p>

 (2) begins with 2

 (3) and now 3with a continuation

 (3) iv. sublist with roman numerals, starting with 4

 (3) v. more items

 (3) v. (A) a subsublist

 (3) v. (B) a subsublist

Nesting:

 A. Upper Alpha

 A. I. Upper Roman.

 A. I. (6) Decimal start with 6

 A. I. (6) c) Lower alpha with paren

Autonumbering:

 1. Autonumber.

 2. More.

 2. 1. Nested.

Should not be a list item:

M.A. 2007

B. Williams

——————————

<p>Definition Lists</p>

Tight using spaces:

apple

    red fruit

orange

    orange fruit

banana

    yellow fruit

Tight using tabs:

apple

    red fruit

orange

    orange fruit

banana

    yellow fruit

Loose:

apple

    red fruit

orange

    orange fruit

banana

    yellow fruit

Multiple blocks with italics:

apple

    red fruit    contains seeds, crisp, pleasant to taste

orange

    orange fruit

    { orange code block }

    orange block quote

Multiple definitions, tight:

apple

    red fruit    computer

orange

    orange fruit    bank

Multiple definitions, loose:

apple

    red fruit    computer

orange

    orange fruit    bank

Blank line after term, indented marker, alternate markers:

apple

    red fruit    computer

orange

    orange fruit

 1. sublist

 2. sublist

<p>HTML Blocks</p>

Simple block on one line:

foo

And nested without indentation:

foo

bar

Interpreted markdown in a table:

This is emphasizedAnd this is strong

Here’s a simple block:

foo

This should be a code block, though:

<div>

foo

</div>

As should this:

<div>foo</div>

Now, nested:

foo

This should just be an HTML comment:

Multiline:

Code block:

<!-- Comment -->

Just plain comment, with trailing spaces on the line:

Code:

<hr />

Hr’s:

——————————

<p>Inline Markup</p>

This is emphasized, and so is this.

This is strong, and so is this.

An emphasized link[1].

This is strong and em.

So is this word.

This is strong and em.

So is this word.

This is code: >, $, \, \$, <html>.

This is strikeout.

Superscripts: abcd ahello ahello there.

Subscripts: H2O, H23O, Hmany of themO.

These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.

——————————

<p>Smart quotes, ellipses, dashes</p>

“Hello,” said the spider. “‘Shelob’ is my name.”

‘A’, ‘B’, and ‘C’ are letters.

‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’

‘He said, “I want to go.”’ Were you alive in the 70’s?

Here is some quoted ‘code’ and a “quoted link[2]”.

Some dashes: one—two — three—four — five.

Dashes between numbers: 5–7, 255–66, 1987–1999.

Ellipses…and…and….

——————————

<p>LaTeX</p>

• 

• 2+2=4

• x \in y

• \alpha \wedge \omega

• 223

• p-Tree

• Here’s some display math: \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}

• Here’s one that has a line break in it: \alpha + \omega \times x^2.

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.)

• Shoes ($20) and socks ($5).

• Escaped $: $73 this should be emphasized 23$.

Here’s a LaTeX table:

——————————

<p>Special Characters</p>

Here is some unicode:

• I hat: Î

• o umlaut: ö

• section: §

• set membership: ∈

• copyright: ©

AT&T has an ampersand in their name.

AT&T is another way to write it.

This & that.

4 < 5.

6 > 5.

Backslash: \

Backtick: `

Asterisk: *

Underscore: _

Left brace: {

Right brace: }

Left bracket: [

Right bracket: ]

Left paren: (

Right paren: )

Greater-than: >

Hash: #

Period: .

Bang: !

Plus: +

Minus: -

——————————

<p>Links</p>
<p>Explicit</p>

Just a URL[3].

URL and title[4].

URL and title[5].

URL and title[6].

URL and title[7]

URL and title[8]

with_underscore[9]

Email link[10]

Empty[11].

<p>Reference</p>

Foo bar[12].

Foo bar[13].

Foo bar[14].

With embedded [brackets][15].

b[16] by itself should be a link.

Indented once[17].

Indented twice[18].

Indented thrice[19].

This should [not][] be a link.

[not]: /url

Foo bar[20].

Foo biz[21].

<p>With ampersands</p>

Here’s a link with an ampersand in the URL[22].

Here’s a link with an amersand in the link text: AT&T[23].

Here’s an inline link[24].

Here’s an inline link in pointy braces[25].

<p>Autolinks</p>

With an ampersand: http://example.com/?foo=1&bar=2[26]

• In a list?

• http://example.com/[27]

• It should.

An e-mail address: nobody@nowhere.net[28]

Blockquoted: http://example.com/[29]

Auto-links should not occur here: <http://example.com/>

or here: <http://example.com/>

——————————

<p>Images</p>

From “Voyage dans la Lune” by Georges Melies (1902):

lalune

Here is a movie movie icon.

——————————

<p>Footnotes</p>

Here is a footnote reference,[30] and another.[31] This should not be a footnote reference, because it contains a space.[^my note] Here is an inline note.[32]

Notes can go in quotes.[33]

 1. And in list items.[34]

This paragraph should not be part of the note, as it is not indented.

<p>1</p>

/url

<p>2</p>

http://example.com/?foo=1&bar=2

<p>3</p>

/url/

<p>4</p>

title: /url/

<p>5</p>

title preceded by two spaces: /url/

<p>6</p>

title preceded by a tab: /url/

<p>7</p>

title with "quotes" in it: /url/

<p>8</p>

title with single quotes: /url/

<p>9</p>

/url/with_underscore

<p>10</p>

mailto:nobody@nowhere.net

<p>11</p>

<p>12</p>

/url/

<p>13</p>

/url/

<p>14</p>

/url/

<p>15</p>

/url/

<p>16</p>

/url/

<p>17</p>

/url

<p>18</p>

/url

<p>19</p>

/url

<p>20</p>

Title with "quotes" inside: /url/

<p>21</p>

Title with "quote" inside: /url/

<p>22</p>

http://example.com/?foo=1&bar=2

<p>23</p>

AT&T: http://att.com/

<p>24</p>

/script?foo=1&bar=2

<p>25</p>

/script?foo=1&bar=2

<p>26</p>

http://example.com/?foo=1&bar=2

<p>27</p>

http://example.com/

<p>28</p>

mailto:nobody@nowhere.net

<p>29</p>

http://example.com/

<p>30</p>

Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.

<p>31</p>

Here’s the long note. This one contains multiple blocks.

Subsequent blocks are indented to show that they belong to the footnote (as with list items).

{ <code> }

If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.

<p>32</p>

This is easier to type. Inline notes may contain links[32] and ] verbatim characters, as well as [bracketed text].

<p>33</p>

In quote.

<p>34</p>

In list.

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
- + + + +Pandoc Test Suite + +John +MacFarlane + + +Anonymous + +July 17, 2006 + + +pandoc + + + + +<p>Pandoc Test Suite</p> + + +

John MacFarlane

+

Anonymous

+

July 17, 2006

+
+
+

This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.

+ +

——————————

+ +
+
+ +<p>Headers</p> + +
+ +<p>Level 2 with an embedded link </url></p> + +
+ +<p>Level 3 with emphasis</p> + +
+ +<p>Level 4</p> + +
+ +<p>Level 5</p> + +
+
+
+
+
+
+ +<p>Level 1</p> + +
+ +<p>Level 2 with emphasis</p> + +
+ +<p>Level 3</p> + +

with no blank line

+
+
+
+ +<p>Level 2</p> + +

with no blank line

+ +

——————————

+ +
+
+
+ +<p>Paragraphs</p> + +

Here’s a regular paragraph.

+

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.

+

There should be a hard line breakhere.

+ +

——————————

+ +
+
+ +<p>Block Quotes</p> + +

E-mail style:

+ +

This is a block quote. It is pretty short.

+
+ +

Code in a block quote:

+ +

+sub status { +

+

+ print "working"; +

+

+} +

+ +

A list:

+

 1. item one

+

 2. item two

+

Nested block quotes:

+ +

nested

+
+ +

nested

+
+
+

This should not be a block quote: 2 > 1.

+

And a following paragraph.

+ +

——————————

+ +
+
+ +<p>Code Blocks</p> + +

Code:

+ +

+---- (should be four hyphens) +

+

+ + +

+

+sub status { +

+

+ print "working"; +

+

+} +

+

+ + +

+

+this code block is indented by one tab +

+ +

And:

+ +

+ this code block is indented by two tabs +

+

+ + +

+

+These should not be escaped: \$ \\ \> \[ \{ +

+ + +

——————————

+ +
+
+ +<p>Lists</p> + +
+ +<p>Unordered</p> + +

Asterisks tight:

+

• asterisk 1

+

• asterisk 2

+

• asterisk 3

+

Asterisks loose:

+

• asterisk 1 +

+

• asterisk 2 +

+

• asterisk 3 +

+

Pluses tight:

+

• Plus 1

+

• Plus 2

+

• Plus 3

+

Pluses loose:

+

• Plus 1 +

+

• Plus 2 +

+

• Plus 3 +

+

Minuses tight:

+

• Minus 1

+

• Minus 2

+

• Minus 3

+

Minuses loose:

+

• Minus 1 +

+

• Minus 2 +

+

• Minus 3 +

+
+
+ +<p>Ordered</p> + +

Tight:

+

 1. First

+

 2. Second

+

 3. Third

+

and:

+

 1. One

+

 2. Two

+

 3. Three

+

Loose using tabs:

+

 1. First +

+

 2. Second +

+

 3. Third +

+

and using spaces:

+

 1. One +

+

 2. Two +

+

 3. Three +

+

Multiple paragraphs:

+

 1. Item 1, graf one.Item 1. graf two. The quick brown fox jumped over the lazy dog’s back. +

+

 2. Item 2. +

+

 3. Item 3. +

+
+
+ +<p>Nested</p> + +

• Tab

◦ Tab

* Tab

+

+

+

Here’s another:

+

 1. First

+

 2. Second:

   • Fee

+

   • Fie

+

   • Foe

+

+

 3. Third

+

Same thing but with paragraphs:

+

 1. First +

+

 2. Second: +

   • Fee

+

   • Fie

+

   • Foe

+

+

 3. Third +

+
+
+ +<p>Tabs and spaces</p> + +

• this is a list item indented with tabs +

+

• this is a list item indented with spaces +

◦ this is an example list item indented with tabs +

+

◦ this is an example list item indented with spaces +

+

+
+
+ +<p>Fancy list markers</p> + +

 (2) begins with 2

+

 (3) and now 3with a continuation +

 (3) iv. sublist with roman numerals, starting with 4

+

 (3) v. more items

 (3) v. (A) a subsublist

+

 (3) v. (B) a subsublist

+

+

+

Nesting:

+

 A. Upper Alpha

 A. I. Upper Roman.

 A. I. (6) Decimal start with 6

 A. I. (6) c) Lower alpha with paren

+

+

+

+

Autonumbering:

+

 1. Autonumber.

+

 2. More.

 2. 1. Nested.

+

+

Should not be a list item:

+

M.A. 2007

+

B. Williams

+ +

——————————

+ +
+
+
+ +<p>Definition Lists</p> + +

Tight using spaces:

+

+apple +

+

    red fruit +

+

+orange +

+

    orange fruit +

+

+banana +

+

    yellow fruit +

+

Tight using tabs:

+

+apple +

+

    red fruit +

+

+orange +

+

    orange fruit +

+

+banana +

+

    yellow fruit +

+

Loose:

+

+apple +

+

    red fruit +

+

+orange +

+

    orange fruit +

+

+banana +

+

    yellow fruit +

+

Multiple blocks with italics:

+

+ +apple + +

+

    red fruit    contains seeds, crisp, pleasant to taste +

+

+ +orange + +

+

    orange fruit + +

+    { orange code block } +

+ + +

    orange block quote

+
+

+

Multiple definitions, tight:

+

+apple +

+

    red fruit    computer +

+

+orange +

+

    orange fruit    bank +

+

Multiple definitions, loose:

+

+apple +

+

    red fruit    computer +

+

+orange +

+

    orange fruit    bank +

+

Blank line after term, indented marker, alternate markers:

+

+apple +

+

    red fruit    computer +

+

+orange +

+

    orange fruit +

 1. sublist

+

 2. sublist

+

+
+
+ +<p>HTML Blocks</p> + +

Simple block on one line:

foo

And nested without indentation:

+

foo

bar

Interpreted markdown in a table:

This is emphasizedAnd this is strong +

Here’s a simple block:

+

foo

+

This should be a code block, though:

+ +

+<div> +

+

+ foo +

+

+</div> +

+ +

As should this:

+ +

+<div>foo</div> +

+ +

Now, nested:

foo

This should just be an HTML comment:

+

Multiline:

+

Code block:

+ +

+<!-- Comment --> +

+ +

Just plain comment, with trailing spaces on the line:

+

Code:

+ +

+<hr /> +

+ +

Hr’s:

+ +

——————————

+ +
+
+ +<p>Inline Markup</p> + +

This is emphasized, and so is this.

+

This is strong, and so is this.

+

An emphasized link +[1] + +.

+

+ +This is strong and em. + +

+

So is +this + word.

+

+ +This is strong and em. + +

+

So is +this + word.

+

This is code: >, $, \, \$, <html>.

+

+This is strikeout. +

+

Superscripts: abcd a +hello + ahello there.

+

Subscripts: H2O, H23O, Hmany of themO.

+

These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.

+ +

——————————

+ +
+
+ +<p>Smart quotes, ellipses, dashes</p> + +

“Hello,” said the spider. “‘Shelob’ is my name.”

+

‘A’, ‘B’, and ‘C’ are letters.

+

‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’

+

‘He said, “I want to go.”’ Were you alive in the 70’s?

+

Here is some quoted ‘code’ and a “quoted link +[2] +”.

+

Some dashes: one—two — three—four — five.

+

Dashes between numbers: 5–7, 255–66, 1987–1999.

+

Ellipses…and…and….

+ +

——————————

+ +
+
+ +<p>LaTeX</p> + +

• 

+

• 2+2=4 +

+

• x \in y +

+

• \alpha \wedge \omega +

+

• 223 +

+

• p-Tree

+

• Here’s some display math: \frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h} +

+

• Here’s one that has a line break in it: \alpha + \omega \times x^2.

+

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.)

+

• Shoes ($20) and socks ($5).

+

• Escaped $: $73 this should be emphasized 23$.

+

Here’s a LaTeX table:

+ +

——————————

+ +
+
+ +<p>Special Characters</p> + +

Here is some unicode:

+

• I hat: Î

+

• o umlaut: ö

+

• section: §

+

• set membership: ∈

+

• copyright: ©

+

AT&T has an ampersand in their name.

+

AT&T is another way to write it.

+

This & that.

+

4 < 5.

+

6 > 5.

+

Backslash: \

+

Backtick: `

+

Asterisk: *

+

Underscore: _

+

Left brace: {

+

Right brace: }

+

Left bracket: [

+

Right bracket: ]

+

Left paren: (

+

Right paren: )

+

Greater-than: >

+

Hash: #

+

Period: .

+

Bang: !

+

Plus: +

+

Minus: -

+ +

——————————

+ +
+
+ +<p>Links</p> + +
+ +<p>Explicit</p> + +

Just a URL +[3] +.

+

URL and title +[4] +.

+

URL and title +[5] +.

+

URL and title +[6] +.

+

URL and title +[7] + +

+

URL and title +[8] + +

+

with_underscore +[9] + +

+

Email link +[10] + +

+

Empty +[11] +.

+
+
+ +<p>Reference</p> + +

Foo bar +[12] +.

+

With embedded [brackets] +[13] +.

+

b +[14] + by itself should be a link.

+

Indented once +[15] +.

+

Indented twice +[16] +.

+

Indented thrice +[17] +.

+

This should [not][] be a link.

+ +

+[not]: /url +

+ +

Foo bar +[18] +.

+

Foo biz +[19] +.

+
+
+ +<p>With ampersands</p> + +

Here’s a link with an ampersand in the URL +[20] +.

+

Here’s a link with an amersand in the link text: AT&T +[21] +.

+

Here’s an inline link +[22] +.

+

Here’s an inline link in pointy braces +[23] +.

+
+
+ +<p>Autolinks</p> + +

With an ampersand: http://example.com/?foo=1&bar=2 +[24] + +

+

• In a list?

+

• http://example.com/ +[25] + +

+

• It should.

+

An e-mail address: nobody@nowhere.net +[26] + +

+ +

Blockquoted: http://example.com/ +[27] + +

+
+

Auto-links should not occur here: <http://example.com/> +

+ +

+or here: <http://example.com/> +

+ + +

——————————

+ +
+
+
+ +<p>Images</p> + +

From “Voyage dans la Lune” by Georges Melies (1902):

+lalune +

Here is a movie movie icon.

+ +

——————————

+ +
+
+ +<p>Footnotes</p> + +

Here is a footnote reference, +[28] + and another. +[29] + This should not be a footnote reference, because it contains a space.[^my note] Here is an inline note. +[30] + +

+ +

Notes can go in quotes. +[31] + +

+
+

 1. And in list items. +[32] + +

+

This paragraph should not be part of the note, as it is not indented.

+
+ + +
+ +<p>1</p> + +

+/url +

+
+
+ +<p>2</p> + +

+http://example.com/?foo=1&bar=2 +

+
+
+ +<p>3</p> + +

+/url/ +

+
+
+ +<p>4</p> + +

title: /url/ +

+
+
+ +<p>5</p> + +

title preceded by two spaces: /url/ +

+
+
+ +<p>6</p> + +

title preceded by a tab: /url/ +

+
+
+ +<p>7</p> + +

title with "quotes" in it: /url/ +

+
+
+ +<p>8</p> + +

title with single quotes: /url/ +

+
+
+ +<p>9</p> + +

+/url/with_underscore +

+
+
+ +<p>10</p> + +

+mailto:nobody@nowhere.net +

+
+
+ +<p>11</p> + +

+ + +

+
+
+ +<p>12</p> + +

+/url/ +

+
+
+ +<p>13</p> + +

+/url/ +

+
+
+ +<p>14</p> + +

+/url/ +

+
+
+ +<p>15</p> + +

+/url +

+
+
+ +<p>16</p> + +

+/url +

+
+
+ +<p>17</p> + +

+/url +

+
+
+ +<p>18</p> + +

Title with "quotes" inside: /url/ +

+
+
+ +<p>19</p> + +

Title with "quote" inside: /url/ +

+
+
+ +<p>20</p> + +

+http://example.com/?foo=1&bar=2 +

+
+
+ +<p>21</p> + +

AT&T: http://att.com/ +

+
+
+ +<p>22</p> + +

+/script?foo=1&bar=2 +

+
+
+ +<p>23</p> + +

+/script?foo=1&bar=2 +

+
+
+ +<p>24</p> + +

+http://example.com/?foo=1&bar=2 +

+
+
+ +<p>25</p> + +

+http://example.com/ +

+
+
+ +<p>26</p> + +

+mailto:nobody@nowhere.net +

+
+
+ +<p>27</p> + +

+http://example.com/ +

+
+
+ +<p>28</p> + +

Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.

+
+
+ +<p>29</p> + +

Here’s the long note. This one contains multiple blocks.

+

Subsequent blocks are indented to show that they belong to the footnote (as with list items).

+ +

+ { <code> } +

+ +

If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.

+
+
+ +<p>30</p> + +

This is easier to type. Inline notes may contain links +[30] + and ] verbatim characters, as well as [bracketed text].

+
+
+ +<p>31</p> + +

In quote.

+
+
+ +<p>32</p> + +

In list.

+
+ +
diff --git a/test/writer.haddock b/test/writer.haddock index 0772331e3..7f783abd1 100644 --- a/test/writer.haddock +++ b/test/writer.haddock @@ -560,10 +560,6 @@ Just a . Foo . -Foo . - -Foo . - With . by itself should be a link. diff --git a/test/writer.html4 b/test/writer.html4 index bac16b14c..89cf07685 100644 --- a/test/writer.html4 +++ b/test/writer.html4 @@ -486,8 +486,6 @@ Blah

Empty.

Reference

Foo bar.

-

Foo bar.

-

Foo bar.

With embedded [brackets].

b by itself should be a link.

Indented once.

diff --git a/test/writer.html5 b/test/writer.html5 index ee921766c..6762f8198 100644 --- a/test/writer.html5 +++ b/test/writer.html5 @@ -489,8 +489,6 @@ Blah

Empty.

Reference

Foo bar.

-

Foo bar.

-

Foo bar.

With embedded [brackets].

b by itself should be a link.

Indented once.

diff --git a/test/writer.icml b/test/writer.icml index b498f568b..c39915120 100644 --- a/test/writer.icml +++ b/test/writer.icml @@ -2564,39 +2564,11 @@ These should not be escaped: \$ \\ \> \[ \{

- - - Foo - - - - . - - -
- - - Foo - - - - . - - -
With -
-
-