{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Writers.LaTeX.Table
   Copyright   : Copyright (C) 2006-2023 John MacFarlane
   License     : GNU GPL, version 2 or above

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

Output LaTeX formatted tables.
-}
module Text.Pandoc.Writers.LaTeX.Table
  ( tableToLaTeX
  ) where
import Control.Monad.State.Strict ( gets, modify )
import Control.Monad (when)
import Data.List (intersperse)
import qualified Data.List.NonEmpty as NonEmpty
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.Text (Text)
import qualified Data.Text as T
import Text.Pandoc.Class.PandocMonad (PandocMonad)
import Text.Pandoc.Definition
import Text.DocLayout
  ( Doc, braces, cr, empty, hcat, hsep, isEmpty, literal, nest
  , text, vcat, ($$) )
import Text.Pandoc.Shared (splitBy, tshow)
import Text.Pandoc.Walk (walk, query)
import Data.Monoid (Any(..))
import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
import Text.Pandoc.Writers.LaTeX.Notes (notesToLaTeX)
import Text.Pandoc.Writers.LaTeX.Types
  ( LW, WriterState (stBeamer, stExternalNotes, stInMinipage, stMultiRow
                    , stNotes, stTable) )
import Text.Pandoc.Writers.LaTeX.Util (labelFor)
import Text.Printf (printf)
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Writers.AnnotatedTable as Ann

tableToLaTeX :: PandocMonad m
             => ([Inline] -> LW m (Doc Text))
             -> ([Block]  -> LW m (Doc Text))
             -> Ann.Table
             -> LW m (Doc Text)
tableToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
([Inline] -> LW m (Doc Text))
-> ([Block] -> LW m (Doc Text)) -> Table -> LW m (Doc Text)
tableToLaTeX [Inline] -> LW m (Doc Text)
inlnsToLaTeX [Block] -> LW m (Doc Text)
blksToLaTeX Table
tbl = do
  let (Ann.Table (Text
ident, [Text]
_, [(Text, Text)]
_) Caption
caption [ColSpec]
specs TableHead
thead [TableBody]
tbodies TableFoot
tfoot) = Table
tbl
  CaptionDocs Doc Text
capt Doc Text
captNotes <- ([Inline] -> LW m (Doc Text))
-> Caption -> Text -> LW m CaptionDocs
forall (m :: * -> *).
PandocMonad m =>
([Inline] -> LW m (Doc Text))
-> Caption -> Text -> LW m CaptionDocs
captionToLaTeX [Inline] -> LW m (Doc Text)
inlnsToLaTeX Caption
caption Text
ident
  let removeNote :: Inline -> Inline
removeNote (Note [Block]
_) = (Text, [Text], [(Text, Text)]) -> [Inline] -> Inline
Span (Text
"", [], []) []
      removeNote Inline
x        = Inline
x
  let colCount :: ColumnCount
colCount = Int -> ColumnCount
ColumnCount (Int -> ColumnCount) -> Int -> ColumnCount
forall a b. (a -> b) -> a -> b
$ [ColSpec] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ColSpec]
specs
  -- The first head is not repeated on the following pages. If we were to just
  -- use a single head, without a separate first head, then the caption would be
  -- repeated on all pages that contain a part of the table. We avoid this by
  -- making the caption part of the first head. The downside is that we must
  -- duplicate the header rows for this.
  Doc Text
head' <- do
    let mkHead :: TableHead -> LW m (Doc Text)
mkHead = ([Block] -> LW m (Doc Text))
-> ColumnCount -> TableHead -> LW m (Doc Text)
forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m -> ColumnCount -> TableHead -> LW m (Doc Text)
headToLaTeX [Block] -> LW m (Doc Text)
blksToLaTeX ColumnCount
colCount
    case (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Doc Text -> Bool
forall a. Doc a -> Bool
isEmpty Doc Text
capt, Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ TableHead -> Bool
isEmptyHead TableHead
thead) of
      (Bool
False, Bool
False) -> Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return Doc Text
"\\toprule\\noalign{}"
      (Bool
False, Bool
True)  -> TableHead -> LW m (Doc Text)
mkHead TableHead
thead
      (Bool
True, Bool
False)  -> Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text
capt Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\toprule\\noalign{}" Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\endfirsthead")
      (Bool
True, Bool
True)   -> do
        -- avoid duplicate notes in head and firsthead:
        Doc Text
firsthead <- TableHead -> LW m (Doc Text)
mkHead TableHead
thead
        Doc Text
repeated  <- TableHead -> LW m (Doc Text)
mkHead ((Inline -> Inline) -> TableHead -> TableHead
forall a b. Walkable a b => (a -> a) -> b -> b
walk Inline -> Inline
removeNote TableHead
thead)
        Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ Doc Text
capt Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
firsthead Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\endfirsthead" Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
repeated
  [Doc Text]
