-- SPDX-FileCopyrightText: 2023 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

{-# LANGUAGE NoImplicitPrelude #-}

-- | Compatibility layer between @prettyprinter@ and @wl-pprint-text@
module Fmt.Utils
  ( Doc
  , SimpleDoc
  , renderOneLine
  , isEmpty
  , linebreak
  , softbreak
  , mkLayoutOptions
  ) where

import Universum (Bool(..), Double, Int, flip, mempty, ($), (+), (...))

import Prettyprinter qualified as PP
import Prettyprinter.Internal qualified as PP (Doc(..))

-- | Document without annotations
type Doc = PP.Doc ()

-- | Simple document without annotations
type SimpleDoc = PP.SimpleDocStream ()

{- | Check if 'Doc' is 'mempty'. Note that empty strings are also considered
empty.

>>> isEmpty mempty
True
>>> isEmpty ""
True
>>> isEmpty "foo"
False
-}
isEmpty :: Doc -> Bool
isEmpty :: Doc () -> Bool
isEmpty Doc ()
PP.Empty = Bool
True
isEmpty Doc ()
_ = Bool
False

-- | Rendered as newline, when undone by @group@, is @mempty@.
linebreak :: Doc
linebreak :: Doc ()
linebreak = Doc () -> Doc () -> Doc ()
forall ann. Doc ann -> Doc ann -> Doc ann
PP.flatAlt Doc ()
forall ann. Doc ann
PP.line Doc ()
forall a. Monoid a => a
mempty

-- | Like @mempty@ if the output fits the page, otherwise like @line@.
softbreak :: Doc
softbreak :: Doc ()
softbreak = Doc () -> Doc ()
forall ann. Doc ann -> Doc ann
PP.group Doc ()
linebreak

renderOneLine :: Doc -> SimpleDoc
renderOneLine :: Doc () -> SimpleDoc
renderOneLine Doc ()
dc = Int -> [Doc ()] -> SimpleDoc
forall {ann} {ann}. Int -> [Doc ann] -> SimpleDocStream ann
scan Int
0 [Doc ()
dc]
  where
    scan :: Int -> [Doc ann] -> SimpleDocStream ann
scan Int
_ [] = SimpleDocStream ann
forall ann. SimpleDocStream ann
PP.SEmpty
    scan !Int
k (Doc ann
d:[Doc ann]
ds) = case Doc ann
d of
      Doc ann
PP.Fail            -> SimpleDocStream ann
forall ann. SimpleDocStream ann
PP.SFail
      Doc ann
PP.Empty           -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k [Doc ann]
ds
      PP.Char Char
c          -> Char -> SimpleDocStream ann -> SimpleDocStream ann
forall ann. Char -> SimpleDocStream ann -> SimpleDocStream ann
PP.SChar Char
c (SimpleDocStream ann -> SimpleDocStream ann)
-> SimpleDocStream ann -> SimpleDocStream ann
forall a b. (a -> b) -> a -> b
$ Int -> [Doc ann] -> SimpleDocStream ann
scan (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) [Doc ann]
ds
      PP.Text Int
l Text
s        -> Int -> Text -> SimpleDocStream ann -> SimpleDocStream ann
forall ann.
Int -> Text -> SimpleDocStream ann -> SimpleDocStream ann
PP.SText Int
l Text
s (SimpleDocStream ann -> SimpleDocStream ann)
-> SimpleDocStream ann -> SimpleDocStream ann
forall a b. (a -> b) -> a -> b
$ Int -> [Doc ann] -> SimpleDocStream ann
scan (Int
k Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
l) [Doc ann]
ds
      Doc ann
PP.Line            -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k [Doc ann]
ds
      PP.Cat Doc ann
x Doc ann
y         -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Doc ann
x Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: Doc ann
y Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.Nest Int
_ Doc ann
x        -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Doc ann
x Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.Union Doc ann
x Doc ann
_       -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Doc ann
x Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.Column Int -> Doc ann
f        -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Int -> Doc ann
f Int
k Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.Nesting Int -> Doc ann
f       -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Int -> Doc ann
f Int
0 Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.FlatAlt Doc ann
_ Doc ann
y     -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Doc ann
y Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.WithPageWidth PageWidth -> Doc ann
f -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (PageWidth -> Doc ann
f PageWidth
PP.Unbounded Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)
      PP.Annotated ann
_ Doc ann
x   -> Int -> [Doc ann] -> SimpleDocStream ann
scan Int
k (Doc ann
x Doc ann -> [Doc ann] -> [Doc ann]
forall a. a -> [a] -> [a]
: [Doc ann]
ds)

mkLayoutOptions :: Double -> Int -> PP.LayoutOptions
mkLayoutOptions :: Double -> Int -> LayoutOptions
mkLayoutOptions = PageWidth -> LayoutOptions
PP.LayoutOptions (PageWidth -> LayoutOptions)
-> (Double -> Int -> PageWidth) -> Double -> Int -> LayoutOptions
forall a b c. SuperComposition a b c => a -> b -> c
... (Int -> Double -> PageWidth) -> Double -> Int -> PageWidth
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Double -> PageWidth
PP.AvailablePerLine