Skip to content

Commit 47ab999

Browse files
committed
Merge pull request scala#3986 from som-snytt/issue/6502-no-cp
SI-6502 Repl reset/replay take settings args
2 parents d4601ba + e720bab commit 47ab999

File tree

5 files changed

+74
-71
lines changed

5 files changed

+74
-71
lines changed

src/compiler/scala/tools/nsc/settings/AbsSettings.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ trait AbsSettings extends scala.reflect.internal.settings.AbsSettings {
3535
case s: AbsSettings => this.userSetSettings == s.userSetSettings
3636
case _ => false
3737
}
38-
override def toString() = "Settings {\n%s}\n" format (userSetSettings map (" " + _ + "\n")).mkString
38+
override def toString() = {
39+
val uss = userSetSettings
40+
val indent = if (uss.nonEmpty) " " * 2 else ""
41+
uss.mkString(f"Settings {%n$indent", f"%n$indent", f"%n}%n")
42+
}
3943
def toConciseString = userSetSettings.mkString("(", " ", ")")
4044

4145
def checkDependencies =

src/compiler/scala/tools/nsc/settings/MutableSettings.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,26 @@ class MutableSettings(val errorFn: String => Unit)
125125
case Some(cmd) => setter(cmd)(args)
126126
}
127127

128-
// if arg is of form -Xfoo:bar,baz,quux
129-
def parseColonArg(s: String): Option[List[String]] = {
130-
val (p, args) = StringOps.splitWhere(s, _ == ':', doDropIndex = true) getOrElse (return None)
131-
132-
// any non-Nil return value means failure and we return s unmodified
133-
tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _)
128+
// -Xfoo: clears Clearables
129+
def clearIfExists(cmd: String): Option[List[String]] = lookupSetting(cmd) match {
130+
case Some(c: Clearable) => c.clear() ; Some(Nil)
131+
case Some(s) => s.errorAndValue(s"Missing argument to $cmd", None)
132+
case None => None
134133
}
135134

135+
// if arg is of form -Xfoo:bar,baz,quux
136+
// the entire arg is consumed, so return None for failure
137+
// any non-Nil return value means failure and we return s unmodified
138+
def parseColonArg(s: String): Option[List[String]] =
139+
if (s endsWith ":") {
140+
clearIfExists(s.init)
141+
} else {
142+
for {
143+
(p, args) <- StringOps.splitWhere(s, _ == ':', doDropIndex = true)
144+
rest <- tryToSetIfExists(p, (args split ",").toList, (s: Setting) => s.tryToSetColon _)
145+
} yield rest
146+
}
147+
136148
// if arg is of form -Xfoo or -Xfoo bar (name = "-Xfoo")
137149
def parseNormalArg(p: String, args: List[String]): Option[List[String]] =
138150
tryToSetIfExists(p, args, (s: Setting) => s.tryToSet _)
@@ -532,6 +544,7 @@ class MutableSettings(val errorFn: String => Unit)
532544
def prepend(s: String) = prependPath.value = join(s, prependPath.value)
533545
def append(s: String) = appendPath.value = join(appendPath.value, s)
534546

