diff options
author | Seth Tisue <seth@tisue.net> | 2015-07-01 15:56:17 -0400 |
---|---|---|
committer | Seth Tisue <seth@tisue.net> | 2015-07-01 15:56:17 -0400 |
commit | 495fdb8119c1941bc210a9b0a186d63971002e22 (patch) | |
tree | 2067bf5985fc138577fa7251b0ab7e4a23236a88 /src | |
parent | c8fbc41631da0a860f749479a610312814c0e88f (diff) | |
parent | fac81d705ff0bfdeb3320fd9e46b6d3d34e47ddf (diff) | |
download | scala-495fdb8119c1941bc210a9b0a186d63971002e22.tar.gz scala-495fdb8119c1941bc210a9b0a186d63971002e22.tar.bz2 scala-495fdb8119c1941bc210a9b0a186d63971002e22.zip |
Merge pull request #4576 from som-snytt/issue/9206-more
SI-9206 REPL custom bits
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/Properties.scala | 8 | ||||
-rw-r--r-- | src/library/scala/sys/BooleanProp.scala | 1 | ||||
-rw-r--r-- | src/library/scala/sys/Prop.scala | 4 | ||||
-rw-r--r-- | src/partest-extras/scala/tools/partest/ReplTest.scala | 34 | ||||
-rw-r--r-- | src/repl-jline/scala/tools/nsc/interpreter/jline/FileBackedHistory.scala | 12 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/Formatting.scala | 3 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/ILoop.scala | 27 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/IMain.scala | 4 | ||||
-rw-r--r-- | src/repl/scala/tools/nsc/interpreter/ReplProps.scala | 46 |
9 files changed, 92 insertions, 47 deletions
diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index ca7d8776d4..cb523edfe5 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -12,8 +12,16 @@ object Properties extends scala.util.PropertiesTrait { protected def pickJarBasedOn = classOf[Global] // settings based on jar properties, falling back to System prefixed by "scala." + + // messages to display at startup or prompt, format string with string parameters + // Scala version, Java version, JVM name def residentPromptString = scalaPropOrElse("resident.prompt", "\nnsc> ") def shellPromptString = scalaPropOrElse("shell.prompt", "%nscala> ") + def shellWelcomeString = scalaPropOrElse("shell.welcome", + """Welcome to Scala %1$#s (%3$s, Java %2$s). + |Type in expressions for evaluation. Or try :help.""".stripMargin + ) + // message to display at EOF (which by default ends with // a newline so as not to break the user's terminal) def shellInterruptedString = scalaPropOrElse("shell.interrupted", f":quit$lineSeparator") diff --git a/src/library/scala/sys/BooleanProp.scala b/src/library/scala/sys/BooleanProp.scala index e5e4668edb..b0008b41fd 100644 --- a/src/library/scala/sys/BooleanProp.scala +++ b/src/library/scala/sys/BooleanProp.scala @@ -50,6 +50,7 @@ object BooleanProp { def get: String = "" + value val clear, enable, disable, toggle = () def option = if (isSet) Some(value) else None + //def or[T1 >: Boolean](alt: => T1): T1 = if (value) true else alt protected def zero = false } diff --git a/src/library/scala/sys/Prop.scala b/src/library/scala/sys/Prop.scala index 17ae8cb69c..52a3d89ecb 100644 --- a/src/library/scala/sys/Prop.scala +++ b/src/library/scala/sys/Prop.scala @@ -58,6 +58,10 @@ trait Prop[+T] { */ def option: Option[T] + // Do not open until 2.12. + //** This value if the property is set, an alternative value otherwise. */ + //def or[T1 >: T](alt: => T1): T1 + /** Removes the property from the underlying map. */ def clear(): Unit diff --git a/src/partest-extras/scala/tools/partest/ReplTest.scala b/src/partest-extras/scala/tools/partest/ReplTest.scala index 1fde2370d3..20dfe0eb16 100644 --- a/src/partest-extras/scala/tools/partest/ReplTest.scala +++ b/src/partest-extras/scala/tools/partest/ReplTest.scala @@ -6,8 +6,9 @@ package scala.tools.partest import scala.tools.nsc.Settings -import scala.tools.nsc.interpreter.ILoop +import scala.tools.nsc.interpreter.{ ILoop, replProps } import java.lang.reflect.{ Method => JMethod, Field => JField } +import scala.util.matching.Regex import scala.util.matching.Regex.Match /** A class for testing repl code. @@ -19,30 +20,33 @@ abstract class ReplTest extends DirectTest { // final because we need to enforce the existence of a couple settings. final override def settings: Settings = { val s = super.settings - // s.Yreplsync.value = true s.Xnojline.value = true transformSettings(s) } + def normalize(s: String) = s /** True for SessionTest to preserve session text. */ def inSession: Boolean = false - /** True to preserve welcome text. */ + /** True to preserve welcome header, eliding version number. */ def welcoming: Boolean = false - lazy val welcome = "(Welcome to Scala) version .*".r - def normalize(s: String) = s match { - case welcome(w) => w - case s => s - } - def unwelcoming(s: String) = s match { - case welcome(w) => false - case _ => true - } + lazy val header = replProps.welcome def eval() = { val s = settings log("eval(): settings = " + s) - //ILoop.runForTranscript(code, s).lines drop 1 // not always first line val lines = ILoop.runForTranscript(code, s, inSession = inSession).lines - if (welcoming) lines map normalize - else lines filter unwelcoming + (if (welcoming) { + val welcome = "(Welcome to Scala).*".r + //val welcome = Regex.quote(header.lines.next).r + //val version = "(.*version).*".r // version on separate line? + //var inHead = false + lines map { + //case s @ welcome() => inHead = true ; s + //case version(s) if inHead => inHead = false ; s + case welcome(s) => s + case s => s + } + } else { + lines drop header.lines.size + }) map normalize } def show() = eval() foreach println } diff --git a/src/repl-jline/scala/tools/nsc/interpreter/jline/FileBackedHistory.scala b/src/repl-jline/scala/tools/nsc/interpreter/jline/FileBackedHistory.scala index b6c9792ec0..53a06ca972 100644 --- a/src/repl-jline/scala/tools/nsc/interpreter/jline/FileBackedHistory.scala +++ b/src/repl-jline/scala/tools/nsc/interpreter/jline/FileBackedHistory.scala @@ -7,9 +7,9 @@ package scala.tools.nsc.interpreter.jline import _root_.jline.console.history.PersistentHistory - import scala.tools.nsc.interpreter -import scala.tools.nsc.io.{File, Path} +import scala.reflect.io.{ File, Path } +import scala.tools.nsc.Properties.{ propOrNone, userHome } /** TODO: file locking. */ @@ -85,9 +85,9 @@ object FileBackedHistory { // val ContinuationChar = '\003' // val ContinuationNL: String = Array('\003', '\n').mkString - import scala.tools.nsc.Properties.userHome - - def defaultFileName = ".scala_history" + final val defaultFileName = ".scala_history" - def defaultFile: File = File(Path(userHome) / defaultFileName) + def defaultFile: File = File( + propOrNone("scala.shell.histfile") map (Path.apply) getOrElse (Path(userHome) / defaultFileName) + ) } diff --git a/src/repl/scala/tools/nsc/interpreter/Formatting.scala b/src/repl/scala/tools/nsc/interpreter/Formatting.scala index 844997429c..4a9548730a 100644 --- a/src/repl/scala/tools/nsc/interpreter/Formatting.scala +++ b/src/repl/scala/tools/nsc/interpreter/Formatting.scala @@ -30,3 +30,6 @@ class Formatting(indent: Int) { } ) } +object Formatting { + def forPrompt(prompt: String) = new Formatting(prompt.lines.toList.last.length) +} diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 525609171e..6470a450b2 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -56,13 +56,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private var globalFuture: Future[Boolean] = _ - /** Print a welcome message */ - def printWelcome() { - echo(s""" - |Welcome to Scala $versionString ($javaVmName, Java $javaVersion). - |Type in expressions to have them evaluated. - |Type :help for more information.""".trim.stripMargin - ) + /** Print a welcome message! */ + def printWelcome(): Unit = { + Option(replProps.welcome) filter (!_.isEmpty) foreach echo replinfo("[info] started at " + new java.util.Date) } @@ -111,10 +107,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } class ILoopInterpreter extends IMain(settings, out) { - // the expanded prompt but without color escapes and without leading newline, for purposes of indenting - override lazy val formatting: Formatting = new Formatting( - (replProps.promptString format Properties.versionNumberString).lines.toList.last.length - ) override protected def parentClassLoader = settings.explicitParentLoader.getOrElse( classOf[ILoop].getClassLoader ) } @@ -680,9 +672,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } def verbosity() = { - val old = intp.printResults - intp.printResults = !old - echo("Switched " + (if (old) "off" else "on") + " result printing.") + intp.printResults = !intp.printResults + replinfo(s"Result printing is ${ if (intp.printResults) "on" else "off" }.") } /** Run one command submitted by the user. Two values are returned: @@ -762,7 +753,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private object paste extends Pasted { import scala.util.matching.Regex.quote - val ContinueString = " | " + val ContinuePrompt = replProps.continuePrompt + val ContinueString = replProps.continueText // " | " val PromptString = prompt.lines.toList.last val anyPrompt = s"""\\s*(?:${quote(PromptString.trim)}|${quote(AltPromptString.trim)})\\s*""".r @@ -806,7 +798,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("You typed two blank lines. Starting a new command.") None case IR.Incomplete => - in.readLine(paste.ContinueString) match { + in.readLine(paste.ContinuePrompt) match { case null => // we know compilation is going to fail since we're at EOF and the // parser thinks the input is still incomplete, but since this is @@ -949,8 +941,9 @@ object ILoop { Console.withOut(ostream) { val output = new JPrintWriter(new OutputStreamWriter(ostream), true) { // skip margin prefix for continuation lines, unless preserving session text for test + // should test for repl.paste.ContinueString or replProps.continueText.contains(ch) override def write(str: String) = - if (!inSession && (str forall (ch => ch.isWhitespace || ch == '|'))) () // repl.paste.ContinueString + if (!inSession && (str forall (ch => ch.isWhitespace || ch == '|'))) () else super.write(str) } val input = new BufferedReader(new StringReader(code.trim + "\n")) { diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 2550a5dc57..841b4abfa5 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -113,9 +113,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def this() = this(new Settings()) // the expanded prompt but without color escapes and without leading newline, for purposes of indenting - lazy val formatting: Formatting = new Formatting( - (replProps.promptString format Properties.versionNumberString).lines.toList.last.length - ) + lazy val formatting = Formatting.forPrompt(replProps.promptText) lazy val reporter: ReplReporter = new ReplReporter(this) import formatting.indentCode diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala index df65e9974d..588d92f81b 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala @@ -6,9 +6,11 @@ package scala.tools.nsc package interpreter -import Properties.shellPromptString +import Properties.{ javaVersion, javaVmName, shellPromptString, shellWelcomeString, + versionString, versionNumberString } import scala.sys._ import Prop._ +import java.util.{ Formattable, FormattableFlags, Formatter } class ReplProps { private def bool(name: String) = BooleanProp.keyExists(name) @@ -22,12 +24,44 @@ class ReplProps { val trace = bool("scala.repl.trace") val power = bool("scala.repl.power") - // Handy system prop for shell prompt, or else pick it up from compiler.properties - val promptString = Prop[String]("scala.repl.prompt").option getOrElse (if (info) "%nscala %s> " else shellPromptString) - val prompt = { + def enversion(s: String) = { + import FormattableFlags._ + val v = new Formattable { + override def formatTo(formatter: Formatter, flags: Int, width: Int, precision: Int) = { + val version = if ((flags & ALTERNATE) != 0) versionNumberString else versionString + val left = if ((flags & LEFT_JUSTIFY) != 0) "-" else "" + val w = if (width >= 0) s"$width" else "" + val p = if (precision >= 0) s".$precision" else "" + val fmt = s"%${left}${w}${p}s" + formatter.format(fmt, version) + } + } + s.format(v, javaVersion, javaVmName) + } + def encolor(s: String) = { import scala.io.AnsiColor.{ MAGENTA, RESET } - val p = promptString format Properties.versionNumberString - if (colorOk) s"$MAGENTA$p$RESET" else p + if (colorOk) s"$MAGENTA$s$RESET" else s + } + + // Handy system prop for shell prompt, or else pick it up from compiler.properties + val promptString = Prop[String]("scala.repl.prompt").option getOrElse (if (info) "%nscala %#s> " else shellPromptString) + val promptText = enversion(promptString) + val prompt = encolor(promptText) + + // Prompt for continued input, will be right-adjusted to width of the primary prompt + val continueString = Prop[String]("scala.repl.continue").option getOrElse "| " + val continueText = { + val text = enversion(continueString) + val margin = promptText.lines.toList.last.length - text.length + if (margin > 0) " " * margin + text else text + } + val continuePrompt = encolor(continueText) + + // Next time. + //def welcome = enversion(Prop[String]("scala.repl.welcome") or shellWelcomeString) + def welcome = enversion { + val p = Prop[String]("scala.repl.welcome") + if (p.isSet) p.get else shellWelcomeString } /** CSV of paged,across to enable pagination or `-x` style |