Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Will WinIO will remove the need for emulation with getReportedCursorPosition? #135

Open
mpilgrem opened this issue May 3, 2022 · 1 comment

Comments

@mpilgrem
Copy link
Collaborator

mpilgrem commented May 3, 2022

WinIO has seen https://gitlab.haskell.org/ghc/ghc/-/issues/806 closed, the issue referred to in the documentation for reportCursorPositionCode.

However, to date, I have not been able to get getChar on Windows with WinIO to behave as I would expect; see https://gitlab.haskell.org/ghc/ghc/-/issues/21488.

@mpilgrem
Copy link
Collaborator Author

mpilgrem commented Jan 4, 2023

GHC issue #21488 is fixed in GHC 9.2.5, but not in GHC 9.4.3 or GHC 9.4.4. So, on Windows, with GHC 9.2.5 and:

ghc-options:
- -with-rtsopts=--io-manager=native
module Main (main) where

import Control.Exception
import qualified Data.List as L
import Data.Maybe
import System.Console.ANSI hiding (getReportedCursorPosition)
import System.IO
import System.Timeout

main :: IO ()
main = do
  -- set no buffering (if 'no buffering' is not already set, the contents of
  -- the buffer will be discarded, so this needs to be done before the cursor
  -- positon is emitted)
  hSetBuffering stdin NoBuffering
  -- ensure that echoing is off
  input <- bracket (hGetEcho stdin) (hSetEcho stdin) $ \_ -> do
    hSetEcho stdin False
    reportCursorPosition
    hFlush stdout -- ensure the report cursor position code is sent to the
                  -- operating system
    getReportedCursorPosition
  print input

getReportedCursorPosition = getReport "\ESC[" ["R"]

getReport :: String -> [String] -> IO String
getReport _ [] = error "getReport requires a list of terminating sequences."
getReport startChars endChars = do
  fromMaybe "" <$> timeout 500000 (getStart startChars "")
 where
  endChars' = mapMaybe L.uncons endChars

  getStart :: String -> String -> IO String
  getStart "" r = getRest r
  getStart (h:hs) r = do
    c <- getChar
    if c == h
      then getStart hs (c:r)
      else return $ reverse (c:r)

  getRest :: String -> IO String
  getRest r = do
    c <- getChar
    case lookup c endChars' of
      Nothing -> getRest (c:r)
      Just es -> getEnd es (c:r)

  getEnd :: String -> String -> IO String
  getEnd "" r = return $ reverse r
  getEnd (e:es) r = do
    c <- getChar
    if c /= e
      then getRest (c:r)
      else getEnd es (c:r)

works as it currently does on Unix-like operating systems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant