-- | See GHC #10762 and #15021.
module GHC.HandleEncoding (configureHandleEncoding) where

import Prelude -- See note [Why do we import Prelude here?]
import GHC.IO.Encoding (textEncodingName)
import System.Environment
import System.IO

-- | Handle GHC-specific character encoding flags, allowing us to control how
-- GHC produces output regardless of OS.
configureHandleEncoding :: IO ()
configureHandleEncoding :: IO ()
configureHandleEncoding = do
   [(String, String)]
env <- IO [(String, String)]
getEnvironment
   case String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup "GHC_CHARENC" [(String, String)]
env of
    Just "UTF-8" -> do
     Handle -> TextEncoding -> IO ()
hSetEncoding Handle
stdout TextEncoding
utf8
     Handle -> TextEncoding -> IO ()
hSetEncoding Handle
stderr TextEncoding
utf8
    _ -> do
     -- Avoid GHC erroring out when trying to display unhandled characters
     Handle -> IO ()
hSetTranslit Handle
stdout
     Handle -> IO ()
hSetTranslit Handle
stderr

-- | Change the character encoding of the given Handle to transliterate
-- on unsupported characters instead of throwing an exception
hSetTranslit :: Handle -> IO ()
hSetTranslit :: Handle -> IO ()
hSetTranslit h :: Handle
h = do
    Maybe TextEncoding
menc <- Handle -> IO (Maybe TextEncoding)
hGetEncoding Handle
h
    case (TextEncoding -> String) -> Maybe TextEncoding -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap TextEncoding -> String
textEncodingName Maybe TextEncoding
menc of
        Just name :: String
name | '/' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` String
name -> do
            TextEncoding
enc' <- String -> IO TextEncoding
mkTextEncoding (String -> IO TextEncoding) -> String -> IO TextEncoding
forall a b. (a -> b) -> a -> b
$ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ "//TRANSLIT"
            Handle -> TextEncoding -> IO ()
hSetEncoding Handle
h TextEncoding
enc'
        _ -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()