aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/Writers/AsciiDoc.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Text/Pandoc/Writers/AsciiDoc.hs')
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs470
1 files changed, 0 insertions, 470 deletions
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
deleted file mode 100644
index 356b29504..000000000
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ /dev/null
@@ -1,470 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-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
--}
-
-{- |
- Module : Text.Pandoc.Writers.AsciiDoc
- Copyright : Copyright (C) 2006-2015 John MacFarlane
- License : GNU GPL, version 2 or above
-
- Maintainer : John MacFarlane <jgm@berkeley.edu>
- Stability : alpha
- Portability : portable
-
-Conversion of 'Pandoc' documents to asciidoc.
-
-Note that some information may be lost in conversion, due to
-expressive limitations of asciidoc. Footnotes and table cells with
-paragraphs (or other block items) are not possible in asciidoc.
-If pandoc encounters one of these, it will insert a message indicating
-that it has omitted the construct.
-
-AsciiDoc: <http://www.methods.co.nz/asciidoc/>
--}
-module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc) where
-import Text.Pandoc.Definition
-import Text.Pandoc.Templates (renderTemplate')
-import Text.Pandoc.Shared
-import Text.Pandoc.Writers.Shared
-import Text.Pandoc.Options
-import Text.Pandoc.Parsing hiding (blankline, space)
-import Data.Maybe (fromMaybe)
-import Data.List ( stripPrefix, intersperse, intercalate )
-import Text.Pandoc.Pretty
-import Text.Pandoc.ImageSize
-import Control.Monad.State
-import qualified Data.Map as M
-import Data.Aeson (Value(String), fromJSON, toJSON, Result(..))
-import qualified Data.Text as T
-import Data.Char (isSpace, isPunctuation)
-import Text.Pandoc.Class (PandocMonad)
-
-data WriterState = WriterState { defListMarker :: String
- , orderedListLevel :: Int
- , bulletListLevel :: Int
- , intraword :: Bool
- }
-
--- | Convert Pandoc to AsciiDoc.
-writeAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> m String
-writeAsciiDoc opts document = return $
- evalState (pandocToAsciiDoc opts document) WriterState{
- defListMarker = "::"
- , orderedListLevel = 1
- , bulletListLevel = 1
- , intraword = False
- }
-
--- | Return asciidoc representation of document.
-pandocToAsciiDoc :: WriterOptions -> Pandoc -> State WriterState String
-pandocToAsciiDoc opts (Pandoc meta blocks) = do
- let titleblock = not $ null (docTitle meta) && null (docAuthors meta) &&
- null (docDate meta)
- let colwidth = if writerWrapText opts == WrapAuto
- then Just $ writerColumns opts
- else Nothing
- metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToAsciiDoc opts)
- (fmap (render colwidth) . inlineListToAsciiDoc opts)
- meta
- let addTitleLine (String t) = String $
- t <> "\n" <> T.replicate (T.length t) "="
- addTitleLine x = x
- let metadata' = case fromJSON metadata of
- Success m -> toJSON $ M.adjust addTitleLine
- ("title" :: T.Text) m
- _ -> metadata
- body <- blockListToAsciiDoc opts blocks
- let main = render colwidth body
- let context = defField "body" main
- $ defField "toc"
- (writerTableOfContents opts &&
- writerTemplate opts /= Nothing)
- $ defField "titleblock" titleblock
- $ metadata'
- case writerTemplate opts of
- Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
-
--- | Escape special characters for AsciiDoc.
-escapeString :: String -> String
-escapeString = escapeStringUsing escs
- where escs = backslashEscapes "{"
-
--- | Ordered list start parser for use in Para below.
-olMarker :: Parser [Char] ParserState Char
-olMarker = do (start, style', delim) <- anyOrderedListMarker
- if delim == Period &&
- (style' == UpperAlpha || (style' == UpperRoman &&
- start `elem` [1, 5, 10, 50, 100, 500, 1000]))
- then spaceChar >> spaceChar
- else spaceChar
-
--- | True if string begins with an ordered list marker
-beginsWithOrderedListMarker :: String -> Bool
-beginsWithOrderedListMarker str =
- case runParser olMarker defaultParserState "para start" (take 10 str) of
- Left _ -> False
- Right _ -> True
-
--- | Convert Pandoc block element to asciidoc.
-blockToAsciiDoc :: WriterOptions -- ^ Options
- -> Block -- ^ Block element
- -> State WriterState Doc
-blockToAsciiDoc _ Null = return empty
-blockToAsciiDoc opts (Plain inlines) = do
- contents <- inlineListToAsciiDoc opts inlines
- return $ contents <> blankline
-blockToAsciiDoc opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = do
- blockToAsciiDoc opts (Para [Image attr alt (src,tit)])
-blockToAsciiDoc opts (Para inlines) = do
- contents <- inlineListToAsciiDoc opts inlines
- -- escape if para starts with ordered list marker
- let esc = if beginsWithOrderedListMarker (render Nothing contents)
- then text "\\"
- else empty
- return $ esc <> contents <> blankline
-blockToAsciiDoc opts (LineBlock lns) = do
- let docify line = if null line
- then return blankline
- else inlineListToAsciiDoc opts line
- let joinWithLinefeeds = nowrap . mconcat . intersperse cr
- contents <- joinWithLinefeeds <$> mapM docify lns
- return $ "[verse]" $$ text "--" $$ contents $$ text "--" $$ blankline
-blockToAsciiDoc _ (RawBlock f s)
- | f == "asciidoc" = return $ text s
- | otherwise = return empty
-blockToAsciiDoc _ HorizontalRule =
- return $ blankline <> text "'''''" <> blankline
-blockToAsciiDoc opts (Header level (ident,_,_) inlines) = do
- contents <- inlineListToAsciiDoc opts inlines
- let len = offset contents
- -- ident seem to be empty most of the time and asciidoc will generate them automatically
- -- so lets make them not show up when null
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
- let setext = writerSetextHeaders opts
- return $
- (if setext
- then
- identifier $$ contents $$
- (case level of
- 1 -> text $ replicate len '-'
- 2 -> text $ replicate len '~'
- 3 -> text $ replicate len '^'
- 4 -> text $ replicate len '+'
- _ -> empty) <> blankline
- else
- identifier $$ text (replicate level '=') <> space <> contents <> blankline)
-blockToAsciiDoc _ (CodeBlock (_,classes,_) str) = return $ (flush $
- if null classes
- then "...." $$ text str $$ "...."
- else attrs $$ "----" $$ text str $$ "----")
- <> blankline
- where attrs = "[" <> text (intercalate "," ("source" : classes)) <> "]"
-blockToAsciiDoc opts (BlockQuote blocks) = do
- contents <- blockListToAsciiDoc opts blocks
- let isBlock (BlockQuote _) = True
- isBlock _ = False
- -- if there are nested block quotes, put in an open block
- let contents' = if any isBlock blocks
- then "--" $$ contents $$ "--"
- else contents
- let cols = offset contents'
- let bar = text $ replicate cols '_'
- return $ bar $$ chomp contents' $$ bar <> blankline
-blockToAsciiDoc opts (Table caption aligns widths headers rows) = do
- caption' <- inlineListToAsciiDoc opts caption
- let caption'' = if null caption
- then empty
- else "." <> caption' <> cr
- let isSimple = all (== 0) widths
- let relativePercentWidths = if isSimple
- then widths
- else map (/ (sum widths)) widths
- let widths'' :: [Integer]
- widths'' = map (floor . (* 100)) relativePercentWidths
- -- ensure that the widths sum to 100
- let widths' = case widths'' of
- _ | isSimple -> widths''
- (w:ws) | sum (w:ws) < 100
- -> (100 - sum ws) : ws
- ws -> ws
- let totalwidth :: Integer
- totalwidth = floor $ sum widths * 100
- let colspec al wi = (case al of
- AlignLeft -> "<"
- AlignCenter -> "^"
- AlignRight -> ">"
- AlignDefault -> "") ++
- if wi == 0 then "" else (show wi ++ "%")
- let headerspec = if all null headers
- then empty
- else text "options=\"header\","
- let widthspec = if totalwidth == 0
- then empty
- else text "width="
- <> doubleQuotes (text $ show totalwidth ++ "%")
- <> text ","
- let tablespec = text "["
- <> widthspec
- <> text "cols="
- <> doubleQuotes (text $ intercalate ","
- $ zipWith colspec aligns widths')
- <> text ","
- <> headerspec <> text "]"
- let makeCell [Plain x] = do d <- blockListToAsciiDoc opts [Plain x]
- return $ text "|" <> chomp d
- makeCell [Para x] = makeCell [Plain x]
- makeCell [] = return $ text "|"
- makeCell bs = do d <- blockListToAsciiDoc opts bs
- return $ text "a|" $$ d
- let makeRow cells = hsep `fmap` mapM makeCell cells
- rows' <- mapM makeRow rows
- head' <- makeRow headers
- let head'' = if all null headers then empty else head'
- let colwidth = if writerWrapText opts == WrapAuto
- then writerColumns opts
- else 100000
- let maxwidth = maximum $ map offset (head':rows')
- let body = if maxwidth > colwidth then vsep rows' else vcat rows'
- let border = text $ "|" ++ replicate (max 5 (min maxwidth colwidth) - 1) '='
- return $
- caption'' $$ tablespec $$ border $$ head'' $$ body $$ border $$ blankline
-blockToAsciiDoc opts (BulletList items) = do
- contents <- mapM (bulletListItemToAsciiDoc opts) items
- return $ cat contents <> blankline
-blockToAsciiDoc opts (OrderedList (_start, sty, _delim) items) = do
- let sty' = case sty of
- UpperRoman -> UpperAlpha
- LowerRoman -> LowerAlpha
- x -> x
- let markers = orderedListMarkers (1, sty', Period) -- start num not used
- let markers' = map (\m -> if length m < 3
- then m ++ replicate (3 - length m) ' '
- else m) markers
- contents <- mapM (\(item, num) -> orderedListItemToAsciiDoc opts item num) $
- zip markers' items
- return $ cat contents <> blankline
-blockToAsciiDoc opts (DefinitionList items) = do
- contents <- mapM (definitionListItemToAsciiDoc opts) items
- return $ cat contents <> blankline
-blockToAsciiDoc opts (Div (ident,_,_) bs) = do
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
- contents <- blockListToAsciiDoc opts bs
- return $ identifier $$ contents
-
--- | Convert bullet list item (list of blocks) to asciidoc.
-bulletListItemToAsciiDoc :: WriterOptions -> [Block] -> State WriterState Doc
-bulletListItemToAsciiDoc opts blocks = do
- let addBlock :: Doc -> Block -> State WriterState Doc
- addBlock d b | isEmpty d = chomp `fmap` blockToAsciiDoc opts b
- addBlock d b@(BulletList _) = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> chomp x
- addBlock d b@(OrderedList _ _) = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> chomp x
- addBlock d b = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> text "+" <> cr <> chomp x
- lev <- bulletListLevel `fmap` get
- modify $ \s -> s{ bulletListLevel = lev + 1 }
- contents <- foldM addBlock empty blocks
- modify $ \s -> s{ bulletListLevel = lev }
- let marker = text (replicate lev '*')
- return $ marker <> text " " <> contents <> cr
-
--- | Convert ordered list item (a list of blocks) to asciidoc.
-orderedListItemToAsciiDoc :: WriterOptions -- ^ options
- -> String -- ^ list item marker
- -> [Block] -- ^ list item (list of blocks)
- -> State WriterState Doc
-orderedListItemToAsciiDoc opts marker blocks = do
- let addBlock :: Doc -> Block -> State WriterState Doc
- addBlock d b | isEmpty d = chomp `fmap` blockToAsciiDoc opts b
- addBlock d b@(BulletList _) = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> chomp x
- addBlock d b@(OrderedList _ _) = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> chomp x
- addBlock d b = do x <- blockToAsciiDoc opts b
- return $ d <> cr <> text "+" <> cr <> chomp x
- lev <- orderedListLevel `fmap` get
- modify $ \s -> s{ orderedListLevel = lev + 1 }
- contents <- foldM addBlock empty blocks
- modify $ \s -> s{ orderedListLevel = lev }
- return $ text marker <> text " " <> contents <> cr
-
--- | Convert definition list item (label, list of blocks) to asciidoc.
-definitionListItemToAsciiDoc :: WriterOptions
- -> ([Inline],[[Block]])
- -> State WriterState Doc
-definitionListItemToAsciiDoc opts (label, defs) = do
- labelText <- inlineListToAsciiDoc opts label
- marker <- defListMarker `fmap` get
- if marker == "::"
- then modify (\st -> st{ defListMarker = ";;"})
- else modify (\st -> st{ defListMarker = "::"})
- let divider = cr <> text "+" <> cr
- let defsToAsciiDoc :: [Block] -> State WriterState Doc
- defsToAsciiDoc ds = (vcat . intersperse divider . map chomp)
- `fmap` mapM (blockToAsciiDoc opts) ds
- defs' <- mapM defsToAsciiDoc defs
- modify (\st -> st{ defListMarker = marker })
- let contents = nest 2 $ vcat $ intersperse divider $ map chomp defs'
- return $ labelText <> text marker <> cr <> contents <> cr
-
--- | Convert list of Pandoc block elements to asciidoc.
-blockListToAsciiDoc :: WriterOptions -- ^ Options
- -> [Block] -- ^ List of block elements
- -> State WriterState Doc
-blockListToAsciiDoc opts blocks = cat `fmap` mapM (blockToAsciiDoc opts) blocks
-
-data SpacyLocation = End | Start
-
--- | Convert list of Pandoc inline elements to asciidoc.
-inlineListToAsciiDoc :: WriterOptions -> [Inline] -> State WriterState Doc
-inlineListToAsciiDoc opts lst = do
- oldIntraword <- gets intraword
- setIntraword False
- result <- go lst
- setIntraword oldIntraword
- return result
- where go [] = return empty
- go (y:x:xs)
- | not (isSpacy End y) = do
- y' <- if isSpacy Start x
- then inlineToAsciiDoc opts y
- else withIntraword $ inlineToAsciiDoc opts y
- x' <- withIntraword $ inlineToAsciiDoc opts x
- xs' <- go xs
- return (y' <> x' <> xs')
- | not (isSpacy Start x) = do
- y' <- withIntraword $ inlineToAsciiDoc opts y
- xs' <- go (x:xs)
- return (y' <> xs')
- go (x:xs) = do
- x' <- inlineToAsciiDoc opts x
- xs' <- go xs
- return (x' <> xs')
- isSpacy :: SpacyLocation -> Inline -> Bool
- isSpacy _ Space = True
- isSpacy _ LineBreak = True
- isSpacy _ SoftBreak = True
- -- Note that \W characters count as spacy in AsciiDoc
- -- for purposes of determining interword:
- isSpacy End (Str xs) = case reverse xs of
- c:_ -> isPunctuation c || isSpace c
- _ -> False
- isSpacy Start (Str (c:_)) = isPunctuation c || isSpace c
- isSpacy _ _ = False
-
-setIntraword :: Bool -> State WriterState ()
-setIntraword b = modify $ \st -> st{ intraword = b }
-
-withIntraword :: State WriterState a -> State WriterState a
-withIntraword p = setIntraword True *> p <* setIntraword False
-
--- | Convert Pandoc inline element to asciidoc.
-inlineToAsciiDoc :: WriterOptions -> Inline -> State WriterState Doc
-inlineToAsciiDoc opts (Emph lst) = do
- contents <- inlineListToAsciiDoc opts lst
- isIntraword <- gets intraword
- let marker = if isIntraword then "__" else "_"
- return $ marker <> contents <> marker
-inlineToAsciiDoc opts (Strong lst) = do
- contents <- inlineListToAsciiDoc opts lst
- isIntraword <- gets intraword
- let marker = if isIntraword then "**" else "*"
- return $ marker <> contents <> marker
-inlineToAsciiDoc opts (Strikeout lst) = do
- contents <- inlineListToAsciiDoc opts lst
- return $ "[line-through]*" <> contents <> "*"
-inlineToAsciiDoc opts (Superscript lst) = do
- contents <- inlineListToAsciiDoc opts lst
- return $ "^" <> contents <> "^"
-inlineToAsciiDoc opts (Subscript lst) = do
- contents <- inlineListToAsciiDoc opts lst
- return $ "~" <> contents <> "~"
-inlineToAsciiDoc opts (SmallCaps lst) = inlineListToAsciiDoc opts lst
-inlineToAsciiDoc opts (Quoted SingleQuote lst) =
- inlineListToAsciiDoc opts (Str "`" : lst ++ [Str "'"])
-inlineToAsciiDoc opts (Quoted DoubleQuote lst) =
- inlineListToAsciiDoc opts (Str "``" : lst ++ [Str "''"])
-inlineToAsciiDoc _ (Code _ str) = return $
- text "`" <> text (escapeStringUsing (backslashEscapes "`") str) <> "`"
-inlineToAsciiDoc _ (Str str) = return $ text $ escapeString str
-inlineToAsciiDoc _ (Math InlineMath str) =
- return $ "latexmath:[$" <> text str <> "$]"
-inlineToAsciiDoc _ (Math DisplayMath str) =
- return $ "latexmath:[\\[" <> text str <> "\\]]"
-inlineToAsciiDoc _ (RawInline f s)
- | f == "asciidoc" = return $ text s
- | otherwise = return empty
-inlineToAsciiDoc _ LineBreak = return $ " +" <> cr
-inlineToAsciiDoc _ Space = return space
-inlineToAsciiDoc opts SoftBreak =
- case writerWrapText opts of
- WrapAuto -> return space
- WrapPreserve -> return cr
- WrapNone -> return space
-inlineToAsciiDoc opts (Cite _ lst) = inlineListToAsciiDoc opts lst
-inlineToAsciiDoc opts (Link _ txt (src, _tit)) = do
--- relative: link:downloads/foo.zip[download foo.zip]
--- abs: http://google.cod[Google]
--- or my@email.com[email john]
- linktext <- inlineListToAsciiDoc opts txt
- let isRelative = ':' `notElem` src
- let prefix = if isRelative
- then text "link:"
- else empty
- let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
- let useAuto = case txt of
- [Str s] | escapeURI s == srcSuffix -> True
- _ -> False
- return $ if useAuto
- then text srcSuffix
- else prefix <> text src <> "[" <> linktext <> "]"
-inlineToAsciiDoc opts (Image attr alternate (src, tit)) = do
--- image:images/logo.png[Company logo, title="blah"]
- let txt = if (null alternate) || (alternate == [Str ""])
- then [Str "image"]
- else alternate
- linktext <- inlineListToAsciiDoc opts txt
- let linktitle = if null tit
- then empty
- else ",title=\"" <> text tit <> "\""
- showDim dir = case (dimension dir attr) of
- Just (Percent a) ->
- ["scaledwidth=" <> text (show (Percent a))]
- Just dim ->
- [text (show dir) <> "=" <> text (showInPixel opts dim)]
- Nothing ->
- []
- dimList = showDim Width ++ showDim Height
- dims = if null dimList
- then empty
- else "," <> cat (intersperse "," dimList)
- return $ "image:" <> text src <> "[" <> linktext <> linktitle <> dims <> "]"
-inlineToAsciiDoc opts (Note [Para inlines]) =
- inlineToAsciiDoc opts (Note [Plain inlines])
-inlineToAsciiDoc opts (Note [Plain inlines]) = do
- contents <- inlineListToAsciiDoc opts inlines
- return $ text "footnote:[" <> contents <> "]"
--- asciidoc can't handle blank lines in notes
-inlineToAsciiDoc _ (Note _) = return "[multiblock footnote omitted]"
-inlineToAsciiDoc opts (Span (ident,_,_) ils) = do
- let identifier = if (null ident) then empty else ("[[" <> text ident <> "]]")
- contents <- inlineListToAsciiDoc opts ils
- return $ identifier <> contents