From 8fbf1907cec7fa89ac9aeb8182d1ac3510f36fac Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Sat, 17 Aug 2019 13:08:12 -0700 Subject: [PATCH 1/2] Allow custom show for a scope I am writing a plugin that uses mangled task keys that are very hard to read. It is helpful to be able to override the show config for these scopes so that they look reasonable in supershell and in error reporting. --- main-settings/src/main/scala/sbt/Def.scala | 14 +++++---- main-settings/src/main/scala/sbt/Scope.scala | 32 +++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/main-settings/src/main/scala/sbt/Def.scala b/main-settings/src/main/scala/sbt/Def.scala index a55ea4979..7db51382a 100644 --- a/main-settings/src/main/scala/sbt/Def.scala +++ b/main-settings/src/main/scala/sbt/Def.scala @@ -54,12 +54,14 @@ object Def extends Init[Scope] with TaskMacroExtra { keyNameColor: Option[String] = None, ): Show[ScopedKey[_]] = Show[ScopedKey[_]]( - key => - Scope.display( - key.scope, - withColor(key.key.label, keyNameColor), - ref => displayRelative2(current, ref) - ) + key => { + val color: String => String = withColor(_, keyNameColor) + key.scope.extra.toOption + .flatMap(_.get(Scope.customShowString).map(color)) + .getOrElse { + Scope.display(key.scope, color(key.key.label), ref => displayRelative2(current, ref)) + } + } ) private[sbt] def showShortKey( diff --git a/main-settings/src/main/scala/sbt/Scope.scala b/main-settings/src/main/scala/sbt/Scope.scala index d241dcdfa..bdf026b3e 100644 --- a/main-settings/src/main/scala/sbt/Scope.scala +++ b/main-settings/src/main/scala/sbt/Scope.scala @@ -178,6 +178,8 @@ object Scope { ): String = displayMasked(scope, sep, showProject, mask, false) + val customShowString = AttributeKey[String]("scope-custom-show-string") + /** * unified slash style introduced in sbt 1.1.0. * By default, sbt will no longer display the Zero-config, @@ -193,20 +195,22 @@ object Scope { showZeroConfig: Boolean ): String = { import scope.{ project, config, task, extra } - val zeroConfig = if (showZeroConfig) "Zero /" else "" - val configPrefix = config.foldStrict(display, zeroConfig, "./") - val taskPrefix = task.foldStrict(_.label + " /", "", "./") - val extras = extra.foldStrict(_.entries.map(_.toString).toList, Nil, Nil) - val postfix = if (extras.isEmpty) "" else extras.mkString("(", ", ", ")") - if (scope == GlobalScope) "Global / " + sep + postfix - else - mask.concatShow( - appendSpace(projectPrefix(project, showProject)), - appendSpace(configPrefix), - appendSpace(taskPrefix), - sep, - postfix - ) + extra.toOption.flatMap(_.get(customShowString)).getOrElse { + val zeroConfig = if (showZeroConfig) "Zero /" else "" + val configPrefix = config.foldStrict(display, zeroConfig, "./") + val taskPrefix = task.foldStrict(_.label + " /", "", "./") + val extras = extra.foldStrict(_.entries.map(_.toString).toList, Nil, Nil) + val postfix = if (extras.isEmpty) "" else extras.mkString("(", ", ", ")") + if (scope == GlobalScope) "Global / " + sep + postfix + else + mask.concatShow( + appendSpace(projectPrefix(project, showProject)), + appendSpace(configPrefix), + appendSpace(taskPrefix), + sep, + postfix + ) + } } private[sbt] def appendSpace(s: String): String = From 09f4fcf94bafa0f6ccaed9520c8fdbe4d8468cba Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Mon, 19 Aug 2019 11:23:18 -0700 Subject: [PATCH 2/2] Add test case and scaladoc --- main-settings/src/main/scala/sbt/Scope.scala | 14 ++++++ .../src/test/scala/sbt/ScopeDisplaySpec.scala | 50 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala diff --git a/main-settings/src/main/scala/sbt/Scope.scala b/main-settings/src/main/scala/sbt/Scope.scala index bdf026b3e..fe8f261f3 100644 --- a/main-settings/src/main/scala/sbt/Scope.scala +++ b/main-settings/src/main/scala/sbt/Scope.scala @@ -178,6 +178,20 @@ object Scope { ): String = displayMasked(scope, sep, showProject, mask, false) + /** + * Allows the user to override the result of `Scope.display` or `Scope.displayMasked` for a + * particular scope. This can be used to enhance super shell and/or error reporting for tasks + * that use mangled names. For example, one might have: + * {{{ + * val mangledKey = TaskKey[Unit]("foo_slash_bar") + * val attributeMap = AttributeMap.empty.put(Scope.customShowString("foo/bar")) + * val sanitizedKey = mangledKey.copy(scope = mangledKey.copy(extra = Select(attributeMap))) + * sanitizedKey := { ... } + * }}} + * + * Now whenever the `foo_slash_bar` task specified by sanitizedKey is evaluated, it will display + * "foo/bar" in super shell progress and in the error message if an error is thrown. + */ val customShowString = AttributeKey[String]("scope-custom-show-string") /** diff --git a/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala b/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala new file mode 100644 index 000000000..6c7798d67 --- /dev/null +++ b/main-settings/src/test/scala/sbt/ScopeDisplaySpec.scala @@ -0,0 +1,50 @@ +/* + * sbt + * Copyright 2011 - 2018, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt + +import org.scalatest.FlatSpec +import sbt.internal.util.{ AttributeKey, AttributeMap } +import sbt.io.syntax.file + +class ScopeDisplaySpec extends FlatSpec { + val project = ProjectRef(file("foo/bar"), "bar") + val mangledName = "bar_slash_blah_blah_blah" + val scopedKey = Def.ScopedKey(Scope.Global in project, AttributeKey[Task[String]](mangledName)) + val am = AttributeMap.empty.put(Scope.customShowString, "blah") + val sanitizedKey = scopedKey.copy(scope = scopedKey.scope.copy(extra = Select(am))) + "Def.displayRelative2" should "display mangled name" in { + assert(Def.showRelativeKey2(project, None).show(scopedKey) == mangledName) + } + it should "display sanitized name with extra setting" in { + assert(Def.showRelativeKey2(project, None).show(sanitizedKey) == "blah") + } + "Scope.display" should "display the full scope" in { + val full = Scope.display( + scopedKey.scope, + "/", + (ref: Reference) => + ref match { + case ProjectRef(_, n) => n + case _ => ??? + } + ) + assert(full == "bar /") + } + it should "display the sanitized scope" in { + val string = Scope.display( + sanitizedKey.scope, + "/", + (ref: Reference) => + ref match { + case ProjectRef(_, n) => n + case _ => ??? + } + ) + assert(string == "blah") + } +}