diff --git a/main/src/main/scala/sbt/internal/Act.scala b/main/src/main/scala/sbt/internal/Act.scala index 982621665..9e595cea3 100644 --- a/main/src/main/scala/sbt/internal/Act.scala +++ b/main/src/main/scala/sbt/internal/Act.scala @@ -18,6 +18,7 @@ import java.net.URI import sbt.internal.CommandStrings.{ MultiTaskCommand, ShowCommand, PrintCommand } import sbt.internal.util.{ AttributeEntry, AttributeKey, AttributeMap, IMap, Settings, Util } import sbt.util.Show +import scala.collection.mutable final class ParsedKey(val key: ScopedKey[_], val mask: ScopeMask) @@ -73,14 +74,19 @@ object Act { defaultConfigs: Option[ResolvedReference] => Seq[String], keyMap: Map[String, AttributeKey[_]] ): Parser[Seq[Parser[ParsedKey]]] = { + val confParserCache: mutable.Map[Option[sbt.ResolvedReference], Parser[ParsedAxis[String]]] = + mutable.Map.empty def fullKey = for { rawProject <- optProjectRef(index, current) proj = resolveProject(rawProject, current) - confAmb <- configIdent( - index configs proj, - index configIdents proj, - index.fromConfigIdent(proj) + confAmb <- confParserCache.getOrElseUpdate( + proj, + configIdent( + index.configs(proj), + index.configIdents(proj), + index.fromConfigIdent(proj) + ) ) partialMask = ScopeMask(rawProject.isExplicit, confAmb.isExplicit, false, false) } yield taskKeyExtra(index, defaultConfigs, keyMap, proj, confAmb, partialMask) diff --git a/main/src/main/scala/sbt/internal/KeyIndex.scala b/main/src/main/scala/sbt/internal/KeyIndex.scala index 343f1d20f..5ce2469ac 100644 --- a/main/src/main/scala/sbt/internal/KeyIndex.scala +++ b/main/src/main/scala/sbt/internal/KeyIndex.scala @@ -194,6 +194,7 @@ private[sbt] final class ConfigIndex( } def configs: Set[String] = data.keySet + private[sbt] lazy val idents: Set[String] = configIdentToName.keySet // guess Configuration name from an identifier. // There's a guessing involved because we could have scoped key that Project is not aware of. @@ -201,6 +202,7 @@ private[sbt] final class ConfigIndex( configIdentToName.getOrElse(ident, Scope.unguessConfigIdent(ident)) } private[sbt] object ConfigIndex + private[sbt] final class ProjectIndex(val data: Map[Option[String], ConfigIndex]) { def add( id: Option[String], @@ -234,7 +236,7 @@ private[sbt] final class KeyIndex0(val data: BuildIndex) extends ExtendableKeyIn def configs(project: Option[ResolvedReference]): Set[String] = confIndex(project).configs private[sbt] def configIdents(project: Option[ResolvedReference]): Set[String] = - confIndex(project).configs + confIndex(project).idents private[sbt] def fromConfigIdent(proj: Option[ResolvedReference])(configIdent: String): String = confIndex(proj).fromConfigIdent(configIdent) diff --git a/main/src/test/scala/testpkg/CompletionSpec.scala b/main/src/test/scala/testpkg/CompletionSpec.scala index ff57d02ae..686001859 100644 --- a/main/src/test/scala/testpkg/CompletionSpec.scala +++ b/main/src/test/scala/testpkg/CompletionSpec.scala @@ -28,13 +28,13 @@ object CompletionSpec extends Properties { property("can complete any project", TestBuild.nonEmptyId.forAll.map { id => complete(projectID = id, line = id.head.toString, expected = id) }), - // property( - // "can complete any configuration", - // TestBuild.nonEmptyId.forAll.map { name => - // val cap = name.capitalize - // complete(configName = name, line = cap.head.toString, expected = cap) - // } - // ), + property( + "can complete any configuration", + TestBuild.nonEmptyId.forAll.map { name => + val cap = name.capitalize + complete(configName = name, line = cap.head.toString, expected = cap) + } + ), // property("can complete any attribute", TestBuild.kebabIdGen.forAll.map { name => // complete(attributeName = name, line = name.head.toString, expected = name) // })