{-# LANGUAGE LambdaCase, CPP #-}

-- | Printer combinators for switching printers depending on situations.
module HIndent.Pretty.Combinators.Switch
  ( (<-|>)
  ) where

import Control.Applicative
import Control.Monad.State
import HIndent.Printer
#if MIN_VERSION_GLASGOW_HASKELL(9,6,0,0)
import Control.Monad
#endif
-- | This function runs the first printer if the result of running it fits
-- in a single line. Otherwise, it runs the second printer.
(<-|>) :: Printer a -> Printer a -> Printer a
Printer a
fit <-|> :: forall a. Printer a -> Printer a -> Printer a
<-|> Printer a
notFit = do
  PrintState
before <- Printer PrintState
forall s (m :: * -> *). MonadState s m => m s
get
  PrintState -> Printer ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put PrintState
before {psFitOnOneLine = True}
  (a -> Maybe a) -> Printer a -> Printer (Maybe a)
forall a b. (a -> b) -> Printer a -> Printer b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Maybe a
forall a. a -> Maybe a
Just Printer a
fit Printer (Maybe a) -> Printer (Maybe a) -> Printer (Maybe a)
forall a. Printer a -> Printer a -> Printer a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe a -> Printer (Maybe a)
forall a. a -> Printer a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing Printer (Maybe a) -> (Maybe a -> Printer a) -> Printer a
forall a b. Printer a -> (a -> Printer b) -> Printer b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Just a
r -> do
      (PrintState -> PrintState) -> Printer ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify ((PrintState -> PrintState) -> Printer ())
-> (PrintState -> PrintState) -> Printer ()
forall a b. (a -> b) -> a -> b
$ \PrintState
st -> PrintState
st {psFitOnOneLine = psFitOnOneLine before}
      a -> Printer a
forall a. a -> Printer a
forall (m :: * -> *) a. Monad m => a -> m a
return a
r
    Maybe a
Nothing -> do
      PrintState -> Printer ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put PrintState
before
      Bool -> Printer ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> Printer ()) -> Bool -> Printer ()
forall a b. (a -> b) -> a -> b
$ Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ PrintState -> Bool
psFitOnOneLine PrintState
before
      Printer a
notFit