Implement hWithEncoding

This function allows one to not only safely set the best encoding on a
file descriptor, but also restore the previous one. The idea is that it
will be used on file descriptors that come from the outside and so we
don’t know how they were used and will be used after us.
This commit is contained in:
Kirill Elagin 2020-02-16 21:49:07 -05:00
parent 35e2ea5ce2
commit 5b98b490bc
3 changed files with 17 additions and 12 deletions

View File

@ -14,6 +14,7 @@ Initial release.
- `withUtf8StdHandles` - `withUtf8StdHandles`
- `hSetEncoding` - `hSetEncoding`
- `hWithEncoding`
- `openFile` - `openFile`
- `withFile` - `withFile`
- `readFile` - `readFile`

View File

@ -57,17 +57,16 @@ All these functions will make sure that the content will be treated as if it
was encoded in UTF-8 (it is 2020, what else can it be encoded in?). was encoded in UTF-8 (it is 2020, what else can it be encoded in?).
If, for some reason, you really need to use `withFile`/`openFile` from `base`, If, for some reason, you really need to use `withFile`/`openFile` from `base`,
just call `hSetEncoding h`, where `h` is your handle and `hSetEncoding` comes or you got your file handle from somewhere else, wrap the code that works
from `System.IO.Utf8` for your convenience: with it in a call to `hWithEncoding` from `System.IO.Utf8`:
```haskell ```haskell
import qualified System.IO as IO import qualified System.IO as IO
import qualified System.IO.Utf8 as Utf8 import qualified System.IO.Utf8 as Utf8
doSomethingWithAFile :: IO () doSomethingWithAFile :: IO.Handle -> IO ()
doSomethingWithAFile = IO.withFile "file.txt" IO.ReadMode $ \h -> do doSomethingWithAFile h = Utf8.hWithEncoding h $ do
Utf8.hSetEncoding h {- ... work with the file ... -}
{- ... work with the file ... -}
``` ```
### Step 4: Write files using UTF-8 ### Step 4: Write files using UTF-8

View File

@ -24,6 +24,7 @@ module System.IO.Utf8
( withUtf8StdHandles ( withUtf8StdHandles
, hSetEncoding , hSetEncoding
, hWithEncoding
, openFile , openFile
, withFile , withFile
@ -66,13 +67,10 @@ hSetBestUtf8Enc h = liftIO $ IO.hGetEncoding h >>= \case
-- After the action finishes, restores the original encodings. -- After the action finishes, restores the original encodings.
withUtf8StdHandles :: IO a -> IO a withUtf8StdHandles :: IO a -> IO a
withUtf8StdHandles action = withUtf8StdHandles action =
withConfiguredHandle stdin $ hWithEncoding stdin $
withConfiguredHandle stdout $ hWithEncoding stdout $
withConfiguredHandle stderr $ hWithEncoding stderr $
action action
where
withConfiguredHandle :: IO.Handle -> IO a -> IO a
withConfiguredHandle h = bracket (hSetBestUtf8Enc h) ($ h) . const
-- | Set handle encoding to the best possible. -- | Set handle encoding to the best possible.
@ -93,6 +91,13 @@ withUtf8StdHandles action =
hSetEncoding :: MonadIO m => IO.Handle -> m () hSetEncoding :: MonadIO m => IO.Handle -> m ()
hSetEncoding = liftIO . void . hSetBestUtf8Enc hSetEncoding = liftIO . void . hSetBestUtf8Enc
-- | Temporarily set handle encoding to the best possible.
--
-- This is like 'hSetEncoding', but it will restore the encoding
-- to the previous one when the action is done.
hWithEncoding :: (MonadIO m, MonadMask m) => IO.Handle -> m r -> m r
hWithEncoding h = bracket (hSetBestUtf8Enc h) ($ h) . const
-- | Like @openFile@, but sets the file encoding to UTF-8, regardless -- | Like @openFile@, but sets the file encoding to UTF-8, regardless
-- of the current locale. -- of the current locale.