clean up whitespace handling in commands. fixes #97

This commit is contained in:
Mark Harrah 2011-07-12 07:47:31 -04:00
parent eb14e97485
commit cbf7b82cdb
3 changed files with 21 additions and 5 deletions

View File

@ -50,8 +50,8 @@ object Command
def single(name: String, briefHelp: (String, String), detail: String)(f: (State, String) => State): Command =
single(name, Help(name, briefHelp, detail) )(f)
def single(name: String, help: Help*)(f: (State, String) => State): Command =
make(name, help : _*)( state => token(trimmed(any.+.string) map apply1(f, state)) )
make(name, help : _*)( state => token(trimmed(spacedAny(name)) map apply1(f, state)) )
def custom(parser: State => Parser[() => State], help: Seq[Help] = Nil): Command = new ArbitraryCommand(parser, help, AttributeMap.empty)
def arb[T](parser: State => Parser[T], help: Help*)(effect: (State, T) => State): Command = custom(applyEffect(parser)(effect), help)
@ -130,6 +130,10 @@ object Command
bs.map { b => (b, distance(a, b) ) } filter (_._2 <= maxDistance) sortBy(_._2) take(maxSuggestions) map(_._1)
def distance(a: String, b: String): Int =
EditDistance.levenshtein(a, b, insertCost = 1, deleteCost = 1, subCost = 2, transposeCost = 1, matchCost = -1, true)
def spacedAny(name: String): Parser[String] = spacedC(name, any)
def spacedC(name: String, c: Parser[Char]): Parser[String] =
( (c & opOrIDSpaced(name)) ~ c.+) map { case (f, rem) => (f +: rem).mkString }
}
trait Help

View File

@ -17,8 +17,12 @@ object Cross
def switchParser(state: State): Parser[(String, String)] =
{
val knownVersions = crossVersions(state)
token(Switch ~ Space) flatMap { _ => token(NotSpace.examples(knownVersions : _*)) ~ (token(Space ~> matched(state.combinedParser)) ?? "") }
lazy val switchArgs = token(OptSpace ~> NotSpace.examples(knownVersions : _*)) ~ (token(Space ~> matched(state.combinedParser)) ?? "")
lazy val nextSpaced = spacedFirst(Switch)
token(Switch) flatMap { _ => switchArgs & nextSpaced }
}
def spacedFirst(name: String) = opOrIDSpaced(name) ~ any.+
lazy val switchVersion = Command.arb(requireSession(switchParser)) { case (state, (version, command)) =>
val x = Project.extract(state)
import x._
@ -32,7 +36,7 @@ object Cross
s.key.key == scalaVersion.key || s.key.key == scalaHome.key
def crossParser(state: State): Parser[String] =
token(Cross ~ Space) flatMap { _ => token(matched(state.combinedParser)) }
token(Cross <~ OptSpace) flatMap { _ => token(matched( state.combinedParser & spacedFirst(Cross) )) }
lazy val crossBuild = Command.arb(requireSession(crossParser)) { (state, command) =>
val x = Project.extract(state)

View File

@ -11,7 +11,7 @@ package sbt.complete
// Some predefined parsers
trait Parsers
{
lazy val any: Parser[Char] = charClass(_ => true)
lazy val any: Parser[Char] = charClass(_ => true, "any character")
lazy val DigitSet = Set("0","1","2","3","4","5","6","7","8","9")
lazy val Digit = charClass(_.isDigit, "digit") examples DigitSet
@ -23,6 +23,14 @@ trait Parsers
lazy val Op = OpChar.+.string
lazy val OpOrID = ID | Op
def opOrIDSpaced(s: String): Parser[Char] =
if(DefaultParsers.matches(ID, s))
OpChar | SpaceClass
else if(DefaultParsers.matches(Op, s))
IDStart | SpaceClass
else
any
def isOpChar(c: Char) = !isDelimiter(c) && isOpType(getType(c))
def isOpType(cat: Int) = cat match { case MATH_SYMBOL | OTHER_SYMBOL | DASH_PUNCTUATION | OTHER_PUNCTUATION | MODIFIER_SYMBOL | CURRENCY_SYMBOL => true; case _ => false }
def isIDChar(c: Char) = c.isLetterOrDigit || c == '-' || c == '_'