Skip to content

Commit 312d33f

Browse files
committed
Allow JLine to fall back to a dumb terminal
Set the `dumb` JLine option to `null` instead of `false` when it is not forced. This allows JLine to fall back to a dumb terminal. Also adapt `CoursierScalaTests` accordingly: test that the `scala` command executes commands fed through standard input correctly.
1 parent b981231 commit 312d33f

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

Diff for: compiler/src/dotty/tools/repl/JLineTerminal.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@ class JLineTerminal extends java.io.Closeable {
2121
// Logger.getLogger("org.jline").setLevel(Level.FINEST)
2222

2323
private val terminal =
24-
TerminalBuilder.builder()
25-
.dumb(dumbTerminal) // fail early if not able to create a terminal
26-
.build()
24+
var builder = TerminalBuilder.builder()
25+
if System.getenv("TERM") == "dumb" then
26+
// Force dumb terminal if `TERM` is `"dumb"`.
27+
// Note: the default value for the `dumb` option is `null`, which allows
28+
// JLine to fall back to a dumb terminal. This is different than `true` or
29+
// `false` and can't be set using the `dumb` setter.
30+
// This option is used at https://github.com/jline/jline3/blob/894b5e72cde28a551079402add4caea7f5527806/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java#L528.
31+
builder.dumb(true)
32+
builder.build()
2733
private val history = new DefaultHistory
28-
def dumbTerminal = Option(System.getenv("TERM")) == Some("dumb")
2934

3035
private def blue(str: String)(using Context) =
3136
if (ctx.settings.color.value != "never") Console.BLUE + str + Console.RESET

Diff for: compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala

+17-11
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ class CoursierScalaTests:
7575
version()
7676

7777
def emptyArgsEqualsRepl() =
78-
val output = CoursierScalaTests.csScalaCmd()
79-
assertTrue(output.mkString("\n").contains("Unable to create a terminal")) // Scala attempted to create REPL so we can assume it is working
78+
val output = CoursierScalaTests.csScalaCmdWithStdin(Seq.empty, Some("println(\"Hello World\")\n:quit"))
79+
assertTrue(output.mkString("\n").contains("Hello World"))
8080
emptyArgsEqualsRepl()
8181

8282
def run() =
@@ -132,8 +132,8 @@ class CoursierScalaTests:
132132
compileFilesToJarAndRun()
133133

134134
def replWithArgs() =
135-
val output = CoursierScalaTests.csScalaCmd("-source", "3.0-migration")
136-
assertTrue(output.mkString("\n").contains("Unable to create a terminal")) // Scala attempted to create REPL so we can assume it is working
135+
val output = CoursierScalaTests.csScalaCmdWithStdin(Seq("-source", "3.0-migration"), Some("println(\"Hello World\")\n:quit"))
136+
assertTrue(output.mkString("\n").contains("Hello World"))
137137
replWithArgs()
138138

139139
def argumentFile() =
@@ -148,25 +148,31 @@ class CoursierScalaTests:
148148

149149
object CoursierScalaTests:
150150

151-
def execCmd(command: String, options: String*): (Int, List[String]) =
151+
private def execCmd(command: String, options: Seq[String] = Seq.empty, stdin: Option[String] = None): (Int, List[String]) =
152152
val cmd = (command :: options.toList).toSeq.mkString(" ")
153153
val out = new ListBuffer[String]
154-
val code = cmd.!(ProcessLogger(out += _, out += _))
154+
val process = stdin match
155+
case Some(input) => Process(cmd) #< new java.io.ByteArrayInputStream(input.getBytes)
156+
case None => Process(cmd)
157+
val code = process.!(ProcessLogger(out += _, out += _))
155158
(code, out.toList)
156159

157160
def csScalaCmd(options: String*): List[String] =
158-
csCmd("dotty.tools.MainGenericRunner", options*)
161+
csScalaCmdWithStdin(options, None)
162+
163+
def csScalaCmdWithStdin(options: Seq[String], stdin: Option[String]): List[String] =
164+
csCmd("dotty.tools.MainGenericRunner", options, stdin)
159165

160166
def csScalaCompilerCmd(options: String*): List[String] =
161-
csCmd("dotty.tools.dotc.Main", options*)
167+
csCmd("dotty.tools.dotc.Main", options)
162168

163-
private def csCmd(entry: String, options: String*): List[String] =
169+
private def csCmd(entry: String, options: Seq[String], stdin: Option[String] = None): List[String] =
164170
val (jOpts, args) = options.partition(_.startsWith("-J"))
165171
val newOptions = args match
166172
case Nil => args
167173
case _ => "--" +: args
168174
val newJOpts = jOpts.map(s => s"--java-opt ${s.stripPrefix("-J")}").mkString(" ")
169-
execCmd("./cs", (s"""launch "org.scala-lang:scala3-compiler_3:${sys.env("DOTTY_BOOTSTRAPPED_VERSION")}" $newJOpts --main-class "$entry" --property "scala.usejavacp=true" --property "scala.use_legacy_launcher=true"""" +: newOptions)*)._2
175+
execCmd("./cs", (s"""launch "org.scala-lang:scala3-compiler_3:${sys.env("DOTTY_BOOTSTRAPPED_VERSION")}" $newJOpts --main-class "$entry" --property "scala.usejavacp=true" --property "scala.use_legacy_launcher=true"""" +: newOptions), stdin)._2
170176

171177
/** Get coursier script */
172178
@BeforeClass def setup(): Unit =
@@ -177,7 +183,7 @@ object CoursierScalaTests:
177183
case other => fail(s"Unsupported OS for coursier launcher: $other")
178184

179185
def runAndCheckCmd(cmd: String, options: String*): Unit =
180-
val (code, out) = execCmd(cmd, options*)
186+
val (code, out) = execCmd(cmd, options)
181187
if code != 0 then
182188
fail(s"Failed to run $cmd ${options.mkString(" ")}, exit code: $code, output: ${out.mkString("\n")}")
183189

0 commit comments

Comments
 (0)