diff --git a/main-settings/src/main/scala/sbt/Reference.scala b/main-settings/src/main/scala/sbt/Reference.scala index 3585af816..fb271916e 100644 --- a/main-settings/src/main/scala/sbt/Reference.scala +++ b/main-settings/src/main/scala/sbt/Reference.scala @@ -14,7 +14,8 @@ import java.net.URI import sbt.internal.util.AttributeKey import sbt.io.IO import sbt.librarymanagement.Configuration -import sbt.ScopeAxis.{ Select, This, RefThenConfig } +import sbt.Scope.RefThenConfig +import sbt.ScopeAxis.{ Select, This } // in all of these, the URI must be resolved and normalized before it is definitive @@ -25,13 +26,13 @@ sealed trait Reference: private[sbt] def asScope: Scope = Scope(asScopeAxis, This, This, This) - def /(c: ConfigKey): RefThenConfig = RefThenConfig(asScope.rescope(c)) + def /(c: ConfigKey): RefThenConfig = RefThenConfig(asScopeAxis, c) - def /(c: Configuration): RefThenConfig = RefThenConfig(asScope.rescope(c)) + def /(c: Configuration): RefThenConfig = RefThenConfig(asScopeAxis, c: ConfigKey) // This is for handling `Zero / Zero / name`. def /(configAxis: ScopeAxis[ConfigKey]): RefThenConfig = - RefThenConfig(asScope.copy(config = configAxis)) + RefThenConfig(asScopeAxis, configAxis) final def /[K](key: Scoped.ScopingSetting[K]): K = asScope.scope(key) diff --git a/main-settings/src/main/scala/sbt/Scope.scala b/main-settings/src/main/scala/sbt/Scope.scala index 79e2647ce..551fc8a03 100644 --- a/main-settings/src/main/scala/sbt/Scope.scala +++ b/main-settings/src/main/scala/sbt/Scope.scala @@ -430,4 +430,23 @@ object Scope: t <- withZeroAxis(scope.task) e <- withZeroAxis(scope.extra) } yield Scope(Zero, c, t, e) + + /** + * Temporary data structure to capture first two axis using slash syntax. + * In theory, we might be able to express this as type parameters of Scope, + * like Scope[Select[ThisBuild.type], Select[ConfigKey], This, This] but then + * scope becomes more complicated to deal with. + */ + opaque type RefThenConfig = (ScopeAxis[Reference], ScopeAxis[ConfigKey]) + + object RefThenConfig: + def apply(project: ScopeAxis[Reference], config: ScopeAxis[ConfigKey]): RefThenConfig = + (project, config) + def apply(project: ScopeAxis[Reference], config: ConfigKey): RefThenConfig = + (project, Select(config)) + + extension (in: RefThenConfig) + def project: ScopeAxis[Reference] = in._1 + def config: ScopeAxis[ConfigKey] = in._2 + end RefThenConfig end Scope diff --git a/main-settings/src/main/scala/sbt/ScopeAxis.scala b/main-settings/src/main/scala/sbt/ScopeAxis.scala index 6a86af166..eb92dff6d 100644 --- a/main-settings/src/main/scala/sbt/ScopeAxis.scala +++ b/main-settings/src/main/scala/sbt/ScopeAxis.scala @@ -10,10 +10,9 @@ package sbt import sbt.internal.util.Util.* import sbt.librarymanagement.Configuration -import sbt.internal.util.AttributeKey enum ScopeAxis[+A1]: - import ScopeAxis.RefThenConfig + import Scope.RefThenConfig /** * Select is a type constructor that is used to wrap type `S` @@ -57,12 +56,12 @@ enum ScopeAxis[+A1]: inline def /[K](key: Scoped.ScopingSetting[K])(using A1 <:< Reference): K = key.rescope(asScope) inline def /(c: ConfigKey)(using A1 <:< Reference): RefThenConfig = - RefThenConfig(asScope.rescope(c)) + RefThenConfig(this.asInstanceOf, c) inline def /(c: Configuration)(using A1 <:< Reference): RefThenConfig = - RefThenConfig(asScope.rescope(c)) + RefThenConfig(this.asInstanceOf, c: ConfigKey) // This is for handling `Zero / Zero / name`. inline def /(configAxis: ScopeAxis[ConfigKey])(using A1 <:< Reference): RefThenConfig = - RefThenConfig(asScope.copy(config = configAxis)) + RefThenConfig(this.asInstanceOf, configAxis) end ScopeAxis object ScopeAxis: @@ -72,15 +71,4 @@ object ScopeAxis: def fromOption[A1](o: Option[A1]): ScopeAxis[A1] = o match case Some(v) => ScopeAxis.Select(v) case None => ScopeAxis.Zero - - /** Temporary data structure to capture first two axis using slash syntax. */ - class RefThenConfig(val scope: Scope): - override def toString(): String = scope.toString() - def /[K](key: Scoped.ScopingSetting[K]): K = scope / key - - def /(task: AttributeKey[?]): Scope = scope.copy(task = Select(task)) - - /** This is for handling `Zero / Zero / Zero / name`. */ - def /(taskAxis: ScopeAxis[AttributeKey[?]]): Scope = scope.copy(task = taskAxis) - end RefThenConfig end ScopeAxis diff --git a/main-settings/src/main/scala/sbt/SlashSyntax.scala b/main-settings/src/main/scala/sbt/SlashSyntax.scala index 1eef153cf..333835014 100644 --- a/main-settings/src/main/scala/sbt/SlashSyntax.scala +++ b/main-settings/src/main/scala/sbt/SlashSyntax.scala @@ -11,6 +11,8 @@ package sbt import sbt.librarymanagement.Configuration import sbt.internal.util.AttributeKey import sbt.ScopeAxis.{ Select, This } +import sbt.Scope.RefThenConfig +import sbt.Scope.RefThenConfig.{ project, config } /** * SlashSyntax implements part of the slash syntax to scope keys for build.sbt DSL. @@ -39,6 +41,15 @@ trait SlashSyntax: def asScope: Scope = (c: ConfigKey).asScope def /[K](key: Scoped.ScopingSetting[K]): K = (c: ConfigKey) / key def /(task: AttributeKey[?]): Scope = (c: ConfigKey) / task + + extension (in: RefThenConfig) + def asScope: Scope = in.project.asScope.copy(config = in.config) + def toString(): String = asScope.toString() + def /[K](key: Scoped.ScopingSetting[K]): K = asScope / key + def /(task: AttributeKey[?]): Scope = asScope.copy(task = Select(task)) + + /** This is for handling `Zero / Zero / Zero / name`. */ + def /(taskAxis: ScopeAxis[AttributeKey[?]]): Scope = asScope.copy(task = taskAxis) end SlashSyntax private[sbt] object SlashSyntax0 extends SlashSyntax diff --git a/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala b/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala index 8eb10df9b..d9071b841 100644 --- a/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala +++ b/main/src/main/scala/sbt/coursierint/CoursierArtifactsTasks.scala @@ -19,6 +19,7 @@ import lmcoursier.definitions.{ import sbt.librarymanagement._ import sbt.Keys._ import sbt.ProjectExtra.extract +import sbt.SlashSyntax0.* object CoursierArtifactsTasks { def coursierPublicationsTask( diff --git a/main/src/main/scala/sbt/internal/ClasspathImpl.scala b/main/src/main/scala/sbt/internal/ClasspathImpl.scala index 2f8c5af69..9404f7d91 100644 --- a/main/src/main/scala/sbt/internal/ClasspathImpl.scala +++ b/main/src/main/scala/sbt/internal/ClasspathImpl.scala @@ -18,6 +18,7 @@ import sbt.Def.Initialize import sbt.internal.util.{ Attributed, Dag } import sbt.librarymanagement.{ Configuration, TrackLevel } import sbt.librarymanagement.Configurations.names +import sbt.SlashSyntax0.* import sbt.std.TaskExtra._ import sbt.util._ import scala.jdk.CollectionConverters.* diff --git a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala index 8346f8cbf..4e4e7ba93 100644 --- a/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala +++ b/main/src/main/scala/sbt/internal/server/BuildServerProtocol.scala @@ -18,6 +18,7 @@ import sbt.Keys._ import sbt.ProjectExtra.* import sbt.ScopeFilter.Make._ import sbt.Scoped.richTaskSeq +import sbt.SlashSyntax0.* import sbt.StandardMain.exchange import sbt.internal.bsp._ import sbt.internal.langserver.ErrorCodes