2011-10-27 7 views
5

Voglio scrivere shell interattiva in scala, con supporto per readline (Ctrl-l, tasti freccia, modifica linea, cronologia, ecc.).Come scrivere shell interattiva con supporto readline in scala?

so come farlo in 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 

Voglio scrivere un semplice programma di scala, con esattamente lo stesso comportamento. La mia soluzione più vicino fino ad ora è la seguente 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) 
    } 
    } 
} 

Le questioni aperte sono:

  • come gestire ctrl-c?
  • è possibile utilizzare le eccezioni in modo simile a Python?
  • è questa soluzione ottimale o può essere migliorata?

risposta

7

Si potrebbe scrivere una gerarchia di jline eventi, ad esempio:

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

Quindi è possibile incapsulare il ciclo while in una funzione che prende come parametro di una funzione di 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)) 
    } 
    } 

Infine puoi chiamarlo con la funzione appropriata:

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

Per la cattura di ctrl+C i ganci di arresto possono essere una soluzione.