MercuryTechnologies / ghciwatch

Load a GHCi session for a Haskell project and reload it when source files change
https://mercurytechnologies.github.io/ghciwatch/
MIT License
104 stars 9 forks source link

Reloading after filechange no longer works when setting `hSetBuffering stdout LineBuffering` in ghci, affecting Tasty tests. #317

Closed erikryb closed 3 weeks ago

erikryb commented 4 weeks ago

What happened?

Ghciwatch stops reloading after file changes if the command hSetBuffering stdout LineBuffering is ran in ghci. This affects running tests with Tasty.

What did you expect to happen?

Ghciwatch should reload after file changes.

Steps to reproduce the issue

Create a project with one file:

module Main where

-- $> hSetBuffering stdout LineBuffering

Run ghciwatch --enable-eval. Edit the file and save. ghciwatch does not reload. If ghciwatch is aborted with CTRL-C, we get the following error:

^CError:   × Tasks failed:
  │ • run_ghci: ghci event channel closed

The version of ghciwatch with the bug

ghciwatch 1.0.1

erikryb commented 4 weeks ago

I have found a workaround, using a wrapper function:

bubblewrap :: IO () -> IO ()
bubblewrap io = do
  try io :: IO (Either SomeException ())
  hSetBuffering stdout NoBuffering

This wrapper function takes an IO action, and returns a new IO action that can be run by ghciwatch. It handles any exception (which is needed if the IO action performs an exit, which is the case for Tasty) and also sets the buffering back to NoBuffering after performing the IO action. We can now run Tasty tests in ghciwatch by adding the following comment in the source file:

-- $> bubblewrap (defaultMain =<< tests)

and running ghciwatch --enable-eval.

9999years commented 3 weeks ago

Yeah, don't do that. The wrapper is a good solution. If stdout is line-buffered, then ghciwatch can't detect when GHCi writes a prompt (because the prompt is written without a trailing newline).