Fixes semicolon showing up in parser errors

Fixes https://github.com/sbt/sbt/issues/5039
Fixes https://github.com/sbt/sbt/issues/4989

This is take 2 on the semicolon fix by emptying out the completion examples in the multi parser.

```
> set scalaV
```

would complete to

```
> set scalaVersion
```

and more importantly

```
coursierUseSbtCredentials := true
```

errors to

```
sbt:hello> coursierUseSbtCredentials := true
[error] Expected ID character
[error] Not a valid command: coursierUseSbtCredentials
[error] Expected project ID
[error] Expected configuration
[error] Expected ':'
[error] Expected key
[error] Not a valid key: coursierUseSbtCredentials (similar: csrExtraCredentials, credentials)
[error] coursierUseSbtCredentials := true
[error]                          ^
```
This commit is contained in:
Eugene Yokota 2019-12-12 01:24:33 -05:00
parent 8521be5ac8
commit 9937230f0c
4 changed files with 16 additions and 7 deletions

View File

@ -208,10 +208,11 @@ object BasicCommands {
else Parser.success(result.toList)
}
(cmdParser ~ multiCmdParser.+).flatMap {
case ("", rest) => validateCommands(rest)
case (p, rest) => validateCommands(rest).map(p :: _)
}
(cmdParser ~ multiCmdParser.+)
.flatMap {
case ("", rest) => validateCommands(rest)
case (p, rest) => validateCommands(rest).map(p :: _)
}
}
def multiParser(s: State): Parser[List[String]] = multiParserImpl(Some(s))

View File

@ -184,7 +184,8 @@ object Command {
)
def process(command: String, state: State): State = {
parse(command, state.combinedParser) match {
(if (command.contains(";")) parse(command, state.combinedParser)
else parse(command, state.nonMultiParser)) match {
case Right(s) => s() // apply command. command side effects happen here
case Left(errMsg) =>
state.log error errMsg

View File

@ -53,7 +53,11 @@ final case class State(
private[sbt] lazy val (multiCommands, nonMultiCommands) =
definedCommands.partition(_.nameOption.contains(BasicCommandStrings.Multi))
private[sbt] lazy val nonMultiParser = Command.combine(nonMultiCommands)(this)
lazy val combinedParser = multiCommands.foldRight(nonMultiParser)(_.parser(this) | _)
lazy val combinedParser: Parser[() => State] =
multiCommands.headOption match {
case Some(multi) => multi.parser(this) | nonMultiParser
case _ => nonMultiParser
}
def source: Option[CommandSource] =
currentCommand match {

View File

@ -14,7 +14,10 @@ import sbt.internal.util.complete.Parser
object MultiParserSpec {
val parser: Parser[Seq[String]] = BasicCommands.multiParserImpl(None)
implicit class StringOps(val s: String) {
def parse: Seq[String] = Parser.parse(s, parser).right.get
def parse: Seq[String] = Parser.parse(s, parser) match {
case Right(x) => x
case Left(x) => sys.error(s)
}
def parseEither: Either[String, Seq[String]] = Parser.parse(s, parser)
}
}