diff options
| author | John MacFarlane <jgm@berkeley.edu> | 2010-12-05 09:34:40 -0800 | 
|---|---|---|
| committer | John MacFarlane <jgm@berkeley.edu> | 2010-12-05 09:34:40 -0800 | 
| commit | e8e491bdbf86b95e2ce2beac2a7062c57bfd9e5d (patch) | |
| tree | f64651c02c7e0bfa8f55d0e4c0c410f8a17c9657 /src | |
| parent | c277d29902eb5dd7fb53ed49cb91a8b915d5cfb2 (diff) | |
| parent | 85263ecda9ba33d3ff8c71e35ee6fe6aa89cf5bc (diff) | |
| download | pandoc-e8e491bdbf86b95e2ce2beac2a7062c57bfd9e5d.tar.gz | |
Merge branch 'punchagan-master'
Diffstat (limited to 'src')
| -rw-r--r-- | src/Text/Pandoc.hs | 2 | ||||
| -rw-r--r-- | src/Text/Pandoc/Writers/Org.hs | 291 | ||||
| -rw-r--r-- | src/pandoc.hs | 2 | 
3 files changed, 295 insertions, 0 deletions
| diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs index d11f084a5..ab1e3cd03 100644 --- a/src/Text/Pandoc.hs +++ b/src/Text/Pandoc.hs @@ -89,6 +89,7 @@ module Text.Pandoc                 , writeRTF                 , writeODT                 , writeEPUB +               , writeOrg                 -- * Writer options used in writers                  , WriterOptions (..)                 , HTMLSlideVariant (..) @@ -121,6 +122,7 @@ import Text.Pandoc.Writers.Man  import Text.Pandoc.Writers.RTF   import Text.Pandoc.Writers.MediaWiki  import Text.Pandoc.Writers.Textile +import Text.Pandoc.Writers.Org  import Text.Pandoc.Templates  import Text.Pandoc.Parsing  import Text.Pandoc.Shared diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs new file mode 100644 index 000000000..9285e9c55 --- /dev/null +++ b/src/Text/Pandoc/Writers/Org.hs @@ -0,0 +1,291 @@ +{- +Copyright (C) 2006-2010 Puneeth Chaganti <punchagan@gmail.com> + +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.Org +   Copyright   : Copyright (C) 2006-2010 Puneeth Chaganti +   License     : GNU GPL, version 2 or above  + +   Maintainer  : Puneeth Chaganti <punchagan@gmail.com> +   Stability   : alpha +   Portability : portable + +Conversion of 'Pandoc' documents to reStructuredText. + +reStructuredText:  <http://docutils.sourceforge.net/rst.html> +-} +module Text.Pandoc.Writers.Org ( writeOrg) where +import Text.Pandoc.Definition +import Text.Pandoc.Shared  +import Text.Pandoc.Blocks +import Text.Pandoc.Templates (renderTemplate) +import Data.List ( intersect, intersperse, transpose ) +import Text.PrettyPrint.HughesPJ hiding ( Str ) +import Control.Monad.State +import Control.Applicative ( (<$>) ) + +data WriterState =  +  WriterState { stNotes     :: [[Block]] +              , stLinks     :: Bool +              , stImages    :: Bool +              , stHasMath   :: Bool +              , stOptions   :: WriterOptions +              } + +-- | Convert Pandoc to Org. +writeOrg :: WriterOptions -> Pandoc -> String +writeOrg opts document =  +  let st = WriterState { stNotes = [], stLinks = False, +                         stImages = False, stHasMath = False, +                         stOptions = opts } +  in evalState (pandocToOrg document) st + +-- | Return Org representation of document. +pandocToOrg :: Pandoc -> State WriterState String +pandocToOrg (Pandoc (Meta tit auth dat) blocks) = do +  opts <- liftM stOptions get +  title <- titleToOrg tit +  authors <- mapM inlineListToOrg auth +  date <- inlineListToOrg dat +  body <- blockListToOrg blocks +  notes <- liftM (reverse . stNotes) get >>= notesToOrg +  -- note that the notes may contain refs, so we do them first +  hasMath <- liftM stHasMath get +  let main = render $ foldl ($+$) empty $ [body, notes] +  let context = writerVariables opts ++ +                [ ("body", main) +                , ("title", render title) +                , ("date", render date) ] ++ +                [ ("math", "yes") | hasMath ] ++ +                [ ("author", render a) | a <- authors ] +  if writerStandalone opts +     then return $ renderTemplate context $ writerTemplate opts +     else return main + +-- | Return Org representation of notes. +notesToOrg :: [[Block]] -> State WriterState Doc +notesToOrg notes =  +  mapM (\(num, note) -> noteToOrg num note) (zip [1..] notes) >>=  +  return . vcat + +-- | Return Org representation of a note. +noteToOrg :: Int -> [Block] -> State WriterState Doc +noteToOrg num note = do +  contents <- blockListToOrg note +  let marker = text "[" <> text (show num) <> text "] " +  return $ marker <> contents + +-- | Take list of inline elements and return wrapped doc. +wrappedOrg :: WriterOptions -> [Inline] -> State WriterState Doc +wrappedOrg opts inlines = do +  lineBreakDoc <- inlineToOrg LineBreak   +  chunks <- mapM (wrapIfNeeded opts inlineListToOrg) +                 (splitBy LineBreak inlines) +  return $ vcat $ intersperse lineBreakDoc chunks + +-- | Escape special characters for Org. +escapeString :: String -> String +escapeString = escapeStringUsing (backslashEscapes "^_") + +titleToOrg :: [Inline] -> State WriterState Doc +titleToOrg [] = return empty +titleToOrg lst = do +  contents <- inlineListToOrg lst +  let titleName = text "#+TITLE: " +  return $ titleName <> contents  + +-- | Convert Pandoc block element to Org.  +blockToOrg :: Block         -- ^ Block element +           -> State WriterState Doc  +blockToOrg Null = return empty +blockToOrg (Plain inlines) = do +  opts <- get >>= (return . stOptions) +  wrappedOrg opts inlines +blockToOrg (Para [Image txt (src,tit)]) = do +  capt <- inlineListToOrg txt +  img <- inlineToOrg (Image txt (src,tit)) +  return $ text "#+CAPTION: " <> capt <> text "\n" $$ img  +blockToOrg (Para inlines) = do +  opts <- get >>= (return . stOptions) +  contents <- wrappedOrg opts inlines +  return $ contents <> text "\n" +blockToOrg (RawHtml str) =  +  return $ (text "\n#+BEGIN_HTML\n") $$ (nest 2 $ vcat $ map text (lines str))  +         $$ (text "\n#+END_HTML\n") +blockToOrg HorizontalRule = return $ text "--------------\n" +blockToOrg (Header level inlines) = do +  contents <- inlineListToOrg inlines +  let headerStr = text $ if level > 999 then " " else replicate level '*' +  return $ headerStr <> text " " <> contents <> text "\n" +blockToOrg (CodeBlock (_,classes,_) str) = do +  opts <- stOptions <$> get +  let tabstop = writerTabStop opts +  let at = classes `intersect` ["asymptote", "C", "clojure", "css", "ditaa",  +                    "dot", "emacs-lisp", "gnuplot", "haskell", "js", "latex",  +                    "ledger", "lisp", "matlab", "mscgen", "ocaml", "octave",  +                    "oz", "perl", "plantuml", "python", "R", "ruby", "sass",  +                    "scheme", "screen", "sh", "sql", "sqlite"] +  let (beg, end) = if null at +                      then ("#+BEGIN_EXAMPLE", "#+END_EXAMPLE") +                      else ("#+BEGIN_SRC" ++ head at, "#+END_SRC") +  return $ text beg $+$ (nest tabstop $ vcat $ map text (lines str))  +         $+$ text end +blockToOrg (BlockQuote blocks) = do +  contents <- blockListToOrg blocks  +  return $ (text "\n#+BEGIN_QUOTE\n") $$ (nest 2 contents)  +         $$ (text "\n#+END_QUOTE\n") +blockToOrg (Table caption' _ _ headers rows) =  do +  caption'' <- inlineListToOrg caption' +  let caption = if null caption' +                   then empty +                   else (text "#+CAPTION: " <> caption'') +  headers' <- mapM blockListToOrg headers +  rawRows <- mapM (mapM blockListToOrg) rows +  let numChars = maximum . map (length . render) +  -- FIXME: width is not being used.  +  let widthsInChars = +       map ((+2) . numChars) $ transpose (headers' : rawRows) +  -- FIXME: Org doesn't allow blocks with height more than 1.  +  let hpipeBlocks blocks = hcatBlocks [beg, middle, end]  +        where height = maximum (map heightOfBlock blocks) +              sep'   = TextBlock 3 height (replicate height " | ") +              beg    = TextBlock 2 height (replicate height "| ") +              end    = TextBlock 2 height (replicate height " |") +              middle = hcatBlocks $ intersperse sep' blocks +  let makeRow = hpipeBlocks . zipWith docToBlock widthsInChars +  let head' = makeRow headers' +  rows' <- mapM (\row -> do cols <- mapM blockListToOrg row +                            return $ makeRow cols) rows +  let border ch = char '|' <> char ch <> +                  (hcat $ intersperse (char ch <> char '+' <> char ch) $  +                          map (\l -> text $ replicate l ch) widthsInChars) <> +                  char ch <> char '|' +  let body = vcat $ map blockToDoc rows' +  let head'' = if all null headers +                  then empty +                  else blockToDoc head' $+$ border '-' +  return $ head'' $+$ body $$ caption $$ text "" +blockToOrg (BulletList items) = do +  contents <- mapM bulletListItemToOrg items +  -- ensure that sublists have preceding blank line +  return $ text "" $+$ vcat contents <> text "\n" +blockToOrg (OrderedList (start, style', delim) items) = do +  let markers = take (length items) $ orderedListMarkers  +                                      (start, style', delim) +  let maxMarkerLength = maximum $ map length markers +  let markers' = map (\m -> let s = maxMarkerLength - length m +                            in  m ++ replicate s ' ') markers +  contents <- mapM (\(item, num) -> orderedListItemToOrg item num) $ +              zip markers' items   +  -- ensure that sublists have preceding blank line +  return $ text "" $+$ vcat contents <> text "\n" +blockToOrg (DefinitionList items) = do +  contents <- mapM definitionListItemToOrg items +  return $ (vcat contents) <> text "\n" + +-- | Convert bullet list item (list of blocks) to Org. +bulletListItemToOrg :: [Block] -> State WriterState Doc +bulletListItemToOrg items = do +  contents <- blockListToOrg items +  return $ (text "-  ") <> contents + +-- | Convert ordered list item (a list of blocks) to Org. +orderedListItemToOrg :: String   -- ^ marker for list item +                     -> [Block]  -- ^ list item (list of blocks) +                     -> State WriterState Doc +orderedListItemToOrg marker items = do +  contents <- blockListToOrg items +  return $ (text marker <> char ' ') <> contents  + +-- | Convert defintion list item (label, list of blocks) to Org. +definitionListItemToOrg :: ([Inline], [[Block]]) -> State WriterState Doc +definitionListItemToOrg (label, defs) = do +  label' <- inlineListToOrg label +  contents <- liftM vcat $ mapM blockListToOrg defs +  return $ (text "-  ") <> label' <> (text " :: ") <> contents + +-- | Convert list of Pandoc block elements to Org. +blockListToOrg :: [Block]       -- ^ List of block elements +               -> State WriterState Doc  +blockListToOrg blocks = mapM blockToOrg blocks >>= return . vcat + +-- | Convert list of Pandoc inline elements to Org. +inlineListToOrg :: [Inline] -> State WriterState Doc +inlineListToOrg lst = mapM inlineToOrg lst >>= return . hcat + +-- | Convert Pandoc inline element to Org. +inlineToOrg :: Inline -> State WriterState Doc +inlineToOrg (Emph lst) = do  +  contents <- inlineListToOrg lst +  return $ char '/' <> contents <> char '/' +inlineToOrg (Strong lst) = do +  contents <- inlineListToOrg lst +  return $ text "*" <> contents <> text "*" +inlineToOrg (Strikeout lst) = do  +  contents <- inlineListToOrg lst +  return $ text "+" <> contents <> char '+' +inlineToOrg (Superscript lst) = do  +  contents <- inlineListToOrg lst +  return $ text "^{" <> contents <> text "}" +inlineToOrg (Subscript lst) = do  +  contents <- inlineListToOrg lst +  return $ text "_{" <> contents <> text "}" +inlineToOrg (SmallCaps lst) = inlineListToOrg lst +inlineToOrg (Quoted SingleQuote lst) = do +  contents <- inlineListToOrg lst +  return $ char '\'' <> contents <> char '\'' +inlineToOrg (Quoted DoubleQuote lst) = do +  contents <- inlineListToOrg lst +  return $ char '\"' <> contents <> char '\"' +inlineToOrg (Cite _  lst) = +  inlineListToOrg lst +inlineToOrg EmDash = return $ text "---" +inlineToOrg EnDash = return $ text "--" +inlineToOrg Apostrophe = return $ char '\'' +inlineToOrg Ellipses = return $ text "..." +inlineToOrg (Code str) = return $ text $ "=" ++ str ++ "=" +inlineToOrg (Str str) = return $ text $ escapeString str +inlineToOrg (Math t str) = do +  modify $ \st -> st{ stHasMath = True } +  return $ if t == InlineMath +              then text $ "$" ++ str ++ "$" +              else text $ "$$" ++ str ++ "$$" +inlineToOrg (TeX str) = return $ text str +inlineToOrg (HtmlInline _) = return empty +inlineToOrg (LineBreak) = do +  return $ empty -- there's no line break in Org +inlineToOrg Space = return $ char ' ' +inlineToOrg (Link txt (src, _)) = do +  case txt of +        [Code x] | x == src ->  -- autolink +             do modify $ \s -> s{ stLinks = True } +                return $ text $ "[[" ++ x ++ "]]" +        _ -> do contents <- inlineListToOrg txt +                modify $ \s -> s{ stLinks = True } +                return $ text ("[[" ++ src ++ "][") <> contents <>  +                         (text "]]") +inlineToOrg (Image _ (source', _)) = do +  let source = unescapeURI source' +  modify $ \s -> s{ stImages = True } +  return $ text $ "[[" ++ source ++ "]]" +inlineToOrg (Note contents) = do  +  -- add to notes in state +  notes <- get >>= (return . stNotes) +  modify $ \st -> st { stNotes = contents:notes } +  let ref = show $ (length notes) + 1 +  return $ text " [" <> text ref <> text "]" diff --git a/src/pandoc.hs b/src/pandoc.hs index 0cf694873..3aa9a4ba8 100644 --- a/src/pandoc.hs +++ b/src/pandoc.hs @@ -121,6 +121,7 @@ writers = [("native"       , writeNative)            ,("mediawiki"    , writeMediaWiki)            ,("textile"      , writeTextile)            ,("rtf"          , writeRTF) +          ,("org"          , writeOrg)            ]  isNonTextOutput :: String -> Bool @@ -616,6 +617,7 @@ defaultWriterName x =      ".db"       -> "docbook"      ".odt"      -> "odt"      ".epub"     -> "epub" +    ".org"      -> "org"      ['.',y] | y `elem` ['1'..'9'] -> "man"      _          -> "html" | 
