mirror of https://github.com/sbt/sbt.git
Add LabeledFunctions to repo
I noticed that debugging settings that return functions is annoying because often the setting is initialized as an anonymous function with a useless toString method. To improve the debugging for users, I'm adding a number of wrapper classes for functions that override the default toString with a provided label. I then used these functions to label all of the anonymous functions in Watched.scala.
This commit is contained in:
parent
ed1200a763
commit
2b831e5988
|
|
@ -17,6 +17,7 @@ import sbt.BasicCommandStrings.{
|
||||||
continuousDetail
|
continuousDetail
|
||||||
}
|
}
|
||||||
import sbt.BasicCommands.otherCommandParser
|
import sbt.BasicCommands.otherCommandParser
|
||||||
|
import sbt.internal.LabeledFunctions._
|
||||||
import sbt.internal.LegacyWatched
|
import sbt.internal.LegacyWatched
|
||||||
import sbt.internal.inc.Stamper
|
import sbt.internal.inc.Stamper
|
||||||
import sbt.internal.io.{ EventMonitor, Source, WatchState }
|
import sbt.internal.io.{ EventMonitor, Source, WatchState }
|
||||||
|
|
@ -159,23 +160,30 @@ object Watched {
|
||||||
private[this] val reRun = if (isWin) "" else " or 'r' to re-run the command"
|
private[this] val reRun = if (isWin) "" else " or 'r' to re-run the command"
|
||||||
private def waitMessage(project: String): String =
|
private def waitMessage(project: String): String =
|
||||||
s"Waiting for source changes$project... (press enter to interrupt$reRun)"
|
s"Waiting for source changes$project... (press enter to interrupt$reRun)"
|
||||||
val defaultStartWatch: Int => Option[String] = count => Some(s"$count. ${waitMessage("")}")
|
val defaultStartWatch: Int => Option[String] =
|
||||||
|
((count: Int) => Some(s"$count. ${waitMessage("")}")).label("Watched.defaultStartWatch")
|
||||||
@deprecated("Use defaultStartWatch in conjunction with the watchStartMessage key", "1.3.0")
|
@deprecated("Use defaultStartWatch in conjunction with the watchStartMessage key", "1.3.0")
|
||||||
val defaultWatchingMessage: WatchState => String = ws => defaultStartWatch(ws.count).get
|
val defaultWatchingMessage: WatchState => String =
|
||||||
|
((ws: WatchState) => defaultStartWatch(ws.count).get).label("Watched.defaultWatchingMessage")
|
||||||
def projectWatchingMessage(projectId: String): WatchState => String =
|
def projectWatchingMessage(projectId: String): WatchState => String =
|
||||||
ws => projectOnWatchMessage(projectId)(ws.count).get
|
((ws: WatchState) => projectOnWatchMessage(projectId)(ws.count).get)
|
||||||
|
.label("Watched.projectWatchingMessage")
|
||||||
def projectOnWatchMessage(project: String): Int => Option[String] =
|
def projectOnWatchMessage(project: String): Int => Option[String] =
|
||||||
count => Some(s"$count. ${waitMessage(s" in project $project")}")
|
((count: Int) => Some(s"$count. ${waitMessage(s" in project $project")}"))
|
||||||
|
.label("Watched.projectOnWatchMessage")
|
||||||
|
|
||||||
val defaultOnTriggerMessage: Int => Option[String] = _ => None
|
val defaultOnTriggerMessage: Int => Option[String] =
|
||||||
|
((_: Int) => None).label("Watched.defaultOnTriggerMessage")
|
||||||
@deprecated(
|
@deprecated(
|
||||||
"Use defaultOnTriggerMessage in conjunction with the watchTriggeredMessage key",
|
"Use defaultOnTriggerMessage in conjunction with the watchTriggeredMessage key",
|
||||||
"1.3.0"
|
"1.3.0"
|
||||||
)
|
)
|
||||||
val defaultTriggeredMessage: WatchState => String = const("")
|
val defaultTriggeredMessage: WatchState => String =
|
||||||
|
const("").label("Watched.defaultTriggeredMessage")
|
||||||
val clearOnTrigger: Int => Option[String] = _ => Some(clearScreen)
|
val clearOnTrigger: Int => Option[String] = _ => Some(clearScreen)
|
||||||
@deprecated("Use clearOnTrigger in conjunction with the watchTriggeredMessage key", "1.3.0")
|
@deprecated("Use clearOnTrigger in conjunction with the watchTriggeredMessage key", "1.3.0")
|
||||||
val clearWhenTriggered: WatchState => String = const(clearScreen)
|
val clearWhenTriggered: WatchState => String =
|
||||||
|
const(clearScreen).label("Watched.clearWhenTriggered")
|
||||||
def clearScreen: String = "\u001b[2J\u001b[0;0H"
|
def clearScreen: String = "\u001b[2J\u001b[0;0H"
|
||||||
|
|
||||||
object WatchSource {
|
object WatchSource {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* sbt
|
||||||
|
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||||
|
* Copyright 2008 - 2010, Mark Harrah
|
||||||
|
* Licensed under Apache License 2.0 (see LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sbt.internal
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides extension methods that allow us to wrap FunctionN instances with another FunctionN that
|
||||||
|
* delegates to the input FunctionN, but overrides the toString method with a user specified
|
||||||
|
* label. Anonymous functions have the default java toString which is just the class name. Because
|
||||||
|
* the anonymous class is generated implicitly, it can be impossible to tell which anonymous
|
||||||
|
* class you are looking at if there are multiple anonymous functions of the same type in a
|
||||||
|
* given object/class/package. We can overcome this limitation by explicitly setting the toString
|
||||||
|
* of the anonymous function instances. This is a fairly crude solution to the problem that
|
||||||
|
* is not ready to be exposed to users. Until the api matures or we decide that it's worth
|
||||||
|
* exposing to users, these should remain sbt package private.
|
||||||
|
*/
|
||||||
|
private[sbt] object LabeledFunctions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds extension methods to a zero argument function.
|
||||||
|
* @param f the function to extend
|
||||||
|
* @tparam R the function result type
|
||||||
|
*/
|
||||||
|
private[sbt] implicit class Function0Ops[R](val f: () => R) extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a label to the function.
|
||||||
|
* @param string the new toString method for the function
|
||||||
|
* @return a wrapped function with an overridden toString method.
|
||||||
|
*/
|
||||||
|
def label(string: String): () => R = new LabeledFunction0(f, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds extension methods to a single argument function.
|
||||||
|
* @param f the function to extend
|
||||||
|
* @tparam T the input parameter
|
||||||
|
* @tparam R the function result type
|
||||||
|
*/
|
||||||
|
private[sbt] implicit class Function1Ops[T, R](val f: T => R) extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a label to the function.
|
||||||
|
* @param string the new toString method for the function
|
||||||
|
* @return a wrapped function with an overridden toString method.
|
||||||
|
*/
|
||||||
|
def label(string: String): T => R = new LabeledFunction1(f, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds extension methods to a two argument function.
|
||||||
|
* @param f the function to extend
|
||||||
|
* @tparam T1 the first function input parameter
|
||||||
|
* @tparam T2 the second function input parameter
|
||||||
|
* @tparam R the function result type
|
||||||
|
*/
|
||||||
|
private[sbt] implicit class Function2Ops[T1, T2, R](val f: (T1, T2) => R) extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a label to the function.
|
||||||
|
* @param string the new toString method for the function
|
||||||
|
* @return a wrapped function with an overridden toString method.
|
||||||
|
*/
|
||||||
|
def label(string: String): (T1, T2) => R = new LabeledFunction2(f, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds extension methods to a three argument function.
|
||||||
|
* @param f the function to extend
|
||||||
|
* @tparam T1 the first function input parameter
|
||||||
|
* @tparam T2 the second function input parameter
|
||||||
|
* @tparam T3 the third function input parameter
|
||||||
|
* @tparam R the function result type
|
||||||
|
*/
|
||||||
|
private[sbt] implicit class Function3Ops[T1, T2, T3, R](val f: (T1, T2, T3) => R) extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a label to the function.
|
||||||
|
* @param string the new toString method for the function
|
||||||
|
* @return a wrapped function with an overridden toString method.
|
||||||
|
*/
|
||||||
|
def label(string: String): (T1, T2, T3) => R = new LabeledFunction3(f, string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds extension methods to a three argument function.
|
||||||
|
* @param f the function to extend
|
||||||
|
* @tparam T1 the first function input parameter
|
||||||
|
* @tparam T2 the second function input parameter
|
||||||
|
* @tparam T3 the third function input parameter
|
||||||
|
* @tparam T4 the fourth function input parameter
|
||||||
|
* @tparam R the function result type
|
||||||
|
*/
|
||||||
|
private[sbt] implicit class Function4Ops[T1, T2, T3, T4, R](val f: (T1, T2, T3, T4) => R)
|
||||||
|
extends AnyVal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a label to the function.
|
||||||
|
* @param string the new toString method for the function
|
||||||
|
* @return a wrapped function with an overridden toString method.
|
||||||
|
*/
|
||||||
|
def label(string: String): (T1, T2, T3, T4) => R = new LabeledFunction4(f, string)
|
||||||
|
}
|
||||||
|
private class LabeledFunction0[+R](private val f: () => R, label: String) extends (() => R) {
|
||||||
|
override def apply(): R = f()
|
||||||
|
override def toString: String = label
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case that: LabeledFunction0[R] @unchecked => this.f == that.f
|
||||||
|
case that: (() => R) @unchecked => this.f == that
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = f.hashCode
|
||||||
|
}
|
||||||
|
private class LabeledFunction1[-T, +R](private val f: T => R, label: String) extends (T => R) {
|
||||||
|
override def apply(t: T): R = f(t)
|
||||||
|
override def toString: String = label
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case that: LabeledFunction1[T, R] @unchecked => this.f == that.f
|
||||||
|
case that: (T => R) @unchecked => this.f == that
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = f.hashCode
|
||||||
|
}
|
||||||
|
private class LabeledFunction2[-T1, -T2, +R](private val f: (T1, T2) => R, label: String)
|
||||||
|
extends ((T1, T2) => R) {
|
||||||
|
override def apply(t1: T1, t2: T2): R = f(t1, t2)
|
||||||
|
override def toString: String = label
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case that: LabeledFunction2[T1, T2, R] @unchecked => this.f == that.f
|
||||||
|
case that: ((T1, T2) => R) @unchecked => this.f == that
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = f.hashCode
|
||||||
|
}
|
||||||
|
private class LabeledFunction3[-T1, -T2, -T3, +R](private val f: (T1, T2, T3) => R, label: String)
|
||||||
|
extends ((T1, T2, T3) => R) {
|
||||||
|
override def apply(t1: T1, t2: T2, t3: T3): R = f(t1, t2, t3)
|
||||||
|
override def toString: String = label
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case that: LabeledFunction3[T1, T2, T3, R] @unchecked => this.f == that.f
|
||||||
|
case that: ((T1, T2, T3) => R) @unchecked => this.f == that
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = f.hashCode
|
||||||
|
}
|
||||||
|
private class LabeledFunction4[-T1, -T2, -T3, T4, +R](
|
||||||
|
private val f: (T1, T2, T3, T4) => R,
|
||||||
|
label: String
|
||||||
|
) extends ((T1, T2, T3, T4) => R) {
|
||||||
|
override def apply(t1: T1, t2: T2, t3: T3, t4: T4): R = f(t1, t2, t3, t4)
|
||||||
|
override def toString: String = label
|
||||||
|
override def equals(o: Any): Boolean = o match {
|
||||||
|
case that: LabeledFunction4[T1, T2, T3, T4, R] @unchecked => this.f == that.f
|
||||||
|
case that: ((T1, T2, T3, T4) => R) @unchecked => this.f == that
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
override def hashCode: Int = f.hashCode
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue