Restore terminal when exiting Terminal.withStreams

There was a reddit comment that the user's tty was messed up after they
exited sbt:
https://www.reddit.com/r/scala/comments/io3z2p/sbt_140rc1_released/.
This attempts to fix that issue by restoring the terminal before
exiting. In order to ensure the tty is restored, it's necessary to move
the work off of a background thread and delay sbt exit. This does take
about 150ms on my machine but I figure that isn't a huge deal in the
scheme of things.
This commit is contained in:
Ethan Atkins 2020-09-10 13:35:53 -07:00
parent 67f6df0bdb
commit b610ce9298
1 changed files with 16 additions and 11 deletions

View File

@ -341,17 +341,21 @@ object Terminal {
* to become non-blocking. After we set it to non-blocking, we spin
* up a thread that reads from the inputstream and the resets it
* back to blocking mode. We can then close the console. We do
* this on a background thread to avoid blocking sbt's exit.
* this on a background thread in case the read blocks indefinitely.
*/
val prev = c.system.enterRawMode()
val runnable: Runnable = () => {
c.inputStream.read()
c.system.setAttributes(prev)
c.close()
try Util.ignoreResult(c.inputStream.read)
catch { case _: InterruptedException => }
}
val thread = new Thread(runnable, "sbt-console-background-close")
thread.setDaemon(true)
thread.start()
// The thread should exit almost instantly but give it 200ms to spin up
thread.join(200)
if (thread.isAlive) thread.interrupt()
c.system.setAttributes(prev)
c.close()
case c => c.close()
}
} else {
@ -723,11 +727,10 @@ object Terminal {
case _: InterruptedException | _: java.io.IOError =>
}
override def restore(): Unit =
if (alive)
try terminal.restore()
catch {
case _: InterruptedException | _: java.io.IOError =>
}
try terminal.restore()
catch {
case _: InterruptedException | _: java.io.IOError =>
}
override def reset(): Unit =
try terminal.reset()
catch { case _: InterruptedException => }
@ -864,8 +867,10 @@ object Terminal {
case _ => false
})
override def close(): Unit = {
try system.close()
catch { case NonFatal(_) => }
try {
system.close()
term.restore()
} catch { case NonFatal(_) => }
super.close()
}
}