packages feed

skeletest-0.3.0: src/Skeletest/Internal/Utils/BoxDrawing.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Skeletest.Internal.Utils.BoxDrawing (
  BoxSpec,
  BoxSpecContent (..),
  drawBox,
) where

import Data.Text (Text)
import Data.Text qualified as Text
import System.Console.Terminal.Size qualified as Term

type BoxSpec = [BoxSpecContent]

data BoxSpecContent
  = BoxText Text
  | BoxHeader Text
  deriving (Show, Eq)

drawBox :: BoxSpec -> IO Text
drawBox box = do
  width <- maybe 80 (max 40 . Term.width) <$> Term.size
  pure $ drawBox' width box

drawBox' :: Int -> BoxSpec -> Text
drawBox' width boxContents = Text.intercalate "\n" $ [header] <> concatMap draw boxContents <> [footer]
 where
  header = "╔" <> Text.replicate (width - 2) "═" <> "╗"
  footer = "╚" <> Text.replicate (width - 2) "═" <> "╝"

  draw = \case
    BoxHeader s ->
      [ drawLine ""
      , "╟─" <> cpad (width - 4) "─" ("⟨ " <> s <> " ⟩") <> "─╢"
      ]
    BoxText s ->
      [ drawLine line
      | rawLine <- Text.lines s
      , line <- if Text.null rawLine then [""] else Text.chunksOf (width - 4) rawLine
      ]
  drawLine s = "║ " <> rpad (width - 4) " " s <> " ║"

  rpad n fill s = s <> Text.replicate (n - Text.length s) fill
  cpad n fill s =
    let total = n - Text.length s
        left = total `div` 2
        right = total - left
     in Text.replicate left fill <> s <> Text.replicate right fill