Transition to all camelCase key labels.

1. Hyphenated labels are still accepted when parsing scoped keys (so 'sbt test-only' still works)
   There is currently no timeline for removing this support for hyphenated keys.
2. Only camelCase is shown for tab completion.
3. AttributeKey.rawLabel provides the unnormalized label.
   This should only be used to implement support for accepting hyphenated keys as input for compatibility.
4. AttributeKey.normLabel provides the normalized label (hyphenated converted to camelCase)
This commit is contained in:
Mark Harrah 2012-11-13 14:52:33 -05:00
parent 49e7214fe3
commit a38bce8d41
7 changed files with 28 additions and 12 deletions

View File

@ -131,8 +131,9 @@ object Act
def key(index: KeyIndex, proj: Option[ResolvedReference], conf: Option[String], task: Option[AttributeKey[_]], keyMap: Map[String,AttributeKey[_]]): Parser[AttributeKey[_]] = def key(index: KeyIndex, proj: Option[ResolvedReference], conf: Option[String], task: Option[AttributeKey[_]], keyMap: Map[String,AttributeKey[_]]): Parser[AttributeKey[_]] =
{ {
def dropHyphenated(keys: Set[String]): Set[String] = keys.filterNot(Util.hasHyphen)
def keyParser(keys: Set[String]): Parser[AttributeKey[_]] = def keyParser(keys: Set[String]): Parser[AttributeKey[_]] =
token(ID !!! "Expected key" examples keys) flatMap { keyString=> token(ID !!! "Expected key" examples dropHyphenated(keys)) flatMap { keyString=>
getKey(keyMap, keyString, idFun) getKey(keyMap, keyString, idFun)
} }
keyParser(index.keys(proj, conf, task)) keyParser(index.keys(proj, conf, task))
@ -155,9 +156,11 @@ object Act
def taskAxis(d: Option[String], tasks: Set[AttributeKey[_]], allKnown: Map[String, AttributeKey[_]]): Parser[ParsedAxis[AttributeKey[_]]] = def taskAxis(d: Option[String], tasks: Set[AttributeKey[_]], allKnown: Map[String, AttributeKey[_]]): Parser[ParsedAxis[AttributeKey[_]]] =
{ {
val knownKeys: Map[String, AttributeKey[_]] = tasks.toSeq.map(key => (key.label, key)).toMap val taskSeq = tasks.toSeq
val valid = allKnown ++ knownKeys def taskKeys(f: AttributeKey[_] => String): Seq[(String, AttributeKey[_])] = taskSeq.map(key => (f(key), key))
val suggested = knownKeys.keySet val normKeys = taskKeys(_.label)
val valid = allKnown ++ normKeys ++ taskKeys(_.rawLabel)
val suggested = normKeys.map(_._1).toSet
val keyP = filterStrings(examples(ID, suggested, "key"), valid.keySet, "key") map valid val keyP = filterStrings(examples(ID, suggested, "key"), valid.keySet, "key") map valid
(token(value(keyP) | GlobalString ^^^ ParsedGlobal ) <~ token("::".id) ) ?? Omitted (token(value(keyP) | GlobalString ^^^ ParsedGlobal ) <~ token("::".id) ) ?? Omitted
} }

View File

@ -125,9 +125,12 @@ object Index
settings.flatMap(s => if(s.key.key.isLocal) Nil else s.key +: s.dependencies).filter(!_.key.isLocal).toSet settings.flatMap(s => if(s.key.key.isLocal) Nil else s.key +: s.dependencies).filter(!_.key.isLocal).toSet
def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[_]] = def attributeKeys(settings: Settings[Scope]): Set[AttributeKey[_]] =
settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]] settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]]
def stringToKeyMap(settings: Set[AttributeKey[_]]): Map[String, AttributeKey[_]] = def stringToKeyMap(settings: Set[AttributeKey[_]]): Map[String, AttributeKey[_]] =
stringToKeyMap0(settings)(_.rawLabel) ++ stringToKeyMap0(settings)(_.label)
private[this] def stringToKeyMap0(settings: Set[AttributeKey[_]])(label: AttributeKey[_] => String): Map[String, AttributeKey[_]] =
{ {
val multiMap = settings.groupBy(_.label) val multiMap = settings.groupBy(label)
val duplicates = multiMap collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) } collect { case (k, xs) if xs.size > 1 => (k, xs) } val duplicates = multiMap collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) } collect { case (k, xs) if xs.size > 1 => (k, xs) }
if(duplicates.isEmpty) if(duplicates.isEmpty)
multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap; multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap;

View File

