Open AliceRixte opened 4 days ago
@AliceRixte this looks like because of IO buffering occurring in the pipeChunks API. Let me check and update.
Try out this fix: https://github.com/composewell/streamly-process/pull/86 . If this works we can add a config option to enable different types of buffering optionally.
Yes it works great ! This is awesome ! I'm amazed at how concise this is :-)
I've been playing a bit more with this and I think it would be great to also have the possibility to use line buffers in the output as well.
For instance, what I'm currently trying to achieve is to make a REPL for an EDSL I made in Haskell, and I'd like to be able to replace the ghci>
prompt with my own language prompt. However for now the output chunks of GHCi are a bit all over the place and I don't see an easy way to do this, except line buffering for the output of pipeChunks
.
Another example of why this would be useful is the (admitedly not great) hack I came up with to quit as soon as GHCi quit using
Fold.takeEndBy ( == stringToByteArray "Leaving GHCi.") Stdio.writeChunks
This does not work for now because the buffering splits "Leaving GHCi." into 2 chunks.
If we do line buffering then you cannot output a line until newline is encountered, since ghci prompt does not end with a newline you wont be able to display the prompt correctly.
Not very efficient, but you can output character-by-character for now like this.
import qualified Streamly.Data.Array as Array -- Streamly.Data.Array.Foreign is deprecated
import qualified Streamly.Internal.Data.Fold as Fold -- takeEndBySeq is not exposed yet
hSetBuffering stdout NoBuffering
let f =
Fold.takeEndBySeq (stringToByteArray "Leaving GHCi.")
$ Fold.drainMapM (putChar . chr . fromIntegral)
Stream.fold f
$ Stream.unfoldMany Array.reader
$ Process.pipeChunks "ghci" []
$ Stdio.readChunks
We can do it more efficiently in chunks as well, but that will require a bit more complicated code.
BTW, using "Leaving GHCi" to detect the end is hacky, if the ghci output has this string elsewhere e.g. the user types it that will end the session.
The simplest is to not detect the end by a string, just use end-of-stream to end the session, something like this should work:
import qualified Streamly.Internal.Console.Stdio as Stdio
Stdio.putChunks
$ Process.pipeChunks "ghci" []
$ Stdio.readChunks
Thank you for your insights !
The second code doesn't end the stream on quitting GHC, but it really nice ! However I will process the input line by line before feeding it to GHCi so I think I'll stick to getLine.
For quitting, I think I will use something in the flavor of your AcidRain example, and hijack the ":q" command to change the program state, send ":q" to GHCi and then quit. This will be less hacky. I will need a state anyway for other purposes.
Thanks again for all the support !
First of all, thank you for this library and the great work !
I've posted this question on stackoverflow, and it looks like nobody there knows the answer, so I'll post it here as an issue. Here is a copy/paste from stack overflow :
I'm trying to use
streamly-process
to communicate with some REPL in background. It could be Python or anything but here I try to run GHCi. I came up with the following code :When I use
fromList
, it works as expected and returns :However, when I'm using
getNewLn
this is what I get :What did I get wrong ?