diff options
author | Paul Phillips <paulp@improving.org> | 2009-12-06 21:35:45 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2009-12-06 21:35:45 +0000 |
commit | 4532a5d7f1cd6bf11e2658843eabc49102a3a1b4 (patch) | |
tree | b806b3a08e1e87f5b296f9033530744e0d6dd1d2 /src/compiler | |
parent | 91d6fa1a8bc97f8b5bb5abbd82f97920393d14e1 (diff) | |
download | scala-4532a5d7f1cd6bf11e2658843eabc49102a3a1b4.tar.gz scala-4532a5d7f1cd6bf11e2658843eabc49102a3a1b4.tar.bz2 scala-4532a5d7f1cd6bf11e2658843eabc49102a3a1b4.zip |
Making the repl-shell bridge nicer.
scala> :sh find /Users/paulp -depth 1 -name '.scala*'
stdout: List[String] = List(/Users/paulp/.scala_dependencies, /Users/paulp/.scala_history, ...)
scala> stdout | "grep history" | "wc -c"
res0: Seq[String] = List( 28)
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/InterpreterLoop.scala | 26 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Process.scala | 27 |
2 files changed, 47 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/InterpreterLoop.scala b/src/compiler/scala/tools/nsc/InterpreterLoop.scala index 4d2228b6fd..8f716edd8d 100644 --- a/src/compiler/scala/tools/nsc/InterpreterLoop.scala +++ b/src/compiler/scala/tools/nsc/InterpreterLoop.scala @@ -6,11 +6,12 @@ package scala.tools.nsc -import java.io.{BufferedReader, File, FileReader, PrintWriter} +import java.io.{ BufferedReader, File, FileReader, PrintWriter } import java.io.IOException -import scala.tools.nsc.{InterpreterResults => IR} -import scala.tools.nsc.interpreter._ +import scala.tools.nsc.{ InterpreterResults => IR } +import interpreter._ +import io.{ Process } // Classes to wrap up interpreter commands and their results // You can add new commands by adding entries to val commands @@ -35,9 +36,7 @@ object InterpreterControl { } case class LineArg(name: String, help: String, f: (String) => Result) extends Command { - def apply(args: List[String]) = - if (args.size == 1) f(args.head) - else error("requires a line of input") + def apply(args: List[String]) = f(args mkString " ") } case class OneArg(name: String, help: String, f: (String) => Result) extends Command { @@ -167,6 +166,7 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { NoArgs("power", "enable power user mode", power), NoArgs("quit", "exits the interpreter", () => Result(false, None)), NoArgs("replay", "resets execution and replays all previous commands", replay), + LineArg("sh", "forks a shell and runs a command", runShellCmd), NoArgs("silent", "disable/enable automatic printing of results", verbosity) ) } @@ -256,6 +256,20 @@ class InterpreterLoop(in0: Option[BufferedReader], out: PrintWriter) { } } + /** fork a shell and run a command */ + def runShellCmd(line: String) { + // we assume if they're using :sh they'd appreciate being able to pipeline + interpreter.beQuietDuring { + interpreter.interpret("import _root_.scala.tools.nsc.io.Process.Pipe._") + } + val p = Process(line) + // only bind non-empty streams + def add(name: String, it: Iterator[String]) = + if (it.hasNext) interpreter.bind(name, "scala.List[String]", it.toList) + + List(("stdout", p.stdout), ("stderr", p.stderr)) foreach (add _).tuple + } + def withFile(filename: String)(action: String => Unit) { if (! new File(filename).exists) out.println("That file does not exist") else action(filename) diff --git a/src/compiler/scala/tools/nsc/io/Process.scala b/src/compiler/scala/tools/nsc/io/Process.scala index 7b10672699..15cbf397fb 100644 --- a/src/compiler/scala/tools/nsc/io/Process.scala +++ b/src/compiler/scala/tools/nsc/io/Process.scala @@ -37,6 +37,33 @@ object Process lazy val javaVmArguments = java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments() lazy val runtime = Runtime.getRuntime() + class Pipe[T](xs: Seq[T], stringify: T => String) { + def |(cmd: String): Seq[String] = { + val p = Process(cmd) + xs foreach (x => p.stdin println stringify(x)) + p.stdin.close() + p.stdin.flush() + p.stdout.toList + } + } + + object Pipe { + /* After importing this implicit you can say for instance + * xs | "grep foo" | "grep bar" + * and it will execute shells and pipe input/output. You can + * also implicitly or explicitly supply a function which translates + * the opening sequence into Strings; if none is given toString is used. + * + * Also, once you use :sh in the repl, this is auto-imported. + */ + implicit def seqToPipelinedProcess[T] + (xs: Seq[T]) + (implicit stringify: T => String = (x: T) => x.toString): Pipe[T] = + { + new Pipe(xs, stringify) + } + } + private[Process] class ProcessBuilder(val pb: JProcessBuilder) { def this(cmd: String*) = this(new JProcessBuilder(cmd: _*)) |