path-text-utf8-0.0.1.12: src/Path/Text/UTF8.hs
-- | Read and write UTF-8 text files.
module Path.Text.UTF8
( -- * Reading
readFile,
tryReadFile,
ReadError (..),
-- * Writing
writeFile,
tryWriteFile,
WriteError,
-- * Re-exports
IOError,
UnicodeException (DecodeError),
parseAbsFile,
parseRelFile,
)
where
import Control.Exception.Safe qualified as Exception
import Data.ByteString qualified as BS
import Data.Either (Either (..))
import Data.Functor ((<$>))
import Data.Text (Text)
import Data.Text.Encoding qualified as TextEncoding
import Data.Text.Encoding.Error (UnicodeException (..))
import Path (Path, parseAbsFile, parseRelFile)
import Path qualified
import System.IO (IO)
import System.IO.Error (IOError)
data ReadError
= ReadErrorIO IOError
| ReadErrorDecode UnicodeException
type WriteError = IOError
-- | Read the contents of a UTF-8 encoded text file
--
-- May throw 'IOError' or 'UnicodeException'. To handle these errors in 'Either'
-- instead, use 'tryReadFile'.
readFile :: Path base Path.File -> IO Text
readFile path =
f <$> BS.readFile (Path.toFilePath path)
where
f bs = let !text = TextEncoding.decodeUtf8 bs in text
-- | Read the contents of a UTF-8 encoded text file
--
-- Any 'IOError' or 'UnicodeException' that occurs is caught and returned as a
-- 'ReadError' on the 'Left' side of the 'Either'. To throw these exceptions
-- instead, use 'readFile'.
tryReadFile :: Path base Path.File -> IO (Either ReadError Text)
tryReadFile path =
f <$> Exception.tryIO (BS.readFile (Path.toFilePath path))
where
f (Left e) = Left (ReadErrorIO e)
f (Right bs) = first ReadErrorDecode (TextEncoding.decodeUtf8' bs)
-- | Write text to a file in a UTF-8 encoding
--
-- May throw 'IOError'. To handle this error in 'Either' instead, use
-- 'tryWriteFile'.
writeFile :: Path base Path.File -> Text -> IO ()
writeFile path text =
BS.writeFile (Path.toFilePath path) (TextEncoding.encodeUtf8 text)
-- | Write text to a file in a UTF-8 encoding
--
-- Any 'IOError' that occurs is caught and returned on the 'Left' side of the
-- 'Either'. To throw the exception instead, use 'writeFile'.
tryWriteFile :: Path base Path.File -> Text -> IO (Either WriteError ())
tryWriteFile path text = Exception.tryIO (writeFile path text)
first :: (a -> a') -> Either a b -> Either a' b
first f (Left x) = Left (f x)
first _ (Right x) = Right x