2011-10-27 10 views
5

Quiero escribir shell interactivo en scala, con soporte para readline (Ctrl-l, teclas de flecha, edición de línea, historial, etc.).Cómo escribir shell interactivo con soporte de lectura en Scala?

sé cómo hacerlo en Python:

# enable support for Ctrl-l, arrow keys, line editing, history, etc. 
import readline 

finished = False 
while not finished: 
    try: 
    line = raw_input('> ') 
    if line: 
     if line == 'q': 
     finished = True 
     else: 
     print line 
    except KeyboardInterrupt: 
    print 'Ctrl-c'; finished = True 
    except EOFError: 
    print 'Ctrl-d'; finished = True 

Quiero escribir un programa Scala sencillo, con exactamente el mismo comportamiento. Mi solución más cercano hasta ahora es la siguiente Scala:

// used to support Ctrl-l, arrow keys, line editing, history, etc. 
import scala.tools.jline 

val consoleReader = new jline.console.ConsoleReader() 
var finished = false 
while (!finished) { 
    val line = consoleReader.readLine("> ") 
    if (line == null) { 
    println("Ctrl-d") 
    finished = true 
    } else if (line.size > 0) { 
    if (line == "q") { 
     finished = true 
    } else { 
     println(line) 
    } 
    } 
} 

Las preguntas abiertas son:

  • cómo manejar ctrl-c?
  • ¿es posible usar excepciones de forma similar a python?
  • es esta solución óptima o se puede mejorar?

Respuesta

7

Se podría escribir una jerarquía de jline eventos, por ejemplo:

sealed trait JLineEvent 
case class Line(value: String) extends JLineEvent 
case object EmptyLine extends JLineEvent 
case object EOF extends JLineEvent 

A continuación, se puede encapsular el bucle while en una función que toma como parámetro una función de JLineEvent:

def console(handler: JLineEvent => Boolean) { 
    val consoleReader = new jline.console.ConsoleReader() 
    var finished = false 
    while (!finished) { 
    val line = consoleReader.readLine("> ") 
    if (line == null) { 
     finished = handler(EOF) 
    } else if (line.size == 0) { 
     finished = handler(EmptyLine) 
    } else if (line.size > 0) { 
     finished = handler(Line(line)) 
    } 
    } 

Finalmente puede llamarlo con la función apropiada:

console { 
    case EOF => 
      println("Ctrl-d") 
      true 
    case Line(s) if s == "q" => 
      true 
    case Line(s) => 
      println(line) 
      false 
    case _ => 
      false 
} 

Para capturar ctrl+C quizás los ganchos de cierre pueden ser una solución.

Cuestiones relacionadas