Skip to content

Commit

Permalink
Handle SIGINT When Reading User Input (#1082)
Browse files Browse the repository at this point in the history
* Handle sigint when reading input

* next work

* signaller fix
  • Loading branch information
mgyucht authored May 14, 2020
1 parent 30a5cb8 commit 92cda8a
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 36 deletions.
4 changes: 3 additions & 1 deletion amm/repl/src/main/scala/ammonite/repl/AmmoniteFrontEnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ case class AmmoniteFrontEnd(extraFilters: Filter = Filter.empty) extends FrontEn

val autocompleteFilter: Filter = Filter.action(SpecialKeys.Tab){
case TermState(rest, b, c, _) =>
val (newCursor, completions, details) = compilerComplete(c, b.mkString)
val (newCursor, completions, details) = TTY.withSttyOverride(TTY.restoreSigInt()) {
compilerComplete(c, b.mkString)
}
val details2 = for (d <- details) yield {

Highlighter.defaultHighlight(
Expand Down
16 changes: 8 additions & 8 deletions amm/repl/src/main/scala/ammonite/repl/Repl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ class Repl(input: InputStream,
case ex => Res.Exception(ex, "")
}

_ <- Signaller("INT") {
// Put a fake `ThreadDeath` error in `lastException`, because `Thread#stop`
// raises an error with the stack trace of *this interrupt thread*, rather
// than the stack trace of *the mainThread*
lastException = new ThreadDeath()
lastException.setStackTrace(Repl.truncateStackTrace(interp.mainThread.getStackTrace))
interp.mainThread.stop()
}
(code, stmts) <- frontEnd().action(
input,
reader,
Expand All @@ -186,14 +194,6 @@ class Repl(input: InputStream,
history = history :+ code
}
)
_ <- Signaller("INT") {
// Put a fake `ThreadDeath` error in `lastException`, because `Thread#stop`
// raises an error with the stack trace of *this interrupt thread*, rather
// than the stack trace of *the mainThread*
lastException = new ThreadDeath()
lastException.setStackTrace(Repl.truncateStackTrace(interp.mainThread.getStackTrace))
interp.mainThread.stop()
}
out <- interp.processLine(code, stmts, currentLine, false, () => currentLine += 1)
} yield {
printer.outStream.println()
Expand Down
5 changes: 3 additions & 2 deletions amm/repl/src/main/scala/ammonite/repl/Signaller.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ case class Signaller(sigStr: String)(f: => Unit) extends Scoped{
finally{
val head::tail = handlers(sig)
handlers(sig) = tail
sun.misc.Signal.handle(sig, head)
val handlerToRegister = tail.headOption.getOrElse(sun.misc.SignalHandler.SIG_DFL)
sun.misc.Signal.handle(sig, handlerToRegister)
}
}
}
Expand All @@ -41,6 +42,6 @@ case class Signaller(sigStr: String)(f: => Unit) extends Scoped{
trait Scoped{
def apply[T](t: => T): T
def foreach[T](t: Unit => T): T = apply(t(()))
def flatMap[T, M[_]](t: Unit => M[T]): M[T] = apply(t(()))
def flatMap[T](t: Unit => T): T = apply(t(()))
def map[T](t: Unit => T): T = apply(t(()))
}
13 changes: 1 addition & 12 deletions terminal/src/main/scala/ammonite/terminal/Terminal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,9 @@ object Terminal {
filters: Filter,
displayTransform: (Vector[Char], Int) => (fansi.Str, Int) = LineReader.noTransform)
: Option[String] = {


val initialConfig = TTY.init()
try {
TTY.withSttyOverride(TTY.readLineStty()) {
new LineReader(ConsoleDim.width(), prompt, reader, writer, filters, displayTransform)
.readChar(TermState(LazyList.continually(reader.read()), Vector.empty, 0, ""), 0)
}finally{

// Don't close these! Closing these closes stdin/stdout,
// which seems to kill the entire program

// reader.close()
// writer.close()
TTY.stty(initialConfig)
}
}
}
32 changes: 19 additions & 13 deletions terminal/src/main/scala/ammonite/terminal/Utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,6 @@ object TTY{
import sys.process._
Seq("sh", "-c", s"$pathedTput $s 2> /dev/tty").!!.trim.toInt
}
def init() = {
stty("-a")

val initialConfig = stty("-g").trim
stty("-icanon min 1 -icrnl -inlcr -ixon")
sttyFailTolerant("dsusp undef")
stty("-echo")
stty("intr undef")

initialConfig
}

private def sttyCmd(s: String) = {
import sys.process._
Expand All @@ -121,8 +110,25 @@ object TTY{
def sttyFailTolerant(s: String) =
sttyCmd(s ++ " 2> /dev/null").!

def restore(initialConfig: String) = {
stty(initialConfig)
def withSttyOverride[A](setupStty: => Unit)(f: => A) = {
val initialConfig = stty("-g").trim
try {
setupStty
f
} finally {
stty(initialConfig)
}
}

def readLineStty(): Unit = {
stty("-icanon min 1 -icrnl -inlcr -ixon")
sttyFailTolerant("dsusp undef")
stty("-echo")
stty("intr undef")
}

def restoreSigInt(): Unit = {
stty("intr ^C")
}
}

Expand Down

0 comments on commit 92cda8a

Please sign in to comment.