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`
- `hSetEncoding`
- `hWithEncoding`
- `openFile`
- `withFile`
- `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?).
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
from `System.IO.Utf8` for your convenience:
or you got your file handle from somewhere else, wrap the code that works
with it in a call to `hWithEncoding` from `System.IO.Utf8`:
```haskell
import qualified System.IO as IO
import qualified System.IO.Utf8 as Utf8
doSomethingWithAFile :: IO ()
doSomethingWithAFile = IO.withFile "file.txt" IO.ReadMode $ \h -> do
Utf8.hSetEncoding h
{- ... work with the file ... -}
doSomethingWithAFile :: IO.Handle -> IO ()
doSomethingWithAFile h = Utf8.hWithEncoding h $ do
{- ... work with the file ... -}
```
### Step 4: Write files using UTF-8

View File

@ -24,6 +24,7 @@ module System.IO.Utf8
( withUtf8StdHandles
, hSetEncoding
, hWithEncoding
, openFile
, withFile
@ -66,13 +67,10 @@ hSetBestUtf8Enc h = liftIO $ IO.hGetEncoding h >>= \case
-- After the action finishes, restores the original encodings.
withUtf8StdHandles :: IO a -> IO a
withUtf8StdHandles action =
withConfiguredHandle stdin $
withConfiguredHandle stdout $
withConfiguredHandle stderr $
hWithEncoding stdin $
hWithEncoding stdout $
hWithEncoding stderr $
action
where
withConfiguredHandle :: IO.Handle -> IO a -> IO a
withConfiguredHandle h = bracket (hSetBestUtf8Enc h) ($ h) . const
-- | Set handle encoding to the best possible.
@ -93,6 +91,13 @@ withUtf8StdHandles action =
hSetEncoding :: MonadIO m => IO.Handle -> m ()
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
-- of the current locale.