如何在scala中编写带有readline支持的交互式shell?

时间:2011-10-27 08:45:30

标签: shell scala interactive readline

我想在scala中编写交互式shell,支持readline(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 个答案:

答案 0 :(得分:7)

您可以编写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,也许关闭挂钩可能是一种解决方案。