sbt/util/complete/TypeString.scala

77 lines
2.9 KiB
Scala

package sbt.complete
import DefaultParsers._
import TypeString._
/** Basic representation of types parsed from Manifest.toString.
* This can only represent the structure of parameterized types.
* All other types are represented by a TypeString with an empty `args`. */
private[sbt] final class TypeString(val base: String, val args: List[TypeString])
{
override def toString =
if(base.startsWith(FunctionName))
args.dropRight(1).mkString("(", ",", ")") + " => " + args.last
else if(base.startsWith(TupleName))
args.mkString("(",",",")")
else
cleanupTypeName(base) + (if(args.isEmpty) "" else args.mkString("[", ",", "]"))
}
private[sbt] object TypeString
{
/** Makes the string representation of a type as returned by Manifest.toString more readable.*/
def cleanup(typeString: String): String =
parse(typeString, typeStringParser) match {
case Right(ts) => ts.toString
case Left(err) => typeString
}
/** Makes a fully qualified type name provided by Manifest.toString more readable.
* The argument should be just a name (like scala.Tuple2) and not a full type (like scala.Tuple2[Int,Boolean])*/
def cleanupTypeName(base: String): String =
dropPrefix(base).replace('$', '.')
/** Removes prefixes from a fully qualified type name that are unnecessary in the presence of standard imports for an sbt setting.
* This does not use the compiler and is therefore a conservative approximation.*/
def dropPrefix(base: String): String =
if(base.startsWith(SbtPrefix))
base.substring(SbtPrefix.length)
else if(base.startsWith(CollectionPrefix))
{
val simple = base.substring(CollectionPrefix.length)
if(ShortenCollection(simple)) simple else base
}
else if(base.startsWith(ScalaPrefix))
base.substring(ScalaPrefix.length)
else if(base.startsWith(JavaPrefix))
base.substring(JavaPrefix.length)
else
TypeMap.getOrElse(base, base)
final val CollectionPrefix = "scala.collection."
final val FunctionName = "scala.Function"
final val TupleName = "scala.Tuple"
final val SbtPrefix = "sbt."
final val ScalaPrefix = "scala."
final val JavaPrefix = "java.lang."
/* scala.collection.X -> X */
val ShortenCollection = Set("Seq", "List", "Set", "Map", "Iterable")
val TypeMap = Map(
"java.io.File" -> "File",
"java.net.URL" -> "URL",
"java.net.URI" -> "URI"
)
/** A Parser that extracts basic structure from the string representation of a type from Manifest.toString.
* This is rudimentary and essentially only decomposes the string into names and arguments for parameterized types.
* */
lazy val typeStringParser: Parser[TypeString] =
{
def isFullScalaIDChar(c: Char) = isScalaIDChar(c) || c == '.' || c == '$'
lazy val fullScalaID = identifier(IDStart, charClass(isFullScalaIDChar, "Scala identifier character") )
lazy val tpe: Parser[TypeString] =
for( id <- fullScalaID; args <- ('[' ~> rep1sep(tpe, ',') <~ ']').?) yield
new TypeString(id, args.toList.flatten)
tpe
}
}