diff options
-rw-r--r-- | build.xml | 16 | ||||
-rw-r--r-- | debian/simpbuild.xml | 12 | ||||
-rw-r--r-- | lib/jline.jar.desired.sha1 | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 84 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Settings.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/InteractiveReader.scala | 32 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/JLineReader.scala | 27 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/SimpleReader.scala | 26 |
9 files changed, 167 insertions, 35 deletions
@@ -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() + } +} |