diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index aa022d3bb..ef1a345b2 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -121,6 +121,10 @@ object LineReader { // ignore } historyPath.foreach(f => reader.setVariable(JLineReader.HISTORY_FILE, f)) + val signalRegistration = terminal match { + case _: Terminal.ConsoleTerminal => Some(Signals.register(() => terminal.write(-1))) + case _ => None + } try terminal.withRawInput { Option(mask.map(reader.readLine(prompt, _)).getOrElse(reader.readLine(prompt))) } catch { @@ -132,6 +136,7 @@ object LineReader { _: UncheckedIOException => throw new InterruptedException } finally { + signalRegistration.foreach(_.remove()) terminal.prompt.reset() term.close() } diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala index 64d84c1da..a4811a2cc 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala @@ -172,7 +172,7 @@ private[sbt] object JLine3 { if (buffer.isEmpty && !peek) fillBuffer() (if (peek) buffer.peek else buffer.take) match { case null => -2 - case i => if (i == -3) throw new ClosedException else i + case i => if (i == -3) throw new InterruptedException else i } } override def peek(timeout: Long): Int = buffer.peek() match { diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 99e37e963..f2e7a2e9e 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -1003,10 +1003,12 @@ object BuiltinCommands { val s1 = exchange.run(s0) val exec: Exec = getExec(s1, Duration.Inf) - val remaining: List[Exec] = - Exec(FailureWall, None) :: Exec(s"${ContinuousCommands.waitWatch} $channel", None) :: - s1.remainingCommands - val newState = s1.copy(remainingCommands = exec +: remaining) + val wait = s"${ContinuousCommands.waitWatch} $channel" + val onFailure = + s1.onFailure.map(of => if (of.commandLine == Shell) of.withCommandLine(wait) else of) + val waitExec = Exec(wait, None) + val remaining: List[Exec] = Exec(FailureWall, None) :: waitExec :: s1.remainingCommands + val newState = s1.copy(remainingCommands = exec +: remaining, onFailure = onFailure) if (exec.commandLine.trim.isEmpty) newState else newState.clearGlobalLog case _ => s0 diff --git a/main/src/main/scala/sbt/internal/Continuous.scala b/main/src/main/scala/sbt/internal/Continuous.scala index c5ba2aec9..92801f32b 100644 --- a/main/src/main/scala/sbt/internal/Continuous.scala +++ b/main/src/main/scala/sbt/internal/Continuous.scala @@ -116,7 +116,7 @@ private[sbt] object Continuous extends DeprecatedContinuous { case None => StandardMain.exchange.run(s) -> ConsoleChannel.defaultName } val ws = ContinuousCommands.setupWatchState(channel, initialCount, commands, s1) - s"${ContinuousCommands.runWatch} $channel" :: ws + s"${ContinuousCommands.runWatch} $channel" :: s"${ContinuousCommands.waitWatch} $channel" :: ws } @deprecated("The input task version of watch is no longer available", "1.4.0") @@ -1279,7 +1279,7 @@ private[sbt] object ContinuousCommands { case None => state case Some(cs) => val pre = StashOnFailure :: s"$preWatch $channel" :: Nil - val post = FailureWall :: PopOnFailure :: s"$postWatch $channel" :: s"$waitWatch $channel" :: Nil + val post = FailureWall :: PopOnFailure :: s"$postWatch $channel" :: Nil pre ::: cs.commands.toList ::: post ::: state } }