{-# LANGUAGE LambdaCase #-}
module System.IO.Utf8
( withHandle
, withTerminalHandle
, setHandleEncoding
, setTerminalHandleEncoding
, openFile
, withFile
) where
import Control.Exception.Safe (MonadMask, bracket)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Functor (void)
import GHC.IO.Encoding (mkTextEncoding, utf8)
import qualified System.IO as IO
import System.IO.Utf8.Internal (EncodingAction (..), chooseBestEnc)
type EncRestoreAction m = IO.Handle -> m ()
hSetBestUtf8Enc
:: MonadIO m
=> (IO.Handle -> IO Bool)
-> IO.Handle
-> m (EncRestoreAction m)
hSetBestUtf8Enc :: (Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
hSetBestUtf8Enc hIsTerm :: Handle -> IO Bool
hIsTerm h :: Handle
h = IO (EncRestoreAction m) -> m (EncRestoreAction m)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (EncRestoreAction m) -> m (EncRestoreAction m))
-> IO (EncRestoreAction m) -> m (EncRestoreAction m)
forall a b. (a -> b) -> a -> b
$ do
Handle -> IO (Maybe TextEncoding)
IO.hGetEncoding Handle
h IO (Maybe TextEncoding)
-> (Maybe TextEncoding -> IO EncodingAction) -> IO EncodingAction
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Handle
-> (Handle -> IO Bool) -> Maybe TextEncoding -> IO EncodingAction
chooseBestEnc Handle
h Handle -> IO Bool
hIsTerm IO EncodingAction
-> (EncodingAction -> IO (EncRestoreAction m))
-> IO (EncRestoreAction m)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Keep -> EncRestoreAction m -> IO (EncRestoreAction m)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (\_ -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
ChangeFromTo enc :: TextEncoding
enc newName :: String
newName -> do
String -> IO TextEncoding
mkTextEncoding String
newName IO TextEncoding -> (TextEncoding -> IO ()) -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Handle -> TextEncoding -> IO ()
IO.hSetEncoding Handle
h
EncRestoreAction m -> IO (EncRestoreAction m)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (EncRestoreAction m -> IO (EncRestoreAction m))
-> EncRestoreAction m -> IO (EncRestoreAction m)
forall a b. (a -> b) -> a -> b
$ IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> EncRestoreAction m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> TextEncoding -> IO ())
-> TextEncoding -> Handle -> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Handle -> TextEncoding -> IO ()
IO.hSetEncoding TextEncoding
enc
setHandleEncoding :: MonadIO m => IO.Handle -> m ()
setHandleEncoding :: Handle -> m ()
setHandleEncoding = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> Handle -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO (Handle -> IO ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Handle -> IO ()) -> IO ())
-> (Handle -> IO (Handle -> IO ())) -> Handle -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> IO Bool) -> Handle -> IO (Handle -> IO ())
forall (m :: * -> *).
MonadIO m =>
(Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
hSetBestUtf8Enc Handle -> IO Bool
IO.hIsTerminalDevice
withHandle :: (MonadIO m, MonadMask m) => IO.Handle -> m r -> m r
withHandle :: Handle -> m r -> m r
withHandle h :: Handle
h = m (EncRestoreAction m)
-> (EncRestoreAction m -> m ())
-> (EncRestoreAction m -> m r)
-> m r
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracket ((Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
forall (m :: * -> *).
MonadIO m =>
(Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
hSetBestUtf8Enc Handle -> IO Bool
IO.hIsTerminalDevice Handle
h) (EncRestoreAction m -> EncRestoreAction m
forall a b. (a -> b) -> a -> b
$ Handle
h) ((EncRestoreAction m -> m r) -> m r)
-> (m r -> EncRestoreAction m -> m r) -> m r -> m r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m r -> EncRestoreAction m -> m r
forall a b. a -> b -> a
const
setTerminalHandleEncoding :: MonadIO m => IO.Handle -> m ()
setTerminalHandleEncoding :: Handle -> m ()
setTerminalHandleEncoding = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> Handle -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO (Handle -> IO ()) -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO (Handle -> IO ()) -> IO ())
-> (Handle -> IO (Handle -> IO ())) -> Handle -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> IO Bool) -> Handle -> IO (Handle -> IO ())
forall (m :: * -> *).
MonadIO m =>
(Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
hSetBestUtf8Enc (IO Bool -> Handle -> IO Bool
forall a b. a -> b -> a
const (IO Bool -> Handle -> IO Bool) -> IO Bool -> Handle -> IO Bool
forall a b. (a -> b) -> a -> b
$ Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True)
withTerminalHandle :: (MonadIO m, MonadMask m) => IO.Handle -> m r -> m r
withTerminalHandle :: Handle -> m r -> m r
withTerminalHandle h :: Handle
h = m (EncRestoreAction m)
-> (EncRestoreAction m -> m ())
-> (EncRestoreAction m -> m r)
-> m r
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracket ((Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
forall (m :: * -> *).
MonadIO m =>
(Handle -> IO Bool) -> Handle -> m (EncRestoreAction m)
hSetBestUtf8Enc (IO Bool -> Handle -> IO Bool
forall a b. a -> b -> a
const (IO Bool -> Handle -> IO Bool) -> IO Bool -> Handle -> IO Bool
forall a b. (a -> b) -> a -> b
$ Bool -> IO Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True) Handle
h) (EncRestoreAction m -> EncRestoreAction m
forall a b. (a -> b) -> a -> b
$ Handle
h) ((EncRestoreAction m -> m r) -> m r)
-> (m r -> EncRestoreAction m -> m r) -> m r -> m r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m r -> EncRestoreAction m -> m r
forall a b. a -> b -> a
const
openFile :: MonadIO m => IO.FilePath -> IO.IOMode -> m IO.Handle
openFile :: String -> IOMode -> m Handle
openFile path :: String
path mode :: IOMode
mode = IO Handle -> m Handle
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Handle -> m Handle) -> IO Handle -> m Handle
forall a b. (a -> b) -> a -> b
$ do
Handle
h <- String -> IOMode -> IO Handle
IO.openFile String
path IOMode
mode
Handle -> TextEncoding -> IO ()
IO.hSetEncoding Handle
h TextEncoding
utf8
Handle -> IO Handle
forall (f :: * -> *) a. Applicative f => a -> f a
pure Handle
h
withFile
:: (MonadIO m, MonadMask m)
=> IO.FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r
withFile :: String -> IOMode -> (Handle -> m r) -> m r
withFile path :: String
path mode :: IOMode
mode = m Handle -> (Handle -> m ()) -> (Handle -> m r) -> m r
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracket (String -> IOMode -> m Handle
forall (m :: * -> *). MonadIO m => String -> IOMode -> m Handle
openFile String
path IOMode
mode) (IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (Handle -> IO ()) -> Handle -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Handle -> IO ()
IO.hClose)