summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml16
-rw-r--r--debian/simpbuild.xml12
-rw-r--r--lib/jline.jar.desired.sha11
-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
9 files changed, 167 insertions, 35 deletions
diff --git a/build.xml b/build.xml
index f7d4d4d086..99b8b6b18c 100644
--- a/build.xml
+++ b/build.xml
@@ -41,7 +41,9 @@ PROPERTIES
<property name="fjbg.jar" value="${lib.dir}/fjbg.jar"/>
<property name="msil.jar" value="${lib.dir}/msil.jar"/>
<property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
+ <property name="jline.jar" value="${lib.dir}/jline.jar"/>
<property name="ant-contrib.jar" value="${lib.dir}/ant-contrib.jar"/>
+
<!-- Sets location of build folders -->
<property name="build.dir" value="${basedir}/build"/>
<property name="locker.dir" value="${build.dir}/locker"/>
@@ -181,6 +183,7 @@ SETUP
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
+ <pathelement location="${jline.jar}"/>
</path>
<!-- Creating boot-level tasks -->
<taskdef
@@ -298,6 +301,15 @@ BUILD SUPPORT MACROS
resource="${msil.jar}" overwrite="yes" failonerror="no"/>
</else></if>
</then></if>
+ <if><not><available file="@{build.dir}/lib/jline.jar"/></not><then>
+ <if><isset property="os.win"/><then>
+ <copy file="${jline.jar}" tofile="@{build.dir}/lib/jline.jar"/>
+ </then><else>
+ <symlink
+ link="@{build.dir}/lib/jline.jar"
+ resource="${jline.jar}" overwrite="yes" failonerror="no"/>
+ </else></if>
+ </then></if>
</sequential>
</macrodef>
@@ -372,6 +384,7 @@ BUILD LOCAL REFERENCE (LOCKER) LAYER
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
+ <pathelement location="${jline.jar}"/>
</classpath>
<include name="**/*.scala"/>
<excludesfile name="${nsc.excludes.file}" if="excludes.avail"/>
@@ -539,6 +552,7 @@ BUILD QUICK-TEST LAYER
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
+ <pathelement location="${jline.jar}"/>
</classpath>
<include name="**/*.scala"/>
<excludesfile name="${nsc.excludes.file}" if="excludes.avail"/>
@@ -922,6 +936,7 @@ TEST
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
+ <pathelement location="${jline.jar}"/>
</classpath>
<include name="**/*.scala"/>
<excludesfile name="${nsc.excludes.file}" if="excludes.avail"/>
@@ -1059,6 +1074,7 @@ DOCUMENTATION
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
+ <pathelement location="${jline.jar}"/>
</classpath>
<include name="**/*.scala"/>
<excludesfile name="${nsc.excludes.file}" if="excludes.avail"/>
diff --git a/debian/simpbuild.xml b/debian/simpbuild.xml
index 8272c124e7..f3707abdf5 100644
--- a/debian/simpbuild.xml
+++ b/debian/simpbuild.xml
@@ -43,6 +43,7 @@
<property name="fjbg.jar" value="${lib.dir}/fjbg.jar"/>
<property name="msil.jar" value="${lib.dir}/msil.jar"/>
+ <property name="jline.jar" value="${lib.dir}/jline.jar"/>
<property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
@@ -128,12 +129,23 @@
</not></condition>
</fail>
+ <echo level="verbose" message="jline.jar=${jline.jar}"/>
+ <fail message="JLine library in 'lib/' is not available">
+ <condition><not>
+ <available
+ classname="jline.ConsoleReader"
+ classpath="${jline.jar}"
+ />
+ </not></condition>
+ </fail>
+
<path id="starr.classpath">
<pathelement location="${fjbg.jar}"/>
<pathelement location="${msil.jar}"/>
<pathelement location="${ant.jar}"/>
<pathelement location="${starr.lib.jar}"/>
<pathelement location="${starr.comp.jar}"/>
+ <pathelement location="${jline.jar}"/>
</path>
<property name="os.type" value="UNIX"/>
diff --git a/lib/jline.jar.desired.sha1 b/lib/jline.jar.desired.sha1
new file mode 100644
index 0000000000..4d3bff1e56
--- /dev/null
+++ b/lib/jline.jar.desired.sha1
@@ -0,0 +1 @@
+22f7477ecc5788bce62698f0a1219d486f7c0e0b ?jline.jar
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()
+ }
+}