Blame src/Text/Pandoc/Writers/RST.hs

Packit Service d2f85f
{-# LANGUAGE OverloadedStrings #-}
Packit Service d2f85f
{-
Packit Service d2f85f
Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
Packit Service d2f85f
Packit Service d2f85f
This program is free software; you can redistribute it and/or modify
Packit Service d2f85f
it under the terms of the GNU General Public License as published by
Packit Service d2f85f
the Free Software Foundation; either version 2 of the License, or
Packit Service d2f85f
(at your option) any later version.
Packit Service d2f85f
Packit Service d2f85f
This program is distributed in the hope that it will be useful,
Packit Service d2f85f
but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d2f85f
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d2f85f
GNU General Public License for more details.
Packit Service d2f85f
Packit Service d2f85f
You should have received a copy of the GNU General Public License
Packit Service d2f85f
along with this program; if not, write to the Free Software
Packit Service d2f85f
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service d2f85f
-}
Packit Service d2f85f
Packit Service d2f85f
{- |
Packit Service d2f85f
   Module      : Text.Pandoc.Writers.RST
Packit Service d2f85f
   Copyright   : Copyright (C) 2006-2017 John MacFarlane
Packit Service d2f85f
   License     : GNU GPL, version 2 or above
Packit Service d2f85f
Packit Service d2f85f
   Maintainer  : John MacFarlane <jgm@berkeley.edu>
Packit Service d2f85f
   Stability   : alpha
Packit Service d2f85f
   Portability : portable
Packit Service d2f85f
Packit Service d2f85f
Conversion of 'Pandoc' documents to reStructuredText.
Packit Service d2f85f
Packit Service d2f85f
reStructuredText:  <http://docutils.sourceforge.net/rst.html>
Packit Service d2f85f
-}
Packit Service d2f85f
module Text.Pandoc.Writers.RST ( writeRST ) where
Packit Service d2f85f
import Control.Monad.State.Strict
Packit Service d2f85f
import Data.Char (isSpace, toLower)
Packit Service d2f85f
import Data.List (isPrefixOf, stripPrefix)
Packit Service d2f85f
import Data.Maybe (fromMaybe)
Packit Service d2f85f
import Data.Text (Text, stripEnd)
Packit Service d2f85f
import qualified Text.Pandoc.Builder as B
Packit Service d2f85f
import Text.Pandoc.Class (PandocMonad, report)
Packit Service d2f85f
import Text.Pandoc.Definition
Packit Service d2f85f
import Text.Pandoc.ImageSize
Packit Service d2f85f
import Text.Pandoc.Logging
Packit Service d2f85f
import Text.Pandoc.Options
Packit Service d2f85f
import Text.Pandoc.Pretty
Packit Service d2f85f
import Text.Pandoc.Shared
Packit Service d2f85f
import Text.Pandoc.Templates (renderTemplate')
Packit Service d2f85f
import Text.Pandoc.Writers.Shared
Packit Service d2f85f
Packit Service d2f85f
type Refs = [([Inline], Target)]
Packit Service d2f85f
Packit Service d2f85f
data WriterState =
Packit Service d2f85f
  WriterState { stNotes       :: [[Block]]
Packit Service d2f85f
              , stLinks       :: Refs
Packit Service d2f85f
              , stImages      :: [([Inline], (Attr, String, String, Maybe String))]
Packit Service d2f85f
              , stHasMath     :: Bool
Packit Service d2f85f
              , stHasRawTeX   :: Bool
Packit Service d2f85f
              , stOptions     :: WriterOptions
Packit Service d2f85f
              , stTopLevel    :: Bool
Packit Service d2f85f
              , stLastNested  :: Bool
Packit Service d2f85f
              }
Packit Service d2f85f
Packit Service d2f85f
type RST = StateT WriterState
Packit Service d2f85f
Packit Service d2f85f
-- | Convert Pandoc to RST.
Packit Service d2f85f
writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m Text
Packit Service d2f85f
writeRST opts document = do
Packit Service d2f85f
  let st = WriterState { stNotes = [], stLinks = [],
Packit Service d2f85f
                         stImages = [], stHasMath = False,
Packit Service d2f85f
                         stHasRawTeX = False, stOptions = opts,
Packit Service d2f85f
                         stTopLevel = True, stLastNested = False}
Packit Service d2f85f
  evalStateT (pandocToRST document) st
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of document.
Packit Service d2f85f
pandocToRST :: PandocMonad m => Pandoc -> RST m Text
Packit Service d2f85f
pandocToRST (Pandoc meta blocks) = do
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  let colwidth = if writerWrapText opts == WrapAuto
Packit Service d2f85f
                    then Just $ writerColumns opts
Packit Service d2f85f
                    else Nothing
Packit Service d2f85f
  let render' :: Doc -> Text
Packit Service d2f85f
      render' = render colwidth
Packit Service d2f85f
  let subtit = case lookupMeta "subtitle" meta of
Packit Service d2f85f
                    Just (MetaBlocks [Plain xs]) -> xs
Packit Service d2f85f
                    _                            -> []
Packit Service d2f85f
  title <- titleToRST (docTitle meta) subtit
Packit Service d2f85f
  metadata <- metaToJSON opts
Packit Service d2f85f
                (fmap render' . blockListToRST)
Packit Service d2f85f
                (fmap (stripEnd . render') . inlineListToRST)
Packit Service d2f85f
                $ B.deleteMeta "title" $ B.deleteMeta "subtitle" meta
Packit Service d2f85f
  body <- blockListToRST' True $ case writerTemplate opts of
Packit Service d2f85f
                                      Just _  -> normalizeHeadings 1 blocks
Packit Service d2f85f
                                      Nothing -> blocks
Packit Service d2f85f
  notes <- gets (reverse . stNotes) >>= notesToRST
Packit Service d2f85f
  -- note that the notes may contain refs, so we do them first
Packit Service d2f85f
  refs <- gets (reverse . stLinks) >>= refsToRST
Packit Service d2f85f
  pics <- gets (reverse . stImages) >>= pictRefsToRST
Packit Service d2f85f
  hasMath <- gets stHasMath
Packit Service d2f85f
  rawTeX <- gets stHasRawTeX
Packit Service d2f85f
  let main = render' $ foldl ($+$) empty [body, notes, refs, pics]
Packit Service d2f85f
  let context = defField "body" main
Packit Service d2f85f
              $ defField "toc" (writerTableOfContents opts)
Packit Service d2f85f
              $ defField "toc-depth" (show $ writerTOCDepth opts)
Packit Service d2f85f
              $ defField "math" hasMath
Packit Service d2f85f
              $ defField "title" (render Nothing title :: String)
Packit Service d2f85f
              $ defField "math" hasMath
Packit Service d2f85f
              $ defField "rawtex" rawTeX metadata
Packit Service d2f85f
  case writerTemplate opts of
Packit Service d2f85f
       Nothing  -> return main
Packit Service d2f85f
       Just tpl -> renderTemplate' tpl context
Packit Service d2f85f
  where
Packit Service d2f85f
    normalizeHeadings lev (Header l a i:bs) =
Packit Service d2f85f
      Header lev a i:normalizeHeadings (lev+1) cont ++ normalizeHeadings lev bs'
Packit Service d2f85f
      where (cont,bs') = break (headerLtEq l) bs
Packit Service d2f85f
            headerLtEq level (Header l' _ _) = l' <= level
Packit Service d2f85f
            headerLtEq _ _                   = False
Packit Service d2f85f
    normalizeHeadings lev (b:bs) = b:normalizeHeadings lev bs
Packit Service d2f85f
    normalizeHeadings _   []     = []
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of reference key table.
Packit Service d2f85f
refsToRST :: PandocMonad m => Refs -> RST m Doc
Packit Service d2f85f
refsToRST refs = mapM keyToRST refs >>= return . vcat
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of a reference key.
Packit Service d2f85f
keyToRST :: PandocMonad m => ([Inline], (String, String)) -> RST m Doc
Packit Service d2f85f
keyToRST (label, (src, _)) = do
Packit Service d2f85f
  label' <- inlineListToRST label
Packit Service d2f85f
  let label'' = if ':' `elem` (render Nothing label' :: String)
Packit Service d2f85f
                   then char '`' <> label' <> char '`'
Packit Service d2f85f
                   else label'
Packit Service d2f85f
  return $ nowrap $ ".. _" <> label'' <> ": " <> text src
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of notes.
Packit Service d2f85f
notesToRST :: PandocMonad m => [[Block]] -> RST m Doc
Packit Service d2f85f
notesToRST notes =
Packit Service d2f85f
  mapM (uncurry noteToRST) (zip [1..] notes) >>=
Packit Service d2f85f
  return . vsep
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of a note.
Packit Service d2f85f
noteToRST :: PandocMonad m => Int -> [Block] -> RST m Doc
Packit Service d2f85f
noteToRST num note = do
Packit Service d2f85f
  contents <- blockListToRST note
Packit Service d2f85f
  let marker = ".. [" <> text (show num) <> "]"
Packit Service d2f85f
  return $ nowrap $ marker $$ nest 3 contents
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of picture reference table.
Packit Service d2f85f
pictRefsToRST :: PandocMonad m
Packit Service d2f85f
              => [([Inline], (Attr, String, String, Maybe String))]
Packit Service d2f85f
              -> RST m Doc
Packit Service d2f85f
pictRefsToRST refs = mapM pictToRST refs >>= return . vcat
Packit Service d2f85f
Packit Service d2f85f
-- | Return RST representation of a picture substitution reference.
Packit Service d2f85f
pictToRST :: PandocMonad m
Packit Service d2f85f
          => ([Inline], (Attr, String, String, Maybe String))
Packit Service d2f85f
          -> RST m Doc
Packit Service d2f85f
pictToRST (label, (attr, src, _, mbtarget)) = do
Packit Service d2f85f
  label' <- inlineListToRST label
Packit Service d2f85f
  dims   <- imageDimsToRST attr
Packit Service d2f85f
  let (_, cls, _) = attr
Packit Service d2f85f
      classes = if null cls
Packit Service d2f85f
                   then empty
Packit Service d2f85f
                   else ":class: " <> text (unwords cls)
Packit Service d2f85f
  return $ nowrap
Packit Service d2f85f
         $ ".. |" <> label' <> "| image:: " <> text src $$ hang 3 empty (classes $$ dims)
Packit Service d2f85f
         $$ case mbtarget of
Packit Service d2f85f
                 Nothing -> empty
Packit Service d2f85f
                 Just t  -> "   :target: " <> text t
Packit Service d2f85f
Packit Service d2f85f
-- | Escape special characters for RST.
Packit Service d2f85f
escapeString :: WriterOptions -> String -> String
Packit Service d2f85f
escapeString = escapeString' True
Packit Service d2f85f
  where
Packit Service d2f85f
  escapeString' _ _  [] = []
Packit Service d2f85f
  escapeString' firstChar opts (c:cs) =
Packit Service d2f85f
    case c of
Packit Service d2f85f
         _ | c `elem` ['\\','`','*','_','|'] &&
Packit Service d2f85f
             (firstChar || null cs) -> '\\':c:escapeString' False opts cs
Packit Service d2f85f
         '\'' | isEnabled Ext_smart opts -> '\\':'\'':escapeString' False opts cs
Packit Service d2f85f
         '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString' False opts cs
Packit Service d2f85f
         '-' | isEnabled Ext_smart opts ->
Packit Service d2f85f
                case cs of
Packit Service d2f85f
                     '-':_ -> '\\':'-':escapeString' False opts cs
Packit Service d2f85f
                     _     -> '-':escapeString' False opts cs
Packit Service d2f85f
         '.' | isEnabled Ext_smart opts ->
Packit Service d2f85f
                case cs of
Packit Service d2f85f
                     '.':'.':rest -> '\\':'.':'.':'.':escapeString' False opts rest
Packit Service d2f85f
                     _            -> '.':escapeString' False opts cs
Packit Service d2f85f
         _ -> c : escapeString' False opts cs
Packit Service d2f85f
Packit Service d2f85f
titleToRST :: PandocMonad m => [Inline] -> [Inline] -> RST m Doc
Packit Service d2f85f
titleToRST [] _ = return empty
Packit Service d2f85f
titleToRST tit subtit = do
Packit Service d2f85f
  title <- inlineListToRST tit
Packit Service d2f85f
  subtitle <- inlineListToRST subtit
Packit Service d2f85f
  return $ bordered title '=' $$ bordered subtitle '-'
Packit Service d2f85f
Packit Service d2f85f
bordered :: Doc -> Char -> Doc
Packit Service d2f85f
bordered contents c =
Packit Service d2f85f
  if len > 0
Packit Service d2f85f
     then border $$ contents $$ border
Packit Service d2f85f
     else empty
Packit Service d2f85f
   where len = offset contents
Packit Service d2f85f
         border = text (replicate len c)
Packit Service d2f85f
Packit Service d2f85f
-- | Convert Pandoc block element to RST.
Packit Service d2f85f
blockToRST :: PandocMonad m
Packit Service d2f85f
           => Block         -- ^ Block element
Packit Service d2f85f
           -> RST m Doc
Packit Service d2f85f
blockToRST Null = return empty
Packit Service d2f85f
blockToRST (Div attr bs) = do
Packit Service d2f85f
  contents <- blockListToRST bs
Packit Service d2f85f
  let startTag = ".. raw:: html" $+$ nest 3 (tagWithAttrs "div" attr)
Packit Service d2f85f
  let endTag = ".. raw:: html" $+$ nest 3 ""
Packit Service d2f85f
  return $ blankline <> startTag $+$ contents $+$ endTag $$ blankline
Packit Service d2f85f
blockToRST (Plain inlines) = inlineListToRST inlines
Packit Service d2f85f
-- title beginning with fig: indicates that the image is a figure
Packit Service d2f85f
blockToRST (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do
Packit Service d2f85f
  capt <- inlineListToRST txt
Packit Service d2f85f
  dims <- imageDimsToRST attr
Packit Service d2f85f
  let fig = "figure:: " <> text src
Packit Service d2f85f
      alt = ":alt: " <> if null tit then capt else text tit
Packit Service d2f85f
      (_,cls,_) = attr
Packit Service d2f85f
      classes = if null cls
Packit Service d2f85f
                   then empty
Packit Service d2f85f
                   else ":figclass: " <> text (unwords cls)
Packit Service d2f85f
  return $ hang 3 ".. " (fig $$ alt $$ classes $$ dims $+$ capt) $$ blankline
Packit Service d2f85f
blockToRST (Para inlines)
Packit Service d2f85f
  | LineBreak `elem` inlines =
Packit Service d2f85f
      linesToLineBlock $ splitBy (==LineBreak) inlines
Packit Service d2f85f
  | otherwise = do
Packit Service d2f85f
      contents <- inlineListToRST inlines
Packit Service d2f85f
      return $ contents <> blankline
Packit Service d2f85f
blockToRST (LineBlock lns) =
Packit Service d2f85f
  linesToLineBlock lns
Packit Service d2f85f
blockToRST (RawBlock f@(Format f') str)
Packit Service d2f85f
  | f == "rst" = return $ text str
Packit Service d2f85f
  | otherwise  = return $ blankline <> ".. raw:: " <>
Packit Service d2f85f
                    text (map toLower f') $+$
Packit Service d2f85f
                    nest 3 (text str) $$ blankline
Packit Service d2f85f
blockToRST HorizontalRule =
Packit Service d2f85f
  return $ blankline $$ "--------------" $$ blankline
Packit Service d2f85f
blockToRST (Header level (name,classes,_) inlines) = do
Packit Service d2f85f
  contents <- inlineListToRST inlines
Packit Service d2f85f
  -- we calculate the id that would be used by auto_identifiers
Packit Service d2f85f
  -- so we know whether to print an explicit identifier
Packit Service d2f85f
  let autoId = uniqueIdent inlines mempty
Packit Service d2f85f
  isTopLevel <- gets stTopLevel
Packit Service d2f85f
  if isTopLevel
Packit Service d2f85f
    then do
Packit Service d2f85f
          let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
Packit Service d2f85f
          let border = text $ replicate (offset contents) headerChar
Packit Service d2f85f
          let anchor | null name || name == autoId = empty
Packit Service d2f85f
                     | otherwise = ".. _" <> text name <> ":" $$ blankline
Packit Service d2f85f
          return $ nowrap $ anchor $$ contents $$ border $$ blankline
Packit Service d2f85f
    else do
Packit Service d2f85f
          let rub     = "rubric:: " <> contents
Packit Service d2f85f
          let name' | null name    = empty
Packit Service d2f85f
                    | otherwise    = ":name: " <> text name
Packit Service d2f85f
          let cls   | null classes = empty
Packit Service d2f85f
                    | otherwise    = ":class: " <> text (unwords classes)
Packit Service d2f85f
          return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
Packit Service d2f85f
blockToRST (CodeBlock (_,classes,kvs) str) = do
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  let tabstop = writerTabStop opts
Packit Service d2f85f
  let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs
Packit Service d2f85f
  let numberlines = if "numberLines" `elem` classes
Packit Service d2f85f
                       then "   :number-lines:" <> startnum
Packit Service d2f85f
                       else empty
Packit Service d2f85f
  if "haskell" `elem` classes && "literate" `elem` classes &&
Packit Service d2f85f
                  isEnabled Ext_literate_haskell opts
Packit Service d2f85f
     then return $ prefixed "> " (text str) $$ blankline
Packit Service d2f85f
     else return $
Packit Service d2f85f
          (case [c | c <- classes,
Packit Service d2f85f
                     c `notElem` ["sourceCode","literate","numberLines"]] of
Packit Service d2f85f
             []       -> "::"
Packit Service d2f85f
             (lang:_) -> (".. code:: " <> text lang) $$ numberlines)
Packit Service d2f85f
          $+$ nest tabstop (text str) $$ blankline
Packit Service d2f85f
blockToRST (BlockQuote blocks) = do
Packit Service d2f85f
  tabstop <- gets $ writerTabStop . stOptions
Packit Service d2f85f
  contents <- blockListToRST blocks
Packit Service d2f85f
  return $ nest tabstop contents <> blankline
Packit Service d2f85f
blockToRST (Table caption aligns widths headers rows) = do
Packit Service d2f85f
  caption' <- inlineListToRST caption
Packit Service d2f85f
  let blocksToDoc opts bs = do
Packit Service d2f85f
         oldOpts <- gets stOptions
Packit Service d2f85f
         modify $ \st -> st{ stOptions = opts }
Packit Service d2f85f
         result <- blockListToRST bs
Packit Service d2f85f
         modify $ \st -> st{ stOptions = oldOpts }
Packit Service d2f85f
         return result
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  tbl <- gridTable opts blocksToDoc (all null headers)
Packit Service d2f85f
            (map (const AlignDefault) aligns) widths
Packit Service d2f85f
            headers rows
Packit Service d2f85f
  return $ if null caption
Packit Service d2f85f
              then tbl $$ blankline
Packit Service d2f85f
              else (".. table:: " <> caption') $$ blankline $$ nest 3 tbl $$
Packit Service d2f85f
                   blankline
Packit Service d2f85f
blockToRST (BulletList items) = do
Packit Service d2f85f
  contents <- mapM bulletListItemToRST items
Packit Service d2f85f
  -- ensure that sublists have preceding blank line
Packit Service d2f85f
  return $ blankline $$ chomp (vcat contents) $$ blankline
Packit Service d2f85f
blockToRST (OrderedList (start, style', delim) items) = do
Packit Service d2f85f
  let markers = if start == 1 && style' == DefaultStyle && delim == DefaultDelim
Packit Service d2f85f
                   then replicate (length items) "#."
Packit Service d2f85f
                   else take (length items) $ orderedListMarkers
Packit Service d2f85f
                                              (start, style', delim)
Packit Service d2f85f
  let maxMarkerLength = maximum $ map length markers
Packit Service d2f85f
  let markers' = map (\m -> let s = maxMarkerLength - length m
Packit Service d2f85f
                            in  m ++ replicate s ' ') markers
Packit Service d2f85f
  contents <- mapM (uncurry orderedListItemToRST) $
Packit Service d2f85f
              zip markers' items
Packit Service d2f85f
  -- ensure that sublists have preceding blank line
Packit Service d2f85f
  return $ blankline $$ chomp (vcat contents) $$ blankline
Packit Service d2f85f
blockToRST (DefinitionList items) = do
Packit Service d2f85f
  contents <- mapM definitionListItemToRST items
Packit Service d2f85f
  -- ensure that sublists have preceding blank line
Packit Service d2f85f
  return $ blankline $$ chomp (vcat contents) $$ blankline
Packit Service d2f85f
Packit Service d2f85f
-- | Convert bullet list item (list of blocks) to RST.
Packit Service d2f85f
bulletListItemToRST :: PandocMonad m => [Block] -> RST m Doc
Packit Service d2f85f
bulletListItemToRST items = do
Packit Service d2f85f
  contents <- blockListToRST items
Packit Service d2f85f
  return $ hang 3 "-  " $ contents <> cr
Packit Service d2f85f
Packit Service d2f85f
-- | Convert ordered list item (a list of blocks) to RST.
Packit Service d2f85f
orderedListItemToRST :: PandocMonad m
Packit Service d2f85f
                     => String   -- ^ marker for list item
Packit Service d2f85f
                     -> [Block]  -- ^ list item (list of blocks)
Packit Service d2f85f
                     -> RST m Doc
Packit Service d2f85f
orderedListItemToRST marker items = do
Packit Service d2f85f
  contents <- blockListToRST items
Packit Service d2f85f
  let marker' = marker ++ " "
Packit Service d2f85f
  return $ hang (length marker') (text marker') $ contents <> cr
Packit Service d2f85f
Packit Service d2f85f
-- | Convert defintion list item (label, list of blocks) to RST.
Packit Service d2f85f
definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc
Packit Service d2f85f
definitionListItemToRST (label, defs) = do
Packit Service d2f85f
  label' <- inlineListToRST label
Packit Service d2f85f
  contents <- liftM vcat $ mapM blockListToRST defs
Packit Service d2f85f
  tabstop <- gets $ writerTabStop . stOptions
Packit Service d2f85f
  return $ nowrap label' $$ nest tabstop (nestle contents <> cr)
Packit Service d2f85f
Packit Service d2f85f
-- | Format a list of lines as line block.
Packit Service d2f85f
linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m Doc
Packit Service d2f85f
linesToLineBlock inlineLines = do
Packit Service d2f85f
  lns <- mapM inlineListToRST inlineLines
Packit Service d2f85f
  return $
Packit Service d2f85f
                      vcat (map (hang 2 (text "| ")) lns) <> blankline
Packit Service d2f85f
Packit Service d2f85f
-- | Convert list of Pandoc block elements to RST.
Packit Service d2f85f
blockListToRST' :: PandocMonad m
Packit Service d2f85f
                => Bool
Packit Service d2f85f
                -> [Block]       -- ^ List of block elements
Packit Service d2f85f
                -> RST m Doc
Packit Service d2f85f
blockListToRST' topLevel blocks = do
Packit Service d2f85f
  tl <- gets stTopLevel
Packit Service d2f85f
  modify (\s->s{stTopLevel=topLevel, stLastNested=False})
Packit Service d2f85f
  res <- vcat `fmap` mapM blockToRST' blocks
Packit Service d2f85f
  modify (\s->s{stTopLevel=tl})
Packit Service d2f85f
  return res
Packit Service d2f85f
Packit Service d2f85f
blockToRST' :: PandocMonad m => Block -> RST m Doc
Packit Service d2f85f
blockToRST' (x@BlockQuote{}) = do
Packit Service d2f85f
  lastNested <- gets stLastNested
Packit Service d2f85f
  res <- blockToRST x
Packit Service d2f85f
  modify (\s -> s{stLastNested = True})
Packit Service d2f85f
  return $ if lastNested
Packit Service d2f85f
              then ".." $+$ res
Packit Service d2f85f
              else res
Packit Service d2f85f
blockToRST' x = do
Packit Service d2f85f
  modify (\s -> s{stLastNested =
Packit Service d2f85f
    case x of
Packit Service d2f85f
         Para [Image _ _ (_,'f':'i':'g':':':_)] -> True
Packit Service d2f85f
         Para{}                                 -> False
Packit Service d2f85f
         Plain{}                                -> False
Packit Service d2f85f
         Header{}                               -> False
Packit Service d2f85f
         LineBlock{}                            -> False
Packit Service d2f85f
         HorizontalRule                         -> False
Packit Service d2f85f
         _                                      -> True
Packit Service d2f85f
    })
Packit Service d2f85f
  blockToRST x
Packit Service d2f85f
Packit Service d2f85f
blockListToRST :: PandocMonad m
Packit Service d2f85f
               => [Block]       -- ^ List of block elements
Packit Service d2f85f
               -> RST m Doc
Packit Service d2f85f
blockListToRST = blockListToRST' False
Packit Service d2f85f
Packit Service d2f85f
-- | Convert list of Pandoc inline elements to RST.
Packit Service d2f85f
inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
Packit Service d2f85f
inlineListToRST lst =
Packit Service d2f85f
  mapM inlineToRST (removeSpaceAfterDisplayMath $ insertBS lst) >>=
Packit Service d2f85f
    return . hcat
Packit Service d2f85f
  where -- remove spaces after displaymath, as they screw up indentation:
Packit Service d2f85f
        removeSpaceAfterDisplayMath (Math DisplayMath x : zs) =
Packit Service d2f85f
              Math DisplayMath x : dropWhile (==Space) zs
Packit Service d2f85f
        removeSpaceAfterDisplayMath (x:xs) = x : removeSpaceAfterDisplayMath xs
Packit Service d2f85f
        removeSpaceAfterDisplayMath [] = []
Packit Service d2f85f
        insertBS :: [Inline] -> [Inline] -- insert '\ ' where needed
Packit Service d2f85f
        insertBS (x:y:z:zs)
Packit Service d2f85f
          | isComplex y && surroundComplex x z =
Packit Service d2f85f
              x : y : insertBS (z : zs)
Packit Service d2f85f
        insertBS (x:y:zs)
Packit Service d2f85f
          | isComplex x && not (okAfterComplex y) =
Packit Service d2f85f
              x : RawInline "rst" "\\ " : insertBS (y : zs)
Packit Service d2f85f
          | isComplex y && not (okBeforeComplex x) =
Packit Service d2f85f
              x : RawInline "rst" "\\ " : insertBS (y : zs)
Packit Service d2f85f
          | otherwise =
Packit Service d2f85f
              x : insertBS (y : zs)
Packit Service d2f85f
        insertBS (x:ys) = x : insertBS ys
Packit Service d2f85f
        insertBS [] = []
Packit Service d2f85f
        surroundComplex :: Inline -> Inline -> Bool
Packit Service d2f85f
        surroundComplex (Str s@(_:_)) (Str s'@(_:_)) =
Packit Service d2f85f
          case (last s, head s') of
Packit Service d2f85f
             ('\'','\'') -> True
Packit Service d2f85f
             ('"','"')   -> True
Packit Service d2f85f
             ('<','>')   -> True
Packit Service d2f85f
             ('[',']')   -> True
Packit Service d2f85f
             ('{','}')   -> True
Packit Service d2f85f
             _           -> False
Packit Service d2f85f
        surroundComplex _ _ = False
Packit Service d2f85f
        okAfterComplex :: Inline -> Bool
Packit Service d2f85f
        okAfterComplex Space = True
Packit Service d2f85f
        okAfterComplex SoftBreak = True
Packit Service d2f85f
        okAfterComplex LineBreak = True
Packit Service d2f85f
        okAfterComplex (Str (c:_)) = isSpace c || c `elem` ("-.,:;!?\\/'\")]}>–—" :: String)
Packit Service d2f85f
        okAfterComplex _ = False
Packit Service d2f85f
        okBeforeComplex :: Inline -> Bool
Packit Service d2f85f
        okBeforeComplex Space = True
Packit Service d2f85f
        okBeforeComplex SoftBreak = True
Packit Service d2f85f
        okBeforeComplex LineBreak = True
Packit Service d2f85f
        okBeforeComplex (Str (c:_)) = isSpace c || c `elem` ("-:/'\"<([{–—" :: String)
Packit Service d2f85f
        okBeforeComplex _ = False
Packit Service d2f85f
        isComplex :: Inline -> Bool
Packit Service d2f85f
        isComplex (Emph _)        = True
Packit Service d2f85f
        isComplex (Strong _)      = True
Packit Service d2f85f
        isComplex (SmallCaps _)   = True
Packit Service d2f85f
        isComplex (Strikeout _)   = True
Packit Service d2f85f
        isComplex (Superscript _) = True
Packit Service d2f85f
        isComplex (Subscript _)   = True
Packit Service d2f85f
        isComplex Link{}          = True
Packit Service d2f85f
        isComplex Image{}         = True
Packit Service d2f85f
        isComplex (Code _ _)      = True
Packit Service d2f85f
        isComplex (Math _ _)      = True
Packit Service d2f85f
        isComplex (Cite _ (x:_))  = isComplex x
Packit Service d2f85f
        isComplex (Span _ (x:_))  = isComplex x
Packit Service d2f85f
        isComplex _               = False
Packit Service d2f85f
Packit Service d2f85f
-- | Convert Pandoc inline element to RST.
Packit Service d2f85f
inlineToRST :: PandocMonad m => Inline -> RST m Doc
Packit Service d2f85f
inlineToRST (Span (_,_,kvs) ils) = do
Packit Service d2f85f
  contents <- inlineListToRST ils
Packit Service d2f85f
  return $
Packit Service d2f85f
    case lookup "role" kvs of
Packit Service d2f85f
          Just role -> ":" <> text role <> ":`" <> contents <> "`"
Packit Service d2f85f
          Nothing   -> contents
Packit Service d2f85f
inlineToRST (Emph lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  return $ "*" <> contents <> "*"
Packit Service d2f85f
inlineToRST (Strong lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  return $ "**" <> contents <> "**"
Packit Service d2f85f
inlineToRST (Strikeout lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  return $ "[STRIKEOUT:" <> contents <> "]"
Packit Service d2f85f
inlineToRST (Superscript lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  return $ ":sup:`" <> contents <> "`"
Packit Service d2f85f
inlineToRST (Subscript lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  return $ ":sub:`" <> contents <> "`"
Packit Service d2f85f
inlineToRST (SmallCaps lst) = inlineListToRST lst
Packit Service d2f85f
inlineToRST (Quoted SingleQuote lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  if isEnabled Ext_smart opts
Packit Service d2f85f
     then return $ "'" <> contents <> "'"
Packit Service d2f85f
     else return $ "‘" <> contents <> "’"
Packit Service d2f85f
inlineToRST (Quoted DoubleQuote lst) = do
Packit Service d2f85f
  contents <- inlineListToRST lst
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  if isEnabled Ext_smart opts
Packit Service d2f85f
     then return $ "\"" <> contents <> "\""
Packit Service d2f85f
     else return $ "“" <> contents <> "”"
Packit Service d2f85f
inlineToRST (Cite _  lst) =
Packit Service d2f85f
  inlineListToRST lst
Packit Service d2f85f
inlineToRST (Code _ str) = do
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  -- we trim the string because the delimiters must adjoin a
Packit Service d2f85f
  -- non-space character; see #3496
Packit Service d2f85f
  -- we use :literal: when the code contains backticks, since
Packit Service d2f85f
  -- :literal: allows backslash-escapes; see #3974
Packit Service d2f85f
  return $ if '`' `elem` str
Packit Service d2f85f
              then ":literal:`" <> text (escapeString opts (trim str)) <> "`"
Packit Service d2f85f
              else "``" <> text (trim str) <> "``"
Packit Service d2f85f
inlineToRST (Str str) = do
Packit Service d2f85f
  opts <- gets stOptions
Packit Service d2f85f
  return $ text $
Packit Service d2f85f
    (if isEnabled Ext_smart opts
Packit Service d2f85f
        then unsmartify opts
Packit Service d2f85f
        else id) $ escapeString opts str
Packit Service d2f85f
inlineToRST (Math t str) = do
Packit Service d2f85f
  modify $ \st -> st{ stHasMath = True }
Packit Service d2f85f
  return $ if t == InlineMath
Packit Service d2f85f
              then ":math:`" <> text str <> "`"
Packit Service d2f85f
              else if '\n' `elem` str
Packit Service d2f85f
                   then blankline $$ ".. math::" $$
Packit Service d2f85f
                        blankline $$ nest 3 (text str) $$ blankline
Packit Service d2f85f
                   else blankline $$ (".. math:: " <> text str) $$ blankline
Packit Service d2f85f
inlineToRST il@(RawInline f x)
Packit Service d2f85f
  | f == "rst" = return $ text x
Packit Service d2f85f
  | f == "latex" || f == "tex" = do
Packit Service d2f85f
      modify $ \st -> st{ stHasRawTeX = True }
Packit Service d2f85f
      return $ ":raw-latex:`" <> text x <> "`"
Packit Service d2f85f
  | otherwise  = empty <$ report (InlineNotRendered il)
Packit Service d2f85f
inlineToRST LineBreak = return cr -- there's no line break in RST (see Para)
Packit Service d2f85f
inlineToRST Space = return space
Packit Service d2f85f
inlineToRST SoftBreak = do
Packit Service d2f85f
  wrapText <- gets $ writerWrapText . stOptions
Packit Service d2f85f
  case wrapText of
Packit Service d2f85f
        WrapPreserve -> return cr
Packit Service d2f85f
        WrapAuto     -> return space
Packit Service d2f85f
        WrapNone     -> return space
Packit Service d2f85f
-- autolink
Packit Service d2f85f
inlineToRST (Link _ [Str str] (src, _))
Packit Service d2f85f
  | isURI src &&
Packit Service d2f85f
    if "mailto:" `isPrefixOf` src
Packit Service d2f85f
       then src == escapeURI ("mailto:" ++ str)
Packit Service d2f85f
       else src == escapeURI str = do
Packit Service d2f85f
  let srcSuffix = fromMaybe src (stripPrefix "mailto:" src)
Packit Service d2f85f
  return $ text srcSuffix
Packit Service d2f85f
inlineToRST (Link _ [Image attr alt (imgsrc,imgtit)] (src, _tit)) = do
Packit Service d2f85f
  label <- registerImage attr alt (imgsrc,imgtit) (Just src)
Packit Service d2f85f
  return $ "|" <> label <> "|"
Packit Service d2f85f
inlineToRST (Link _ txt (src, tit)) = do
Packit Service d2f85f
  useReferenceLinks <- gets $ writerReferenceLinks . stOptions
Packit Service d2f85f
  linktext <- inlineListToRST $ B.toList . B.trimInlines . B.fromList $ txt
Packit Service d2f85f
  if useReferenceLinks
Packit Service d2f85f
    then do refs <- gets stLinks
Packit Service d2f85f
            case lookup txt refs of
Packit Service d2f85f
                 Just (src',tit') ->
Packit Service d2f85f
                   if src == src' && tit == tit'
Packit Service d2f85f
                      then return $ "`" <> linktext <> "`_"
Packit Service d2f85f
                      else
Packit Service d2f85f
                        return $ "`" <> linktext <> " <" <> text src <> ">`__"
Packit Service d2f85f
                 Nothing -> do
Packit Service d2f85f
                   modify $ \st -> st { stLinks = (txt,(src,tit)):refs }
Packit Service d2f85f
                   return $ "`" <> linktext <> "`_"
Packit Service d2f85f
    else return $ "`" <> linktext <> " <" <> text src <> ">`__"
Packit Service d2f85f
inlineToRST (Image attr alternate (source, tit)) = do
Packit Service d2f85f
  label <- registerImage attr alternate (source,tit) Nothing
Packit Service d2f85f
  return $ "|" <> label <> "|"
Packit Service d2f85f
inlineToRST (Note contents) = do
Packit Service d2f85f
  -- add to notes in state
Packit Service d2f85f
  notes <- gets stNotes
Packit Service d2f85f
  modify $ \st -> st { stNotes = contents:notes }
Packit Service d2f85f
  let ref = show $ length notes + 1
Packit Service d2f85f
  return $ " [" <> text ref <> "]_"
Packit Service d2f85f
Packit Service d2f85f
registerImage :: PandocMonad m => Attr -> [Inline] -> Target -> Maybe String -> RST m Doc
Packit Service d2f85f
registerImage attr alt (src,tit) mbtarget = do
Packit Service d2f85f
  pics <- gets stImages
Packit Service d2f85f
  txt <- case lookup alt pics of
Packit Service d2f85f
               Just (a,s,t,mbt) | (a,s,t,mbt) == (attr,src,tit,mbtarget)
Packit Service d2f85f
                 -> return alt
Packit Service d2f85f
               _ -> do
Packit Service d2f85f
                 let alt' = if null alt || alt == [Str ""]
Packit Service d2f85f
                               then [Str $ "image" ++ show (length pics)]
Packit Service d2f85f
                               else alt
Packit Service d2f85f
                 modify $ \st -> st { stImages =
Packit Service d2f85f
                        (alt', (attr,src,tit, mbtarget)):stImages st }
Packit Service d2f85f
                 return alt'
Packit Service d2f85f
  inlineListToRST txt
Packit Service d2f85f
Packit Service d2f85f
imageDimsToRST :: PandocMonad m => Attr -> RST m Doc
Packit Service d2f85f
imageDimsToRST attr = do
Packit Service d2f85f
  let (ident, _, _) = attr
Packit Service d2f85f
      name = if null ident
Packit Service d2f85f
                then empty
Packit Service d2f85f
                else ":name: " <> text ident
Packit Service d2f85f
      showDim dir = let cols d = ":" <> text (show dir) <> ": " <> text (show d)
Packit Service d2f85f
                    in  case dimension dir attr of
Packit Service d2f85f
                          Just (Percent a) ->
Packit Service d2f85f
                            case dir of
Packit Service d2f85f
                              Height -> empty
Packit Service d2f85f
                              Width  -> cols (Percent a)
Packit Service d2f85f
                          Just dim -> cols dim
Packit Service d2f85f
                          Nothing  -> empty
Packit Service d2f85f
  return $ cr <> name $$ showDim Width $$ showDim Height