New module, Text.Pandoc.MediaBag.

Moved `MediaBag` definition and functions from Shared:
`lookupMedia`, `mediaDirectory`, `insertMedia`, `extractMediaBag`.
Removed `emptyMediaBag`; use `mempty` instead, since `MediaBag`
is a Monoid.
This commit is contained in:
John MacFarlane 2014-07-31 12:00:21 -07:00
parent 00662faefb
commit 6dd2418476
10 changed files with 129 additions and 86 deletions

View file

@ -273,6 +273,7 @@ Library
Text.Pandoc.Options,
Text.Pandoc.Pretty,
Text.Pandoc.Shared,
Text.Pandoc.MediaBag,
Text.Pandoc.Readers.HTML,
Text.Pandoc.Readers.LaTeX,
Text.Pandoc.Readers.Markdown,

View file

@ -37,8 +37,8 @@ import Text.Pandoc.Walk (walk)
import Text.Pandoc.Readers.LaTeX (handleIncludes)
import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
safeRead, headerShift, normalize, err, warn,
openURL, mediaDirectory, extractMediaBag,
emptyMediaBag )
openURL )
import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag )
import Text.Pandoc.XML ( toEntities )
import Text.Pandoc.SelfContained ( makeSelfContained )
import Text.Pandoc.Process (pipeProcess)
@ -69,6 +69,7 @@ import qualified Data.Yaml as Yaml
import qualified Data.Text as T
import Control.Applicative ((<$>))
import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
import Data.Monoid
copyrightMessage :: String
copyrightMessage = "\nCopyright (C) 2006-2014 John MacFarlane\n" ++
@ -1217,7 +1218,7 @@ main = do
inp <- readSources sources >>=
handleIncludes' . convertTabs . intercalate "\n"
d <- r readerOpts inp
return (d, emptyMediaBag)
return (d, mempty)
ByteStringReader r -> do
(d, media) <- readFiles sources >>= r readerOpts
d' <- case mbExtractMedia of

View file

@ -160,7 +160,8 @@ import Text.Pandoc.Writers.Haddock
import Text.Pandoc.Writers.Custom
import Text.Pandoc.Templates
import Text.Pandoc.Options
import Text.Pandoc.Shared (safeRead, warn, MediaBag)
import Text.Pandoc.Shared (safeRead, warn)
import Text.Pandoc.MediaBag (MediaBag)
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
import Data.List (intercalate)

107
src/Text/Pandoc/MediaBag.hs Normal file
View file