547+
override def isDefault = super.isDefault && prependPath.isDefault && appendPath.isDefault
535548
override def value = join(
536549
prependPath.value,
537550
super.value,

src/repl/scala/tools/nsc/interpreter/ILoop.scala

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
7575
def history = in.history
7676

7777
// classpath entries added via :cp
78+
@deprecated("Use reset, replay or require to update class path", since = "2.11")
7879
var addedClasspath: String = ""
7980

8081
/** 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)
207208

208209
/** Standard commands **/
209210
lazy val standardCommands = List(
210-
cmd("cp", "<path>", "add a jar or directory to the classpath", addClasspath),
211211
cmd("edit", "<id>|<line>", "edit history", editCommand),
212212
cmd("help", "[command]", "print this summary or command-specific help", helpCommand),
213213
historyCommand,
@@ -220,11 +220,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
220220
cmd("paste", "[-raw] [path]", "enter paste mode or paste a file", pasteCommand),
221221
nullary("power", "enable power user mode", powerCmd),
222222
nullary("quit", "exit the interpreter", () => Result(keepRunning = false, None)),
223-
nullary("replay", "reset execution and replay all previous commands", replay),
224-
nullary("reset", "reset the repl to its initial state, forgetting all session entries", resetCommand),
223+
cmd("replay", "[options]", "reset the repl and replay all previous commands", replayCommand),
224+
//cmd("require", "<path>", "add a jar or directory to the classpath", require), // TODO
225+
cmd("reset", "[options]", "reset the repl to its initial state, forgetting all session entries", resetCommand),
225226
cmd("save", "<path>", "save replayable session to a file", saveCommand),
226227
shCommand,
227-
cmd("settings", "[+|-]<options>", "+enable/-disable flags, set compiler options", changeSettings),
228+
cmd("settings", "<options>", "update compiler options, if possible; see reset", changeSettings),
228229
nullary("silent", "disable/enable automatic printing of results", verbosity),
229230
cmd("type", "[-v] <expr>", "display the type of an expression without evaluating it", typeCommand),
230231
cmd("kind", "[-v] <expr>", "display the kind of expression's type", kindCommand),
@@ -304,57 +305,23 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
304305
intp.lastWarnings foreach { case (pos, msg) => intp.reporter.warning(pos, msg) }
305306
}
306307

307-
private def changeSettings(args: String): Result = {
308-
def showSettings() = {
309-
for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString)
310-
}
311-
def updateSettings() = {
312-
// put aside +flag options
313-
val (pluses, rest) = (args split "\\s+").toList partition (_.startsWith("+"))
314-
val tmps = new Settings
315-
val (ok, leftover) = tmps.processArguments(rest, processAll = true)
316-
if (!ok) echo("Bad settings request.")
317-
else if (leftover.nonEmpty) echo("Unprocessed settings.")
318-
else {
319-
// boolean flags set-by-user on tmp copy should be off, not on
320-
val offs = tmps.userSetSettings filter (_.isInstanceOf[Settings#BooleanSetting])
321-
val (minuses, nonbools) = rest partition (arg => offs exists (_ respondsTo arg))
322-
// update non-flags
323-
settings.processArguments(nonbools, processAll = true)
324-
// also snag multi-value options for clearing, e.g. -Ylog: and -language:
325-
for {
326-
s <- settings.userSetSettings
327-
if s.isInstanceOf[Settings#MultiStringSetting] || s.isInstanceOf[Settings#PhasesSetting]
328-
if nonbools exists (arg => arg.head == '-' && arg.last == ':' && (s respondsTo arg.init))
329-
} s match {
330-
case c: Clearable => c.clear()
331-
case _ =>
332-
}
333-
def update(bs: Seq[String], name: String=>String, setter: Settings#Setting=>Unit) = {
334-
for (b <- bs)
335-
settings.lookupSetting(name(b)) match {
336-
case Some(s) =>
337-
if (s.isInstanceOf[Settings#BooleanSetting]) setter(s)
338-
else echo(s"Not a boolean flag: $b")
339-
case _ =>
340-
echo(s"Not an option: $b")
341-
}
342-
}
343-
update(minuses, identity, _.tryToSetFromPropertyValue("false")) // turn off
344-
update(pluses, "-" + _.drop(1), _.tryToSet(Nil)) // turn on
345-
}
346-
}
347-
if (args.isEmpty) showSettings() else updateSettings()
308+
private def changeSettings(line: String): Result = {
309+
def showSettings() = for (s <- settings.userSetSettings.toSeq.sorted) echo(s.toString)
310+
if (line.isEmpty) showSettings() else { updateSettings(line) ; () }
311+
}
312+
private def updateSettings(line: String) = {
313+
val (ok, rest) = settings.processArguments(words(line), processAll = false)
314+
ok && rest.isEmpty
348315
}
349316

350317
private def javapCommand(line: String): Result = {
351318
if (javap == null)
352-
":javap unavailable, no tools.jar at %s. Set JDK_HOME.".format(jdkHome)
319+
s":javap unavailable, no tools.jar at $jdkHome. Set JDK_HOME."
353320
else if (line == "")
354321
":javap [-lcsvp] [path1 path2 ...]"
355322
else
356323
javap(words(line)) foreach { res =>
357-
if (res.isError) return "Failed: " + res.value
324+
if (res.isError) return s"Failed: ${res.value}"
358325
else res.show()
359326
}
360327
}
@@ -472,8 +439,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
472439
}
473440

474441
/** create a new interpreter and replay the given commands */
475-
def replay() {
476-
reset()
442+
def replayCommand(line: String): Unit = {
443+
def run(destructive: Boolean): Unit = {
444+
if (destructive) createInterpreter() else reset()
445+
replay()
446+
}
447+
if (line.isEmpty) run(destructive = false)
448+
else if (updateSettings(line)) run(destructive = true)
449+
}
450+
/** Announces as it replays. */
451+
def replay(): Unit = {
477452
if (replayCommandStack.isEmpty)
478453
echo("Nothing to replay.")
479454
else for (cmd <- replayCommands) {
@@ -482,21 +457,28 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
482457
echo("")
483458
}
484459
}
485-
def resetCommand() {
486-
echo("Resetting interpreter state.")
487-
if (replayCommandStack.nonEmpty) {
488-
echo("Forgetting this session history:\n")
489-
replayCommands foreach echo
490-
echo("")
491-
replayCommandStack = Nil
460+
/** `reset` the interpreter in an attempt to start fresh.
461+
* Supplying settings creates a new compiler.
462+
*/
463+
def resetCommand(line: String): Unit = {
464+
def run(destructive: Boolean): Unit = {
465+
echo("Resetting interpreter state.")
466+
if (replayCommandStack.nonEmpty) {
467+
echo("Forgetting this session history:\n")
468+
replayCommands foreach echo
469+
echo("")
470+
replayCommandStack = Nil
471+
}
472+
if (intp.namedDefinedTerms.nonEmpty)
473+
echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", "))
474+
if (intp.definedTypes.nonEmpty)
475+
echo("Forgetting defined types: " + intp.definedTypes.mkString(", "))
476+
if (destructive) createInterpreter() else reset()
492477
}
493-
if (intp.namedDefinedTerms.nonEmpty)
494-
echo("Forgetting all expression results and named terms: " + intp.namedDefinedTerms.mkString(", "))
495-
if (intp.definedTypes.nonEmpty)
496-
echo("Forgetting defined types: " + intp.definedTypes.mkString(", "))
497-
498-
reset()
478+
if (line.isEmpty) run(destructive = false)
479+
else if (updateSettings(line)) run(destructive = true)
499480
}
481+
/** Resets without announcements. */
500482
def reset() {
501483
intp.reset()
502484
unleashAndSetPhase()
@@ -619,6 +601,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
619601
else File(filename).printlnAll(replayCommands: _*)
620602
)
621603

604+
@deprecated("Use reset, replay or require to update class path", since = "2.11")
622605
def addClasspath(arg: String): Unit = {
623606
val f = File(arg).normalize
624607
if (f.exists) {

src/repl/scala/tools/nsc/interpreter/ReplStrings.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,8 @@ trait ReplStrings {
2828
def any2stringOf(x: Any, maxlen: Int) =
2929
"scala.runtime.ScalaRunTime.replStringOf(%s, %s)".format(x, maxlen)
3030

31-
def words(s: String) = (s.trim split "\\s+" filterNot (_ == "")).toList
31+
// no escaped or nested quotes
32+
private[this] val inquotes = """(['"])(.*?)\1""".r
33+
def unquoted(s: String) = s match { case inquotes(_, w) => w ; case _ => s }
34+
def words(s: String) = (s.trim split "\\s+" filterNot (_ == "") map unquoted).toList
3235
}

test/files/run/t4594-repl-settings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ object Test extends SessionTest {
1414
|warning: there was one deprecation warning; re-run with -deprecation for details
1515
|a: String
1616
|
17-
|scala> :settings +deprecation
17+
|scala> :settings -deprecation
1818
|
1919
|scala> def b = depp
2020
|<console>:8: warning: method depp is deprecated: Please don't do that.

0 commit comments

Comments
 (0)