    -- | Write 'Text' to files using UTF8 and ignoring native
    -- line ending conventions.
    module Ormolu.Utils.IO
      ( writeFileUtf8,
        readFileUtf8,
        getContentsUtf8,
      )
    where

    import Control.Exception (throwIO)
    import Control.Monad.IO.Class
    import Data.ByteString (ByteString)
    import qualified Data.ByteString as B
    import Data.Text (Text)
    import qualified Data.Text.Encoding as TE

    -- | Write a 'Text' to a file using UTF8 and ignoring native
    -- line ending conventions.
    writeFileUtf8 :: (MonadIO m) => FilePath -> Text -> m ()
    writeFileUtf8 :: forall (m :: * -> *). MonadIO m => FilePath -> Text -> m ()
    writeFileUtf8 FilePath
    p = IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> (Text -> IO ()) -> Text -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . FilePath -> ByteString -> IO ()
    B.writeFile FilePath
    p (ByteString -> IO ()) -> (Text -> ByteString) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> ByteString
    TE.encodeUtf8

    -- | Read an entire file strictly into a 'Text' using UTF8 and
    -- ignoring native line ending conventions.
    readFileUtf8 :: (MonadIO m) => FilePath -> m Text
    readFileUtf8 :: forall (m :: * -> *). MonadIO m => FilePath -> m Text
    readFileUtf8 FilePath
    p = IO ByteString -> m ByteString
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (FilePath -> IO ByteString
    B.readFile FilePath
    p) m ByteString -> (ByteString -> m Text) -> m Text
    forall a b. m a -> (a -> m b) -> m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= ByteString -> m Text
    forall (m :: * -> *). MonadIO m => ByteString -> m Text
    decodeUtf8

    -- | Read stdin as UTF8-encoded 'Text' value.
    getContentsUtf8 :: (MonadIO m) => m Text
    getContentsUtf8 :: forall (m :: * -> *). MonadIO m => m Text
    getContentsUtf8 = IO ByteString -> m ByteString
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO IO ByteString
    B.getContents m ByteString -> (ByteString -> m Text) -> m Text
    forall a b. m a -> (a -> m b) -> m b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= ByteString -> m Text
    forall (m :: * -> *). MonadIO m => ByteString -> m Text
    decodeUtf8

    -- | A helper function for decoding a strict 'ByteString' into 'Text'. It is
    -- strict and fails immediately if decoding encounters a problem.
    decodeUtf8 :: (MonadIO m) => ByteString -> m Text
    decodeUtf8 :: forall (m :: * -> *). MonadIO m => ByteString -> m Text
    decodeUtf8 = IO Text -> m Text
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Text -> m Text)
    -> (ByteString -> IO Text) -> ByteString -> m Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (UnicodeException -> IO Text)
    -> (Text -> IO Text) -> Either UnicodeException Text -> IO Text
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either UnicodeException -> IO Text
    forall e a. Exception e => e -> IO a
    throwIO Text -> IO Text
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure (Either UnicodeException Text -> IO Text)
    -> (ByteString -> Either UnicodeException Text)
    -> ByteString
    -> IO Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> Either UnicodeException Text
    TE.decodeUtf8'