Как написать интерактивную оболочку с поддержкой readline в scala?

#shell #scala #interactive #readline

#оболочка #scala #интерактивная #строка чтения

Вопрос:

Я хочу написать интерактивную оболочку в scala с поддержкой строки чтения (Ctrl-l, клавиши со стрелками, редактирование строк, история и т. Д.).

Я знаю, как это сделать на 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
 

Я хочу написать простую программу scala с точно таким же поведением. Моим ближайшим решением до сих пор является следующий 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)
    }
  }
}
 

Открытые вопросы:

  • как обрабатывать ctrl-c?
  • можно ли использовать исключения аналогично python?
  • является ли это оптимальным решением или его можно улучшить?

Ответ №1:

Вы могли бы написать иерархию jline событий, например:

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

Затем вы можете инкапсулировать while цикл в функцию, которая принимает в качестве параметра функцию 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 ) )
    }
  }
 

Наконец, вы можете вызвать его с помощью соответствующей функции:

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

Для перехвата ctrl C , возможно, могут быть перехваты выключения.