diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/InterpreterLoop.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 76f09f07f7..2b926d8e80 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -10,6 +10,7 @@ import java.io.{ BufferedReader, File, FileReader, PrintWriter } import java.io.IOException import scala.tools.nsc.{ InterpreterResults => IR } +import scala.collection.JavaConversions.asBuffer import interpreter._ import io.{ Process } @@ -22,30 +23,34 @@ object InterpreterControl { // a single interpreter command sealed abstract class Command extends Function1[List[String], Result] { - val name: String - val help: String + def name: String + def help: String def error(msg: String) = { println(":" + name + " " + msg + ".") Result(true, None) } - def getHelp(): String = ":" + name + " " + help + "." + def usage(): String } case class NoArgs(name: String, help: String, f: () => Result) extends Command { + def usage(): String = ":" + name def apply(args: List[String]) = if (args.isEmpty) f() else error("accepts no arguments") } case class LineArg(name: String, help: String, f: (String) => Result) extends Command { + def usage(): String = ":" + name + " <line>" def apply(args: List[String]) = f(args mkString " ") } case class OneArg(name: String, help: String, f: (String) => Result) extends Command { + def usage(): String = ":" + name + " <arg>" def apply(args: List[String]) = if (args.size == 1) f(args.head) else error("requires exactly one argument") } case class VarArgs(name: String, help: String, f: (List[String]) => Result) extends Command { + def usage(): String = ":" + name + " [arg]" def apply(args: List[String]) = f(args) } @@ -54,8 +59,6 @@ object InterpreterControl { } import InterpreterControl._ -// import scala.concurrent.ops.defaultRunner - /** The * <a href="http://scala-lang.org/" target="_top">Scala</a> * interactive shell. It provides a read-eval-print loop around @@ -76,6 +79,12 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** The input stream from which commands come, set by main() */ var in: InteractiveReader = _ + def history = in match { + case x: JLineReader => Some(x.history) + case _ => None + } + def historyList: Seq[String] = + history map (x => asBuffer(x.getHistoryList): Seq[String]) getOrElse Nil /** The context class loader at the time this object was created */ protected val originalClassLoader = Thread.currentThread.getContextClassLoader @@ -126,8 +135,11 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { /** print a friendly help message */ def printHelp() = { - out println "All commands can be abbreviated - for example :h or :he instead of :help.\n" - commands foreach { c => out println c.getHelp } + out println "All commands can be abbreviated - for example :he instead of :help.\n" + val cmds = commands map (x => (x.usage, x.help)) + val width: Int = cmds map { case (x, _) => x.length } max + val formatStr = "%-" + width + "s %s" + cmds foreach { case (usage, help) => out println formatStr.format(usage, help) } } /** Print a welcome message */ @@ -143,6 +155,36 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { out.flush } + /** Show the history */ + def printHistory(xs: List[String]) { + val defaultLines = 20 + + if (history.isEmpty) + return println("No history available.") + + val current = history.get.getCurrentIndex + val count = try xs.head.toInt catch { case _: Exception => defaultLines } + val lines = historyList takeRight count + val offset = current - lines.size + 1 + + for ((line, index) <- lines.zipWithIndex) + println("%d %s".format(index + offset, line)) + } + + /** Search the history */ + def searchHistory(_cmdline: String) { + val cmdline = _cmdline.toLowerCase + + if (history.isEmpty) + return println("No history available.") + + val current = history.get.getCurrentIndex + val offset = current - historyList.size + 1 + + for ((line, index) <- historyList.zipWithIndex ; if line.toLowerCase contains cmdline) + println("%d %s".format(index + offset, line)) + } + /** Prompt to print when awaiting input */ val prompt = Properties.shellPromptString @@ -160,13 +202,15 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { val standardCommands: List[Command] = { import CommandImplicits._ List( - NoArgs("help", "prints this help message", printHelp), + NoArgs("help", "print this help message", printHelp), + VarArgs("history", "show the history (optional arg: lines to show)", printHistory), + LineArg("h?", "search the history", searchHistory), OneArg("jar", "add a jar to the classpath", addJar), - OneArg("load", "followed by a filename loads a Scala file", load), + OneArg("load", "load and interpret a Scala file", load), NoArgs("power", "enable power user mode", power), - NoArgs("quit", "exits the interpreter", () => Result(false, None)), - NoArgs("replay", "resets execution and replays all previous commands", replay), - LineArg("sh", "forks a shell and runs a command", runShellCmd), + NoArgs("quit", "exit the interpreter", () => Result(false, None)), + NoArgs("replay", "reset execution and replay all previous commands", replay), + LineArg("sh", "fork a shell and run a command", runShellCmd), NoArgs("silent", "disable/enable automatic printing of results", verbosity) ) } @@ -296,9 +340,10 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { replay() } - def power() = { + def power() { powerUserOn = true interpreter.powerUser() + interpreter.quietBind("history", "scala.collection.immutable.List[String]", historyList.toList) } def verbosity() = { @@ -381,7 +426,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { // the interpeter is passed as an argument to expose tab completion info if (settings.Xnojline.value || emacsShell) new SimpleReader else if (settings.noCompletion.value) InteractiveReader.createDefault() - else InteractiveReader.createDefault(interpreter) + else InteractiveReader.createDefault(interpreter, this) } loadFiles(settings) @@ -399,7 +444,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { // injects one value into the repl; returns pair of name and class def injectOne(name: String, obj: Any): Tuple2[String, String] = { val className = obj.asInstanceOf[AnyRef].getClass.getName - interpreter.bind(name, className, obj) + interpreter.quietBind(name, className, obj) (name, className) } |