OXMO456 OXMO456 - 3 months ago 21
Scala Question

how to cancel ConsoleReader.readLine()

first of all, i'm learning scala and new to the java world.
I want to create a console and run this console as a service that you could start and stop.
I was able to run a ConsoleReader into an Actor but i don't know how to stop properly the ConsoleReader.
Here is the code :

import eu.badmood.util.trace
import scala.actors.Actor._

import tools.jline.console.ConsoleReader

object Main {

def main(args:Array[String]){
//start the console
Console.start(message => {
//handle console inputs
message match {
case "exit" => Console.stop()
case _ => trace(message)

//try to stop the console after a time delay



object Console {

private val consoleReader = new ConsoleReader()

private var running = false

def start(handler:(String)=>Unit){
running = true
while (running){
handler(consoleReader.readLine("\33[32m> \33[0m"))

def stop(){
//how to cancel an active call to ConsoleReader.readLine ?
running = false


I'm also looking for any advice concerning this code !


The underlying call to read a characters from the input is blocking. On non-Windows platform, it will use System.in.read() and on Windows it will use org.fusesource.jansi.internal.WindowsSupport.readByte.

So your challenge is to cause that blocking call to return when you want to stop your console service. See http://www.javaspecialists.eu/archive/Issue153.html and Is it possible to read from a Java InputStream with a timeout? for some ideas... Once you figure that out, have read return -1 when your console service stops, so that ConsoleReader thinks it's done. You'll need ConsoleReader to use your version of that call:

  • If you are on Windows, you'll probably need to override tools.jline.AnsiWindowsTerminal and use the ConsoleReader constructor that takes a Terminal (otherwise AnsiWindowsTerminal will just use WindowsSupport.readByte` directly)
  • On unix, there is one ConsoleReader constructor that takes an InputStream, you could provide your own wrapper around System.in

A few more thoughts:

  • There is a scala.Console object already, so for less confusion name yours differently.
  • System.in is a unique resource, so you probably need to ensure that only one caller uses Console.readLine at a time. Right now start will directly call readLine and multiple callers can call start. Probably the console service can readLine and maintain a list of handlers.