@ -62,7 +62,7 @@ trait ExtendableKeyIndex extends KeyIndex
// task axis <-> key // task axis <-> key
private final class AKeyIndex(val data: Relation[ Option[AttributeKey[_]], String]) private final class AKeyIndex(val data: Relation[ Option[AttributeKey[_]], String])
{ {
def add(task: Option[AttributeKey[_]], key: AttributeKey[_]): AKeyIndex = new AKeyIndex(data + (task, key.label)) def add(task: Option[AttributeKey[_]], key: AttributeKey[_]): AKeyIndex = new AKeyIndex(data + (task, key.rawLabel) + (task, key.label))
def keys(task: Option[AttributeKey[_]]): Set[String] = data.forward(task) def keys(task: Option[AttributeKey[_]]): Set[String] = data.forward(task)
def allKeys: Set[String] = data._2s.toSet def allKeys: Set[String] = data._2s.toSet
def tasks: Set[AttributeKey[_]] = data._1s.flatten.toSet def tasks: Set[AttributeKey[_]] = data._1s.flatten.toSet

View File

@ -163,7 +163,7 @@ object BuiltinCommands
val extracted = Project.extract(s) val extracted = Project.extract(s)
import extracted._ import extracted._
val index = structure.index val index = structure.index
index.keyIndex.keys(Some(currentRef)).toSeq map index.keyMap index.keyIndex.keys(Some(currentRef)).toSeq.map(index.keyMap).distinct
} }
def sortByLabel(keys: Seq[AttributeKey[_]]): Seq[AttributeKey[_]] = keys.sortBy(_.label) def sortByLabel(keys: Seq[AttributeKey[_]]): Seq[AttributeKey[_]] = keys.sortBy(_.label)

View File

@ -285,7 +285,7 @@ private[sbt] object SettingCompletions
/** Transforms the hypenated key label `k` into camel-case and quotes it with backticks if it is a Scala keyword. /** Transforms the hypenated key label `k` into camel-case and quotes it with backticks if it is a Scala keyword.
* This is intended to be an estimate of the Scala identifier that may be used to reference the keyword in the default sbt context. */ * This is intended to be an estimate of the Scala identifier that may be used to reference the keyword in the default sbt context. */
def keyScalaID(k: String): String = Util.quoteIfKeyword(Util.hypenToCamel(k)) def keyScalaID(k: String): String = Util.quoteIfKeyword(Util.hyphenToCamel(k))
/** Transforms the configuration name `c` so that the first letter is capitalized and the name is quoted with backticks if it is a Scala keyword. /** Transforms the configuration name `c` so that the first letter is capitalized and the name is quoted with backticks if it is a Scala keyword.
* This is intended to be an estimate of the Scala identifier that may be used to reference the keyword in the default sbt context. */ * This is intended to be an estimate of the Scala identifier that may be used to reference the keyword in the default sbt context. */

View File

@ -11,6 +11,8 @@ import scala.reflect.Manifest
// a single AttributeKey instance cannot conform to AttributeKey[T] for different Ts // a single AttributeKey instance cannot conform to AttributeKey[T] for different Ts
sealed trait AttributeKey[T] { sealed trait AttributeKey[T] {
def manifest: Manifest[T] def manifest: Manifest[T]
@deprecated("Should only be used for compatibility during the transition from hyphenated labels to camelCase labels.", "0.13.0")
def rawLabel: String
def label: String def label: String
def description: Option[String] def description: Option[String]
def extend: Seq[AttributeKey[_]] def extend: Seq[AttributeKey[_]]
@ -48,13 +50,15 @@ object AttributeKey
private[this] def make[T](name: String, description0: Option[String], extend0: Seq[AttributeKey[_]], rank0: Int)(implicit mf: Manifest[T]): AttributeKey[T] = new SharedAttributeKey[T] { private[this] def make[T](name: String, description0: Option[String], extend0: Seq[AttributeKey[_]], rank0: Int)(implicit mf: Manifest[T]): AttributeKey[T] = new SharedAttributeKey[T] {
def manifest = mf def manifest = mf
def label = name def rawLabel = name
val label = Util.hyphenToCamel(name)
def description = description0 def description = description0
def extend = extend0 def extend = extend0
def rank = rank0 def rank = rank0
} }
private[sbt] def local[T](implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { private[sbt] def local[T](implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] {
def manifest = mf def manifest = mf
def rawLabel = LocalLabel
def label = LocalLabel def label = LocalLabel
def description = None def description = None
def extend = Nil def extend = Nil

View File

@ -26,8 +26,14 @@ object Util
def pairID[A,B] = (a: A, b: B) => (a,b) def pairID[A,B] = (a: A, b: B) => (a,b)
private[this] lazy val Hypen = """-(\p{javaLowerCase})""".r private[this] lazy val Hypen = """-(\p{javaLowerCase})""".r
def hypenToCamel(s: String): String = def hasHyphen(s: String): Boolean = s.indexOf('-') >= 0
Hypen.replaceAllIn(s, _.group(1).toUpperCase) @deprecated("Use the properly spelled version: hyphenToCamel", "0.13.0")
def hypenToCamel(s: String): String = hyphenToCamel(s)
def hyphenToCamel(s: String): String =
if(hasHyphen(s))
Hypen.replaceAllIn(s, _.group(1).toUpperCase)
else
s
private[this] lazy val Camel = """(\p{javaLowerCase})(\p{javaUpperCase})""".r private[this] lazy val Camel = """(\p{javaLowerCase})(\p{javaUpperCase})""".r
def camelToHypen(s: String): String = def camelToHypen(s: String): String =