    {-# LANGUAGE FlexibleContexts    #-}

    {-# LANGUAGE ScopedTypeVariables #-}
    {- |
       Module      : Text.Pandoc.Readers.CSV
       Copyright   : Copyright (C) 2006-2024 John MacFarlane
       License     : GNU GPL, version 2 or above

       Maintainer  : John MacFarlane <jgm@berkeley.edu>
       Stability   : alpha
       Portability : portable

    Conversion from CSV or TSV to a 'Pandoc' table.
    -}
    module Text.Pandoc.Readers.CSV (
      readCSV,
      readTSV
    ) where
    import qualified Data.Text as T
    import Text.Pandoc.CSV (parseCSV, defaultCSVOptions, CSVOptions(..))
    import Text.Pandoc.Definition
    import qualified Text.Pandoc.Builder as B
    import Text.Pandoc.Class (PandocMonad)
    import Text.Pandoc.Sources (ToSources(..), sourcesToText)
    import Text.Pandoc.Options (ReaderOptions)
    import Control.Monad.Except (throwError)
    import Data.Text (Text)
    import Data.List (intersperse)
    import Text.Pandoc.Parsing (fromParsecError)

    readCSV :: (PandocMonad m, ToSources a)
            => ReaderOptions -- ^ Reader options
            -> a
            -> m Pandoc
    readCSV :: forall (m :: * -> *) a.
    (PandocMonad m, ToSources a) =>
    ReaderOptions -> a -> m Pandoc
    readCSV ReaderOptions
    _opts a
    s = do
      CSVOptions -> Text -> m Pandoc
    forall (m :: * -> *).
    PandocMonad m =>
    CSVOptions -> Text -> m Pandoc
    readCSVWith CSVOptions
    defaultCSVOptions (Text -> m Pandoc) -> Text -> m Pandoc
    forall a b. (a -> b) -> a -> b
    $ Sources -> Text
    sourcesToText (Sources -> Text) -> Sources -> Text
    forall a b. (a -> b) -> a -> b
    $ a -> Sources
    forall a. ToSources a => a -> Sources
    toSources a
    s

    readTSV :: (PandocMonad m, ToSources a)
            => ReaderOptions -- ^ Reader options
            -> a
            -> m Pandoc
    readTSV :: forall (m :: * -> *) a.
    (PandocMonad m, ToSources a) =>
    ReaderOptions -> a -> m Pandoc
    readTSV ReaderOptions
    _opts a
    s = do
      CSVOptions -> Text -> m Pandoc
    forall (m :: * -> *).
    PandocMonad m =>
    CSVOptions -> Text -> m Pandoc
    readCSVWith CSVOptions
    tsvOpts (Text -> m Pandoc) -> Text -> m Pandoc
    forall a b. (a -> b) -> a -> b
    $ Sources -> Text
    sourcesToText (Sources -> Text) -> Sources -> Text
    forall a b. (a -> b) -> a -> b
    $ a -> Sources
    forall a. ToSources a => a -> Sources
    toSources a
    s
     where
      tsvOpts :: CSVOptions
    tsvOpts = CSVOptions{
        csvDelim :: Char
    csvDelim = Char
    '\t',
        csvQuote :: Maybe Char
    csvQuote = Maybe Char
    forall a. Maybe a
    Nothing,
        csvKeepSpace :: Bool
    csvKeepSpace = Bool
    False,
        csvEscape :: Maybe Char
    csvEscape = Maybe Char
    forall a. Maybe a
    Nothing }

    readCSVWith :: PandocMonad m
                => CSVOptions
                -> Text
                -> m Pandoc
    readCSVWith :: forall (m :: * -> *).
    PandocMonad m =>
    CSVOptions -> Text -> m Pandoc
    readCSVWith CSVOptions
    csvopts Text
    txt = do
      case CSVOptions -> Text -> Either ParseError [[Text]]
    parseCSV CSVOptions
    csvopts Text
    txt of
        Right ([Text]
    r:[[Text]]
    rs) -> Pandoc -> m Pandoc
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Pandoc -> m Pandoc) -> Pandoc -> m Pandoc
    forall a b. (a -> b) -> a -> b
    $ Blocks -> Pandoc
    B.doc (Blocks -> Pandoc) -> Blocks -> Pandoc
    forall a b. (a -> b) -> a -> b
    $ Caption
    -> [ColSpec] -> TableHead -> [TableBody] -> TableFoot -> Blocks
    B.table Caption
    capt
                                                 ([Alignment] -> [ColWidth] -> [ColSpec]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Alignment]
    aligns [ColWidth]
    widths)
                                                 (Attr -> [Row] -> TableHead
    TableHead Attr
    nullAttr [Row]
    hdrs)
                                                 [Attr -> RowHeadColumns -> [Row] -> [Row] -> TableBody
    TableBody Attr
    nullAttr RowHeadColumns
    0 [] [Row]
    rows]
                                                 (Attr -> [Row] -> TableFoot
    TableFoot Attr
    nullAttr [])
           where capt :: Caption
    capt = Caption
    B.emptyCaption
                 numcols :: Int
    numcols = [Text] -> Int
    forall a. [a] -> Int
    forall (t :: * -> *) a. Foldable t => t a -> Int
    length [Text]
    r
                 toplain :: Text -> Cell
    toplain = Blocks -> Cell
    B.simpleCell (Blocks -> Cell) -> (Text -> Blocks) -> Text -> Cell
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Inlines -> Blocks
    B.plain (Inlines -> Blocks) -> (Text -> Inlines) -> Text -> Blocks
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Inlines] -> Inlines
    forall a. Monoid a => [a] -> a
    mconcat ([Inlines] -> Inlines) -> (Text -> [Inlines]) -> Text -> Inlines
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                           Inlines -> [Inlines] -> [Inlines]
    forall a. a -> [a] -> [a]
    intersperse Inlines
    B.linebreak ([Inlines] -> [Inlines])
    -> (Text -> [Inlines]) -> Text -> [Inlines]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Inlines) -> [Text] -> [Inlines]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Inlines
    B.text ([Text] -> [Inlines]) -> (Text -> [Text]) -> Text -> [Inlines]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> [Text]
    T.lines
                 toRow :: [Text] -> Row
    toRow = Attr -> [Cell] -> Row
    Row Attr
    nullAttr ([Cell] -> Row) -> ([Text] -> [Cell]) -> [Text] -> Row
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Cell) -> [Text] -> [Cell]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Cell
    toplain
                 toHeaderRow :: [Text] -> [Row]
    toHeaderRow [Text]
    l = [[Text] -> Row
    toRow [Text]
    l | Bool -> Bool
    not ([Text] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Text]
    l)]
                 hdrs :: [Row]
    hdrs = [Text] -> [Row]
    toHeaderRow [Text]
    r
                 rows :: [Row]
    rows = ([Text] -> Row) -> [[Text]] -> [Row]
    forall a b. (a -> b) -> [a] -> [b]
    map [Text] -> Row
    toRow [[Text]]
    rs
                 aligns :: [Alignment]
    aligns = Int -> Alignment -> [Alignment]
    forall a. Int -> a -> [a]
    replicate Int
    numcols Alignment
    AlignDefault
                 widths :: [ColWidth]
    widths = Int -> ColWidth -> [ColWidth]
    forall a. Int -> a -> [a]
    replicate Int
    numcols ColWidth
    ColWidthDefault
        Right []     -> Pandoc -> m Pandoc
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Pandoc -> m Pandoc) -> Pandoc -> m Pandoc
    forall a b. (a -> b) -> a -> b
    $ Blocks -> Pandoc
    B.doc Blocks
    forall a. Monoid a => a
    mempty
        Left ParseError
    e       -> PandocError -> m Pandoc
    forall a. PandocError -> m a
    forall e (m :: * -> *) a. MonadError e m => e -> m a
    throwError (PandocError -> m Pandoc) -> PandocError -> m Pandoc
    forall a b. (a -> b) -> a -> b
    $ Sources -> ParseError -> PandocError
    fromParsecError ([(String, Text)] -> Sources
    forall a. ToSources a => a -> Sources
    toSources [(String
    "",Text
    txt)]) ParseError
    e