[GHC] #12958: Properly detect if GHCi is running in MinTTY
GHC
ghc-devs at haskell.org
Sat Dec 10 18:04:58 UTC 2016
#12958: Properly detect if GHCi is running in MinTTY
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner:
Type: bug | Status: new
Priority: normal | Milestone: 8.2.1
Component: GHCi | Version: 8.0.1
Keywords: | Operating System: Windows
Architecture: | Type of failure: Poor/confusing
Unknown/Multiple | error message
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
Since the user experience of GHCi is known to be rather poor when run in
MinTTY (e.g., see #12720), GHCi emits a warning when it thinks it's being
run in a terminal that uses MinTTY (such as Cygwin or MSYS2).
[http://git.haskell.org/ghc.git/blob/17ac9b19438d5e8f6de33f99828e8c0e7c8c1129:/driver/ghci/ghci.c#l18
Here] is the code that checks for this in `ghci.c`:
{{{#!c
if (getenv("_")) {
printf("WARNING: GHCi invoked via 'ghci.exe' in *nix-like shells
(cygwin-bash, in particular)\n");
printf(" doesn't handle Ctrl-C well; use the 'ghcii.sh' shell
wrapper instead\n");
fflush(stdout);
}
}}}
This is a rather shoddy way to detect MinTTY's presence, however. It's
quite easy to define an environmental variable named `_` in terminals that
don't use MinTTY (e.g., ConEmu).
After seeing Phab:D2809, I learned of a much more reliable way to detect
for MinTTY's presence:
{{{#!hs
queryCygwinTerminal :: Win32.HANDLE -> IO Bool
queryCygwinTerminal h = do
fileType <- Win32.getFileType h
if fileType /= Win32.fILE_TYPE_PIPE
then pure False
else do
fn <- getFileNameByHandle h
pure (("\\cygwin-" `isPrefixOf` fn || "\\msys-" `isPrefixOf` fn)
&&
"-pty" `isInfixOf` fn &&
"-master" `isSuffixOf` fn)
`catch` \ (_ :: IOError) ->
pure False
getFileNameByHandle :: Win32.HANDLE -> IO String
getFileNameByHandle h = do
let sizeOfDWORD = sizeOf (undefined :: Win32.DWORD)
let sizeOfWchar = sizeOf (undefined :: CWchar)
-- note: implicitly assuming that DWORD has stronger alignment than
wchar_t
let bufSize = sizeOfDWORD + mAX_PATH * sizeOfWchar
allocaBytes bufSize $ \ buf -> do
getFileInformationByHandleEx h fileNameInfo buf (fromIntegral bufSize)
len :: Win32.DWORD <- peek buf
let len' = fromIntegral len `div` sizeOfWchar
peekCWStringLen (buf `plusPtr` sizeOfDWORD, min len' mAX_PATH)
getFileInformationByHandleEx
:: Win32.HANDLE -> CInt -> Ptr a -> Win32.DWORD -> IO ()
getFileInformationByHandleEx h cls buf bufSize = do
lib <- Win32.getModuleHandle (Just "kernel32.dll")
ptr <- Win32.getProcAddress lib "GetFileInformationByHandleEx"
let c_GetFileInformationByHandleEx =
mk_GetFileInformationByHandleEx (castPtrToFunPtr ptr)
Win32.failIfFalse_ "getFileInformationByHandleEx"
(c_GetFileInformationByHandleEx h cls buf bufSize)
type F_GetFileInformationByHandleEx a =
Win32.HANDLE -> CInt -> Ptr a -> Win32.DWORD -> IO Win32.BOOL
foreign import WINAPI "dynamic"
mk_GetFileInformationByHandleEx
:: FunPtr (F_GetFileInformationByHandleEx a)
-> F_GetFileInformationByHandleEx a
}}}
We should port this to C and use this in `ghci.c` instead of what we have
now.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12958>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list