{-# LANGUAGE UndecidableInstances #-}
module Shrun.Configuration.Data.Truncation
( TruncRegion (..),
Truncation (..),
parseTruncation,
LineTruncation (..),
parseLineTruncation,
decodeCommandNameTrunc,
decodeLineTrunc,
DetectResult (..),
mergeLineTrunc,
lineTruncMeta,
)
where
import Effects.System.Terminal (getTerminalWidth)
import Shrun.Configuration.Data.WithDisabled
( WithDisabled
( Disabled,
With
),
)
import Shrun.Prelude
import Shrun.Utils ((∸))
import Shrun.Utils qualified as Utils
data TruncRegion
=
TruncCommandName
|
TruncLine
deriving stock (TruncRegion -> TruncRegion -> Bool
(TruncRegion -> TruncRegion -> Bool)
-> (TruncRegion -> TruncRegion -> Bool) -> Eq TruncRegion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TruncRegion -> TruncRegion -> Bool
== :: TruncRegion -> TruncRegion -> Bool
$c/= :: TruncRegion -> TruncRegion -> Bool
/= :: TruncRegion -> TruncRegion -> Bool
Eq, Int -> TruncRegion -> ShowS
[TruncRegion] -> ShowS
TruncRegion -> String
(Int -> TruncRegion -> ShowS)
-> (TruncRegion -> String)
-> ([TruncRegion] -> ShowS)
-> Show TruncRegion
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TruncRegion -> ShowS
showsPrec :: Int -> TruncRegion -> ShowS
$cshow :: TruncRegion -> String
show :: TruncRegion -> String
$cshowList :: [TruncRegion] -> ShowS
showList :: [TruncRegion] -> ShowS
Show)
type Truncation :: TruncRegion -> Type
newtype Truncation a = MkTruncation
{ forall (a :: TruncRegion). Truncation a -> Int
unTruncation :: Int
}
deriving stock (Truncation a -> Truncation a -> Bool
(Truncation a -> Truncation a -> Bool)
-> (Truncation a -> Truncation a -> Bool) -> Eq (Truncation a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
$c== :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
== :: Truncation a -> Truncation a -> Bool
$c/= :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
/= :: Truncation a -> Truncation a -> Bool
Eq, Eq (Truncation a)
Eq (Truncation a) =>
(Truncation a -> Truncation a -> Ordering)
-> (Truncation a -> Truncation a -> Bool)
-> (Truncation a -> Truncation a -> Bool)
-> (Truncation a -> Truncation a -> Bool)
-> (Truncation a -> Truncation a -> Bool)
-> (Truncation a -> Truncation a -> Truncation a)
-> (Truncation a -> Truncation a -> Truncation a)
-> Ord (Truncation a)
Truncation a -> Truncation a -> Bool
Truncation a -> Truncation a -> Ordering
Truncation a -> Truncation a -> Truncation a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall (a :: TruncRegion). Eq (Truncation a)
forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
forall (a :: TruncRegion). Truncation a -> Truncation a -> Ordering
forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
$ccompare :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Ordering
compare :: Truncation a -> Truncation a -> Ordering
$c< :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
< :: Truncation a -> Truncation a -> Bool
$c<= :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
<= :: Truncation a -> Truncation a -> Bool
$c> :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
> :: Truncation a -> Truncation a -> Bool
$c>= :: forall (a :: TruncRegion). Truncation a -> Truncation a -> Bool
>= :: Truncation a -> Truncation a -> Bool
$cmax :: forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
max :: Truncation a -> Truncation a -> Truncation a
$cmin :: forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
min :: Truncation a -> Truncation a -> Truncation a
Ord, Int -> Truncation a -> ShowS
[Truncation a] -> ShowS
Truncation a -> String
(Int -> Truncation a -> ShowS)
-> (Truncation a -> String)
-> ([Truncation a] -> ShowS)
-> Show (Truncation a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (a :: TruncRegion). Int -> Truncation a -> ShowS
forall (a :: TruncRegion). [Truncation a] -> ShowS
forall (a :: TruncRegion). Truncation a -> String
$cshowsPrec :: forall (a :: TruncRegion). Int -> Truncation a -> ShowS
showsPrec :: Int -> Truncation a -> ShowS
$cshow :: forall (a :: TruncRegion). Truncation a -> String
show :: Truncation a -> String
$cshowList :: forall (a :: TruncRegion). [Truncation a] -> ShowS
showList :: [Truncation a] -> ShowS
Show)
deriving (Integer -> Truncation a
Truncation a -> Truncation a
Truncation a -> Truncation a -> Truncation a
(Truncation a -> Truncation a -> Truncation a)
-> (Truncation a -> Truncation a -> Truncation a)
-> (Truncation a -> Truncation a -> Truncation a)
-> (Truncation a -> Truncation a)
-> (Truncation a -> Truncation a)
-> (Truncation a -> Truncation a)
-> (Integer -> Truncation a)
-> Num (Truncation a)
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
forall (a :: TruncRegion). Integer -> Truncation a
forall (a :: TruncRegion). Truncation a -> Truncation a
forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
$c+ :: forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
+ :: Truncation a -> Truncation a -> Truncation a
$c- :: forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
- :: Truncation a -> Truncation a -> Truncation a
$c* :: forall (a :: TruncRegion).
Truncation a -> Truncation a -> Truncation a
* :: Truncation a -> Truncation a -> Truncation a
$cnegate :: forall (a :: TruncRegion). Truncation a -> Truncation a
negate :: Truncation a -> Truncation a
$cabs :: forall (a :: TruncRegion). Truncation a -> Truncation a
abs :: Truncation a -> Truncation a
$csignum :: forall (a :: TruncRegion). Truncation a -> Truncation a
signum :: Truncation a -> Truncation a
$cfromInteger :: forall (a :: TruncRegion). Integer -> Truncation a
fromInteger :: Integer -> Truncation a
Num, (forall ann. Truncation a -> Doc ann)
-> (forall ann. [Truncation a] -> Doc ann) -> Pretty (Truncation a)
forall ann. [Truncation a] -> Doc ann
forall ann. Truncation a -> Doc ann
forall a.
(forall ann. a -> Doc ann)
-> (forall ann. [a] -> Doc ann) -> Pretty a
forall (a :: TruncRegion) ann. [Truncation a] -> Doc ann
forall (a :: TruncRegion) ann. Truncation a -> Doc ann
$cpretty :: forall (a :: TruncRegion) ann. Truncation a -> Doc ann
pretty :: forall ann. Truncation a -> Doc ann
$cprettyList :: forall (a :: TruncRegion) ann. [Truncation a] -> Doc ann
prettyList :: forall ann. [Truncation a] -> Doc ann
Pretty) via Int
instance
(k ~ An_Iso, a ~ Int, b ~ Int) =>
LabelOptic "unTruncation" k (Truncation r) (Truncation r) a b
where
labelOptic :: Optic k NoIx (Truncation r) (Truncation r) a b
labelOptic = (Truncation r -> a)
-> (b -> Truncation r) -> Iso (Truncation r) (Truncation r) a b
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\(MkTruncation Int
x) -> a
Int
x) b -> Truncation r
Int -> Truncation r
forall (a :: TruncRegion). Int -> Truncation a
MkTruncation
{-# INLINE labelOptic #-}
instance DecodeTOML (Truncation a) where
tomlDecoder :: Decoder (Truncation a)
tomlDecoder = Decoder Natural -> Decoder (Truncation a)
forall (m :: Type -> Type) (r :: TruncRegion).
MonadFail m =>
m Natural -> m (Truncation r)
parseTruncation Decoder Natural
forall a. DecodeTOML a => Decoder a
tomlDecoder
parseTruncation :: (MonadFail m) => m Natural -> m (Truncation r)
parseTruncation :: forall (m :: Type -> Type) (r :: TruncRegion).
MonadFail m =>
m Natural -> m (Truncation r)
parseTruncation m Natural
getNat = do
Natural
n <- m Natural
getNat
case Natural -> Either String Int
forall a b.
(Bits a, Bits b, Integral a, Integral b, Show a, Typeable a,
Typeable b) =>
a -> Either String b
convertIntegral Natural
n of
Left String
err -> String -> m (Truncation r)
forall a. String -> m a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
err
Right Int
x -> Truncation r -> m (Truncation r)
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Truncation r -> m (Truncation r))
-> Truncation r -> m (Truncation r)
forall a b. (a -> b) -> a -> b
$ Int -> Truncation r
forall (a :: TruncRegion). Int -> Truncation a
MkTruncation Int
x
{-# INLINEABLE parseTruncation #-}
data LineTruncation
= Undetected (Truncation TruncLine)
| Detected
deriving stock (LineTruncation -> LineTruncation -> Bool
(LineTruncation -> LineTruncation -> Bool)
-> (LineTruncation -> LineTruncation -> Bool) -> Eq LineTruncation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LineTruncation -> LineTruncation -> Bool
== :: LineTruncation -> LineTruncation -> Bool
$c/= :: LineTruncation -> LineTruncation -> Bool
/= :: LineTruncation -> LineTruncation -> Bool
Eq, Int -> LineTruncation -> ShowS
[LineTruncation] -> ShowS
LineTruncation -> String
(Int -> LineTruncation -> ShowS)
-> (LineTruncation -> String)
-> ([LineTruncation] -> ShowS)
-> Show LineTruncation
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LineTruncation -> ShowS
showsPrec :: Int -> LineTruncation -> ShowS
$cshow :: LineTruncation -> String
show :: LineTruncation -> String
$cshowList :: [LineTruncation] -> ShowS
showList :: [LineTruncation] -> ShowS
Show)
instance DecodeTOML LineTruncation where
tomlDecoder :: Decoder LineTruncation
tomlDecoder = Decoder Natural -> Decoder Text -> Decoder LineTruncation
forall (m :: Type -> Type).
(Alternative m, MonadFail m) =>
m Natural -> m Text -> m LineTruncation
parseLineTruncation Decoder Natural
forall a. DecodeTOML a => Decoder a
tomlDecoder Decoder Text
forall a. DecodeTOML a => Decoder a
tomlDecoder
parseLineTruncation ::
(Alternative m, MonadFail m) =>
m Natural ->
m Text ->
m LineTruncation
parseLineTruncation :: forall (m :: Type -> Type).
(Alternative m, MonadFail m) =>
m Natural -> m Text -> m LineTruncation
parseLineTruncation m Natural
getNat m Text
getTxt =
Truncation 'TruncLine -> LineTruncation
Undetected
(Truncation 'TruncLine -> LineTruncation)
-> m (Truncation 'TruncLine) -> m LineTruncation
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> m Natural -> m (Truncation 'TruncLine)
forall (m :: Type -> Type) (r :: TruncRegion).
MonadFail m =>
m Natural -> m (Truncation r)
parseTruncation m Natural
getNat
m LineTruncation -> m LineTruncation -> m LineTruncation
forall a. m a -> m a -> m a
forall (f :: Type -> Type) a. Alternative f => f a -> f a -> f a
<|> m Text -> m LineTruncation
forall (m :: Type -> Type).
MonadFail m =>
m Text -> m LineTruncation
parseDetected m Text
getTxt
{-# INLINEABLE parseLineTruncation #-}
parseDetected :: (MonadFail m) => m Text -> m LineTruncation
parseDetected :: forall (m :: Type -> Type).
MonadFail m =>
m Text -> m LineTruncation
parseDetected m Text
getTxt =
m Text
getTxt m Text -> (Text -> m LineTruncation) -> m LineTruncation
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Text
"detect" -> LineTruncation -> m LineTruncation
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure LineTruncation
Detected
Text
bad ->
String -> m LineTruncation
forall a. String -> m a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail
(String -> m LineTruncation) -> String -> m LineTruncation
forall a b. (a -> b) -> a -> b
$ String -> (Bool, [String]) -> ShowS
forall a. (IsString a, Monoid a) => a -> (Bool, [a]) -> a -> a
Utils.fmtUnrecognizedError
String
"line truncation"
(Bool, [String])
forall a. IsString a => (Bool, [a])
lineTruncMeta
(Text -> String
unpack Text
bad)
{-# INLINEABLE parseDetected #-}
lineTruncMeta :: (IsString a) => Tuple2 Bool (List a)
lineTruncMeta :: forall a. IsString a => (Bool, [a])
lineTruncMeta = (Bool
True, [a
"NATURAL", a
"detect"])
decodeCommandNameTrunc :: Decoder (Maybe (WithDisabled (Truncation TruncCommandName)))
decodeCommandNameTrunc :: Decoder (Maybe (WithDisabled (Truncation 'TruncCommandName)))
decodeCommandNameTrunc = Decoder (WithDisabled (Truncation 'TruncCommandName))
-> Text
-> Decoder (Maybe (WithDisabled (Truncation 'TruncCommandName)))
forall a. Decoder a -> Text -> Decoder (Maybe a)
getFieldOptWith Decoder (WithDisabled (Truncation 'TruncCommandName))
forall a. DecodeTOML a => Decoder a
tomlDecoder Text
"command-name-trunc"
decodeLineTrunc :: Decoder (Maybe (WithDisabled LineTruncation))
decodeLineTrunc :: Decoder (Maybe (WithDisabled LineTruncation))
decodeLineTrunc = Decoder (WithDisabled LineTruncation)
-> Text -> Decoder (Maybe (WithDisabled LineTruncation))
forall a. Decoder a -> Text -> Decoder (Maybe a)
getFieldOptWith Decoder (WithDisabled LineTruncation)
forall a. DecodeTOML a => Decoder a
tomlDecoder Text
"line-trunc"
data DetectResult
= DetectNotRun
| DetectFailed
| DetectSucceeded Int
mergeLineTrunc ::
( HasCallStack,
MonadCatch m,
MonadIORef m,
MonadTerminal m
) =>
Bool ->
IORef DetectResult ->
Maybe (WithDisabled LineTruncation) ->
Maybe (WithDisabled LineTruncation) ->
m (Maybe (Truncation TruncLine))
mergeLineTrunc :: forall (m :: Type -> Type).
(HasCallStack, MonadCatch m, MonadIORef m, MonadTerminal m) =>
Bool
-> IORef DetectResult
-> Maybe (WithDisabled LineTruncation)
-> Maybe (WithDisabled LineTruncation)
-> m (Maybe (Truncation 'TruncLine))
mergeLineTrunc Bool
defaultDetect IORef DetectResult
detectRef Maybe (WithDisabled LineTruncation)
args Maybe (WithDisabled LineTruncation)
toml = case Maybe (WithDisabled LineTruncation)
args Maybe (WithDisabled LineTruncation)
-> Maybe (WithDisabled LineTruncation)
-> Maybe (WithDisabled LineTruncation)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: Type -> Type) a. Alternative f => f a -> f a -> f a
<|> Maybe (WithDisabled LineTruncation)
toml of
Maybe (WithDisabled LineTruncation)
Nothing ->
if Bool
defaultDetect
then IORef DetectResult
-> Maybe LineTruncation -> m (Maybe (Truncation 'TruncLine))
forall (m :: Type -> Type).
(HasCallStack, MonadCatch m, MonadIORef m, MonadTerminal m) =>
IORef DetectResult
-> Maybe LineTruncation -> m (Maybe (Truncation 'TruncLine))
configToLineTrunc IORef DetectResult
detectRef (LineTruncation -> Maybe LineTruncation
forall a. a -> Maybe a
Just LineTruncation
Detected)
else Maybe (Truncation 'TruncLine) -> m (Maybe (Truncation 'TruncLine))
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe (Truncation 'TruncLine)
forall a. Maybe a
Nothing
Just WithDisabled LineTruncation
Disabled -> Maybe (Truncation 'TruncLine) -> m (Maybe (Truncation 'TruncLine))
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe (Truncation 'TruncLine)
forall a. Maybe a
Nothing
(Just (With LineTruncation
t)) -> IORef DetectResult
-> Maybe LineTruncation -> m (Maybe (Truncation 'TruncLine))
forall (m :: Type -> Type).
(HasCallStack, MonadCatch m, MonadIORef m, MonadTerminal m) =>
IORef DetectResult
-> Maybe LineTruncation -> m (Maybe (Truncation 'TruncLine))
configToLineTrunc IORef DetectResult
detectRef (LineTruncation -> Maybe LineTruncation
forall a. a -> Maybe a
Just LineTruncation
t)
configToLineTrunc ::
( HasCallStack,
MonadCatch m,
MonadIORef m,
MonadTerminal m
) =>
IORef DetectResult ->
Maybe LineTruncation ->
m (Maybe (Truncation TruncLine))
configToLineTrunc :: forall (m :: Type -> Type).
(HasCallStack, MonadCatch m, MonadIORef m, MonadTerminal m) =>
IORef DetectResult
-> Maybe LineTruncation -> m (Maybe (Truncation 'TruncLine))
configToLineTrunc IORef DetectResult
_ Maybe LineTruncation
Nothing = Maybe (Truncation 'TruncLine) -> m (Maybe (Truncation 'TruncLine))
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe (Truncation 'TruncLine)
forall a. Maybe a
Nothing
configToLineTrunc IORef DetectResult
detectRef (Just LineTruncation
Detected) = do
Int
width <-
IORef DetectResult -> m DetectResult
forall a. HasCallStack => IORef a -> m a
forall (m :: Type -> Type) a.
(MonadIORef m, HasCallStack) =>
IORef a -> m a
readIORef' IORef DetectResult
detectRef m DetectResult -> (DetectResult -> m Int) -> m Int
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
DetectSucceeded Int
w -> Int -> m Int
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Int
w
DetectResult
DetectFailed -> Int -> m Int
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Int
defLen
DetectResult
DetectNotRun -> do
m Int -> m (Either SomeException Int)
forall (m :: Type -> Type) a.
(HasCallStack, MonadCatch m) =>
m a -> m (Either SomeException a)
tryMySync m Int
forall a (m :: Type -> Type).
(HasCallStack, Integral a, MonadTerminal m) =>
m a
getTerminalWidth m (Either SomeException Int)
-> (Either SomeException Int -> m Int) -> m Int
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left SomeException
ex -> do
let msg :: Text
msg =
[Text] -> Text
forall a. Monoid a => [a] -> a
mconcat
[ Text
"Failed detecting terminal width, defaulting to 80: ",
SomeException -> Text
forall e. Exception e => e -> Text
displayExceptiont SomeException
ex
]
Text -> m ()
forall (m :: Type -> Type).
(HasCallStack, MonadTerminal m) =>
Text -> m ()
putTextLn Text
msg
IORef DetectResult -> DetectResult -> m ()
forall a. HasCallStack => IORef a -> a -> m ()
forall (m :: Type -> Type) a.
(MonadIORef m, HasCallStack) =>
IORef a -> a -> m ()
writeIORef' IORef DetectResult
detectRef DetectResult
DetectFailed
pure Int
defLen
Right Int
w -> do
let w' :: Int
w' = Int
w Int -> Int -> Int
forall a. (Ord a, Num a) => a -> a -> a
∸ Int
1
IORef DetectResult -> DetectResult -> m ()
forall a. HasCallStack => IORef a -> a -> m ()
forall (m :: Type -> Type) a.
(MonadIORef m, HasCallStack) =>
IORef a -> a -> m ()
writeIORef' IORef DetectResult
detectRef (Int -> DetectResult
DetectSucceeded Int
w') m () -> Int -> m Int
forall (f :: Type -> Type) a b. Functor f => f a -> b -> f b
$> Int
w'
pure $ Truncation 'TruncLine -> Maybe (Truncation 'TruncLine)
forall a. a -> Maybe a
Just (Truncation 'TruncLine -> Maybe (Truncation 'TruncLine))
-> Truncation 'TruncLine -> Maybe (Truncation 'TruncLine)
forall a b. (a -> b) -> a -> b
$ Int -> Truncation 'TruncLine
forall (a :: TruncRegion). Int -> Truncation a
MkTruncation Int
width
where
defLen :: Int
defLen = Int
80
configToLineTrunc IORef DetectResult
_ (Just (Undetected Truncation 'TruncLine
x)) = Maybe (Truncation 'TruncLine) -> m (Maybe (Truncation 'TruncLine))
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Maybe (Truncation 'TruncLine)
-> m (Maybe (Truncation 'TruncLine)))
-> Maybe (Truncation 'TruncLine)
-> m (Maybe (Truncation 'TruncLine))
forall a b. (a -> b) -> a -> b
$ Truncation 'TruncLine -> Maybe (Truncation 'TruncLine)
forall a. a -> Maybe a
Just Truncation 'TruncLine
x
{-# INLINEABLE configToLineTrunc #-}