diff options
-rw-r--r-- | INSTALL | 26 | ||||
-rw-r--r-- | MANUAL.txt | 7 | ||||
m--------- | data/templates | 14 | ||||
-rw-r--r-- | src/Text/Pandoc/Error.hs | 12 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/MediaWiki.hs | 22 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/Org/Blocks.hs | 45 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/Org/Inlines.hs | 33 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/Org/Shared.hs | 25 | ||||
-rw-r--r-- | src/Text/Pandoc/Readers/Textile.hs | 5 | ||||
-rw-r--r-- | src/Text/Pandoc/Writers/LaTeX.hs | 4 | ||||
-rw-r--r-- | tests/Tests/Readers/Org.hs | 26 |
11 files changed, 146 insertions, 73 deletions
@@ -8,6 +8,32 @@ There are also binary installers for Windows and Mac OS X. If you are installing the development version from github, see also: https://github.com/jgm/pandoc/wiki/Installing-the-development-version-of-pandoc +How to get the source +--------------------- + +Source tarballs can be found at +<https://hackage.haskell.org/package/pandoc>. The tarball +for a particular version `VERSION` can be found at + + https://hackage.haskell.org/package/pandoc-VERSION/pandoc-VERSION.tar.gz + +**Do not use the automatically generated tarball that can be +downloaded from pandoc's GitHub releases page.** It does not +include some essential template files, which come from a GitHub +submodule. + +If you want the latest development code, you can fetch it +by cloning the repository: + + git clone https://github.com/jgm/pandoc + cd pandoc + git submodule update --init # to fetch the templates + +Note: there may be times when the development code is broken +or depends on other libraries which must be installed +separately. Unless you really know what you're doing, install +the last released version. + Quick install with stack ------------------------ diff --git a/MANUAL.txt b/MANUAL.txt index 8d5be98f8..2177cf926 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -1164,6 +1164,9 @@ including all [reveal.js configuration options]. `theme`, `colortheme`, `fonttheme`, `innertheme`, `outertheme` : themes for LaTeX [`beamer`] documents +`themeoptions` +: options for LaTeX beamer themes (a list). + `navigation` : controls navigation symbols in `beamer` documents (default is `empty` for no navigation symbols; other valid values @@ -1173,6 +1176,10 @@ including all [reveal.js configuration options]. : enables on "title pages" for new sections in `beamer` documents (default = true). +`beamerarticle` +: when true, the `beamerarticle` package is loaded (for + producing an article from beamer slides). + [reveal.js configuration options]: https://github.com/hakimel/reveal.js#configuration Variables for LaTeX diff --git a/data/templates b/data/templates -Subproject 8bed1acf2271c84ae564d6f0b9adcdc4d5c71d2 +Subproject 284279f61e493bf70a8375eb772d293b9fb5d6b diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs index 792098b35..292396aee 100644 --- a/src/Text/Pandoc/Error.hs +++ b/src/Text/Pandoc/Error.hs @@ -62,8 +62,12 @@ handleError (Left err) = let errPos = errorPos err' errLine = sourceLine errPos errColumn = sourceColumn errPos - theline = (lines input ++ [""]) !! (errLine - 1) - in error $ "\nError at " ++ show err' ++ "\n" ++ - theline ++ "\n" ++ replicate (errColumn - 1) ' ' ++ - "^" + ls = lines input ++ [""] + errorInFile = if length ls > errLine - 1 + then concat ["\n", (ls !! (errLine - 1)) + ,"\n", replicate (errColumn - 1) ' ' + ,"^"] + else "" + in error $ "\nError at " ++ show err' + ++ errorInFile diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs index d3cee08e2..dcf0c5f4a 100644 --- a/src/Text/Pandoc/Readers/MediaWiki.hs +++ b/src/Text/Pandoc/Readers/MediaWiki.hs @@ -253,7 +253,7 @@ parseAttr = try $ do k <- many1 letter char '=' v <- (char '"' >> many1Till (satisfy (/='\n')) (char '"')) - <|> many1 nonspaceChar + <|> many1 (satisfy $ \c -> not (isSpace c) && c /= '|') return (k,v) tableStart :: MWParser () @@ -376,11 +376,17 @@ preformatted = try $ do spacesStr _ = False if F.all spacesStr contents then return mempty - else return $ B.para $ walk strToCode contents - -strToCode :: Inline -> Inline -strToCode (Str s) = Code ("",[],[]) s -strToCode x = x + else return $ B.para $ encode contents + +encode :: Inlines -> Inlines +encode = B.fromList . normalizeCode . B.toList . walk strToCode + where strToCode (Str s) = Code ("",[],[]) s + strToCode Space = Code ("",[],[]) " " + strToCode x = x + normalizeCode [] = [] + normalizeCode (Code a1 x : Code a2 y : zs) | a1 == a2 = + normalizeCode $ (Code a1 (x ++ y)) : zs + normalizeCode (x:xs) = x : normalizeCode xs header :: MWParser Blocks header = try $ do @@ -545,8 +551,8 @@ inlineTag = do TagOpen "del" _ -> B.strikeout <$> inlinesInTags "del" TagOpen "sub" _ -> B.subscript <$> inlinesInTags "sub" TagOpen "sup" _ -> B.superscript <$> inlinesInTags "sup" - TagOpen "code" _ -> walk strToCode <$> inlinesInTags "code" - TagOpen "tt" _ -> walk strToCode <$> inlinesInTags "tt" + TagOpen "code" _ -> encode <$> inlinesInTags "code" + TagOpen "tt" _ -> encode <$> inlinesInTags "tt" TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask" _ -> B.rawInline "html" . snd <$> htmlTag (~== tag) diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index 0bd82ce2f..6a8bb8b28 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -39,8 +39,8 @@ import Text.Pandoc.Readers.Org.Inlines import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing import Text.Pandoc.Readers.Org.Shared - ( isImageFilename, rundocBlockClass, toRundocAttrib - , translateLang ) + ( cleanLinkString, isImageFilename, rundocBlockClass + , toRundocAttrib, translateLang ) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Builder ( Inlines, Blocks ) @@ -422,7 +422,16 @@ verseBlock blockType = try $ do ignHeaders content <- rawBlockContent blockType fmap B.para . mconcat . intersperse (pure B.linebreak) - <$> mapM (parseFromString inlines) (map (++ "\n") . lines $ content) + <$> mapM parseVerseLine (lines content) + where + -- replace initial spaces with nonbreaking spaces to preserve + -- indentation, parse the rest as normal inline + parseVerseLine :: String -> OrgParser (F Inlines) + parseVerseLine cs = do + let (initialSpaces, indentedLine) = span isSpace cs + let nbspIndent = B.str $ map (const '\160') initialSpaces + line <- parseFromString inlines (indentedLine ++ "\n") + return (pure nbspIndent <> line) -- | Read a code block and the associated results block if present. Which of -- boths blocks is included in the output is determined using the "exports" @@ -571,23 +580,33 @@ figure :: OrgParser (F Blocks) figure = try $ do figAttrs <- blockAttributes src <- skipSpaces *> selfTarget <* skipSpaces <* newline - guard . not . isNothing . blockAttrCaption $ figAttrs - guard (isImageFilename src) - let figName = fromMaybe mempty $ blockAttrName figAttrs - let figLabel = fromMaybe mempty $ blockAttrLabel figAttrs - let figCaption = fromMaybe mempty $ blockAttrCaption figAttrs - let figKeyVals = blockAttrKeyValues figAttrs - let attr = (figLabel, mempty, figKeyVals) - return $ (B.para . B.imageWith attr src (withFigPrefix figName) <$> figCaption) + case cleanLinkString src of + Nothing -> mzero + Just imgSrc -> do + guard (not . isNothing . blockAttrCaption $ figAttrs) + guard (isImageFilename imgSrc) + return $ figureBlock figAttrs imgSrc where + selfTarget :: OrgParser String + selfTarget = try $ char '[' *> linkTarget <* char ']' + + figureBlock :: BlockAttributes -> String -> (F Blocks) + figureBlock figAttrs imgSrc = + let + figName = fromMaybe mempty $ blockAttrName figAttrs + figLabel = fromMaybe mempty $ blockAttrLabel figAttrs + figCaption = fromMaybe mempty $ blockAttrCaption figAttrs + figKeyVals = blockAttrKeyValues figAttrs + attr = (figLabel, mempty, figKeyVals) + in + B.para . B.imageWith attr imgSrc (withFigPrefix figName) <$> figCaption + withFigPrefix :: String -> String withFigPrefix cs = if "fig:" `isPrefixOf` cs then cs else "fig:" ++ cs - selfTarget :: OrgParser String - selfTarget = try $ char '[' *> linkTarget <* char ']' -- -- Examples diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs index e1a66a8c7..31f098d27 100644 --- a/src/Text/Pandoc/Readers/Org/Inlines.hs +++ b/src/Text/Pandoc/Readers/Org/Inlines.hs @@ -37,8 +37,8 @@ import Text.Pandoc.Readers.Org.BlockStarts import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing import Text.Pandoc.Readers.Org.Shared - ( isImageFilename, rundocBlockClass, toRundocAttrib - , translateLang ) + ( cleanLinkString, isImageFilename, rundocBlockClass + , toRundocAttrib, translateLang ) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Builder ( Inlines ) @@ -52,7 +52,7 @@ import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap import Prelude hiding (sequence) import Control.Monad ( guard, mplus, mzero, when, void ) import Data.Char ( isAlphaNum, isSpace ) -import Data.List ( intersperse, isPrefixOf ) +import Data.List ( intersperse ) import Data.Maybe ( fromMaybe ) import qualified Data.Map as M import Data.Traversable (sequence) @@ -435,9 +435,11 @@ explicitOrImageLink = try $ do char ']' return $ do src <- srcF - if isImageFilename title - then pure $ B.link src "" $ B.image title mempty mempty - else linkToInlinesF src =<< title' + case cleanLinkString title of + Just imgSrc | isImageFilename imgSrc -> + pure $ B.link src "" $ B.image imgSrc mempty mempty + _ -> + linkToInlinesF src =<< title' selflinkOrImage :: OrgParser (F Inlines) selflinkOrImage = try $ do @@ -482,25 +484,6 @@ linkToInlinesF linkStr = else pure . B.link cleanedLink "" Nothing -> internalLink linkStr -- other internal link --- | Cleanup and canonicalize a string describing a link. Return @Nothing@ if --- the string does not appear to be a link. -cleanLinkString :: String -> Maybe String -cleanLinkString s = - case s of - '/':_ -> Just $ "file://" ++ s -- absolute path - '.':'/':_ -> Just s -- relative path - '.':'.':'/':_ -> Just s -- relative path - -- Relative path or URL (file schema) - 'f':'i':'l':'e':':':s' -> Just $ if ("//" `isPrefixOf` s') then s else s' - _ | isUrl s -> Just s -- URL - _ -> Nothing - where - isUrl :: String -> Bool - isUrl cs = - let (scheme, path) = break (== ':') cs - in all (\c -> isAlphaNum c || c `elem` (".-"::String)) scheme - && not (null path) - internalLink :: String -> Inlines -> F Inlines internalLink link title = do anchorB <- (link `elem`) <$> asksF orgStateAnchorIds diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs index 3ba46b9e4..8c87cfa25 100644 --- a/src/Text/Pandoc/Readers/Org/Shared.hs +++ b/src/Text/Pandoc/Readers/Org/Shared.hs @@ -27,13 +27,15 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Utility functions used in other Pandoc Org modules. -} module Text.Pandoc.Readers.Org.Shared - ( isImageFilename + ( cleanLinkString + , isImageFilename , rundocBlockClass , toRundocAttrib , translateLang ) where import Control.Arrow ( first ) +import Data.Char ( isAlphaNum ) import Data.List ( isPrefixOf, isSuffixOf ) @@ -41,12 +43,31 @@ import Data.List ( isPrefixOf, isSuffixOf ) isImageFilename :: String -> Bool isImageFilename filename = any (\x -> ('.':x) `isSuffixOf` filename) imageExtensions && - (any (\x -> (x++":") `isPrefixOf` filename) protocols || + (any (\x -> (x ++ "://") `isPrefixOf` filename) protocols || ':' `notElem` filename) where imageExtensions = [ "jpeg" , "jpg" , "png" , "gif" , "svg" ] protocols = [ "file", "http", "https" ] +-- | Cleanup and canonicalize a string describing a link. Return @Nothing@ if +-- the string does not appear to be a link. +cleanLinkString :: String -> Maybe String +cleanLinkString s = + case s of + '/':_ -> Just $ "file://" ++ s -- absolute path + '.':'/':_ -> Just s -- relative path + '.':'.':'/':_ -> Just s -- relative path + -- Relative path or URL (file schema) + 'f':'i':'l':'e':':':s' -> Just $ if ("//" `isPrefixOf` s') then s else s' + _ | isUrl s -> Just s -- URL + _ -> Nothing + where + isUrl :: String -> Bool + isUrl cs = + let (scheme, path) = break (== ':') cs + in all (\c -> isAlphaNum c || c `elem` (".-"::String)) scheme + && not (null path) + -- | Prefix used for Rundoc classes and arguments. rundocPrefix :: String rundocPrefix = "rundoc-" diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs index 4ab0243fe..a4de85dfb 100644 --- a/src/Text/Pandoc/Readers/Textile.hs +++ b/src/Text/Pandoc/Readers/Textile.hs @@ -60,7 +60,7 @@ import Text.Pandoc.Parsing import Text.Pandoc.Readers.HTML ( htmlTag, isBlockTag, isInlineTag ) import Text.Pandoc.Shared (trim) import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock ) -import Text.HTML.TagSoup (parseTags, innerText, fromAttrib, Tag(..)) +import Text.HTML.TagSoup (fromAttrib, Tag(..)) import Text.HTML.TagSoup.Match import Data.List ( intercalate, transpose, intersperse ) import Data.Char ( digitToInt, isUpper ) @@ -182,8 +182,7 @@ trimTrailingNewlines = reverse . dropWhile (=='\n') . reverse codeBlockPre :: Parser [Char] ParserState Blocks codeBlockPre = try $ do (t@(TagOpen _ attrs),_) <- htmlTag (tagOpen (=="pre") (const True)) - result' <- (innerText . parseTags) `fmap` -- remove internal tags - manyTill anyChar (htmlTag (tagClose (=="pre"))) + result' <- manyTill anyChar (htmlTag (tagClose (=="pre"))) optional blanklines -- drop leading newline if any let result'' = case result' of diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 5829bcd33..29e8c962c 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -732,7 +732,6 @@ sectionHeader unnumbered ident level lst = do noNote x = x let lstNoNotes = walk noNote lst txtNoNotes <- inlineListToLaTeX lstNoNotes - let star = if unnumbered then text "*" else empty -- footnotes in sections don't work (except for starred variants) -- unless you specify an optional argument: -- \section[mysec]{mysec\footnote{blah}} @@ -745,7 +744,6 @@ sectionHeader unnumbered ident level lst = do else braces (text "\\texorpdfstring" <> braces txt <> braces (text plain)) - let stuffing = star <> optional <> contents book <- gets stBook opts <- gets stOptions let level' = if book || writerChapters opts then level - 1 else level @@ -765,6 +763,8 @@ sectionHeader unnumbered ident level lst = do -- see http://tex.stackexchange.com/questions/169830/ else empty lab <- labelFor ident + let star = if unnumbered && level < 4 then text "*" else empty + let stuffing = star <> optional <> contents stuffing' <- hypertarget ident $ text ('\\':sectionType) <> stuffing <> lab return $ if level' > 5 then txt diff --git a/tests/Tests/Readers/Org.hs b/tests/Tests/Readers/Org.hs index 1f8a8a01e..0a3f9c222 100644 --- a/tests/Tests/Readers/Org.hs +++ b/tests/Tests/Readers/Org.hs @@ -219,12 +219,12 @@ tests = (para $ link "" "" "New Link") , "Image link" =: - "[[sunset.png][dusk.svg]]" =?> + "[[sunset.png][file:dusk.svg]]" =?> (para $ link "sunset.png" "" (image "dusk.svg" "" "")) , "Image link with non-image target" =: - "[[http://example.com][logo.png]]" =?> - (para $ link "http://example.com" "" (image "logo.png" "" "")) + "[[http://example.com][./logo.png]]" =?> + (para $ link "http://example.com" "" (image "./logo.png" "" "")) , "Plain link" =: "Posts on http://zeitlens.com/ can be funny at times." =?> @@ -810,29 +810,29 @@ tests = [ "Figure" =: unlines [ "#+caption: A very courageous man." , "#+name: goodguy" - , "[[edward.jpg]]" + , "[[file:edward.jpg]]" ] =?> para (image "edward.jpg" "fig:goodguy" "A very courageous man.") , "Figure with no name" =: unlines [ "#+caption: I've been through the desert on this" - , "[[horse.png]]" + , "[[file:horse.png]]" ] =?> para (image "horse.png" "fig:" "I've been through the desert on this") , "Figure with `fig:` prefix in name" =: unlines [ "#+caption: Used as a metapher in evolutionary biology." , "#+name: fig:redqueen" - , "[[the-red-queen.jpg]]" + , "[[./the-red-queen.jpg]]" ] =?> - para (image "the-red-queen.jpg" "fig:redqueen" + para (image "./the-red-queen.jpg" "fig:redqueen" "Used as a metapher in evolutionary biology.") , "Figure with HTML attributes" =: unlines [ "#+CAPTION: mah brain just explodid" , "#+NAME: lambdacat" , "#+ATTR_HTML: :style color: blue :role button" - , "[[lambdacat.jpg]]" + , "[[file:lambdacat.jpg]]" ] =?> let kv = [("style", "color: blue"), ("role", "button")] name = "fig:lambdacat" @@ -842,7 +842,7 @@ tests = , "Labelled figure" =: unlines [ "#+CAPTION: My figure" , "#+LABEL: fig:myfig" - , "[[blub.png]]" + , "[[file:blub.png]]" ] =?> let attr = ("fig:myfig", mempty, mempty) in para (imageWith attr "blub.png" "fig:" "My figure") @@ -1440,6 +1440,14 @@ tests = ] =?> para ("foo" <> linebreak <> linebreak <> "bar") + , "Verse block with varying indentation" =: + unlines [ "#+BEGIN_VERSE" + , " hello darkness" + , "my old friend" + , "#+END_VERSE" + ] =?> + para ("\160\160hello darkness" <> linebreak <> "my old friend") + , "Raw block LaTeX" =: unlines [ "#+BEGIN_LaTeX" , "The category $\\cat{Set}$ is adhesive." |