@ -0,0 +1,107 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
Copyright (C) 2014 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.MediaBag
Copyright : Copyright (C) 2014 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
Stability : alpha
Portability : portable
Definition of a MediaBag object to hold binary resources, and an
interface for interacting with it.
-}
module Text.Pandoc.MediaBag (
MediaBag,
lookupMedia,
insertMedia,
mediaDirectory,
extractMediaBag
) where
import System.FilePath
import System.Directory (createDirectoryIfMissing)
import qualified Data.Map as M
import qualified Data.ByteString.Lazy as BL
import Data.Monoid (Monoid)
import Control.Monad (when, MonadPlus(..))
import Text.Pandoc.MIME (getMimeType)
import qualified Text.Pandoc.UTF8 as UTF8
import Data.Maybe (fromMaybe)
import System.IO (stderr)
-- | A container for a collection of binary resources, with names and
-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
-- can be used for an empty 'MediaBag', and '<>' can be used to append
-- two 'MediaBag's.
newtype MediaBag = MediaBag (M.Map String (String, BL.ByteString))
deriving (Monoid)
instance Show MediaBag where
show bag = "MediaBag " ++ show (mediaDirectory bag)
-- | Insert a media item into a 'MediaBag', replacing any existing
-- value with the same name.
insertMedia :: FilePath -- ^ relative path and canonical name of resource
-> Maybe String -- ^ mime type (Nothing = determine from extension)
-> BL.ByteString -- ^ contents of resource
-> MediaBag
-> MediaBag
insertMedia fp mbMime contents (MediaBag mediamap) =
MediaBag (M.insert fp (mime, contents) mediamap)
where mime = fromMaybe "application/octet-stream" (mbMime `mplus` fallback)
fallback = case takeExtension fp of
".gz" -> getMimeType $ dropExtension fp
_ -> getMimeType fp
-- | Lookup a media item in a 'MediaBag', returning mime type and contents.
lookupMedia :: FilePath
-> MediaBag
-> Maybe (String, BL.ByteString)
lookupMedia fp (MediaBag mediamap) = M.lookup fp mediamap
-- | Get a list of the file paths stored in a 'MediaBag', with
-- their corresponding mime types and the lengths in bytes of the contents.
mediaDirectory :: MediaBag -> [(String, String, Int)]
mediaDirectory (MediaBag mediamap) =
M.foldWithKey (\fp (mime,contents) ->
((fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
-- | Extract contents of MediaBag to a given directory. Print informational
-- messages if 'verbose' is true.
extractMediaBag :: Bool
-> FilePath
-> MediaBag
-> IO ()
extractMediaBag verbose dir (MediaBag mediamap) = do
sequence_ $ M.foldWithKey
(\fp (_ ,contents) ->
((writeMedia verbose dir (fp, contents)):)) [] mediamap
writeMedia :: Bool -> FilePath -> (FilePath, BL.ByteString) -> IO ()
writeMedia verbose dir (subpath, bs) = do
-- we join and split to convert a/b/c to a\b\c on Windows;
-- in zip containers all paths use /
let fullpath = dir </> joinPath (splitPath subpath)
createDirectoryIfMissing True $ takeDirectory fullpath
when verbose $ UTF8.hPutStrLn stderr $ "pandoc: extracting " ++ fullpath
BL.writeFile fullpath bs

View file

@ -49,7 +49,8 @@ import Data.Set (Set)
import qualified Data.Set as Set
import Data.Default
import Text.Pandoc.Highlighting (Style, pygments)
import Text.Pandoc.Shared (MediaBag, emptyMediaBag)
import Text.Pandoc.MediaBag (MediaBag)
import Data.Monoid
-- | Individually selectable syntax extensions.
data Extension =
@ -358,7 +359,7 @@ instance Default WriterOptions where
, writerTOCDepth = 3
, writerReferenceODT = Nothing
, writerReferenceDocx = Nothing
, writerMediaBag = emptyMediaBag
, writerMediaBag = mempty
}
-- | Returns True if the given extension is enabled.

View file

@ -84,8 +84,10 @@ import Text.Pandoc.Readers.Docx.Lists
import Text.Pandoc.Readers.Docx.Reducible
import Text.Pandoc.Readers.Docx.TexChar
import Text.Pandoc.Shared
import Text.Pandoc.MediaBag (insertMedia, MediaBag)
import Data.Maybe (mapMaybe, fromMaybe)
import Data.List (delete, isPrefixOf, (\\), intercalate, intersect)
import Data.Monoid
import qualified Data.ByteString.Lazy as B
import qualified Data.Map as M
import Control.Monad.Reader
@ -108,7 +110,7 @@ data DState = DState { docxAnchorMap :: M.Map String String
defaultDState :: DState
defaultDState = DState { docxAnchorMap = M.empty
, docxMediaBag = emptyMediaBag
, docxMediaBag = mempty
, docxInHeaderBlock = False
, docxInTexSubscript = False}

View file

@ -41,8 +41,8 @@ import System.FilePath (takeExtension, dropExtension, takeDirectory, (</>))
import Data.Char (toLower, isAscii, isAlphaNum)
import Codec.Compression.GZip as Gzip
import qualified Data.ByteString.Lazy as L
import Text.Pandoc.Shared (renderTags', openURL, readDataFile, err,
MediaBag, lookupMedia)
import Text.Pandoc.Shared (renderTags', openURL, readDataFile, err)
import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
import Text.Pandoc.UTF8 (toString, fromString)
import Text.Pandoc.MIME (getMimeType)
import System.Directory (doesFileExist)

View file

@ -1,5 +1,5 @@
{-# LANGUAGE DeriveDataTypeable, CPP, MultiParamTypeClasses,
FlexibleContexts, ScopedTypeVariables, GeneralizedNewtypeDeriving #-}
FlexibleContexts, ScopedTypeVariables #-}
{-
Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
@ -48,13 +48,6 @@ module Text.Pandoc.Shared (
toRomanNumeral,
escapeURI,
tabFilter,
-- * Media Handling
MediaBag,
emptyMediaBag,
lookupMedia,
insertMedia,
mediaDirectory,
extractMediaBag,
-- * Date/time
normalizeDate,
-- * Pandoc block and inline list processing
@ -97,6 +90,7 @@ module Text.Pandoc.Shared (
import Text.Pandoc.Definition
import Text.Pandoc.Walk
import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
import Text.Pandoc.Builder (Inlines, Blocks, ToMetaValue(..))
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.UTF8 as UTF8
@ -106,18 +100,16 @@ import Data.Char ( toLower, isLower, isUpper, isAlpha,
isLetter, isDigit, isSpace )
import Data.List ( find, isPrefixOf, intercalate )
import qualified Data.Map as M
import Data.Maybe ( fromMaybe )
import Network.URI ( escapeURIString, isURI, nonStrictRelativeTo,
unEscapeString, parseURIReference )
import qualified Data.Set as Set
import System.Directory
import Text.Pandoc.MIME (getMimeType)
import System.FilePath ( (</>), takeExtension, dropExtension, takeDirectory,
splitPath, joinPath )
import System.FilePath ( (</>), takeExtension, dropExtension)
import Data.Generics (Typeable, Data)
import qualified Control.Monad.State as S
import qualified Control.Exception as E
import Control.Monad (msum, unless, MonadPlus(..), when)
import Control.Monad (msum, unless)
import Text.Pandoc.Pretty (charWidth)
import System.Locale (defaultTimeLocale)
import Data.Time
@ -127,7 +119,6 @@ import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
renderOptions)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL
import Text.Pandoc.Compat.Monoid
import Data.ByteString.Base64 (decodeLenient)
import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
@ -294,68 +285,6 @@ tabFilter tabStop =
x : go (spsToNextStop - 1) xs
in go tabStop
---
--- Media handling
---
-- | A container for a collection of binary resources, with names and
-- mime types.
newtype MediaBag = MediaBag (M.Map String (String, BL.ByteString))
deriving (Monoid)
instance Show MediaBag where
show bag = "MediaBag " ++ show (mediaDirectory bag)
emptyMediaBag :: MediaBag
emptyMediaBag = MediaBag M.empty
-- | Insert a media item into a 'MediaBag', replacing any existing
-- value with the same name.
insertMedia :: FilePath -- ^ relative path and canonical name of resource
-> Maybe String -- ^ mime type (Nothing = determine from extension)
-> BL.ByteString -- ^ contents of resource
-> MediaBag
-> MediaBag
insertMedia fp mbMime contents (MediaBag mediamap) =
MediaBag (M.insert fp (mime, contents) mediamap)
where mime = fromMaybe "application/octet-stream" (mbMime `mplus` fallback)
fallback = case takeExtension fp of
".gz" -> getMimeType $ dropExtension fp
_ -> getMimeType fp
-- | Lookup a media item in a 'MediaBag', returning mime type and contents.
lookupMedia :: FilePath
-> MediaBag
-> Maybe (String, BL.ByteString)
lookupMedia fp (MediaBag mediamap) = M.lookup fp mediamap
-- | Get a list of the file paths stored in a 'MediaBag', with
-- their corresponding mime types and the lengths in bytes of the contents.
mediaDirectory :: MediaBag -> [(String, String, Int)]
mediaDirectory (MediaBag mediamap) =
M.foldWithKey (\fp (mime,contents) ->
((fp, mime, fromIntegral $ BL.length contents):)) [] mediamap
-- | Extract contents of MediaBag to a given directory. Print informational
-- messages if 'verbose' is true.
extractMediaBag :: Bool
-> FilePath
-> MediaBag
-> IO ()
extractMediaBag verbose dir (MediaBag mediamap) = do
sequence_ $ M.foldWithKey
(\fp (_ ,contents) ->
((writeMedia verbose dir (fp, contents)):)) [] mediamap
writeMedia :: Bool -> FilePath -> (FilePath, BL.ByteString) -> IO ()
writeMedia verbose dir (subpath, bs) = do
-- we join and split to convert a/b/c to a\b\c on Windows;
-- in zip containers all paths use /
let fullpath = dir </> joinPath (splitPath subpath)
createDirectoryIfMissing True $ takeDirectory fullpath
when verbose $ warn $ "extracting " ++ fullpath
BL.writeFile fullpath bs
--
-- Date/time
--

View file

@ -61,6 +61,7 @@ import Text.Pandoc.MIME (getMimeType)
import qualified Control.Exception as E
import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
import Text.HTML.TagSoup
import Data.Monoid
-- A Chapter includes a list of blocks and maybe a section
-- number offset. Note, some chapters are unnumbered. The section
@ -793,7 +794,7 @@ transformInline opts mediaRef (Image lab (src,tit)) = do
return $ Image lab (newsrc, tit)
transformInline opts _ (x@(Math _ _))
| WebTeX _ <- writerHTMLMathMethod opts = do
raw <- makeSelfContained emptyMediaBag Nothing $ writeHtmlInline opts x
raw <- makeSelfContained mempty Nothing $ writeHtmlInline opts x
return $ RawInline (Format "html") raw
transformInline opts mediaRef (RawInline fmt raw)
| fmt == Format "html" = do

View file

@ -12,7 +12,7 @@ import qualified Data.ByteString.Base64 as B64
import Text.Pandoc.Readers.Docx
import Text.Pandoc.Writers.Native (writeNative)
import qualified Data.Map as M
import Text.Pandoc.Shared (lookupMedia)
import Text.Pandoc.MediaBag (lookupMedia)
-- We define a wrapper around pandoc that doesn't normalize in the
-- tests. Since we do our own normalization, we want to make sure