content: -- | Basic table building for prettier futhark-test output.
  module Futhark.Util.Table
    ( hPutTable,
      mkEntry,
      Entry,
      AnsiStyle,
      Color (..),
      color,
    )
  where
  
  import Data.List (intersperse, transpose)
  import Futhark.Util (maxinum)
  import Futhark.Util.Pretty hiding (sep, width)
  import System.IO (Handle)
  
  data RowTemplate = RowTemplate [Int] Int deriving (Show)
  
  -- | A table entry. Consists of the content as well as how it should
  -- be styled..
  data Entry = Entry {entryText :: String, _entryStyle :: AnsiStyle}
  
  -- | Makes a table entry.
  mkEntry :: String -> AnsiStyle -> Entry
  mkEntry = Entry
  
  buildRowTemplate :: [[Entry]] -> Int -> RowTemplate
  buildRowTemplate rows = RowTemplate widths
    where
      widths = map (maxinum . map (length . entryText)) . transpose $ rows
  
  buildRow :: RowTemplate -> [Entry] -> Doc AnsiStyle
  buildRow (RowTemplate widths pad) entries = cells <> hardline
    where
      bar = "\x2502"
      cells = mconcat (zipWith buildCell entries widths) <> bar
      buildCell (Entry entry sgr) width =
        let padding = width - length entry + pad
         in bar <> " " <> annotate sgr (pretty entry) <> mconcat (replicate padding " ")
  
  buildSep :: Char -> Char -> Char -> RowTemplate -> Doc AnsiStyle
  buildSep lCorner rCorner sep (RowTemplate widths pad) =
    corners . concatMap cellFloor $ widths
    where
      cellFloor width = replicate (width + pad + 1) '\x2500' <> [sep]
      corners [] = ""
      corners s = pretty lCorner <> pretty (init s) <> pretty rCorner
  
  -- | Produce a table from a list of entries and a padding amount that
  -- determines padding from the right side of the widest entry in each column.
  hPutTable :: Handle -> [[Entry]] -> Int -> IO ()
  hPutTable h rows pad = hPutDoc h $ buildTop template <> sepRows <> buildBottom template <> hardline
    where
      sepRows = mconcat $ intersperse (buildFloor template) builtRows
      builtRows = map (buildRow template) rows
      template = buildRowTemplate rows pad
      buildTop rt = buildSep '\x250C' '\x2510' '\x252C' rt <> hardline
      buildFloor rt = buildSep '\x251C' '\x2524' '\x253C' rt <> hardline
      buildBottom = buildSep '\x2514' '\x2518' '\x2534'
  