From 252901054e40276abdb734673e41c6ce01adb7cc Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Fri, 12 Sep 2014 08:03:08 -0700 Subject: SI-6502 Remove cp command as unworkable People expect to change the class path midstream. Let's disabuse them by removing the broken command. The internals are deprecated. --- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/repl') diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 50c89f7442..9353d03a08 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -75,6 +75,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def history = in.history // classpath entries added via :cp + @deprecated("Use reset, replay or require to update class path", since = "2.11") var addedClasspath: String = "" /** A reverse list of commands to replay if the user requests a :replay */ @@ -207,7 +208,6 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) /** Standard commands **/ lazy val standardCommands = List( - cmd("cp", "", "add a jar or directory to the classpath", addClasspath), cmd("edit", "|", "edit history", editCommand), cmd("help", "[command]", "print this summary or command-specific help", helpCommand), historyCommand, @@ -221,6 +221,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) nullary("power", "enable power user mode", powerCmd), nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)), nullary("replay", "reset execution and replay all previous commands", replay), + //cmd("require", "", "add a jar or directory to the classpath", require), // TODO nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand), cmd("save", "", "save replayable session to a file", saveCommand), shCommand, @@ -482,6 +483,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("") } } + /** `reset` the interpreter in an attempt to start fresh. + */ def resetCommand() { echo("Resetting interpreter state.") if (replayCommandStack.nonEmpty) { @@ -619,6 +622,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) else File(filename).printlnAll(replayCommands: _*) ) + @deprecated("Use reset, replay or require to update class path", since = "2.11") def addClasspath(arg: String): Unit = { val f = File(arg).normalize if (f.exists) { -- cgit v1.2.3 From e720babdaf999878642c18cebec4c18e93988d54 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 15 Sep 2014 23:32:09 -0700 Subject: SI-6502 Repl reset/replay take settings args The reset and replay commands take arbitrary command line args. When settings args are supplied, the compiler is recreated. For uniformity, the settings command performs only the usual arg parsing: use -flag:true instead of +flag, and clearing a setting is promoted to the command line, so that -Xlint: is not an error but clears the flags. ``` scala> maqicode.Test main null :8: error: not found: value maqicode maqicode.Test main null ^ scala> :reset -classpath/a target/scala-2.11/sample_2.11-1.0.jar Resetting interpreter state. Forgetting all expression results and named terms: $intp scala> maqicode.Test main null Hello, world. scala> val i = 42 i: Int = 42 scala> s"$i is the loneliest numbah." res1: String = 42 is the loneliest numbah. scala> :replay -classpath "" Replaying: maqicode.Test main null Hello, world. Replaying: val i = 42 i: Int = 42 Replaying: s"$i is the loneliest numbah." res1: String = 42 is the loneliest numbah. scala> :replay -classpath/a "" Replaying: maqicode.Test main null :8: error: not found: value maqicode maqicode.Test main null ^ Replaying: val i = 42 i: Int = 42 Replaying: s"$i is the loneliest numbah." res1: String = 42 is the loneliest numbah. ``` Clearing a clearable setting: ``` scala> :reset -Xlint:missing-interpolator Resetting interpreter state. scala> { val i = 42 ; "$i is the loneliest numbah." } :8: warning: possible missing interpolator: detected interpolated identifier `$i` { val i = 42 ; "$i is the loneliest numbah." } ^ res0: String = $i is the loneliest numbah. scala> :reset -Xlint: Resetting interpreter state. Forgetting this session history: { val i = 42 ; "$i is the loneliest numbah." } scala> { val i = 42 ; "$i is the loneliest numbah." } res0: String = $i is the loneliest numbah. ``` --- .../scala/tools/nsc/settings/AbsSettings.scala | 6 +- .../scala/tools/nsc/settings/MutableSettings.scala | 25 +++-- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 101 ++++++++------------- .../scala/tools/nsc/interpreter/ReplStrings.scala | 5 +- test/files/run/t4594-repl-settings.scala | 2 +- 5 files changed, 69 insertions(+), 70 deletions(-) (limited to 'src/repl') diff --git a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala index 4727e6d867..060a24d8d4 100644 --- a/src/compiler/scala/tools/nsc/settings/AbsSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/AbsSettings.scala @@ -35,7 +35,11 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings { case s: AbsSettings => this.userSetSettings == s.userSetSettings case _ => false } - override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n")).mkString + override def toString() = { + val uss = userSetSettings + val indent = if (uss.nonEmpty) " " * 2 else "" + uss.mkString(f"Settings {%n$indent", f"%n$indent", f"%n}%n") + } def toConciseString = userSetSettings.mkString("(", " ", ")") def checkDependencies = diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index bbe21477cb..23611bb629 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -125,14 +125,26 @@ class MutableSettings(val errorFn: String => Unit) case Some(cmd) => setter(cmd)(args) } - // if arg is of form -Xfoo:bar,baz,quux - def parseColonArg(s: String): Option[List[String]] = { - val (p, args) = StringOps.splitWhere(s, _ == ':', doDropIndex = true) getOrElse (return None) - - // any non-Nil return value means failure and we return s unmodified - tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _) + // -Xfoo: clears Clearables + def clearIfExists(cmd: String): Option[List[String]] = lookupSetting(cmd) match { + case Some(c: Clearable) => c.clear() ; Some(Nil) + case Some(s) => s.errorAndValue(s"Missing argument to $cmd", None) + case None => None } + // if arg is of form -Xfoo:bar,baz,quux + // the entire arg is consumed, so return None for failure + // any non-Nil return value means failure and we return s unmodified + def parseColonArg(s: String): Option[List[String]] = + if (s endsWith ":") { + clearIfExists(s.init) + } else { + for { + (p, args) <- StringOps.splitWhere(s, _ == ':', doDropIndex = true) + rest <- tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _) + } yield rest + } + // if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo") def parseNormalArg(p: String, args: List[String]): Option[List[String]] = tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _) @@ -532,6 +544,7 @@ class MutableSettings(val errorFn: String => Unit) def prepend(s: String) = prependPath.value = join(s, prependPath.value) def append(s: String) = appendPath.value = join(appendPath.value, s) + override def isDefault = super.isDefault && prependPath.isDefault && appendPath.isDefault override def value = join( prependPath.value, super.value, diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 9353d03a08..6a3528d1c9 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -220,12 +220,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand), nullary("power", "enable power user mode", powerCmd), nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)), - nullary("replay", "reset execution and replay all previous commands", replay), + cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand), //cmd("require", "", "add a jar or directory to the classpath", require), // TODO - nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand), + cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand), cmd("save", "", "save replayable session to a file", saveCommand), shCommand, - cmd("settings", "[+|-]", "+enable/-disable flags, set compiler options", changeSettings), + cmd("settings", "", "update compiler options, if possible; see reset", changeSettings), nullary("silent", "disable/enable automatic printing of results", verbosity), cmd("type", "[-v] ", "display the type of an expression without evaluating it", typeCommand), cmd("kind", "[-v] ", "display the kind of expression's type", kindCommand), @@ -305,57 +305,23 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) intp.lastWarnings foreach { case (pos, msg) => intp.reporter.warning(pos, msg) } } - private def changeSettings(args: String): Result = { - def showSettings() = { - for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString) - } - def updateSettings() = { - // put aside +flag options - val (pluses, rest) = (args split "\\s+").toList partition (_.startsWith("+")) - val tmps = new Settings - val (ok, leftover) = tmps.processArguments(rest, processAll = true) - if (!ok) echo("Bad settings request.") - else if (leftover.nonEmpty) echo("Unprocessed settings.") - else { - // boolean flags set-by-user on tmp copy should be off, not on - val offs = tmps.userSetSettings filter (_.isInstanceOf[Settings#BooleanSetting]) - val (minuses, nonbools) = rest partition (arg => offs exists (_ respondsTo arg)) - // update non-flags - settings.processArguments(nonbools, processAll = true) - // also snag multi-value options for clearing, e.g. -Ylog: and -language: - for { - s <- settings.userSetSettings - if s.isInstanceOf[Settings#MultiStringSetting] || s.isInstanceOf[Settings#PhasesSetting] - if nonbools exists (arg => arg.head == '-' && arg.last == ':' && (s respondsTo arg.init)) - } s match { - case c: Clearable => c.clear() - case _ => - } - def update(bs: Seq[String], name: String=>String, setter: Settings#Setting=>Unit) = { - for (b <- bs) - settings.lookupSetting(name(b)) match { - case Some(s) => - if (s.isInstanceOf[Settings#BooleanSetting]) setter(s) - else echo(s"Not a boolean flag: $b") - case _ => - echo(s"Not an option: $b") - } - } - update(minuses, identity, _.tryToSetFromPropertyValue("false")) // turn off - update(pluses, "-" + _.drop(1), _.tryToSet(Nil)) // turn on - } - } - if (args.isEmpty) showSettings() else updateSettings() + private def changeSettings(line: String): Result = { + def showSettings() = for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString) + if (line.isEmpty) showSettings() else { updateSettings(line) ; () } + } + private def updateSettings(line: String) = { + val (ok, rest) = settings.processArguments(words(line), processAll = false) + ok && rest.isEmpty } private def javapCommand(line: String): Result = { if (javap == null) - ":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome) + s":javap unavailable, no tools.jar at $jdkHome. Set JDK_HOME." else if (line == "") ":javap [-lcsvp] [path1 path2 ...]" else javap(words(line)) foreach { res => - if (res.isError) return "Failed: " + res.value + if (res.isError) return s"Failed: ${res.value}" else res.show() } } @@ -473,8 +439,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } /** create a new interpreter and replay the given commands */ - def replay() { - reset() + def replayCommand(line: String): Unit = { + def run(destructive: Boolean): Unit = { + if (destructive) createInterpreter() else reset() + replay() + } + if (line.isEmpty) run(destructive = false) + else if (updateSettings(line)) run(destructive = true) + } + /** Announces as it replays. */ + def replay(): Unit = { if (replayCommandStack.isEmpty) echo("Nothing to replay.") else for (cmd <- replayCommands) { @@ -484,22 +458,27 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } /** `reset` the interpreter in an attempt to start fresh. + * Supplying settings creates a new compiler. */ - def resetCommand() { - echo("Resetting interpreter state.") - if (replayCommandStack.nonEmpty) { - echo("Forgetting this session history:\n") - replayCommands foreach echo - echo("") - replayCommandStack = Nil + def resetCommand(line: String): Unit = { + def run(destructive: Boolean): Unit = { + echo("Resetting interpreter state.") + if (replayCommandStack.nonEmpty) { + echo("Forgetting this session history:\n") + replayCommands foreach echo + echo("") + replayCommandStack = Nil + } + if (intp.namedDefinedTerms.nonEmpty) + echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", ")) + if (intp.definedTypes.nonEmpty) + echo("Forgetting defined types: " + intp.definedTypes.mkString(", ")) + if (destructive) createInterpreter() else reset() } - if (intp.namedDefinedTerms.nonEmpty) - echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", ")) - if (intp.definedTypes.nonEmpty) - echo("Forgetting defined types: " + intp.definedTypes.mkString(", ")) - - reset() + if (line.isEmpty) run(destructive = false) + else if (updateSettings(line)) run(destructive = true) } + /** Resets without announcements. */ def reset() { intp.reset() unleashAndSetPhase() diff --git a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala index 43da5c6f12..1664546cab 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplStrings.scala @@ -28,5 +28,8 @@ trait ReplStrings { def any2stringOf(x: Any, maxlen: Int) = "scala.runtime.ScalaRunTime.replStringOf(%s, %s)".format(x, maxlen) - def words(s: String) = (s.trim split "\\s+" filterNot (_ == "")).toList + // no escaped or nested quotes + private[this] val inquotes = """(['"])(.*?)\1""".r + def unquoted(s: String) = s match { case inquotes(_, w) => w ; case _ => s } + def words(s: String) = (s.trim split "\\s+" filterNot (_ == "") map unquoted).toList } diff --git a/test/files/run/t4594-repl-settings.scala b/test/files/run/t4594-repl-settings.scala index 4202991607..db5dc19866 100644 --- a/test/files/run/t4594-repl-settings.scala +++ b/test/files/run/t4594-repl-settings.scala @@ -14,7 +14,7 @@ object Test extends SessionTest { |warning: there was one deprecation warning; re-run with -deprecation for details |a: String | - |scala> :settings +deprecation + |scala> :settings -deprecation | |scala> def b = depp |:8: warning: method depp is deprecated: Please don't do that. -- cgit v1.2.3