From 6b67a342ab5b9f1630cff1d8b20491fed3c2a5f5 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 3 Jun 2011 08:21:22 +0000 Subject: More polishing up repl power mode, no review. --- .../scala/tools/nsc/interpreter/ILoop.scala | 30 +++---- .../scala/tools/nsc/interpreter/ILoopInit.scala | 11 ++- .../scala/tools/nsc/interpreter/Imports.scala | 7 +- .../scala/tools/nsc/interpreter/JLineReader.scala | 9 +- .../scala/tools/nsc/interpreter/Naming.scala | 6 +- .../scala/tools/nsc/interpreter/Power.scala | 100 ++++++++++----------- test/files/run/repl-power.check | 1 - 7 files changed, 76 insertions(+), 88 deletions(-) diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 75cbf6cdbc..d794845593 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -177,15 +177,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) // When you know you are most likely breaking into the middle // of a line being typed. This softens the blow. protected def echoAndRefresh(msg: String) = { - if (in.currentLine == "") { - in.eraseLine() - echo(msg) - echoNoNL(prompt) - } - else { - echo("\n" + msg) - in.redrawLine() - } + echo("\n" + msg) + in.redrawLine() } protected def echo(msg: String) = { out println msg @@ -495,8 +488,8 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) ) val replayQuestionMessage = - """|The repl compiler has crashed spectacularly. Shall I replay your - |session? I can re-run all lines except the last one. + """|That entry seems to have slain the compiler. Shall I replay + |your session? I can re-run each line except the last one. |[y/n] """.trim.stripMargin @@ -509,14 +502,12 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) if (isReplDebug) "[searching " + sources.path + " for exception contexts...]" else "[searching for exception contexts...]" ) - echo(Exceptional(ex).force().context()) - } - else { - echo(util.stackTraceString(ex)) } + echo(intp.global.throwableAsString(ex)) + ex match { case _: NoSuchMethodError | _: NoClassDefFoundError => - echo("Unrecoverable error.") + echo("\nUnrecoverable error.") throw ex case _ => def fn(): Boolean = @@ -623,12 +614,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def powerCmd(): Result = { if (isReplPower) "Already in power mode." - else enablePowerMode() + else enablePowerMode(false) } - def enablePowerMode() = { + def enablePowerMode(isAsync: Boolean) = { replProps.power setValue true power.unleash() - echoAndRefresh(power.banner) + if (isAsync) asyncMessage(power.banner) + else echo(power.banner) } def verbosity() = { diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala index dbd4d77a44..a8fb619f97 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala @@ -24,12 +24,11 @@ trait ILoopInit { |Type :help for more information.""" . stripMargin.format(versionString, javaVmName, javaVersion) echo(welcomeMsg) - if (isReplDebug || isReplPower) - echo("[info] started at " + new java.util.Date) + replinfo("[info] started at " + new java.util.Date) } - private def asyncMessage(msg: String) { - if (isReplDebug || isReplPower) + protected def asyncMessage(msg: String) { + if (isReplInfo || isReplPower) echoAndRefresh(msg) } @@ -95,10 +94,10 @@ trait ILoopInit { // called once after init condition is signalled protected def postInitialization() { addThunk(intp.setContextClassLoader()) + if (isReplPower) + addThunk(enablePowerMode(true)) // do this last to avoid annoying uninterruptible startups addThunk(installSigIntHandler()) - if (isReplPower) - addThunk(enablePowerMode()) runThunks() initIsComplete = true diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala index df8c1e7851..10e3796404 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Imports.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala @@ -117,12 +117,11 @@ trait Imports { * 'wanted' is the set of names that need to be imported. */ def select(reqs: List[ReqAndHandler], wanted: Set[Name]): List[ReqAndHandler] = { - val isWanted = wanted contains _ // Single symbol imports might be implicits! See bug #1752. Rather than // try to finesse this, we will mimic all imports for now. def keepHandler(handler: MemberHandler) = handler match { case _: ImportHandler => true - case x => x.definesImplicit || (x.definedNames exists isWanted) + case x => x.definesImplicit || (x.definedNames exists wanted) } reqs match { @@ -160,7 +159,7 @@ trait Imports { // If the user entered an import, then just use it; add an import wrapping // level if the import might conflict with some other import case x: ImportHandler => - if (x.importsWildcard || (currentImps exists (x.importedNames contains _))) + if (x.importsWildcard || currentImps.exists(x.importedNames contains _)) addWrapper() code append (x.member + "\n") @@ -178,7 +177,7 @@ trait Imports { for (imv <- x.definedNames) { if (currentImps contains imv) addWrapper() - code append ("import %s\n" format (req fullPath imv)) + code append ("import " + (req fullPath imv) + "\n") currentImps += imv } } diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala index ed61240542..2e3dc506c6 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala @@ -68,12 +68,11 @@ class JLineReader(_completion: => Completion) extends InteractiveReader { } } - def currentLine: String = consoleReader.getCursorBuffer.buffer.toString + def currentLine = consoleReader.getCursorBuffer.buffer.toString def redrawLine() = consoleReader.redrawLineAndFlush() - def eraseLine() = { - // while (consoleReader.delete()) { } - consoleReader.eraseLine() - } + def eraseLine() = consoleReader.eraseLine() + // Alternate implementation, not sure if/when I need this. + // def eraseLine() = while (consoleReader.delete()) { } def readOneLine(prompt: String) = consoleReader readLine prompt def readOneKey(prompt: String) = consoleReader readOneKey prompt } diff --git a/src/compiler/scala/tools/nsc/interpreter/Naming.scala b/src/compiler/scala/tools/nsc/interpreter/Naming.scala index 14322620b3..89868abfb5 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Naming.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Naming.scala @@ -75,9 +75,9 @@ trait Naming { private lazy val userVar = new NameCreator(sessionNames.res) // var name, like res0 private lazy val internalVar = new NameCreator(sessionNames.ires) // internal var name, like $ires0 - def isLineName(name: String) = (name startsWith sessionNames.line) && (name stripPrefix sessionNames.line forall (_.isDigit)) - def isUserVarName(name: String) = userVar didGenerate name - def isInternalVarName(name: String): Boolean = internalVar didGenerate name + def isLineName(name: String) = (name startsWith sessionNames.line) && (name stripPrefix sessionNames.line forall (_.isDigit)) + def isUserVarName(name: String) = userVar didGenerate name + def isInternalVarName(name: String) = internalVar didGenerate name val freshLineId = { var x = 0 diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 34b324f0ca..d706cb8245 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -225,81 +225,81 @@ abstract class Power[G <: Global]( trait LowPriorityPrettifier { implicit object AnyPrettifier extends Prettifier[Any] { - def prettify(x: Any): List[String] = x match { + def show(x: Any): Unit = prettify(x) foreach println + def prettify(x: Any): TraversableOnce[String] = x match { case x: Name => List(x.decode) - case Tuple2(k, v) => List(prettify(k) ++ Seq("->") ++ prettify(v) mkString " ") + case Tuple2(k, v) => List(prettify(k).toIterator ++ Iterator("->") ++ prettify(v) mkString " ") case xs: TraversableOnce[_] => (xs.toList flatMap prettify).sorted - case x => List(rutil.stringOf(x)) + case x => List(Prettifier.stringOf(x)) } } } + object StringPrettifier extends Prettifier[String] { + def show(x: String) = println(x) + def prettify(x: String) = List(Prettifier stringOf x) + } object Prettifier extends LowPriorityPrettifier { - def prettify[T](value: T): List[String] = default[T] prettify value + def stringOf(x: Any): String = scala.runtime.ScalaRunTime.stringOf(x) + def prettify[T](value: T): TraversableOnce[String] = default[T] prettify value def default[T] = new Prettifier[T] { - def prettify(x: T): List[String] = AnyPrettifier prettify x + def prettify(x: T): TraversableOnce[String] = AnyPrettifier prettify x + def show(x: T): Unit = AnyPrettifier show x } } trait Prettifier[T] { - def prettify(x: T): List[String] - - private var indentLevel = 0 - private def spaces = " " * indentLevel - def indented[T](body: => T): T = { - indentLevel += 1 - try body - finally indentLevel -= 1 - } + def show(x: T): Unit + def prettify(x: T): TraversableOnce[String] - def show(x: T): Unit = grep(x, _ => true) - def grep(x: T, p: String => Boolean): Unit = - prettify(x) filter p foreach (x => println(spaces + x)) + def show(xs: TraversableOnce[T]): Unit = prettify(xs) foreach println + def prettify(xs: TraversableOnce[T]): TraversableOnce[String] = xs flatMap (x => prettify(x)) } - class MultiPrintingConvenience[T: Prettifier](coll: TraversableOnce[T]) { + + abstract class PrettifierClass[T: Prettifier]() { + private implicit val ord: Ordering[T] = Ordering[String] on (_.toString) val pretty = implicitly[Prettifier[T]] import pretty._ - def freqBy[U](p: T => U) = { - val map = coll.toList groupBy p - map.toList sortBy (-_._2.size) - } - def freqByFormatted[U](p: T => U) = { - val buf = new mutable.ListBuffer[String] + def value: Seq[T] - freqBy(p) foreach { case (k, vs) => - buf += "%d: %s".format(vs.size, Prettifier.prettify(k)) - vs flatMap prettify foreach (buf += " " + _) - } - buf.toList - } + def pp(f: Seq[T] => Seq[T]): Unit = + pretty prettify f(value) foreach (StringPrettifier show _) - /** It makes sense. - * - * # means how many - * ? means "I said, HOW MANY?" - * > means print - * - * Now don't you feel silly for what you were thinking. - */ - def #?>[U](p: T => U) = this freqByFormatted p foreach println - def #?[U](p: T => U) = this freqByFormatted p - } + def freq[U](p: T => U) = (value.toSeq groupBy p mapValues (_.size)).toList sortBy (-_._2) map (_.swap) + def ppfreq[U](p: T => U): Unit = freq(p) foreach { case (count, key) => println("%5d %s".format(count, key)) } - class PrintingConvenience[T: Prettifier](value: T) { - val pretty = implicitly[Prettifier[T]] + def |[U](f: Seq[T] => Seq[U]): Seq[U] = f(value) + def ^^[U](f: T => U): Seq[U] = value map f + def ^?[U](pf: PartialFunction[T, U]): Seq[U] = value collect pf + + def >>!(): Unit = pp(_.sorted.distinct) + def >>(): Unit = pp(_.sorted) + def >!(): Unit = pp(_.distinct) + def >(): Unit = pp(identity) - def >() { >(_ => true) } - def >(s: String): Unit = >(_ contains s) - def >(r: Regex): Unit = >(_ matches r.pattern.toString) - def >(p: String => Boolean): Unit = pretty.grep(value, p) + def >#(): Unit = this ># (identity[T] _) + def >#[U](p: T => U): Unit = this ppfreq p + + def >?(p: T => Boolean): Unit = pp(_ filter p) + def >?(s: String): Unit = pp(_ filter (_.toString contains s)) + def >?(r: Regex): Unit = pp(_ filter (_.toString matches r.pattern.toString)) } + + class MultiPrettifierClass[T: Prettifier](val value: Seq[T]) extends PrettifierClass[T]() { } + class SinglePrettifierClass[T: Prettifier](single: T) extends PrettifierClass[T]() { + val value = List(single) + } + class RichInputStream(in: InputStream)(implicit codec: Codec) { def bytes(): Array[Byte] = io.Streamable.bytes(in) def slurp(): String = io.Streamable.slurp(in) + def <(url: URL): String = io.Streamable.slurp(url) + def <(): String = slurp() } protected trait Implicits1 { // fallback - implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) = new PrintingConvenience[T](x) + implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) = + new SinglePrettifierClass[T](x) } trait Implicits2 extends Implicits1 { class RichSymbol(sym: Symbol) { @@ -316,7 +316,8 @@ abstract class Power[G <: Global]( implicit lazy val powerSymbolOrdering: Ordering[Symbol] = Ordering[Name] on (_.name) implicit lazy val powerTypeOrdering: Ordering[Type] = Ordering[Symbol] on (_.typeSymbol) - implicit def replCollPrinting[T: Prettifier](xs: TraversableOnce[T]): MultiPrintingConvenience[T] = new MultiPrintingConvenience[T](xs) + implicit def replMultiPrinting[T: Prettifier](xs: TraversableOnce[T]): MultiPrettifierClass[T] = + new MultiPrettifierClass[T](xs.toSeq) implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x)) implicit def replPrettifier[T] : Prettifier[T] = Prettifier.default[T] implicit def replTypeApplication(sym: Symbol): RichSymbol = new RichSymbol(sym) @@ -346,7 +347,6 @@ abstract class Power[G <: Global]( case (next, rest) => next.map(_.toChar).mkString :: strings(rest) } } - def stringOf(x: Any): String = scala.runtime.ScalaRunTime.stringOf(x) } lazy val rutil: ReplUtilities = new ReplUtilities { } diff --git a/test/files/run/repl-power.check b/test/files/run/repl-power.check index 249e0f71e8..9561c04eca 100644 --- a/test/files/run/repl-power.check +++ b/test/files/run/repl-power.check @@ -9,7 +9,6 @@ scala> :power ** New cmds! :help to discover them ** ** New defs! Type power. to reveal ** -scala> scala> // guarding against "error: reference to global is ambiguous" scala> global.emptyValDef // "it is imported twice in the same scope by ..." -- cgit v1.2.3