From 1a9ffaa895e37c141561783c8596810c26d69d6a Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 17 Jun 2015 13:10:48 -0700 Subject: SI-9206 BooleanProp if set and not untrue Previously, handy `sys.BooleanProp.keyExists` ignored the property value. While trying not to make any real estate puns, this commit will let it go false if a value is supplied that is not true in the usual Java sense. But what is truth? Allows `scala -Dscala.color=off`, for example. --- src/library/scala/sys/BooleanProp.scala | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/library/scala/sys/BooleanProp.scala b/src/library/scala/sys/BooleanProp.scala index 74b0a9077b..e5e4668edb 100644 --- a/src/library/scala/sys/BooleanProp.scala +++ b/src/library/scala/sys/BooleanProp.scala @@ -63,12 +63,13 @@ object BooleanProp { def valueIsTrue[T](key: String): BooleanProp = new BooleanPropImpl(key, _.toLowerCase == "true") /** As an alternative, this method creates a BooleanProp which is true - * if the key exists in the map. This way -Dfoo.bar is enough to be - * considered true. + * if the key exists in the map and is not assigned a value other than "true", + * compared case-insensitively, or the empty string. This way -Dmy.property + * results in a true-valued property, but -Dmy.property=false does not. * * @return A BooleanProp with a liberal truth policy */ - def keyExists[T](key: String): BooleanProp = new BooleanPropImpl(key, _ => true) + def keyExists[T](key: String): BooleanProp = new BooleanPropImpl(key, s => s == "" || s.equalsIgnoreCase("true")) /** A constant true or false property which ignores all method calls. */ -- cgit v1.2.3 From aa98d9a8c19ca27d85b62d1eccfc868440dc9ab2 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 17 Jun 2015 13:24:53 -0700 Subject: SI-9206 REPL prompt is more easily configured The scala shell prompt can be provided as either a system property or in compiler.properties. The prompt string is taken as a format string with one argument that is the version string. ``` $ scala -Dscala.repl.prompt="%nScala %s> " Welcome to Scala version 2.11.7-20150616-093756-43a56fb5a1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45). Type in expressions to have them evaluated. Type :help for more information. Scala 2.11.7-20150616-093756-43a56fb5a1> 42 res0: Int = 42 Scala 2.11.7-20150616-093756-43a56fb5a1> :quit ``` --- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 22 +++++++++++----------- .../scala/tools/nsc/interpreter/ReplProps.scala | 10 +++++++++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 4221126caa..11c843248a 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -197,10 +197,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("%d %s".format(index + offset, line)) } - private val currentPrompt = Properties.shellPromptString - /** Prompt to print when awaiting input */ - def prompt = currentPrompt + def prompt = replProps.prompt import LoopCommand.{ cmd, nullary } @@ -410,14 +408,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } private def readOneLine() = { - import scala.io.AnsiColor.{ MAGENTA, RESET } out.flush() - in readLine ( - if (replProps.colorOk) - MAGENTA + prompt + RESET - else - prompt - ) + in readLine prompt } /** The main read-eval-print loop for the repl. It calls @@ -776,6 +768,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private object paste extends Pasted { val ContinueString = " | " val PromptString = "scala> " + val testPrompt = PromptString.trim + val testOurPrompt = prompt.trim + val testBoth = testPrompt != testOurPrompt + + def isPrompt(line: String) = { + val text = line.trim + text == testOurPrompt || (testBoth && text == testPrompt) + } def interpret(line: String): Unit = { echo(line.trim) @@ -785,7 +785,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def transcript(start: String) = { echo("\n// Detected repl transcript paste: ctrl-D to finish.\n") - apply(Iterator(start) ++ readWhile(_.trim != PromptString.trim)) + apply(Iterator(start) ++ readWhile(!isPrompt(_))) } } import paste.{ ContinueString, PromptString } diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala index 8c4faf7278..19f66e98a2 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala @@ -11,11 +11,19 @@ import Prop._ class ReplProps { private def bool(name: String) = BooleanProp.keyExists(name) - private def int(name: String) = IntProp(name) + private def int(name: String) = Prop[Int](name) // This property is used in TypeDebugging. Let's recycle it. val colorOk = bool("scala.color") + // Handy system prop for shell prompt, or else pick it up from compiler.properties + val prompt = { + import scala.io.AnsiColor.{ MAGENTA, RESET } + val p = Prop[String]("scala.repl.prompt").option getOrElse Properties.shellPromptString + val q = String.format(p, Properties.versionNumberString) + if (colorOk) s"$MAGENTA$q$RESET" else q + } + val info = bool("scala.repl.info") val debug = bool("scala.repl.debug") val trace = bool("scala.repl.trace") -- cgit v1.2.3 From c3aca109e95e2259d9909f8457a1422c5c995940 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 17 Jun 2015 14:47:13 -0700 Subject: SI-9206 Fix REPL code indentation To make code in error messages line up with the original line of code, templated code is indented by the width of the prompt. Use the raw prompt (without ANSI escapes or newlines) to determine the indentation. Also, indent only once per line. --- src/compiler/scala/tools/nsc/Properties.scala | 2 +- .../scala/tools/nsc/interpreter/Formatting.scala | 27 +++--- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 9 +- src/repl/scala/tools/nsc/interpreter/IMain.scala | 19 +++-- .../scala/tools/nsc/interpreter/ReplProps.scala | 6 +- test/files/jvm/interpreter.check | 18 ++-- test/files/run/constrained-types.check | 8 +- test/files/run/kind-repl-command.check | 6 +- test/files/run/reify-repl-fail-gracefully.check | 6 +- test/files/run/reify_newimpl_22.check | 6 +- test/files/run/reify_newimpl_23.check | 2 +- test/files/run/reify_newimpl_25.check | 6 +- test/files/run/reify_newimpl_26.check | 2 +- test/files/run/repl-bare-expr.check | 36 ++++---- test/files/run/repl-colon-type.check | 4 +- test/files/run/repl-parens.check | 36 ++++---- test/files/run/repl-paste-2.check | 2 +- test/files/run/repl-reset.check | 24 +++--- test/files/run/repl-trim-stack-trace.scala | 6 +- test/files/run/t4542.check | 2 +- test/files/run/t4594-repl-settings.scala | 2 +- test/files/run/t5655.check | 12 +-- test/files/run/t7319.check | 18 ++-- test/files/run/t7747-repl.check | 96 +++++++++++----------- test/files/run/t9170.scala | 24 +++--- test/files/run/t9206.scala | 26 ++++++ test/files/run/xMigration.check | 18 ++-- 27 files changed, 223 insertions(+), 200 deletions(-) create mode 100644 test/files/run/t9206.scala diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala index 9f160e2485..ca7d8776d4 100644 --- a/src/compiler/scala/tools/nsc/Properties.scala +++ b/src/compiler/scala/tools/nsc/Properties.scala @@ -13,7 +13,7 @@ object Properties extends scala.util.PropertiesTrait { // settings based on jar properties, falling back to System prefixed by "scala." def residentPromptString = scalaPropOrElse("resident.prompt", "\nnsc> ") - def shellPromptString = scalaPropOrElse("shell.prompt", "\nscala> ") + def shellPromptString = scalaPropOrElse("shell.prompt", "%nscala> ") // 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/repl/scala/tools/nsc/interpreter/Formatting.scala b/src/repl/scala/tools/nsc/interpreter/Formatting.scala index 43e653edfd..844997429c 100644 --- a/src/repl/scala/tools/nsc/interpreter/Formatting.scala +++ b/src/repl/scala/tools/nsc/interpreter/Formatting.scala @@ -8,28 +8,25 @@ package interpreter import util.stringFromWriter -trait Formatting { - def prompt: String +class Formatting(indent: Int) { - def spaces(code: String): String = { + private val indentation = " " * indent + + private def indenting(code: String): Boolean = { /** Heuristic to avoid indenting and thereby corrupting """-strings and XML literals. */ val tokens = List("\"\"\"", "") val noIndent = (code contains "\n") && (tokens exists code.contains) - if (noIndent) "" - else prompt drop 1 map (_ => ' ') + !noIndent } /** Indent some code by the width of the scala> prompt. * This way, compiler error messages read better. */ - def indentCode(code: String) = { - val indent = spaces(code) - stringFromWriter(str => - for (line <- code.lines) { - str print indent - str print (line + "\n") - str.flush() - } - ) - } + def indentCode(code: String) = stringFromWriter(str => + for (line <- code.lines) { + if (indenting(code)) str print indentation + str println line + str.flush() + } + ) } diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 11c843248a..89061730f6 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -109,11 +109,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } class ILoopInterpreter extends IMain(settings, out) { - outer => - - override lazy val formatting = new Formatting { - def prompt = ILoop.this.prompt - } + // 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 ) } diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index e355d9f864..2550a5dc57 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -112,12 +112,13 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def this(factory: ScriptEngineFactory) = this(factory, new Settings()) def this() = this(new Settings()) - lazy val formatting: Formatting = new Formatting { - val prompt = Properties.shellPromptString - } + // 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 reporter: ReplReporter = new ReplReporter(this) - import formatting._ + import formatting.indentCode import reporter.{ printMessage, printUntruncatedMessage } // This exists mostly because using the reporter too early leads to deadlock. @@ -468,7 +469,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set } private def requestFromLine(line: String, synthetic: Boolean): Either[IR.Result, Request] = { - val content = indentCode(line) + val content = line //indentCode(line) val trees = parse(content) match { case parse.Incomplete => return Left(IR.Incomplete) case parse.Error => return Left(IR.Error) @@ -909,10 +910,10 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set else List("def %s = %s".format("$line", tquoted(originalLine)), "def %s = Nil".format("$trees")) } def preamble = s""" - |$preambleHeader - |%s%s%s - """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, - importsPreamble, indentCode(toCompute)) + |${preambleHeader format lineRep.readName} + |${envLines mkString (" ", ";\n ", ";\n")} + |$importsPreamble + |${indentCode(toCompute)}""".stripMargin val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala index 19f66e98a2..945129a868 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala @@ -17,11 +17,11 @@ class ReplProps { val colorOk = bool("scala.color") // Handy system prop for shell prompt, or else pick it up from compiler.properties + val promptString = Prop[String]("scala.repl.prompt").option getOrElse Properties.shellPromptString val prompt = { import scala.io.AnsiColor.{ MAGENTA, RESET } - val p = Prop[String]("scala.repl.prompt").option getOrElse Properties.shellPromptString - val q = String.format(p, Properties.versionNumberString) - if (colorOk) s"$MAGENTA$q$RESET" else q + val p = promptString format Properties.versionNumberString + if (colorOk) s"$MAGENTA$p$RESET" else p } val info = bool("scala.repl.info") diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check index d03edb638c..9e875235c7 100644 --- a/test/files/jvm/interpreter.check +++ b/test/files/jvm/interpreter.check @@ -32,7 +32,7 @@ scala> val four: anotherint = 4 four: anotherint = 4 scala> val bogus: anotherint = "hello" -:8: error: type mismatch; +:11: error: type mismatch; found : String("hello") required: anotherint (which expands to) Int @@ -280,13 +280,13 @@ scala> // both of the following should abort immediately: scala> def x => y => z :1: error: '=' expected but '=>' found. - def x => y => z - ^ +def x => y => z + ^ scala> [1,2,3] :1: error: illegal start of definition - [1,2,3] - ^ +[1,2,3] +^ scala> @@ -355,7 +355,7 @@ defined class Term scala> def f(e: Exp) = e match { // non-exhaustive warning here case _:Fact => 3 } -:18: warning: match may not be exhaustive. +:21: warning: match may not be exhaustive. It would fail on the following inputs: Exp(), Term() def f(e: Exp) = e match { // non-exhaustive warning here ^ @@ -365,6 +365,6 @@ scala> :quit plusOne: (x: Int)Int res0: Int = 6 res0: String = after reset -:8: error: not found: value plusOne - plusOne(5) // should be undefined now - ^ +:11: error: not found: value plusOne + plusOne(5) // should be undefined now + ^ diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check index 89a08d5ccb..6dbf8088c9 100644 --- a/test/files/run/constrained-types.check +++ b/test/files/run/constrained-types.check @@ -135,16 +135,16 @@ y: String = hello scala> scala> val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message -:8: error: not found: value e +:11: error: not found: value e val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message ^ -:8: error: not found: value f +:11: error: not found: value f val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message ^ -:8: error: not found: value g +:11: error: not found: value g val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message ^ -:8: error: not found: value h +:11: error: not found: value h val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message ^ diff --git a/test/files/run/kind-repl-command.check b/test/files/run/kind-repl-command.check index 586b2710e1..1853213555 100644 --- a/test/files/run/kind-repl-command.check +++ b/test/files/run/kind-repl-command.check @@ -21,8 +21,8 @@ scala> :k new { def empty = false } AnyRef{def empty: Boolean}'s kind is A scala> :k Nonexisting -:8: error: not found: value Nonexisting - Nonexisting - ^ +:11: error: not found: value Nonexisting + Nonexisting + ^ scala> :quit diff --git a/test/files/run/reify-repl-fail-gracefully.check b/test/files/run/reify-repl-fail-gracefully.check index c9e69744d6..eac4d25869 100644 --- a/test/files/run/reify-repl-fail-gracefully.check +++ b/test/files/run/reify-repl-fail-gracefully.check @@ -10,8 +10,8 @@ import scala.reflect.runtime.universe._ scala> scala> reify -:12: error: too few argument lists for macro invocation - reify - ^ +:15: error: too few argument lists for macro invocation + reify + ^ scala> :quit diff --git a/test/files/run/reify_newimpl_22.check b/test/files/run/reify_newimpl_22.check index 952f384a1c..24334df92c 100644 --- a/test/files/run/reify_newimpl_22.check +++ b/test/files/run/reify_newimpl_22.check @@ -17,9 +17,9 @@ scala> { } println(code.eval) } -:15: free term: Ident(TermName("x")) defined by res0 in :14:21 - val code = reify { - ^ +:18: free term: Ident(TermName("x")) defined by res0 in :17:14 + val code = reify { + ^ 2 scala> :quit diff --git a/test/files/run/reify_newimpl_23.check b/test/files/run/reify_newimpl_23.check index b7e9bfdfbc..f8379958db 100644 --- a/test/files/run/reify_newimpl_23.check +++ b/test/files/run/reify_newimpl_23.check @@ -16,7 +16,7 @@ scala> def foo[T]{ } println(code.eval) } -:13: free type: Ident(TypeName("T")) defined by foo in :12:16 +:16: free type: Ident(TypeName("T")) defined by foo in :15:16 val code = reify { ^ foo: [T]=> Unit diff --git a/test/files/run/reify_newimpl_25.check b/test/files/run/reify_newimpl_25.check index 4f36ba10ee..f9a5d7b578 100644 --- a/test/files/run/reify_newimpl_25.check +++ b/test/files/run/reify_newimpl_25.check @@ -7,9 +7,9 @@ scala> { val tt = implicitly[TypeTag[x.type]] println(tt) } -:11: free term: Ident(TermName("x")) defined by res0 in :10:21 - val tt = implicitly[TypeTag[x.type]] - ^ +:14: free term: Ident(TermName("x")) defined by res0 in :13:14 + val tt = implicitly[TypeTag[x.type]] + ^ TypeTag[x.type] scala> :quit diff --git a/test/files/run/reify_newimpl_26.check b/test/files/run/reify_newimpl_26.check index 681b862795..bd77d3d707 100644 --- a/test/files/run/reify_newimpl_26.check +++ b/test/files/run/reify_newimpl_26.check @@ -6,7 +6,7 @@ scala> def foo[T]{ val tt = implicitly[WeakTypeTag[List[T]]] println(tt) } -:9: free type: Ident(TypeName("T")) defined by foo in :7:16 +:12: free type: Ident(TypeName("T")) defined by foo in :10:16 val tt = implicitly[WeakTypeTag[List[T]]] ^ foo: [T]=> Unit diff --git a/test/files/run/repl-bare-expr.check b/test/files/run/repl-bare-expr.check index 07cf23412f..38ad7e818d 100644 --- a/test/files/run/repl-bare-expr.check +++ b/test/files/run/repl-bare-expr.check @@ -2,33 +2,33 @@ Type in expressions to have them evaluated. Type :help for more information. scala> 2 ; 3 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 2 ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 2 ;; + ^ res0: Int = 3 scala> { 2 ; 3 } -:8: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - { 2 ; 3 } - ^ +:11: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + { 2 ; 3 } + ^ res1: Int = 3 scala> 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { 1 + 2 + 3 } ; bippy+88+11 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ defined object Cow defined class Moo bippy: Int diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check index 9898027c1d..fa33af3beb 100644 --- a/test/files/run/repl-colon-type.check +++ b/test/files/run/repl-colon-type.check @@ -3,8 +3,8 @@ Type :help for more information. scala> :type List[1, 2, 3] :1: error: identifier expected but integer literal found. - List[1, 2, 3] - ^ +List[1, 2, 3] + ^ scala> :type List(1, 2, 3) List[Int] diff --git a/test/files/run/repl-parens.check b/test/files/run/repl-parens.check index 74d15ff93c..756a063b68 100644 --- a/test/files/run/repl-parens.check +++ b/test/files/run/repl-parens.check @@ -20,12 +20,12 @@ scala> ( (2 + 2 ) ) res5: Int = 4 scala> 5 ; ( (2 + 2 ) ) ; ((5)) -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; ( (2 + 2 ) ) ;; - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; ( (2 + 2 ) ) ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; ( (2 + 2 ) ) ;; + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; ( (2 + 2 ) ) ;; + ^ res6: Int = 5 scala> (((2 + 2)), ((2 + 2))) @@ -40,18 +40,18 @@ res9: String = 4423 scala> scala> 55 ; ((2 + 2)) ; (1, 2, 3) -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; ((2 + 2)) ;; - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; ((2 + 2)) ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; ((2 + 2)) ;; + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; ((2 + 2)) ;; + ^ res10: (Int, Int, Int) = (1,2,3) scala> 55 ; (x: Int) => x + 1 ; () => ((5)) -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; (x: Int) => x + 1 ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; (x: Int) => x + 1 ;; + ^ res11: () => Int = scala> @@ -60,9 +60,9 @@ scala> () => 5 res12: () => Int = scala> 55 ; () => 5 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ;; + ^ res13: () => Int = scala> () => { class X ; new X } diff --git a/test/files/run/repl-paste-2.check b/test/files/run/repl-paste-2.check index 6ea8e2f419..bc80615107 100644 --- a/test/files/run/repl-paste-2.check +++ b/test/files/run/repl-paste-2.check @@ -44,7 +44,7 @@ scala> res5 + res6 res1: Int = 690 scala> val x = dingus -:7: error: not found: value dingus +:10: error: not found: value dingus val x = dingus ^ diff --git a/test/files/run/repl-reset.check b/test/files/run/repl-reset.check index cd7893bbc3..a2d88fd445 100644 --- a/test/files/run/repl-reset.check +++ b/test/files/run/repl-reset.check @@ -30,23 +30,23 @@ Forgetting all expression results and named terms: $intp, BippyBungus, x1, x2, x Forgetting defined types: BippyBungus scala> x1 + x2 + x3 -:8: error: not found: value x1 - x1 + x2 + x3 - ^ -:8: error: not found: value x2 - x1 + x2 + x3 - ^ -:8: error: not found: value x3 - x1 + x2 + x3 - ^ +:11: error: not found: value x1 + x1 + x2 + x3 + ^ +:11: error: not found: value x2 + x1 + x2 + x3 + ^ +:11: error: not found: value x3 + x1 + x2 + x3 + ^ scala> val x1 = 4 x1: Int = 4 scala> new BippyBungus -:8: error: not found: type BippyBungus - new BippyBungus - ^ +:11: error: not found: type BippyBungus + new BippyBungus + ^ scala> class BippyBungus() { def f = 5 } defined class BippyBungus diff --git a/test/files/run/repl-trim-stack-trace.scala b/test/files/run/repl-trim-stack-trace.scala index a53ce3b3e4..b8c1668691 100644 --- a/test/files/run/repl-trim-stack-trace.scala +++ b/test/files/run/repl-trim-stack-trace.scala @@ -13,7 +13,7 @@ f: Nothing scala> f java.lang.Exception: Uh-oh - at .f(:7) + at .f(:10) ... 69 elided scala> def f = throw new Exception("") @@ -21,7 +21,7 @@ f: Nothing scala> f java.lang.Exception: - at .f(:7) + at .f(:10) ... 69 elided scala> def f = throw new Exception @@ -29,7 +29,7 @@ f: Nothing scala> f java.lang.Exception - at .f(:7) + at .f(:10) ... 69 elided scala> :quit""" diff --git a/test/files/run/t4542.check b/test/files/run/t4542.check index f7716dc2f0..f7aad3deb2 100644 --- a/test/files/run/t4542.check +++ b/test/files/run/t4542.check @@ -7,7 +7,7 @@ scala> @deprecated("foooo", "ReplTest version 1.0-FINAL") class Foo() { defined class Foo scala> val f = new Foo -:8: warning: class Foo is deprecated: foooo +:11: warning: class Foo is deprecated: foooo val f = new Foo ^ f: Foo = Bippy diff --git a/test/files/run/t4594-repl-settings.scala b/test/files/run/t4594-repl-settings.scala index db5dc19866..1b883983cf 100644 --- a/test/files/run/t4594-repl-settings.scala +++ b/test/files/run/t4594-repl-settings.scala @@ -17,7 +17,7 @@ object Test extends SessionTest { |scala> :settings -deprecation | |scala> def b = depp - |:8: warning: method depp is deprecated: Please don't do that. + |:11: warning: method depp is deprecated: Please don't do that. | def b = depp | ^ |b: String diff --git a/test/files/run/t5655.check b/test/files/run/t5655.check index 4bbc54b641..e8375c3e90 100644 --- a/test/files/run/t5655.check +++ b/test/files/run/t5655.check @@ -8,19 +8,19 @@ scala> import x._ import x._ scala> x -:12: error: reference to x is ambiguous; +:15: error: reference to x is ambiguous; it is imported twice in the same scope by import x._ and import x - x - ^ + x + ^ scala> x -:12: error: reference to x is ambiguous; +:15: error: reference to x is ambiguous; it is imported twice in the same scope by import x._ and import x - x - ^ + x + ^ scala> :quit diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check index e35cfc90c0..885136b432 100644 --- a/test/files/run/t7319.check +++ b/test/files/run/t7319.check @@ -17,25 +17,25 @@ warning: there was one feature warning; re-run with -feature for details convert: [F[X <: F[X]]](builder: F[_ <: F[_]])Int scala> convert(Some[Int](0)) -:12: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int]) +:15: error: no type parameters for method convert: (builder: F[_ <: F[_]])Int exist so that it can be applied to arguments (Some[Int]) --- because --- argument expression's type is not compatible with formal parameter type; found : Some[Int] required: ?F[_$1] forSome { type _$1 <: ?F[_$2] forSome { type _$2 } } - convert(Some[Int](0)) - ^ -:12: error: type mismatch; + convert(Some[Int](0)) + ^ +:15: error: type mismatch; found : Some[Int] required: F[_ <: F[_]] - convert(Some[Int](0)) - ^ + convert(Some[Int](0)) + ^ scala> Range(1,2).toArray: Seq[_] -:11: error: polymorphic expression cannot be instantiated to expected type; +:14: error: polymorphic expression cannot be instantiated to expected type; found : [B >: Int]Array[B] required: Seq[_] - Range(1,2).toArray: Seq[_] - ^ + Range(1,2).toArray: Seq[_] + ^ scala> 0 res2: Int = 0 diff --git a/test/files/run/t7747-repl.check b/test/files/run/t7747-repl.check index 5f436ba6b1..98e3d3b821 100644 --- a/test/files/run/t7747-repl.check +++ b/test/files/run/t7747-repl.check @@ -17,33 +17,33 @@ scala> val z = x * y z: Int = 156 scala> 2 ; 3 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 2 ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 2 ;; + ^ res0: Int = 3 scala> { 2 ; 3 } -:8: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - { 2 ; 3 } - ^ +:11: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + { 2 ; 3 } + ^ res1: Int = 3 scala> 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { 1 + 2 + 3 } ; bippy+88+11 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; 10 ; case object Cow ; 20 ; class Moo { override def toString = "Moooooo" } ; 30 ; def bippy = { + ^ defined object Cow defined class Moo bippy: Int @@ -83,12 +83,12 @@ scala> ( (2 + 2 ) ) res10: Int = 4 scala> 5 ; ( (2 + 2 ) ) ; ((5)) -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; ( (2 + 2 ) ) ;; - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 5 ; ( (2 + 2 ) ) ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; ( (2 + 2 ) ) ;; + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 5 ; ( (2 + 2 ) ) ;; + ^ res11: Int = 5 scala> (((2 + 2)), ((2 + 2))) @@ -103,18 +103,18 @@ res14: String = 4423 scala> scala> 55 ; ((2 + 2)) ; (1, 2, 3) -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; ((2 + 2)) ;; - ^ -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; ((2 + 2)) ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; ((2 + 2)) ;; + ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; ((2 + 2)) ;; + ^ res15: (Int, Int, Int) = (1,2,3) scala> 55 ; (x: Int) => x + 1 ; () => ((5)) -:9: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ; (x: Int) => x + 1 ;; - ^ +:12: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ; (x: Int) => x + 1 ;; + ^ res16: () => Int = scala> @@ -123,9 +123,9 @@ scala> () => 5 res17: () => Int = scala> 55 ; () => 5 -:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses - 55 ;; - ^ +:10: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses + 55 ;; + ^ res18: () => Int = scala> () => { class X ; new X } @@ -211,23 +211,23 @@ Forgetting all expression results and named terms: $intp, BippyBungus, Bovine, C Forgetting defined types: BippyBungus, Moo, Ruminant scala> x1 + x2 + x3 -:8: error: not found: value x1 - x1 + x2 + x3 - ^ -:8: error: not found: value x2 - x1 + x2 + x3 - ^ -:8: error: not found: value x3 - x1 + x2 + x3 - ^ +:11: error: not found: value x1 + x1 + x2 + x3 + ^ +:11: error: not found: value x2 + x1 + x2 + x3 + ^ +:11: error: not found: value x3 + x1 + x2 + x3 + ^ scala> val x1 = 4 x1: Int = 4 scala> new BippyBungus -:8: error: not found: type BippyBungus - new BippyBungus - ^ +:11: error: not found: type BippyBungus + new BippyBungus + ^ scala> class BippyBungus() { def f = 5 } defined class BippyBungus diff --git a/test/files/run/t9170.scala b/test/files/run/t9170.scala index 25a0e84581..67a58d6803 100644 --- a/test/files/run/t9170.scala +++ b/test/files/run/t9170.scala @@ -10,17 +10,17 @@ object Test extends SessionTest { Type :help for more information. scala> object Y { def f[A](a: => A) = 1 ; def f[A](a: => Either[Exception, A]) = 2 } -:7: error: double definition: -def f[A](a: => A): Int at line 7 and -def f[A](a: => Either[Exception,A]): Int at line 7 +:10: error: double definition: +def f[A](a: => A): Int at line 10 and +def f[A](a: => Either[Exception,A]): Int at line 10 have same type after erasure: (a: Function0)Int object Y { def f[A](a: => A) = 1 ; def f[A](a: => Either[Exception, A]) = 2 } ^ scala> object Y { def f[A](a: => A) = 1 ; def f[A](a: => Either[Exception, A]) = 2 } -:7: error: double definition: -def f[A](a: => A): Int at line 7 and -def f[A](a: => Either[Exception,A]): Int at line 7 +:10: error: double definition: +def f[A](a: => A): Int at line 10 and +def f[A](a: => Either[Exception,A]): Int at line 10 have same type after erasure: (a: Function0)Int object Y { def f[A](a: => A) = 1 ; def f[A](a: => Either[Exception, A]) = 2 } ^ @@ -29,9 +29,9 @@ scala> object Y { | def f[A](a: => A) = 1 | def f[A](a: => Either[Exception, A]) = 2 | } -:9: error: double definition: -def f[A](a: => A): Int at line 8 and -def f[A](a: => Either[Exception,A]): Int at line 9 +:12: error: double definition: +def f[A](a: => A): Int at line 11 and +def f[A](a: => Either[Exception,A]): Int at line 12 have same type after erasure: (a: Function0)Int def f[A](a: => Either[Exception, A]) = 2 ^ @@ -46,9 +46,9 @@ object Y { // Exiting paste mode, now interpreting. -:9: error: double definition: -def f[A](a: => A): Int at line 8 and -def f[A](a: => Either[Exception,A]): Int at line 9 +:12: error: double definition: +def f[A](a: => A): Int at line 11 and +def f[A](a: => Either[Exception,A]): Int at line 12 have same type after erasure: (a: Function0)Int def f[A](a: => Either[Exception, A]) = 2 ^ diff --git a/test/files/run/t9206.scala b/test/files/run/t9206.scala new file mode 100644 index 0000000000..c0484d9217 --- /dev/null +++ b/test/files/run/t9206.scala @@ -0,0 +1,26 @@ + +import scala.tools.partest.SessionTest + +object Test extends SessionTest { +//Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40). + def session = + s"""|Type in expressions to have them evaluated. + |Type :help for more information. + | + |scala> val i: Int = "foo" + |:10: error: type mismatch; + | found : String("foo") + | required: Int + | val i: Int = "foo" + | ^ + | + |scala> { val j = 42 ; val i: Int = "foo" + j } + |:11: error: type mismatch; + | found : String + | required: Int + | { val j = 42 ; val i: Int = "foo" + j } + | ^ + | + |scala> :quit""" + +} diff --git a/test/files/run/xMigration.check b/test/files/run/xMigration.check index 378f7bb6c3..304132a848 100644 --- a/test/files/run/xMigration.check +++ b/test/files/run/xMigration.check @@ -12,10 +12,10 @@ res1: Iterable[String] = MapLike(eis) scala> :setting -Xmigration:any scala> Map(1 -> "eis").values // warn -:8: warning: method values in trait MapLike has changed semantics in version 2.8.0: +:11: warning: method values in trait MapLike has changed semantics in version 2.8.0: `values` returns `Iterable[B]` rather than `Iterator[B]`. - Map(1 -> "eis").values // warn - ^ + Map(1 -> "eis").values // warn + ^ res2: Iterable[String] = MapLike(eis) scala> :setting -Xmigration:2.8 @@ -26,10 +26,10 @@ res3: Iterable[String] = MapLike(eis) scala> :setting -Xmigration:2.7 scala> Map(1 -> "eis").values // warn -:8: warning: method values in trait MapLike has changed semantics in version 2.8.0: +:11: warning: method values in trait MapLike has changed semantics in version 2.8.0: `values` returns `Iterable[B]` rather than `Iterator[B]`. - Map(1 -> "eis").values // warn - ^ + Map(1 -> "eis").values // warn + ^ res4: Iterable[String] = MapLike(eis) scala> :setting -Xmigration:2.11 @@ -40,10 +40,10 @@ res5: Iterable[String] = MapLike(eis) scala> :setting -Xmigration // same as :any scala> Map(1 -> "eis").values // warn -:8: warning: method values in trait MapLike has changed semantics in version 2.8.0: +:11: warning: method values in trait MapLike has changed semantics in version 2.8.0: `values` returns `Iterable[B]` rather than `Iterator[B]`. - Map(1 -> "eis").values // warn - ^ + Map(1 -> "eis").values // warn + ^ res6: Iterable[String] = MapLike(eis) scala> :quit -- cgit v1.2.3 From a9053f429983cc322a2fd2eca8fd0188036c7378 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 17 Jun 2015 23:25:39 -0700 Subject: SI-9206 Verbose REPL prompt for info mode Only for exactly `-Dscala.repl.info`, include the complete version number string in the REPL prompt. One could imagine this is the mode for posting snippets to stackoverflow. --- src/repl/scala/tools/nsc/interpreter/ReplProps.scala | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala index 945129a868..df65e9974d 100644 --- a/src/repl/scala/tools/nsc/interpreter/ReplProps.scala +++ b/src/repl/scala/tools/nsc/interpreter/ReplProps.scala @@ -6,6 +6,7 @@ package scala.tools.nsc package interpreter +import Properties.shellPromptString import scala.sys._ import Prop._ @@ -16,19 +17,19 @@ class ReplProps { // This property is used in TypeDebugging. Let's recycle it. val colorOk = bool("scala.color") + val info = bool("scala.repl.info") + val debug = bool("scala.repl.debug") + 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 Properties.shellPromptString + val promptString = Prop[String]("scala.repl.prompt").option getOrElse (if (info) "%nscala %s> " else shellPromptString) val prompt = { import scala.io.AnsiColor.{ MAGENTA, RESET } val p = promptString format Properties.versionNumberString if (colorOk) s"$MAGENTA$p$RESET" else p } - val info = bool("scala.repl.info") - val debug = bool("scala.repl.debug") - val trace = bool("scala.repl.trace") - val power = bool("scala.repl.power") - /** CSV of paged,across to enable pagination or `-x` style * columns, "across" instead of down the column. Since * pagination turns off columnar output, these flags are -- cgit v1.2.3 From 3bfafbcf5903fc5c43190f1738c50bbbe0ca7d2b Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sat, 20 Jun 2015 13:52:34 -0700 Subject: SI-9206 Accept paste with custom prompt But sans test. --- .../scala/tools/partest/ReplTest.scala | 12 +++++++----- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 20 ++++++++------------ src/repl/scala/tools/nsc/interpreter/Pasted.scala | 20 +++++++++++++------- test/files/run/t9206.scala | 13 +++++++++++++ 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/partest-extras/scala/tools/partest/ReplTest.scala b/src/partest-extras/scala/tools/partest/ReplTest.scala index 5b65d6ab9b..1fde2370d3 100644 --- a/src/partest-extras/scala/tools/partest/ReplTest.scala +++ b/src/partest-extras/scala/tools/partest/ReplTest.scala @@ -75,18 +75,20 @@ abstract class SessionTest extends ReplTest { * Retain user input: prompt lines and continuations, without the prefix; or pasted text plus ctl-D. */ import SessionTest._ - override final def code = input findAllMatchIn (expected mkString ("", "\n", "\n")) map { - case input(null, null, prompted) => + lazy val pasted = input(prompt) + override final def code = pasted findAllMatchIn (expected mkString ("", "\n", "\n")) map { + case pasted(null, null, prompted) => def continued(m: Match): Option[String] = m match { case margin(text) => Some(text) case _ => None } margin.replaceSomeIn(prompted, continued) - case input(cmd, pasted, null) => + case pasted(cmd, pasted, null) => cmd + pasted + "\u0004" } mkString - final def prompt = "scala> " + // Just the last line of the interactive prompt + def prompt = "scala> " /** Default test is to compare expected and actual output and emit the diff on a failed comparison. */ override def show() = { @@ -98,7 +100,7 @@ abstract class SessionTest extends ReplTest { } object SessionTest { // \R for line break is Java 8, \v for vertical space might suffice - val input = """(?m)^scala> (:pa.*\u000A)// Entering paste mode.*\u000A\u000A((?:.*\u000A)*)\u000A// Exiting paste mode.*\u000A|^scala> (.*\u000A(?:\s*\| .*\u000A)*)""".r + def input(prompt: String) = s"""(?m)^$prompt(:pa.*\u000A)// Entering paste mode.*\u000A\u000A((?:.*\u000A)*)\u000A// Exiting paste mode.*\u000A|^scala> (.*\u000A(?:\\s*\\| .*\u000A)*)""".r val margin = """(?m)^\s*\| (.*)$""".r } diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 89061730f6..992cafb9c6 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -765,16 +765,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } private object paste extends Pasted { + import scala.util.matching.Regex.quote val ContinueString = " | " - val PromptString = "scala> " - val testPrompt = PromptString.trim - val testOurPrompt = prompt.trim - val testBoth = testPrompt != testOurPrompt + val PromptString = prompt.lines.toList.last + val anyPrompt = s"""\\s*(?:${quote(PromptString.trim)}|${quote(AltPromptString.trim)})\\s*""".r - def isPrompt(line: String) = { - val text = line.trim - text == testOurPrompt || (testBoth && text == testPrompt) - } + def isPrompted(line: String) = matchesPrompt(line) + def isPromptOnly(line: String) = line match { case anyPrompt() => true ; case _ => false } def interpret(line: String): Unit = { echo(line.trim) @@ -784,10 +781,9 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def transcript(start: String) = { echo("\n// Detected repl transcript paste: ctrl-D to finish.\n") - apply(Iterator(start) ++ readWhile(!isPrompt(_))) + apply(Iterator(start) ++ readWhile(!isPromptOnly(_))) } } - import paste.{ ContinueString, PromptString } /** Interpret expressions starting with the first line. * Read lines until a complete compilation unit is available @@ -809,7 +805,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("You typed two blank lines. Starting a new command.") None } - else in.readLine(ContinueString) match { + else in.readLine(paste.ContinueString) 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 @@ -833,7 +829,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) * and avoid the interpreter, as it's likely not valid scala code. */ if (code == "") None - else if (!paste.running && code.trim.startsWith(PromptString)) { + else if (!paste.running && paste.isPrompted(code)) { paste.transcript(code) None } diff --git a/src/repl/scala/tools/nsc/interpreter/Pasted.scala b/src/repl/scala/tools/nsc/interpreter/Pasted.scala index f5db3d9e3a..1600f32946 100644 --- a/src/repl/scala/tools/nsc/interpreter/Pasted.scala +++ b/src/repl/scala/tools/nsc/interpreter/Pasted.scala @@ -16,17 +16,21 @@ package interpreter * the same result. */ abstract class Pasted { + def interpret(line: String): Unit def ContinueString: String def PromptString: String - def interpret(line: String): Unit + def AltPromptString: String = "scala> " + + private val testBoth = PromptString != AltPromptString + private val spacey = " \t".toSet - def matchesPrompt(line: String) = matchesString(line, PromptString) + def matchesPrompt(line: String) = matchesString(line, PromptString) || testBoth && matchesString(line, AltPromptString) def matchesContinue(line: String) = matchesString(line, ContinueString) def running = isRunning private def matchesString(line: String, target: String): Boolean = ( (line startsWith target) || - (line.nonEmpty && " \t".toSet(line.head) && matchesString(line.tail, target)) + (line.nonEmpty && spacey(line.head) && matchesString(line.tail, target)) ) private def stripString(line: String, target: String) = line indexOf target match { case -1 => line @@ -39,7 +43,9 @@ abstract class Pasted { private class PasteAnalyzer(val lines: List[String]) { val referenced = lines flatMap (resReference findAllIn _.trim.stripPrefix("res")) toSet - val cmds = lines reduceLeft append split PromptString filterNot (_.trim == "") toList + val ActualPromptString = lines find matchesPrompt map (s => + if (matchesString(s, PromptString)) PromptString else AltPromptString) getOrElse PromptString + val cmds = lines reduceLeft append split ActualPromptString filterNot (_.trim == "") toList /** If it's a prompt or continuation line, strip the formatting bits and * assemble the code. Otherwise ship it off to be analyzed for res references @@ -67,10 +73,10 @@ abstract class Pasted { */ def fixResRefs(code: String, line: String) = line match { case resCreation(resName) if referenced(resName) => - code.lastIndexOf(PromptString) match { + code.lastIndexOf(ActualPromptString) match { case -1 => code case idx => - val (str1, str2) = code splitAt (idx + PromptString.length) + val (str1, str2) = code splitAt (idx + ActualPromptString.length) str2 match { case resAssign(`resName`) => code case _ => "%sval %s = { %s }".format(str1, resName, str2) @@ -82,7 +88,7 @@ abstract class Pasted { def run() { println("// Replaying %d commands from transcript.\n" format cmds.size) cmds foreach { cmd => - print(PromptString) + print(ActualPromptString) interpret(cmd) } } diff --git a/test/files/run/t9206.scala b/test/files/run/t9206.scala index c0484d9217..2942d0f73e 100644 --- a/test/files/run/t9206.scala +++ b/test/files/run/t9206.scala @@ -2,6 +2,7 @@ import scala.tools.partest.SessionTest object Test extends SessionTest { + //override def prompt = "XXX> " //Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40). def session = s"""|Type in expressions to have them evaluated. @@ -22,5 +23,17 @@ object Test extends SessionTest { | ^ | |scala> :quit""" + /* + |XXX> XXX> def f = 42 + | + |// Detected repl transcript paste: ctrl-D to finish. + | + |// Replaying 1 commands from transcript. + | + |XXX> def f = 42 + |f: Int + | + |XXX> :quit""" + */ } -- cgit v1.2.3 From 7968421bd6515eeb88fb420bae3ff3bc23e5876d Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 21 Jun 2015 11:13:30 -0700 Subject: SI-9206 Local refactor to save eyesight We talk about bit rot but not about how dust accumulates on code that hasn't been swept since the last time the furniture was moved around. --- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 79 +++++++++++------------ src/repl/scala/tools/nsc/interpreter/Pasted.scala | 2 +- 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 992cafb9c6..bf4d107215 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -783,8 +783,16 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) echo("\n// Detected repl transcript paste: ctrl-D to finish.\n") apply(Iterator(start) ++ readWhile(!isPromptOnly(_))) } + + def unapply(line: String): Boolean = isPrompted(line) + } + + private object invocation { + def unapply(line: String): Boolean = Completion.looksLikeInvocation(line) } + private val lineComment = """\s*//.*""".r // all comment + /** Interpret expressions starting with the first line. * Read lines until a complete compilation unit is available * or until a syntax error has been seen. If a full unit is @@ -795,53 +803,42 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // signal completion non-completion input has been received in.completion.resetVerbosity() - def reallyInterpret = { - val reallyResult = intp.interpret(code) - (reallyResult, reallyResult match { - case IR.Error => None - case IR.Success => Some(code) - case IR.Incomplete => - if (in.interactive && code.endsWith("\n\n")) { - echo("You typed two blank lines. Starting a new command.") + def reallyInterpret = intp.interpret(code) match { + case IR.Error => None + case IR.Success => Some(code) + case IR.Incomplete if in.interactive && code.endsWith("\n\n") => + echo("You typed two blank lines. Starting a new command.") + None + case IR.Incomplete => + in.readLine(paste.ContinueString) 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 + // a file being read non-interactively we want to fail. So we send + // it straight to the compiler for the nice error message. + intp.compileString(code) None - } - else in.readLine(paste.ContinueString) 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 - // a file being read non-interactively we want to fail. So we send - // it straight to the compiler for the nice error message. - intp.compileString(code) - None - - case line => interpretStartingWith(code + "\n" + line) - } - }) + + case line => interpretStartingWith(code + "\n" + line) + } } - /** Here we place ourselves between the user and the interpreter and examine - * the input they are ostensibly submitting. We intervene in several cases: + /* Here we place ourselves between the user and the interpreter and examine + * the input they are ostensibly submitting. We intervene in several cases: * - * 1) If the line starts with "scala> " it is assumed to be an interpreter paste. - * 2) If the line starts with "." (but not ".." or "./") it is treated as an invocation - * on the previous result. - * 3) If the Completion object's execute returns Some(_), we inject that value - * and avoid the interpreter, as it's likely not valid scala code. + * 1) If the line starts with "scala> " it is assumed to be an interpreter paste. + * 2) If the line starts with "." (but not ".." or "./") it is treated as an invocation + * on the previous result. + * 3) If the Completion object's execute returns Some(_), we inject that value + * and avoid the interpreter, as it's likely not valid scala code. */ - if (code == "") None - else if (!paste.running && paste.isPrompted(code)) { - paste.transcript(code) - None - } - else if (Completion.looksLikeInvocation(code) && intp.mostRecentVar != "") { - interpretStartingWith(intp.mostRecentVar + code) + code match { + case "" => None + case lineComment() => None // line comment, do nothing + case paste() if !paste.running => paste.transcript(code) ; None + case invocation() if intp.mostRecentVar != "" => interpretStartingWith(intp.mostRecentVar + code) + case _ => reallyInterpret } - else if (code.trim startsWith "//") { - // line comment, do nothing - None - } - else - reallyInterpret._2 } // runs :load `file` on any files passed via -i diff --git a/src/repl/scala/tools/nsc/interpreter/Pasted.scala b/src/repl/scala/tools/nsc/interpreter/Pasted.scala index 1600f32946..5f388eb15b 100644 --- a/src/repl/scala/tools/nsc/interpreter/Pasted.scala +++ b/src/repl/scala/tools/nsc/interpreter/Pasted.scala @@ -85,7 +85,7 @@ abstract class Pasted { case _ => code } - def run() { + def run(): Unit = { println("// Replaying %d commands from transcript.\n" format cmds.size) cmds foreach { cmd => print(ActualPromptString) -- cgit v1.2.3