From 5badefea73271042658daf0ee923f82fc32b1382 Mon Sep 17 00:00:00 2001
From: Li Haoyi <haoyi.sg@gmail.com>
Date: Tue, 10 Sep 2024 12:52:14 +0800
Subject: [PATCH] Fix `ScalaModule#console` by properly inheriting streams
 (#3500)

`SystemStreamswithStreams(SystemStreams.original)` didn't quite do the
right thing because it continued to use the `PumpedProcess*put`s for
subprocesses rather than directly inheriting the streams. This fixes it.

Tested manually via `./mill dist.launcher && (cd
example/scalalib/basic/1-simple &&
../../../../out/dist/launcher.dest/run -i console)`, which previously
would print `Unable to create system terminal` and not allow keyboard
navigation in the REPL, and with this PR it no longer warns and keyboard
navigation works correctly

Fixes https://github.com/com-lihaoyi/mill/issues/3491
---
 main/api/src/mill/api/SystemStreams.scala | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/main/api/src/mill/api/SystemStreams.scala b/main/api/src/mill/api/SystemStreams.scala
index 55ed8598ca9..5b687d18191 100644
--- a/main/api/src/mill/api/SystemStreams.scala
+++ b/main/api/src/mill/api/SystemStreams.scala
@@ -66,15 +66,32 @@ object SystemStreams {
     val out = System.out
     val err = System.err
     try {
+      // If we are setting a stream back to its original value, make sure we reset
+      // `os.Inherit` to `os.InheritRaw` for that stream. This direct inheritance
+      // ensures that interactive applications involving console IO work, as the
+      // presence of a `PumpedProcess` would cause most interactive CLIs (e.g.
+      // scala console, REPL, etc.) to misbehave
+      val inheritIn =
+        if (systemStreams.in eq original.in) os.InheritRaw
+        else new PumpedProcessInput
+
+      val inheritOut =
+        if (systemStreams.out eq original.out) os.InheritRaw
+        else new PumpedProcessOutput(systemStreams.out)
+
+      val inheritErr =
+        if (systemStreams.err eq original.err) os.InheritRaw
+        else new PumpedProcessOutput(systemStreams.err)
+
       System.setIn(systemStreams.in)
       System.setOut(systemStreams.out)
       System.setErr(systemStreams.err)
       Console.withIn(systemStreams.in) {
         Console.withOut(systemStreams.out) {
           Console.withErr(systemStreams.err) {
-            os.Inherit.in.withValue(new PumpedProcessInput) {
-              os.Inherit.out.withValue(new PumpedProcessOutput(System.out)) {
-                os.Inherit.err.withValue(new PumpedProcessOutput(System.err)) {
+            os.Inherit.in.withValue(inheritIn) {
+              os.Inherit.out.withValue(inheritOut) {
+                os.Inherit.err.withValue(inheritErr) {
                   t
                 }
               }