2

Simple code below does not work correctly in Windows terminal with UTF-8 characters, whether with getLine/putStrLn from Prelude or from Data.Text.IO:

main = forever $ getLine >>= putStrLn

It echoes utf-8 characters during the input, then it prints "?"s in place of utf-8 characters; switching encoding with chcp 65001 makes them spaces.

I've downloaded the new terminal and enabled utf-8 support as this page suggested, but it had no effect.

This explanation seems related, but the solution proposed there does not work (the code does the same).

Apparently python has a similar issue

Is there any library/workaround that would work with GHC 8.x?

Please help!

EDIT: after more investigation, the problem is during the input as well - if instead of putStrLn I print character codes with mapM_ (print . ord) s they are all either 63 without changing encoding or 0 after chcp 65001.

hSetEncoding stdin utf8 does not help

esp
  • 7,314
  • 6
  • 49
  • 79

1 Answers1

1

I've found the library that does it: https://hackage.haskell.org/package/terminal

It does not include getLine (only key events), but it's simple enough to implement:

import Control.Monad.IO.Class (liftIO)
import System.Exit (exitSuccess)
import System.Terminal as C

getTermLine :: MonadTerminal m => m String
getTermLine = getChars ""
  where
    getChars s = awaitEvent >>= processKey s
    processKey s = \case
      Right (KeyEvent key ms) -> case key of
        CharKey c
          | ms == mempty || ms == shiftKey -> do
            C.putChar c
            flush -- works without flush in Windows, but not in Mac
            getChars (c : s)
          | otherwise -> getChars s
        EnterKey -> do
          putLn
          flush
          pure $ reverse s
        BackspaceKey -> do
          moveCursorBackward 1
          eraseChars 1
          flush
          getChars $ if null s then s else tail s
        _ -> getChars s
      Left Interrupt -> liftIO exitSuccess
      _ -> getChars s
esp
  • 7,314
  • 6
  • 49
  • 79