From 816a444f177b5f2bb90a2e89802d06c26f6a21ff Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 1 Jul 2013 00:30:16 -0700 Subject: SI-4684 Repl supports whole-file paste Add a file argument to the :paste command which loads the file's contents as though entered in :paste mode. The :paste command is replayable. Samples, including companions defined together: ``` scala> :paste junk.scala File contains no code: junk.scala scala> :paste no-file.scala That file does not exist scala> :paste obj-repl.scala Pasting file obj-repl.scala... :2: error: expected start of definition private foo = 7 ^ scala> :paste hw-repl.scala Pasting file hw-repl.scala... The pasted code is incomplete! :5: error: illegal start of simple expression } ^ scala> :replay Replaying: :paste junk.scala File contains no code: junk.scala Replaying: :paste obj-repl.scala Pasting file obj-repl.scala... defined trait Foo defined object Foo Replaying: Foo(new Foo{}) res0: Int = 7 ``` --- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 42 +++++++++++++++--------- test/files/run/repl-paste-4.pastie | 4 +++ test/files/run/repl-paste-4.scala | 20 +++++++++++ 3 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 test/files/run/repl-paste-4.pastie create mode 100644 test/files/run/repl-paste-4.scala diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index ccc9621fad..aa65a858df 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -216,8 +216,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("implicits", "[-v]", "show the implicits in scope", intp.implicitsCommand), cmd("javap", "", "disassemble a file or class name", javapCommand), cmd("line", "|", "place line(s) at the end of history", lineCommand), - cmd("load", "", "load and interpret a Scala file", loadCommand), - nullary("paste", "enter paste mode: all input up to ctrl-D compiled together", pasteCommand), + cmd("load", "", "interpret lines in a file", loadCommand), + cmd("paste", "[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), @@ -585,11 +585,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) } } - def withFile(filename: String)(action: File => Unit) { - val f = File(filename) - - if (f.exists) action(f) - else echo("That file does not exist") + def withFile[A](filename: String)(action: File => A): Option[A] = { + val res = Some(File(filename)) filter (_.exists) map action + if (res.isEmpty) echo("That file does not exist") // courtesy side-effect + res } def loadCommand(arg: String) = { @@ -665,13 +664,26 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) Iterator continually in.readLine("") takeWhile (x => x != null && cond(x)) } - def pasteCommand(): Result = { - echo("// Entering paste mode (ctrl-D to finish)\n") - val code = readWhile(_ => true) mkString "\n" - if (code.trim.isEmpty) { - echo("\n// Nothing pasted, nothing gained.\n") - } else { - echo("\n// Exiting paste mode, now interpreting.\n") + def pasteCommand(arg: String): Result = { + var shouldReplay: Option[String] = None + val code = ( + if (arg.nonEmpty) { + withFile(arg)(f => { + shouldReplay = Some(s":paste $arg") + val s = f.slurp.trim + if (s.isEmpty) echo(s"File contains no code: $f") + else echo(s"Pasting file $f...") + s + }) getOrElse "" + } else { + echo("// Entering paste mode (ctrl-D to finish)\n") + val text = (readWhile(_ => true) mkString "\n").trim + if (text.isEmpty) echo("\n// Nothing pasted, nothing gained.\n") + else echo("\n// Exiting paste mode, now interpreting.\n") + text + } + ) + if (code.nonEmpty) { val res = intp interpret code // if input is incomplete, let the compiler try to say why if (res == IR.Incomplete) { @@ -681,7 +693,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) if (errless) echo("...but compilation found no error? Good luck with that.") } } - () + Result(keepRunning = true, shouldReplay) } private object paste extends Pasted { diff --git a/test/files/run/repl-paste-4.pastie b/test/files/run/repl-paste-4.pastie new file mode 100644 index 0000000000..853a66f6a4 --- /dev/null +++ b/test/files/run/repl-paste-4.pastie @@ -0,0 +1,4 @@ + +// if we are truly companions, I can see your foo +class Foo { private val foo = 7 } +object Foo { def apply(f: Foo) = f.foo } diff --git a/test/files/run/repl-paste-4.scala b/test/files/run/repl-paste-4.scala new file mode 100644 index 0000000000..0060dc1ff6 --- /dev/null +++ b/test/files/run/repl-paste-4.scala @@ -0,0 +1,20 @@ + +import scala.tools.partest.SessionTest + +object Test extends SessionTest { + def session = +s"""|Type in expressions to have them evaluated. + |Type :help for more information. + | + |scala> :paste $pastie + |Pasting file $pastie... + |defined class Foo + |defined object Foo + | + |scala> Foo(new Foo) + |res0: Int = 7 + | + |scala> """ + def pastie = testPath changeExtension "pastie" +} + -- cgit v1.2.3 From e7468f3a1aaae7ac4a763226f0a2b9a7a375f493 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Mon, 8 Jul 2013 12:26:48 -0700 Subject: SI-4684 Repl supports raw paste By special request, :paste -raw simply compiles the pasted code to the repl output dir. The -raw flag means no wrapping; the pasted code must be ordinary top level Scala code, not script. --- src/repl/scala/tools/nsc/interpreter/ILoop.scala | 39 ++++++++++++++++++------ test/files/run/repl-paste-raw.pastie | 8 +++++ test/files/run/repl-paste-raw.scala | 20 ++++++++++++ 3 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 test/files/run/repl-paste-raw.pastie create mode 100644 test/files/run/repl-paste-raw.scala diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index aa65a858df..a623ee5055 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -217,7 +217,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) cmd("javap", "", "disassemble a file or class name", javapCommand), cmd("line", "|", "place line(s) at the end of history", lineCommand), cmd("load", "", "interpret lines in a file", loadCommand), - cmd("paste", "[path]", "enter paste mode or paste a file", pasteCommand), + 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), @@ -666,24 +666,38 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def pasteCommand(arg: String): Result = { var shouldReplay: Option[String] = None - val code = ( - if (arg.nonEmpty) { - withFile(arg)(f => { + def result = Result(keepRunning = true, shouldReplay) + val (raw, file) = + if (arg.isEmpty) (false, None) + else { + val r = """(-raw)?(\s+)?([^\-]\S*)?""".r + arg match { + case r(flag, sep, name) => + if (flag != null && name != null && sep == null) + echo(s"""I assume you mean "$flag $name"?""") + (flag != null, Option(name)) + case _ => + echo("usage: :paste -raw file") + return result + } + } + val code = file match { + case Some(name) => + withFile(name)(f => { shouldReplay = Some(s":paste $arg") val s = f.slurp.trim if (s.isEmpty) echo(s"File contains no code: $f") else echo(s"Pasting file $f...") s }) getOrElse "" - } else { + case None => echo("// Entering paste mode (ctrl-D to finish)\n") val text = (readWhile(_ => true) mkString "\n").trim if (text.isEmpty) echo("\n// Nothing pasted, nothing gained.\n") else echo("\n// Exiting paste mode, now interpreting.\n") text - } - ) - if (code.nonEmpty) { + } + def interpretCode() = { val res = intp interpret code // if input is incomplete, let the compiler try to say why if (res == IR.Incomplete) { @@ -693,7 +707,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) if (errless) echo("...but compilation found no error? Good luck with that.") } } - Result(keepRunning = true, shouldReplay) + def compileCode() = { + val errless = intp compileSources new BatchSourceFile("", code) + if (!errless) echo("There were compilation errors!") + } + if (code.nonEmpty) { + if (raw) compileCode() else interpretCode() + } + result } private object paste extends Pasted { diff --git a/test/files/run/repl-paste-raw.pastie b/test/files/run/repl-paste-raw.pastie new file mode 100644 index 0000000000..f13b4bcf8b --- /dev/null +++ b/test/files/run/repl-paste-raw.pastie @@ -0,0 +1,8 @@ + +// a raw paste is not a script +// hence it can be packaged + +package brown_paper + +// these are a few of my favorite things +case class Gift (hasString: Boolean) diff --git a/test/files/run/repl-paste-raw.scala b/test/files/run/repl-paste-raw.scala new file mode 100644 index 0000000000..2953796f99 --- /dev/null +++ b/test/files/run/repl-paste-raw.scala @@ -0,0 +1,20 @@ + +import scala.tools.partest.SessionTest + +object Test extends SessionTest { + def session = +s"""|Type in expressions to have them evaluated. + |Type :help for more information. + | + |scala> :paste -raw $pastie + |Pasting file $pastie... + | + |scala> val favoriteThing = brown_paper.Gift(true) + |favoriteThing: brown_paper.Gift = Gift(true) + | + |scala> favoriteThing.hasString + |res0: Boolean = true + | + |scala> """ + def pastie = testPath changeExtension "pastie" +} -- cgit v1.2.3