Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
151 lines (137 sloc) 5.73 KB
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt.complete
/**
* Represents a set of completions.
* It exists instead of implicitly defined operations on top of Set[Completion]
* for laziness.
*/
sealed trait Completions
{
def get: Set[Completion]
final def x(o: Completions): Completions = flatMap(_ x o)
final def ++(o: Completions): Completions = Completions( get ++ o.get )
final def +:(o: Completion): Completions = Completions(get + o)
final def filter(f: Completion => Boolean): Completions = Completions(get filter f)
final def filterS(f: String => Boolean): Completions = filter(c => f(c.append))
override def toString = get.mkString("Completions(",",",")")
final def flatMap(f: Completion => Completions): Completions = Completions(get.flatMap(c => f(c).get))
final def map(f: Completion => Completion): Completions = Completions(get map f)
override final def hashCode = get.hashCode
override final def equals(o: Any) = o match { case c: Completions => get == c.get; case _ => false }
}
object Completions
{
/** Returns a lazy Completions instance using the provided Completion Set. */
def apply(cs: => Set[Completion]): Completions = new Completions {
lazy val get = cs
}
/** Returns a strict Completions instance using the provided Completion Set. */
def strict(cs: Set[Completion]): Completions = apply(cs)
/** No suggested completions, not even the empty Completion.
* This typically represents invalid input. */
val nil: Completions = strict(Set.empty)
/** Only includes an empty Suggestion.
* This typically represents valid input that either has no completions or accepts no further input. */
val empty: Completions = strict(Set.empty + Completion.empty)
/** Returns a strict Completions instance containing only the provided Completion.*/
def single(c: Completion): Completions = strict(Set.empty + c)
}
/**
* Represents a completion.
* The abstract members `display` and `append` are best explained with an example.
*
* Assuming space-delimited tokens, processing this:
* am is are w<TAB>
* could produce these Completions:
* Completion { display = "was"; append = "as" }
* Completion { display = "were"; append = "ere" }
* to suggest the tokens "was" and "were".
*
* In this way, two pieces of information are preserved:
* 1) what needs to be appended to the current input if a completion is selected
* 2) the full token being completed, which is useful for presenting a user with choices to select
*/
sealed trait Completion
{
/** The proposed suffix to append to the existing input to complete the last token in the input.*/
def append: String
/** The string to present to the user to represent the full token being suggested.*/
def display: String
/** True if this Completion is suggesting the empty string.*/
def isEmpty: Boolean
/** Appends the completions in `o` with the completions in this Completion.*/
def ++(o: Completion): Completion = Completion.concat(this, o)
final def x(o: Completions): Completions = if(Completion evaluatesRight this) o.map(this ++ _) else Completions.strict(Set.empty + this)
override final lazy val hashCode = Completion.hashCode(this)
override final def equals(o: Any) = o match { case c: Completion => Completion.equal(this, c); case _ => false }
}
final class DisplayOnly(val display: String) extends Completion
{
def isEmpty = display.isEmpty
def append = ""
override def toString = "{" + display + "}"
}
final class Token(val display: String, val append: String) extends Completion
{
@deprecated("Retained only for compatibility. All information is now in `display` and `append`.", "0.12.1")
lazy val prepend = display.stripSuffix(append)
def isEmpty = display.isEmpty && append.isEmpty
override final def toString = "[" + display + "]++" + append
}
final class Suggestion(val append: String) extends Completion
{
def isEmpty = append.isEmpty
def display = append
override def toString = append
}
object Completion
{
def concat(a: Completion, b: Completion): Completion =
(a,b) match
{
case (as: Suggestion, bs: Suggestion) => suggestion(as.append + bs.append)
case (at: Token, _) if at.append.isEmpty => b
case _ if a.isEmpty => b
case _ => a
}
def evaluatesRight(a: Completion): Boolean =
a match
{
case _: Suggestion => true
case at: Token if at.append.isEmpty => true
case _ => a.isEmpty
}
def equal(a: Completion, b: Completion): Boolean =
(a,b) match
{
case (as: Suggestion, bs: Suggestion) => as.append == bs.append
case (ad: DisplayOnly, bd: DisplayOnly) => ad.display == bd.display
case (at: Token, bt: Token) => at.display == bt.display && at.append == bt.append
case _ => false
}
def hashCode(a: Completion): Int =
a match
{
case as: Suggestion => (0, as.append).hashCode
case ad: DisplayOnly => (1, ad.display).hashCode
case at: Token => (2, at.display, at.append).hashCode
}
val empty: Completion = suggestion("")
def single(c: Char): Completion = suggestion(c.toString)
// TODO: make strict in 0.13.0 to match DisplayOnly
def displayOnly(value: => String): Completion = new DisplayOnly(value)
@deprecated("Use displayOnly.", "0.12.1")
def displayStrict(value: String): Completion = displayOnly(value)
// TODO: make strict in 0.13.0 to match Token
def token(prepend: => String, append: => String): Completion = new Token(prepend+append, append)
@deprecated("Use token.", "0.12.1")
def tokenStrict(prepend: String, append: String): Completion = token(prepend, append)
/** @since 0.12.1 */
def tokenDisplay(append: String, display: String): Completion = new Token(display, append)
// TODO: make strict in 0.13.0 to match Suggestion
def suggestion(value: => String): Completion = new Suggestion(value)
@deprecated("Use suggestion.", "0.12.1")
def suggestStrict(value: String): Completion = suggestion(value)
}
Jump to Line
Something went wrong with that request. Please try again.