ndmitchell / ghcid

Very low feature GHCi based IDE
Other
1.13k stars 114 forks source link

Bug: ghcid crashes when executing main #291

Closed umnikos closed 4 years ago

umnikos commented 4 years ago

This occurred in the middle of coding so I don't know the cause. Here's code:

import System.Console.ANSI

main = do
  Just (height, width) <- getTerminalSize
  putStrLn "hello"

Here's how I run it: ghcid bug.hs --test=:main

And this is the result:

*** Exception: user error (Pattern match failure in do expression at bug.hs:4:3-22)

<interactive>:96:1-22: error:
    Not in scope: ‘NTERNAL_GHCID.putStrLn’
    Perhaps you meant one of these:
      ‘INTERNAL_GHCID.putStrLn’ (imported from System.IO),
      ‘INTERNAL_GHCID.hPutStrLn’ (imported from System.IO),
      ‘INTERNAL_GHCID.putStr’ (imported from System.IO)
    No module named ‘NTERNAL_GHCID’ is imported.

This code runs in ghci but not ghcid. I'm just putting it out here. :smiley_cat:

ndmitchell commented 4 years ago

Thanks. Looks like the message GHCID sends to GHCI has had a newline inserted in it. I wonder if getTerminalSize is putting escape codes on the console. Linux or Windows? If you can reproduce I'd be really keen to know if the print or terminal size is the minimal reproduction example.

umnikos commented 4 years ago

Linux; Debian 10 (buster); ghc version 8.4.4.

The issue seems to be solely coming from getTerminalSize, as this even smaller code still reproduces the bug:

import System.Console.ANSI
main = getTerminalSize

The error message changes slightly, though (no more "pattern match failure"):

Running test...                                            
<interactive>:24:1-22: error:                              
    Not in scope: ‘NTERNAL_GHCID.putStrLn’                 
    Perhaps you meant one of these:                        
      ‘INTERNAL_GHCID.putStrLn’ (imported from System.IO), 
      ‘INTERNAL_GHCID.hPutStrLn’ (imported from System.IO),
      ‘INTERNAL_GHCID.putStr’ (imported from System.IO)    
    No module named ‘NTERNAL_GHCID’ is imported.           

Also, it may be helpful to know that ghcid takes a longer time to reload (several seconds) when changing these examples compared to regular working code.

ndmitchell commented 4 years ago

On Windows it's significantly worse, even the correct output gives:

*** Exception: Error: GetNumberOfConsoleInputEvents: invalid argument (The handle is invalid.)
This error may be avoided by using a console based on the Win32 console of the Windows API, such as Command Prompt or PowerShell.

My guess is that getTerminalSize is messing with the terminal, which is what ghcid is using to communicate with ghci, and that leads to all kinds of problems. I pushed a patch that puts a leading \n in front of the INTERNAL_GHCID, and thus hopefully avoids whatever is already on the console input. Can you see if that helps?

umnikos commented 4 years ago

Given this code:

import System.Console.ANSI

main = do
  Just (width, height) <- getTerminalSize
  putStrLn (show width ++ " - " ++ show height)

This is the output:

All good (1 module, at 18:57:49)
Running test...*** Exception: user error (Pattern match failure in do expression at bug.hs:4:3-22)

So, no, it doesn't work. :stuck_out_tongue:

ndmitchell commented 4 years ago

At least it isn't talking about NTERNAL_GHCID.putStrLn. Does it then rerun if you save again? And report an error if you introduce one? It could well be that the result you are seeing is correct, and that getTerminalSize is returning Nothing because the code knows its connected to a pipe.

umnikos commented 4 years ago

You're right, it returns Nothing. But now we get even more interesting bugs:

import System.Console.ANSI

main = do
  result <- getTerminalSize
  print "hello"
  print "hello"
All good (1 module, at 21:54:21)
Running test..."hello"          
"hello"                         
^[[37;75R                       
...done                         

the ^[[37;75R prints no matter how many times I refresh (and it is not part of the output because then it would print twice) (it appears

ndmitchell commented 4 years ago

Does everything else work? My guess is getTerminalSize is sending gunk in all directions, so the fact some shows up on the output is no great surprise.

umnikos commented 4 years ago

The fact that getConsoleSize (and the rest of the functions from the library for that matter) doesn't work is kinda sad but nothing else seems to be broken from the changes, sooo issue solved??

ndmitchell commented 4 years ago

I see no way to fix those functions (there is no console under their control), so nothing to be done about that. Yep, let's declare it solved. Thanks for your help experimenting!