summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLex Spoon <lex@lexspoon.org>2007-07-17 11:31:53 +0000
committerLex Spoon <lex@lexspoon.org>2007-07-17 11:31:53 +0000
commit51ff43f81193caed211017c3b92644b7a33667f5 (patch)
tree6a29ab0efb606756b526a0010678d6237d56d536 /src
parenta840917b32e1c0f25b846f48bd0f12088fe170b2 (diff)
downloadscala-51ff43f81193caed211017c3b92644b7a33667f5.tar.gz
scala-51ff43f81193caed211017c3b92644b7a33667f5.tar.bz2
scala-51ff43f81193caed211017c3b92644b7a33667f5.zip
Support jline in the interactive shell.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Interpreter.scala3
-rw-r--r--src/compiler/scala/tools/nsc/InterpreterLoop.scala84
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala32
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/JLineReader.scala27
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala26
6 files changed, 138 insertions, 35 deletions
diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala
index 6e1507e9fd..0e3dcca570 100644
--- a/src/compiler/scala/tools/nsc/Interpreter.scala
+++ b/src/compiler/scala/tools/nsc/Interpreter.scala
@@ -53,6 +53,9 @@ import nsc.{InterpreterResults=>IR}
* The main weakness is that redefining classes and methods is not handled
* properly, because rebinding at the Java level is technically difficult.
* </p>
+ *
+ * @author Moez A. Abdel-Gawad
+ * @author Lex Spoon
*/
class Interpreter(val settings: Settings, out: PrintWriter) {
import symtab.Names
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
index 1a9afe6fa7..67cfbf1dd0 100644
--- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala
+++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala
@@ -12,6 +12,7 @@ import java.io.IOException
import scala.tools.nsc.util.{ClassPath, Position}
import nsc.{InterpreterResults=>IR}
+import nsc.interpreter._
/** The
* <a href="http://scala-lang.org/" target="_top">Scala</a>
@@ -19,20 +20,22 @@ import nsc.{InterpreterResults=>IR}
* the Interpreter class.
* After instantiation, clients should call the <code>main()</code> method.
*
+ * <p>If no in0 is specified, then input will come from the console, and
+ * the class will attempt to provide input editing feature such as
+ * input history.
+ *
+ * @author Moez A. Abdel-Gawad
* @author Lex Spoon
- * @version 1.1
+ * @version 1.2
*/
-class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
- def this() = this(new BufferedReader(new InputStreamReader(System.in)),
- new PrintWriter(System.out))
+class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) {
+ def this(in0: BufferedReader, out: PrintWriter) =
+ this(Some(in0), out)
- /** The input stream from which interpreter commands come */
- var in = in0
+ def this() = this(None, new PrintWriter(Console.out))
- /** Whether the interpreter is interactive (like normal), or instead
- * is reading from a file.
- */
- var interactive = true
+ /** The input stream from which interpreter commands come */
+ var in: InteractiveReader = _ //set by main()
/** The context class loader at the time this object was created */
protected val originalClassLoader =
@@ -103,7 +106,7 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
/** Print a welcome message */
def printWelcome() {
- out.println("Welcome to Scala version " + Properties.versionString + ".")
+ out.println("Welcome to Scala " + Properties.versionString + ".")
out.println("Type in expressions to have them evaluated.")
out.println("Type :help for more information.")
out.flush()
@@ -119,22 +122,26 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
def repl() {
var first = true
while (true) {
- if (interactive) {
- out.print(prompt)
- out.flush
- }
- if (first) {
- /* For some reason, the first interpreted command always takes
- * a second or two. So, wait until the welcome message
- * has been printed before calling bindSettings. That way,
- * the user can read the welcome message while this
- * command executes.
- */
- bindSettings()
- first = false
+ out.flush()
+
+ val line =
+ if (first) {
+ /* For some reason, the first interpreted command always takes
+ * a second or two. So, wait until the welcome message
+ * has been printed before calling bindSettings. That way,
+ * the user can read the welcome message while this
+ * command executes.
+ */
+ val futLine = scala.concurrent.ops.future(in.readLine(prompt))
+
+ bindSettings()
+ first = false
+
+ futLine()
+ } else {
+ in.readLine(prompt)
}
- var line = in.readLine()
if (line eq null)
return () // assumes null means EOF
@@ -160,16 +167,14 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
return
}
val oldIn = in
- val oldInteractive = interactive
try {
- in = new BufferedReader(fileIn)
- interactive = false
+ val inFile = new BufferedReader(fileIn)
+ in = new SimpleReader(inFile, out, false)
out.println("Loading " + filename + "...")
out.flush
repl
} finally {
in = oldIn
- interactive = oldInteractive
fileIn.close
}
}
@@ -242,15 +247,11 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
case IR.Success => Some(code)
case IR.Error => None
case IR.Incomplete =>
- if (interactive && code.endsWith("\n\n")) {
+ if (in.interactive && code.endsWith("\n\n")) {
out.println("You typed two blank lines. Starting a new command.")
None
} else {
- if (interactive) {
- out.print(" | ")
- out.flush
- }
- val nextLine = in.readLine
+ val nextLine = in.readLine(" | ")
if (nextLine == null)
None // end of file
else
@@ -260,9 +261,22 @@ class InterpreterLoop(in0: BufferedReader, out: PrintWriter) {
}
+
def main(settings: Settings) {
this.settings = settings
+ in =
+ in0 match {
+ case Some(in0) => new SimpleReader(in0, out, true)
+
+ case None =>
+ if (settings.Xnojline.value)
+ new SimpleReader()
+ else
+ InteractiveReader.createDefault()
+ }
+
+
uglinessxxx =
new java.net.URLClassLoader(
ClassPath.expandPath(settings.classpath.value).
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 31d3d741b3..4f0215ac7d 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -97,6 +97,7 @@ class Settings(error: String => Unit) {
val debug = BooleanSetting ("-Xdebug", "Output debugging messages").hideToIDE
val noassertions = BooleanSetting ("-Xdisable-assertions", "Generate no assertions and assumptions")
val Xexperimental = BooleanSetting ("-Xexperimental", "Enable experimental extensions")
+ val Xnojline = new BooleanSetting("-Xnojline", "Do not use JLine for editing").hideToIDE
val nouescape = BooleanSetting ("-Xno-uescape", "Disables handling of \\u unicode escapes")
val Xplugtypes = BooleanSetting ("-Xplug-types", "Process annotations on types")
val plugin = MultiStringSetting("-Xplugin", "file", "Load a plugin from a file")
diff --git a/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
new file mode 100644
index 0000000000..eb3c475d26
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala
@@ -0,0 +1,32 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2007 LAMP/EPFL
+ * @author Stepan Koltsov
+ */
+// $Id$
+
+package scala.tools.nsc.interpreter
+
+/** Reads lines from an input stream */
+trait InteractiveReader {
+ def readLine(prompt: String): String
+ val interactive: Boolean
+}
+
+
+
+object InteractiveReader {
+ /** Create an interactive reader. Uses JLine if the
+ * library is available, but otherwise uses a
+ * SimpleReader. */
+ def createDefault(): InteractiveReader = {
+ try {
+ new JlineReader
+ } catch {
+ case e =>
+ //out.println("jline is not available: " + e) //debug
+ new SimpleReader()
+ }
+ }
+
+
+}
diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
new file mode 100644
index 0000000000..cce34476e0
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala
@@ -0,0 +1,27 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2007 LAMP/EPFL
+ * @author Stepan Koltsov
+ */
+// $Id$
+
+
+package scala.tools.nsc.interpreter
+import java.io.File
+
+/** Reads from the console using JLine */
+class JlineReader extends InteractiveReader {
+ val consoleReader = {
+ val history = try {
+ new jline.History(new File(System.getProperty("user.home"), ".scala_history"))
+ } catch {
+ // do not store history if error
+ case _ => new jline.History()
+ }
+ val r = new jline.ConsoleReader()
+ r.setHistory(history)
+ r
+ }
+ def readLine(prompt: String) = consoleReader.readLine(prompt)
+ val interactive = true
+}
+
diff --git a/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
new file mode 100644
index 0000000000..1961ba761c
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala
@@ -0,0 +1,26 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2007 LAMP/EPFL
+ * @author Stepan Koltsov
+ */
+// $Id$
+
+package scala.tools.nsc.interpreter
+import java.io.{BufferedReader, PrintWriter}
+
+
+/** Reads using standard JDK API */
+class SimpleReader(
+ in: BufferedReader,
+ out: PrintWriter,
+ val interactive: Boolean)
+extends InteractiveReader {
+ def this() = this(Console.in, new PrintWriter(Console.out), true)
+
+ def readLine(prompt: String) = {
+ if (interactive) {
+ out.print(prompt)
+ out.flush()
+ }
+ in.readLine()
+ }
+}