@@ -1,3 +1,4 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-
@@ -35,6 +36,8 @@ import Text.Pandoc.Builder (setMeta, fromList)
3536import Text.Pandoc.Shared
3637import Text.Pandoc.Parsing
3738import Text.Pandoc.Options
39+import Text.Pandoc.Error
40+import qualified Text.Pandoc.UTF8 as UTF8
3841import Control.Monad ( when, liftM, guard, mzero )
3942import Data.List ( findIndex, intercalate,
4043 transpose, sort, deleteFirstsBy, isSuffixOf , nub, union)
@@ -46,9 +49,9 @@ import qualified Text.Pandoc.Builder as B
4649import Data.Sequence (viewr, ViewR(..))
4750import Data.Char (toLower, isHexDigit, isSpace)
4851import Data.Monoid ((<>))
49−import Control.Monad.Except (throwError)
52+import Control.Monad.Except (throwError, catchError)
5053import Control.Monad.Trans (lift)
51−import Text.Pandoc.Class (PandocMonad)
54+import Text.Pandoc.Class (PandocMonad, warning, readFileLazy)
5255import qualified Text.Pandoc.Class as P
5356
5457-- | Parse reStructuredText string and return Pandoc document.
@@ -177,6 +180,7 @@ block :: PandocMonad m => RSTParser m Blocks
177180block = choice [ codeBlock
178181 , blockQuote
179182 , fieldList
183+ , include
180184 , directive
181185 , comment
182186 , header
@@ -397,6 +401,65 @@ blockQuote = do
397401 contents <- parseFromString parseBlocks $ raw ++ "\n\n"
398402 return $ B.blockQuote contents
399403
404+{-
405+From RST docs:
406+The following options are recognized:
407+
408+start-line : integer
409+Only the content starting from this line will be included. (As usual in Python, the first line has index 0 and negative values count from the end.)
410+end-line : integer
411+Only the content up to (but excluding) this line will be included.
412+start-after : text to find in the external data file
413+Only the content after the first occurrence of the specified text will be included.
414+end-before : text to find in the external data file
415+Only the content before the first occurrence of the specified text (but after any after text) will be included.
416+literal : flag (empty)
417+The entire included text is inserted into the document as a single literal block.
418+code : formal language (optional)
419+The argument and the content of the included file are passed to the code directive (useful for program listings). (New in Docutils 0.9)
420+number-lines : [start line number]
421+Precede every code line with a line number. The optional argument is the number of the first line (defaut 1). Works only with code or literal. (New in Docutils 0.9)
422+encoding : name of text encoding
423+The text encoding of the external data file. Defaults to the document's input_encoding.
424+tab-width : integer
425+Number of spaces for hard tab expansion. A negative value prevents expansion of hard tabs. Defaults to the tab_width configuration setting.
426+With code or literal the common options :class: and :name: are recognized as well.
427+
428+Combining start/end-line and start-after/end-before is possible. The text markers will be searched in the specified lines (further limiting the included content).
429+
430+-}
431+
432+include :: PandocMonad m => RSTParser m Blocks
433+include = try $ do
434+ string ".. include::"
435+ skipMany spaceChar
436+ f <- trim <$> anyLine
437+ -- TODO options
438+ guard $ not (null f)
439+ oldPos <- getPosition
440+ oldInput <- getInput
441+ containers <- stateContainers <$> getState
442+ when (f `elem` containers) $
443+ throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
444+ updateState $ \s -> s{ stateContainers = f : stateContainers s }
445+ res <- lift $ readFileLazy' f
446+ contents <- case res of
447+ Right x -> return x
448+ Left _e -> do
449+ lift $ warning $ "Could not read include file " ++ f ++ "."
450+ return ""
451+ setPosition $ newPos f 1 1
452+ setInput contents
453+ bs <- optional blanklines >> (mconcat <$> many block)
454+ setInput oldInput
455+ setPosition oldPos
456+ updateState $ \s -> s{ stateContainers = tail $ stateContainers s }
457+ return bs
458+
459+readFileLazy' :: PandocMonad m => FilePath -> m (Either PandocError String)
460+readFileLazy' f = catchError ((Right . UTF8.toStringLazy) <$> readFileLazy f) $
461+ \(e :: PandocError) -> return (Left e)
462+
400463--
401464-- list blocks
402465--