diff --git a/main-settings/src/main/scala/sbt/SlashSyntax.scala b/main-settings/src/main/scala/sbt/SlashSyntax.scala index 0e512c487..93d31b1aa 100644 --- a/main-settings/src/main/scala/sbt/SlashSyntax.scala +++ b/main-settings/src/main/scala/sbt/SlashSyntax.scala @@ -50,18 +50,25 @@ trait SlashSyntax { */ implicit def sbtSlashSyntaxRichScopeFromScoped(t: Scoped): RichScope = new RichScope(t.scope.copy(task = Select(t.key))) + + implicit def sbtSlashSyntaxRichScopeFromAttributeKey(a: AttributeKey[_]): RichScope = + Scope(This, This, Select(a), This) + } object SlashSyntax { - /** RichScopeLike wraps a general scope to provide the `/` operator for key scoping. */ - sealed trait RichScopeLike { + sealed trait HasSlashKey { protected def scope: Scope final def /[K](key: Scoped.ScopingSetting[K]): K = key in scope } + sealed trait HasSlashKeyOrAttrKey extends HasSlashKey { + final def /(key: AttributeKey[_]): RichScope = new RichScope(scope in key) + } + /** RichReference wraps a reference to provide the `/` operator for scoping. */ - final class RichReference(protected val scope: Scope) extends RichScopeLike { + final class RichReference(protected val scope: Scope) extends HasSlashKeyOrAttrKey { def /(c: ConfigKey): RichConfiguration = new RichConfiguration(scope in c) def /(c: Configuration): RichConfiguration = new RichConfiguration(scope in c) @@ -71,12 +78,13 @@ object SlashSyntax { } /** RichConfiguration wraps a configuration to provide the `/` operator for scoping. */ - final class RichConfiguration(protected val scope: Scope) extends RichScopeLike { + final class RichConfiguration(protected val scope: Scope) extends HasSlashKeyOrAttrKey { // This is for handling `Zero / Zero / Zero / name`. def /(taskAxis: ScopeAxis[AttributeKey[_]]): RichScope = new RichScope(scope.copy(task = taskAxis)) } /** RichScope wraps a general scope to provide the `/` operator for scoping. */ - final class RichScope(protected val scope: Scope) extends RichScopeLike {} + final class RichScope(protected val scope: Scope) extends HasSlashKey + } diff --git a/main-settings/src/test/scala/sbt/SlashSyntaxSpec.scala b/main-settings/src/test/scala/sbt/SlashSyntaxSpec.scala index 8a267f81a..93a2e77bb 100644 --- a/main-settings/src/test/scala/sbt/SlashSyntaxSpec.scala +++ b/main-settings/src/test/scala/sbt/SlashSyntaxSpec.scala @@ -148,6 +148,22 @@ object SlashSyntaxSpec extends Properties("SlashSyntax") with SlashSyntax { check[InputKey[String]] && check[SettingKey[String]] && check[TaskKey[String]] } + property("Reference / task.key / key == key in Reference in task") = { + def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = + forAll((r: Reference, t: K, k: K) => expectValue(k in (r, t))(r / t.key / k)) + (true + && check[InputKey[String], InputKey[String]] + && check[InputKey[String], SettingKey[String]] + && check[InputKey[String], TaskKey[String]] + && check[SettingKey[String], InputKey[String]] + && check[SettingKey[String], SettingKey[String]] + && check[SettingKey[String], TaskKey[String]] + && check[TaskKey[String], InputKey[String]] + && check[TaskKey[String], SettingKey[String]] + && check[TaskKey[String], TaskKey[String]] + ) + } + property("Reference / task / key ~= key in Reference in task") = { import WithoutScope._ def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = @@ -165,6 +181,22 @@ object SlashSyntaxSpec extends Properties("SlashSyntax") with SlashSyntax { ) } + property("Reference / Config / task.key / key == key in Reference in Config in task") = { + def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = + forAll((r: Reference, c: ConfigKey, t: K, k: K) => expectValue(k in (r, c, t))(r / c / t.key / k)) + (true + && check[InputKey[String], InputKey[String]] + && check[InputKey[String], SettingKey[String]] + && check[InputKey[String], TaskKey[String]] + && check[SettingKey[String], InputKey[String]] + && check[SettingKey[String], SettingKey[String]] + && check[SettingKey[String], TaskKey[String]] + && check[TaskKey[String], InputKey[String]] + && check[TaskKey[String], SettingKey[String]] + && check[TaskKey[String], TaskKey[String]] + ) + } + property("Reference / Config / task / key ~= key in Reference in Config in task") = { import WithoutScope._ def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = @@ -188,6 +220,22 @@ object SlashSyntaxSpec extends Properties("SlashSyntax") with SlashSyntax { check[InputKey[String]] && check[SettingKey[String]] && check[TaskKey[String]] } + property("Config / task.key / key == key in Config in task") = { + def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = + forAll((c: ConfigKey, t: K, k: K) => expectValue(k in c in t)(c / t.key / k)) + (true + && check[InputKey[String], InputKey[String]] + && check[InputKey[String], SettingKey[String]] + && check[InputKey[String], TaskKey[String]] + && check[SettingKey[String], InputKey[String]] + && check[SettingKey[String], SettingKey[String]] + && check[SettingKey[String], TaskKey[String]] + && check[TaskKey[String], InputKey[String]] + && check[TaskKey[String], SettingKey[String]] + && check[TaskKey[String], TaskKey[String]] + ) + } + property("Config / task / key ~= key in Config in task") = { import WithoutScope._ def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = @@ -205,6 +253,22 @@ object SlashSyntaxSpec extends Properties("SlashSyntax") with SlashSyntax { ) } + property("task / key == key in task") = { + def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] = + forAll((t: K, k: K) => expectValue(k in t)(t.key / k)) + (true + && check[InputKey[String], InputKey[String]] + && check[InputKey[String], SettingKey[String]] + && check[InputKey[String], TaskKey[String]] + && check[SettingKey[String], InputKey[String]] + && check[SettingKey[String], SettingKey[String]] + && check[SettingKey[String], TaskKey[String]] + && check[TaskKey[String], InputKey[String]] + && check[TaskKey[String], SettingKey[String]] + && check[TaskKey[String], TaskKey[String]] + ) + } + property("task / key ~= key in task") = { import WithoutScope._ def check[T <: Key[T]: Arbitrary, K <: Key[K]: Arbitrary] =