{-# LANGUAGE OverloadedStrings #-} -- | Shared utility functions module Dhall.Util ( snip , snipDoc ) where import Data.Monoid ((<>)) import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc) import Dhall.Pretty (Ann) import qualified Data.Text import qualified Data.Text.Prettyprint.Doc as Pretty import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty import qualified Dhall.Pretty -- | Utility function to cut out the interior of a large text block snip :: Text -> Text snip text | length ls <= 7 = text | otherwise = if Data.Text.last text == '\n' then preview else Data.Text.init preview where ls = Data.Text.lines text header = take 3 ls footer = takeEnd 3 ls excerpt = filter (Data.Text.any (/= ' ')) (header <> footer) leadingSpaces = Data.Text.length . Data.Text.takeWhile (== ' ') minSpaces = minimum (map leadingSpaces excerpt) maxLength = maximum (map Data.Text.length excerpt) separator = Data.Text.replicate minSpaces " " <> Data.Text.replicate (maxLength - minSpaces) "=" preview = Data.Text.unlines header <> separator <> "\n" <> Data.Text.unlines footer {-| Like `snip`, but for `Doc`s Note that this has to be opinionated and render ANSI color codes, but that should be fine because we don't use this in a non-interactive context -} snipDoc :: Doc Ann -> Doc a snipDoc doc = Pretty.align (Pretty.pretty (snip text)) where stream = Pretty.layoutSmart Dhall.Pretty.layoutOpts doc ansiStream = fmap Dhall.Pretty.annToAnsiStyle stream text = Pretty.renderStrict ansiStream takeEnd :: Int -> [a] -> [a] takeEnd n l = go (drop n l) l where go (_:xs) (_:ys) = go xs ys go _ r = r