rows' <- ([Cell] -> LW m (Doc Text))
-> [[Cell]] -> StateT WriterState m [Doc Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (([Block] -> LW m (Doc Text))
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
rowToLaTeX [Block] -> LW m (Doc Text)
blksToLaTeX ColumnCount
colCount CellType
BodyCell) ([[Cell]] -> StateT WriterState m [Doc Text])
-> [[Cell]] -> StateT WriterState m [Doc Text]
forall a b. (a -> b) -> a -> b
$
                [[[Cell]]] -> [[Cell]]
forall a. Monoid a => [a] -> a
mconcat ((TableBody -> [[Cell]]) -> [TableBody] -> [[[Cell]]]
forall a b. (a -> b) -> [a] -> [b]
map TableBody -> [[Cell]]
bodyRows [TableBody]
tbodies)
  Doc Text
foot' <- if TableFoot -> Bool
isEmptyFoot TableFoot
tfoot
           then Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Doc Text
forall a. Doc a
empty
           else do
             [Doc Text]
lastfoot <- ([Cell] -> LW m (Doc Text))
-> [[Cell]] -> StateT WriterState m [Doc Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (([Block] -> LW m (Doc Text))
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
rowToLaTeX [Block] -> LW m (Doc Text)
blksToLaTeX ColumnCount
colCount CellType
BodyCell) ([[Cell]] -> StateT WriterState m [Doc Text])
-> [[Cell]] -> StateT WriterState m [Doc Text]
forall a b. (a -> b) -> a -> b
$
                              TableFoot -> [[Cell]]
footRows TableFoot
tfoot
             Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ Doc Text
"\\midrule\\noalign{}" Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat [Doc Text]
lastfoot
  (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((WriterState -> WriterState) -> StateT WriterState m ())
-> (WriterState -> WriterState) -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$ \WriterState
s -> WriterState
s{ stTable :: Bool
stTable = Bool
True }
  Doc Text
notes <- [Doc Text] -> Doc Text
notesToLaTeX ([Doc Text] -> Doc Text)
-> StateT WriterState m [Doc Text] -> LW m (Doc Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (WriterState -> [Doc Text]) -> StateT WriterState m [Doc Text]
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> [Doc Text]
stNotes
  Bool
beamer <- (WriterState -> Bool) -> StateT WriterState m Bool
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> Bool
stBeamer
  Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return
    (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$  Doc Text
"\\begin{longtable}[]" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
          Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces (Doc Text
"@{}" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Table -> Doc Text
colDescriptors Table
tbl Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
"@{}")
          -- the @{} removes extra space at beginning and end
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
head'
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\endhead"
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat
       -- Longtable is not able to detect pagebreaks in Beamer; this
       -- causes problems with the placement of the footer, so make
       -- footer and bottom rule part of the body when targeting Beamer.
       -- See issue #8638.
       (if Bool
beamer
             then [ [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat [Doc Text]
rows'
                  , Doc Text
foot'
                  , Doc Text
"\\bottomrule\\noalign{}"
                  ]
             else [ Doc Text
foot'
                  , Doc Text
"\\bottomrule\\noalign{}"
                  , Doc Text
"\\endlastfoot"
                  ,  [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat [Doc Text]
rows'
                  ])
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\end{longtable}"
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
captNotes
    Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
notes

-- | Total number of columns in a table.
newtype ColumnCount = ColumnCount Int

-- | Creates column descriptors for the table.
colDescriptors :: Ann.Table -> Doc Text
colDescriptors :: Table -> Doc Text
colDescriptors (Ann.Table (Text, [Text], [(Text, Text)])
_attr Caption
_caption [ColSpec]
specs TableHead
thead [TableBody]
tbodies TableFoot
tfoot) =
  let ([Alignment]
aligns, [ColWidth]
widths) = [ColSpec] -> ([Alignment], [ColWidth])
forall a b. [(a, b)] -> ([a], [b])
unzip [ColSpec]
specs

      defaultWidthsOnly :: Bool
defaultWidthsOnly = (ColWidth -> Bool) -> [ColWidth] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (ColWidth -> ColWidth -> Bool
forall a. Eq a => a -> a -> Bool
== ColWidth
ColWidthDefault) [ColWidth]
widths
      isSimpleTable :: Bool
isSimpleTable = ([Cell] -> Bool) -> [[Cell]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((Cell -> Bool) -> [Cell] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Cell -> Bool
isSimpleCell) ([[Cell]] -> Bool) -> [[Cell]] -> Bool
forall a b. (a -> b) -> a -> b
$ [[[Cell]]] -> [[Cell]]
forall a. Monoid a => [a] -> a
mconcat
                      [ TableHead -> [[Cell]]
headRows TableHead
thead
                      , (TableBody -> [[Cell]]) -> [TableBody] -> [[Cell]]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap TableBody -> [[Cell]]
bodyRows [TableBody]
tbodies
                      , TableFoot -> [[Cell]]
footRows TableFoot
tfoot
                      ]

      relativeWidths :: [Double]
relativeWidths = if Bool
defaultWidthsOnly
                       then Int -> Double -> [Double]
forall a. Int -> a -> [a]
replicate ([ColSpec] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ColSpec]
specs)
                            (Double
1 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([ColSpec] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ColSpec]
specs))
                       else (ColWidth -> Double) -> [ColWidth] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map ColWidth -> Double
toRelWidth [ColWidth]
widths
  in if Bool
defaultWidthsOnly Bool -> Bool -> Bool
&& Bool
isSimpleTable
     then [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
hcat ([Doc Text] -> Doc Text) -> [Doc Text] -> Doc Text
forall a b. (a -> b) -> a -> b
$ (Alignment -> Doc Text) -> [Alignment] -> [Doc Text]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal (Text -> Doc Text) -> (Alignment -> Text) -> Alignment -> Doc Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Alignment -> Text
colAlign) [Alignment]
aligns
     else (Doc Text
forall a. Doc a
cr Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>) (Doc Text -> Doc Text)
-> ([Text] -> Doc Text) -> [Text] -> Doc Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Doc Text -> Doc Text
forall a. IsString a => Int -> Doc a -> Doc a
nest Int
2 (Doc Text -> Doc Text)
-> ([Text] -> Doc Text) -> [Text] -> Doc Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat ([Doc Text] -> Doc Text)
-> ([Text] -> [Doc Text]) -> [Text] -> Doc Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Doc Text) -> [Text] -> [Doc Text]
forall a b. (a -> b) -> [a] -> [b]
map Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal ([Text] -> Doc Text) -> [Text] -> Doc Text
forall a b. (a -> b) -> a -> b
$
          (Alignment -> Double -> Text) -> [Alignment] -> [Double] -> [Text]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (Int -> Alignment -> Double -> Text
toColDescriptor ([ColSpec] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ColSpec]
specs))
                  [Alignment]
aligns
                  [Double]
relativeWidths
  where
    toColDescriptor :: Int -> Alignment -> Double -> Text
    toColDescriptor :: Int -> Alignment -> Double -> Text
toColDescriptor Int
numcols Alignment
align Double
width =
      String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> String -> Int -> Double -> String
forall r. PrintfType r => String -> r
printf
      String
">{%s\\arraybackslash}p{(\\columnwidth - %d\\tabcolsep) * \\real{%0.4f}}"
      (Text -> String
T.unpack (Alignment -> Text
alignCommand Alignment
align))
      ((Int
numcols Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
      Double
width

    isSimpleCell :: Cell -> Bool
isSimpleCell (Ann.Cell NonEmpty ColSpec
_ ColNumber
_ (Cell (Text, [Text], [(Text, Text)])
_attr Alignment
_align RowSpan
_rowspan ColSpan
_colspan [Block]
blocks)) =
      case [Block]
blocks of
        [Para [Inline]
_]  -> Bool
True
        [Plain [Inline]
_] -> Bool
True
        []        -> Bool
True
        [Block]
_         -> Bool
False

    toRelWidth :: ColWidth -> Double
toRelWidth ColWidth
ColWidthDefault = Double
0
    toRelWidth (ColWidth Double
w)    = Double
w

alignCommand :: Alignment -> Text
alignCommand :: Alignment -> Text
alignCommand = \case
  Alignment
AlignLeft    -> Text
"\\raggedright"
  Alignment
AlignRight   -> Text
"\\raggedleft"
  Alignment
AlignCenter  -> Text
"\\centering"
  Alignment
AlignDefault -> Text
"\\raggedright"

colAlign :: Alignment -> Text
colAlign :: Alignment -> Text
colAlign = \case
  Alignment
AlignLeft    -> Text
"l"
  Alignment
AlignRight   -> Text
"r"
  Alignment
AlignCenter  -> Text
"c"
  Alignment
AlignDefault -> Text
"l"

data CaptionDocs =
  CaptionDocs
  { CaptionDocs -> Doc Text
captionCommand :: Doc Text
  , CaptionDocs -> Doc Text
captionNotes :: Doc Text
  }

captionToLaTeX :: PandocMonad m
               => ([Inline] -> LW m (Doc Text))
               -> Caption
               -> Text     -- ^ table identifier (label)
               -> LW m CaptionDocs
captionToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
([Inline] -> LW m (Doc Text))
-> Caption -> Text -> LW m CaptionDocs
captionToLaTeX [Inline] -> LW m (Doc Text)
inlnsToLaTeX Caption
caption Text
ident = do
  (Doc Text
captionText, Doc Text
captForLot, Doc Text
captNotes) <- ([Inline] -> LW m (Doc Text))
-> Bool -> Caption -> LW m (Doc Text, Doc Text, Doc Text)
forall (m :: * -> *).
PandocMonad m =>
([Inline] -> LW m (Doc Text))
-> Bool -> Caption -> LW m (Doc Text, Doc Text, Doc Text)
getCaption [Inline] -> LW m (Doc Text)
inlnsToLaTeX Bool
False Caption
caption
  Doc Text
label <- Text -> LW m (Doc Text)
forall (m :: * -> *). PandocMonad m => Text -> LW m (Doc Text)
labelFor Text
ident
  CaptionDocs -> LW m CaptionDocs
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (CaptionDocs -> LW m CaptionDocs)
-> CaptionDocs -> LW m CaptionDocs
forall a b. (a -> b) -> a -> b
$ CaptionDocs
    { captionNotes :: Doc Text
captionNotes = Doc Text
captNotes
    , captionCommand :: Doc Text
captionCommand = if Doc Text -> Bool
forall a. Doc a -> Bool
isEmpty Doc Text
captionText Bool -> Bool -> Bool
&& Doc Text -> Bool
forall a. Doc a -> Bool
isEmpty Doc Text
label
                       then Doc Text
forall a. Doc a
empty
                       else Doc Text
"\\caption" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
captForLot Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
                            Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces Doc Text
captionText
                            Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
label
                            Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
"\\tabularnewline"
    }

type BlocksWriter m = [Block] -> LW m (Doc Text)

headToLaTeX :: PandocMonad m
            => BlocksWriter m
            -> ColumnCount
            -> Ann.TableHead
            -> LW m (Doc Text)
headToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m -> ColumnCount -> TableHead -> LW m (Doc Text)
headToLaTeX BlocksWriter m
blocksWriter ColumnCount
colCount (Ann.TableHead (Text, [Text], [(Text, Text)])
_attr [HeaderRow]
headerRows) = do
  [Doc Text]
rowsContents <-
    (HeaderRow -> LW m (Doc Text))
-> [HeaderRow] -> StateT WriterState m [Doc Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (BlocksWriter m
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
rowToLaTeX BlocksWriter m
blocksWriter ColumnCount
colCount CellType
HeaderCell ([Cell] -> LW m (Doc Text))
-> (HeaderRow -> [Cell]) -> HeaderRow -> LW m (Doc Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeaderRow -> [Cell]
headerRowCells)
         [HeaderRow]
headerRows
  Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text
"\\toprule\\noalign{}" Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat [Doc Text]
rowsContents Doc Text -> Doc Text -> Doc Text
forall a. Doc a -> Doc a -> Doc a
$$ Doc Text
"\\midrule\\noalign{}")

-- | Converts a row of table cells into a LaTeX row.
rowToLaTeX :: PandocMonad m
           => BlocksWriter m
           -> ColumnCount
           -> CellType
           -> [Ann.Cell]
           -> LW m (Doc Text)
rowToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> [Cell] -> LW m (Doc Text)
rowToLaTeX BlocksWriter m
blocksWriter ColumnCount
colCount CellType
celltype [Cell]
row = do
  [Doc Text]
cellsDocs <- (Cell -> LW m (Doc Text))
-> [Cell] -> StateT WriterState m [Doc Text]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (BlocksWriter m
-> ColumnCount -> CellType -> Cell -> LW m (Doc Text)
forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> Cell -> LW m (Doc Text)
cellToLaTeX BlocksWriter m
blocksWriter ColumnCount
colCount CellType
celltype) ([Cell] -> [Cell]
fillRow [Cell]
row)
  Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
hsep (Doc Text -> [Doc Text] -> [Doc Text]
forall a. a -> [a] -> [a]
intersperse Doc Text
"&" [Doc Text]
cellsDocs) Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
" \\\\"

-- | Pads row with empty cells to adjust for rowspans above this row.
fillRow :: [Ann.Cell] -> [Ann.Cell]
fillRow :: [Cell] -> [Cell]
fillRow = Int -> [Cell] -> [Cell]
go Int
0
  where
    go :: Int -> [Cell] -> [Cell]
go Int
_ [] = []
    go Int
n (acell :: Cell
acell@(Ann.Cell NonEmpty ColSpec
_spec (Ann.ColNumber Int
colnum) Cell
cell):[Cell]
cells) =
      let (Cell (Text, [Text], [(Text, Text)])
_ Alignment
_ RowSpan
_ (ColSpan Int
colspan) [Block]
_) = Cell
cell
      in (Int -> Cell) -> [Int] -> [Cell]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Cell
mkEmptyCell [Int
n .. Int
colnum Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1] [Cell] -> [Cell] -> [Cell]
forall a. [a] -> [a] -> [a]
++
         Cell
acell Cell -> [Cell] -> [Cell]
forall a. a -> [a] -> [a]
: Int -> [Cell] -> [Cell]
go (Int
colnum Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
colspan) [Cell]
cells

    mkEmptyCell :: Int -> Ann.Cell
    mkEmptyCell :: Int -> Cell
mkEmptyCell Int
colnum =
      NonEmpty ColSpec -> ColNumber -> Cell -> Cell
Ann.Cell ((Alignment
AlignDefault, ColWidth
ColWidthDefault)ColSpec -> [ColSpec] -> NonEmpty ColSpec
forall a. a -> [a] -> NonEmpty a
:|[])
               (Int -> ColNumber
Ann.ColNumber Int
colnum)
               Cell
B.emptyCell

isEmptyHead :: Ann.TableHead -> Bool
isEmptyHead :: TableHead -> Bool
isEmptyHead (Ann.TableHead (Text, [Text], [(Text, Text)])
_attr []) = Bool
True
isEmptyHead (Ann.TableHead (Text, [Text], [(Text, Text)])
_attr [HeaderRow]
rows) = (HeaderRow -> Bool) -> [HeaderRow] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ([Cell] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Cell] -> Bool) -> (HeaderRow -> [Cell]) -> HeaderRow -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeaderRow -> [Cell]
headerRowCells) [HeaderRow]
rows

isEmptyFoot :: Ann.TableFoot -> Bool
isEmptyFoot :: TableFoot -> Bool
isEmptyFoot (Ann.TableFoot (Text, [Text], [(Text, Text)])
_attr []) = Bool
True
isEmptyFoot (Ann.TableFoot (Text, [Text], [(Text, Text)])
_attr [HeaderRow]
rows) = (HeaderRow -> Bool) -> [HeaderRow] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ([Cell] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Cell] -> Bool) -> (HeaderRow -> [Cell]) -> HeaderRow -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HeaderRow -> [Cell]
headerRowCells) [HeaderRow]
rows

-- | Gets all cells in a header row.
headerRowCells :: Ann.HeaderRow -> [Ann.Cell]
headerRowCells :: HeaderRow -> [Cell]
headerRowCells (Ann.HeaderRow (Text, [Text], [(Text, Text)])
_attr RowNumber
_rownum [Cell]
cells) = [Cell]
cells

-- | Gets all cells in a body row.
bodyRowCells :: Ann.BodyRow -> [Ann.Cell]
bodyRowCells :: BodyRow -> [Cell]
bodyRowCells (Ann.BodyRow (Text, [Text], [(Text, Text)])
_attr RowNumber
_rownum [Cell]
rowhead [Cell]
cells) = [Cell]
rowhead [Cell] -> [Cell] -> [Cell]
forall a. Semigroup a => a -> a -> a
<> [Cell]
cells

-- | Gets a list of rows of the table body, where a row is a simple
-- list of cells.
bodyRows :: Ann.TableBody -> [[Ann.Cell]]
bodyRows :: TableBody -> [[Cell]]
bodyRows (Ann.TableBody (Text, [Text], [(Text, Text)])
_attr RowHeadColumns
_rowheads [HeaderRow]
headerRows [BodyRow]
rows) =
  (HeaderRow -> [Cell]) -> [HeaderRow] -> [[Cell]]
forall a b. (a -> b) -> [a] -> [b]
map HeaderRow -> [Cell]
headerRowCells [HeaderRow]
headerRows [[Cell]] -> [[Cell]] -> [[Cell]]
forall a. Semigroup a => a -> a -> a
<> (BodyRow -> [Cell]) -> [BodyRow] -> [[Cell]]
forall a b. (a -> b) -> [a] -> [b]
map BodyRow -> [Cell]
bodyRowCells [BodyRow]
rows

-- | Gets a list of rows of the table head, where a row is a simple
-- list of cells.
headRows :: Ann.TableHead -> [[Ann.Cell]]
headRows :: TableHead -> [[Cell]]
headRows (Ann.TableHead (Text, [Text], [(Text, Text)])
_attr [HeaderRow]
rows) = (HeaderRow -> [Cell]) -> [HeaderRow] -> [[Cell]]
forall a b. (a -> b) -> [a] -> [b]
map HeaderRow -> [Cell]
headerRowCells [HeaderRow]
rows

-- | Gets a list of rows from the foot, where a row is a simple list
-- of cells.
footRows :: Ann.TableFoot -> [[Ann.Cell]]
footRows :: TableFoot -> [[Cell]]
footRows (Ann.TableFoot (Text, [Text], [(Text, Text)])
_attr [HeaderRow]
rows) = (HeaderRow -> [Cell]) -> [HeaderRow] -> [[Cell]]
forall a b. (a -> b) -> [a] -> [b]
map HeaderRow -> [Cell]
headerRowCells [HeaderRow]
rows

-- For simple latex tables (without minipages or parboxes),
-- we need to go to some lengths to get line breaks working:
-- as LineBreak bs = \vtop{\hbox{\strut as}\hbox{\strut bs}}.
fixLineBreaks :: Block -> Block
fixLineBreaks :: Block -> Block
fixLineBreaks = ([Inline] -> [Inline]) -> Block -> Block
forall a b. Walkable a b => (a -> a) -> b -> b
walk [Inline] -> [Inline]
fixLineBreaks'

fixLineBreaks' :: [Inline] -> [Inline]
fixLineBreaks' :: [Inline] -> [Inline]
fixLineBreaks' [Inline]
ils = case (Inline -> Bool) -> [Inline] -> [[Inline]]
forall a. (a -> Bool) -> [a] -> [[a]]
splitBy (Inline -> Inline -> Bool
forall a. Eq a => a -> a -> Bool
== Inline
LineBreak) [Inline]
ils of
                       []     -> []
                       [[Inline]
xs]   -> [Inline]
xs
                       [[Inline]]
chunks -> Format -> Text -> Inline
RawInline Format
"tex" Text
"\\vtop{" Inline -> [Inline] -> [Inline]
forall a. a -> [a] -> [a]
:
                                 ([Inline] -> [Inline]) -> [[Inline]] -> [Inline]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap [Inline] -> [Inline]
tohbox [[Inline]]
chunks [Inline] -> [Inline] -> [Inline]
forall a. Semigroup a => a -> a -> a
<>
                                 [Format -> Text -> Inline
RawInline Format
"tex" Text
"}"]
  where tohbox :: [Inline] -> [Inline]
tohbox [Inline]
ys = Format -> Text -> Inline
RawInline Format
"tex" Text
"\\hbox{\\strut " Inline -> [Inline] -> [Inline]
forall a. a -> [a] -> [a]
: [Inline]
ys [Inline] -> [Inline] -> [Inline]
forall a. Semigroup a => a -> a -> a
<>
                    [Format -> Text -> Inline
RawInline Format
"tex" Text
"}"]

-- We also change display math to inline math, since display
-- math breaks in simple tables.
displayMathToInline :: Inline -> Inline
displayMathToInline :: Inline -> Inline
displayMathToInline (Math MathType
DisplayMath Text
x) = MathType -> Text -> Inline
Math MathType
InlineMath Text
x
displayMathToInline Inline
x                    = Inline
x

cellToLaTeX :: PandocMonad m
            => BlocksWriter m
            -> ColumnCount
            -> CellType
            -> Ann.Cell
            -> LW m (Doc Text)
cellToLaTeX :: forall (m :: * -> *).
PandocMonad m =>
BlocksWriter m
-> ColumnCount -> CellType -> Cell -> LW m (Doc Text)
cellToLaTeX BlocksWriter m
blockListToLaTeX ColumnCount
colCount CellType
celltype Cell
annotatedCell = do
  let (Ann.Cell NonEmpty ColSpec
specs ColNumber
colnum Cell
cell) = Cell
annotatedCell
  let colWidths :: NonEmpty ColWidth
colWidths = (ColSpec -> ColWidth) -> NonEmpty ColSpec -> NonEmpty ColWidth
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
NonEmpty.map ColSpec -> ColWidth
forall a b. (a, b) -> b
snd NonEmpty ColSpec
specs
  let hasWidths :: Bool
hasWidths = NonEmpty ColWidth -> ColWidth
forall a. NonEmpty a -> a
NonEmpty.head NonEmpty ColWidth
colWidths ColWidth -> ColWidth -> Bool
forall a. Eq a => a -> a -> Bool
/= ColWidth
ColWidthDefault
  let specAlign :: Alignment
specAlign = ColSpec -> Alignment
forall a b. (a, b) -> a
fst (NonEmpty ColSpec -> ColSpec
forall a. NonEmpty a -> a
NonEmpty.head NonEmpty ColSpec
specs)
  let (Cell (Text, [Text], [(Text, Text)])
_attr Alignment
align' RowSpan
rowspan ColSpan
colspan [Block]
blocks) = Cell
cell
  let align :: Alignment
align = case Alignment
align' of
                Alignment
AlignDefault -> Alignment
specAlign
                Alignment
_            -> Alignment
align'
  Bool
beamer <- (WriterState -> Bool) -> StateT WriterState m Bool
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> Bool
stBeamer
  Bool
externalNotes <- (WriterState -> Bool) -> StateT WriterState m Bool
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> Bool
stExternalNotes
  -- See #5367 -- footnotehyper/footnote don't work in beamer,
  -- so we need to produce the notes outside the table...
  (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((WriterState -> WriterState) -> StateT WriterState m ())
-> (WriterState -> WriterState) -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$ \WriterState
st -> WriterState
st{ stExternalNotes :: Bool
stExternalNotes = Bool
beamer }
  let isPlainOrPara :: Block -> Bool
isPlainOrPara = \case
        Para{}  -> Bool
True
        Plain{} -> Bool
True
        Block
_       -> Bool
False
  let hasLineBreak :: Inline -> Any
hasLineBreak Inline
LineBreak = Bool -> Any
Any Bool
True
      hasLineBreak Inline
_ = Bool -> Any
Any Bool
False
  let hasLineBreaks :: Bool
hasLineBreaks = Any -> Bool
getAny (Any -> Bool) -> Any -> Bool
forall a b. (a -> b) -> a -> b
$ (Inline -> Any) -> [Block] -> Any
forall c. Monoid c => (Inline -> c) -> [Block] -> c
forall a b c. (Walkable a b, Monoid c) => (a -> c) -> b -> c
query Inline -> Any
hasLineBreak [Block]
blocks
  Doc Text
result <-
    if Bool -> Bool
not Bool
hasWidths Bool -> Bool -> Bool
|| (CellType
celltype CellType -> CellType -> Bool
forall a. Eq a => a -> a -> Bool
/= CellType
HeaderCell
                           Bool -> Bool -> Bool
&& (Block -> Bool) -> [Block] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Block -> Bool
isPlainOrPara [Block]
blocks
                           Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
hasLineBreaks)
       then
         BlocksWriter m
blockListToLaTeX BlocksWriter m -> BlocksWriter m
forall a b. (a -> b) -> a -> b
$ (Block -> Block) -> [Block] -> [Block]
forall a b. Walkable a b => (a -> a) -> b -> b
walk Block -> Block
fixLineBreaks ([Block] -> [Block]) -> [Block] -> [Block]
forall a b. (a -> b) -> a -> b
$ (Inline -> Inline) -> [Block] -> [Block]
forall a b. Walkable a b => (a -> a) -> b -> b
walk Inline -> Inline
displayMathToInline [Block]
blocks
       else do
         Doc Text
cellContents <- LW m (Doc Text) -> LW m (Doc Text)
forall (m :: * -> *) a. Monad m => LW m a -> LW m a
inMinipage (LW m (Doc Text) -> LW m (Doc Text))
-> LW m (Doc Text) -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ BlocksWriter m
blockListToLaTeX [Block]
blocks
         let valign :: Doc Text
valign = String -> Doc Text
forall a. HasChars a => String -> Doc a
text (String -> Doc Text) -> String -> Doc Text
forall a b. (a -> b) -> a -> b
$ case CellType
celltype of
                               CellType
HeaderCell -> String
"[b]"
                               CellType
BodyCell   -> String
"[t]"
         let halign :: Doc Text
halign = Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal (Text -> Doc Text) -> Text -> Doc Text
forall a b. (a -> b) -> a -> b
$ Alignment -> Text
alignCommand Alignment
align
         Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ Doc Text
"\\begin{minipage}" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
valign Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
                  Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces Doc Text
"\\linewidth" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
halign Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
forall a. Doc a
cr Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
                  Doc Text
cellContents Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
                  (if Bool
hasLineBreaks then Doc Text
"\\strut" else Doc Text
forall a. Monoid a => a
mempty)
                  Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
forall a. Doc a
cr Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<>
                  Doc Text
"\\end{minipage}"
  (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((WriterState -> WriterState) -> StateT WriterState m ())
-> (WriterState -> WriterState) -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$ \WriterState
st -> WriterState
st{ stExternalNotes :: Bool
stExternalNotes = Bool
externalNotes }
  Bool -> StateT WriterState m () -> StateT WriterState m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (RowSpan
rowspan RowSpan -> RowSpan -> Bool
forall a. Eq a => a -> a -> Bool
/= Int -> RowSpan
RowSpan Int
1) (StateT WriterState m () -> StateT WriterState m ())
-> StateT WriterState m () -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$
    (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\WriterState
st -> WriterState
st{ stMultiRow :: Bool
stMultiRow = Bool
True })
  let inMultiColumn :: Doc Text -> Doc Text
inMultiColumn Doc Text
x = case ColSpan
colspan of
                          (ColSpan Int
1) -> Doc Text
x
                          (ColSpan Int
n) ->
                            let colDescr :: Text
colDescr = Alignment -> NonEmpty ColWidth -> ColumnCount -> ColNumber -> Text
multicolumnDescriptor Alignment
align
                                                                 NonEmpty ColWidth
colWidths
                                                                 ColumnCount
colCount
                                                                 ColNumber
colnum
                            in Doc Text
"\\multicolumn"
                               Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces (Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal (Int -> Text
forall a. Show a => a -> Text
tshow Int
n))
                               Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces (Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal Text
colDescr)
                               Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces (Doc Text
"%\n" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text
x)
                                  -- linebreak for readability
  let inMultiRow :: Doc Text -> Doc Text
inMultiRow Doc Text
x = case RowSpan
rowspan of
                       (RowSpan Int
1) -> Doc Text
x
                       (RowSpan Int
n) -> let nrows :: Doc Text
nrows = Text -> Doc Text
forall a. HasChars a => a -> Doc a
literal (Int -> Text
forall a. Show a => a -> Text
tshow Int
n)
                                      in Doc Text
"\\multirow" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces Doc Text
nrows
                                         Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces Doc Text
"*" Doc Text -> Doc Text -> Doc Text
forall a. Semigroup a => a -> a -> a
<> Doc Text -> Doc Text
forall a. HasChars a => Doc a -> Doc a
braces Doc Text
x
  Doc Text -> LW m (Doc Text)
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Doc Text -> LW m (Doc Text))
-> (Doc Text -> Doc Text) -> Doc Text -> LW m (Doc Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc Text -> Doc Text
inMultiColumn (Doc Text -> Doc Text)
-> (Doc Text -> Doc Text) -> Doc Text -> Doc Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc Text -> Doc Text
inMultiRow (Doc Text -> LW m (Doc Text)) -> Doc Text -> LW m (Doc Text)
forall a b. (a -> b) -> a -> b
$ Doc Text
result

-- | Returns the width of a cell spanning @n@ columns.
multicolumnDescriptor :: Alignment
                      -> NonEmpty ColWidth
                      -> ColumnCount
                      -> Ann.ColNumber
                      -> Text
multicolumnDescriptor :: Alignment -> NonEmpty ColWidth -> ColumnCount -> ColNumber -> Text
multicolumnDescriptor Alignment
align
  NonEmpty ColWidth
colWidths
  (ColumnCount Int
numcols)
  (Ann.ColNumber Int
colnum) =
  let toWidth :: ColWidth -> Double
toWidth = \case
        ColWidth
ColWidthDefault -> Double
0
        ColWidth Double
x      -> Double
x
      colspan :: Int
colspan = NonEmpty ColWidth -> Int
forall a. NonEmpty a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length NonEmpty ColWidth
colWidths
      width :: Double
width = NonEmpty Double -> Double
forall a. Num a => NonEmpty a -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (NonEmpty Double -> Double) -> NonEmpty Double -> Double
forall a b. (a -> b) -> a -> b
$ (ColWidth -> Double) -> NonEmpty ColWidth -> NonEmpty Double
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
NonEmpty.map ColWidth -> Double
toWidth NonEmpty ColWidth
colWidths

      -- no column separators at beginning of first and end of last column.
      skipColSep :: String
skipColSep = String
"@{}" :: String
  in String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$
     String
-> String -> String -> Int -> Double -> Int -> String -> String
forall r. PrintfType r => String -> r
printf String
"%s>{%s\\arraybackslash}p{(\\columnwidth - %d\\tabcolsep) * \\real{%0.4f} + %d\\tabcolsep}%s"
            (if Int
colnum Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then String
skipColSep else String
"")
            (Text -> String
T.unpack (Alignment -> Text
alignCommand Alignment
align))
            (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
numcols Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
            Double
width
            (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* (Int
colspan Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))
            (if Int
colnum Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
colspan Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
numcols then String
skipColSep else String
"")

-- | Perform a conversion, assuming that the context is a minipage.
inMinipage :: Monad m => LW m a -> LW m a
inMinipage :: forall (m :: * -> *) a. Monad m => LW m a -> LW m a
inMinipage LW m a
action = do
  Bool
isInMinipage <- (WriterState -> Bool) -> StateT WriterState m Bool
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets WriterState -> Bool
stInMinipage
  (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((WriterState -> WriterState) -> StateT WriterState m ())
-> (WriterState -> WriterState) -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$ \WriterState
st -> WriterState
st{ stInMinipage :: Bool
stInMinipage = Bool
True }
  a
result <- LW m a
action
  (WriterState -> WriterState) -> StateT WriterState m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((WriterState -> WriterState) -> StateT WriterState m ())
-> (WriterState -> WriterState) -> StateT WriterState m ()
forall a b. (a -> b) -> a -> b
$ \WriterState
st -> WriterState
st{ stInMinipage :: Bool
stInMinipage = Bool
isInMinipage }
  a -> LW m a
forall a. a -> StateT WriterState m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
result

data CellType
  = HeaderCell
  | BodyCell
  deriving CellType -> CellType -> Bool
(CellType -> CellType -> Bool)
-> (CellType -> CellType -> Bool) -> Eq CellType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CellType -> CellType -> Bool
== :: CellType -> CellType -> Bool
$c/= :: CellType -> CellType -> Bool
/= :: CellType -> CellType -> Bool
Eq