Do not require leading semicolon for multi command

It has long been a frustration of mine that it is necessary to prepend
multiple commands with a ';'. In this commit, I relax that restriction.
I had to reorder the command definitions so that multi comes before act.
This was because if the multi command did not have a leading semicolon,
then it would be handled by the action parser before the multi command
parser had a shot at it. Sadness ensued.
This commit is contained in:
Ethan Atkins 2018-11-19 08:36:58 -08:00
parent 51d986d751
commit c00cc37953
5 changed files with 37 additions and 2 deletions

View File

@ -39,7 +39,6 @@ object BasicCommands {
ignore,
help,
completionsCommand,
multi,
ifLast,
append,
setOnFailure,
@ -164,7 +163,10 @@ object BasicCommands {
)
def commandParser = state.map(s => (s.combinedParser & cmdPart) | cmdPart).getOrElse(cmdPart)
val part = semi.flatMap(_ => matched(commandParser) <~ token(OptSpace)).map(_.trim)
part.+ map (_.toList)
(cmdPart.? ~ part.+).map {
case (Some(h), t) => h.mkString.trim +: t.toList
case (_, t) => t.toList
}
}
def multiParser(s: State): Parser[List[String]] = multiParserImpl(Some(s))

View File

@ -14,6 +14,7 @@ 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 parseEither: Either[String, Seq[String]] = Parser.parse(s, parser)
}
}
import MultiParserSpec._
@ -45,4 +46,20 @@ class MultiParserSpec extends FlatSpec with Matchers {
"""; setStringValue "foo;bar"; checkStringValue "foo;bar"""".parse shouldBe
Seq("""setStringValue "foo;bar"""", """checkStringValue "foo;bar"""")
}
it should "parse commands without leading ';'" in {
"setStringValue foo; setStringValue bar".parse shouldBe Seq(
"setStringValue foo",
"setStringValue bar"
)
"foo; bar".parse shouldBe Seq("foo", "bar")
"foo bar ;bar".parse shouldBe Seq("foo bar", "bar")
"foo \"a;b\"; bar".parse shouldBe Seq("foo \"a;b\"", "bar")
" foo ; bar \"b;c\"".parse shouldBe Seq("foo", "bar \"b;c\"")
}
it should "not parse single commands without leading ';'" in {
"foo".parseEither shouldBe Left("Expected ';'\nfoo\n ^")
"foo bar baz".parseEither shouldBe Left("Expected ';'\nfoo bar baz\n ^")
"foo bar baz;".parseEither shouldBe
Left("Expected not ';'\nExpected '\"'\nfoo bar baz;\n ^")
}
}

View File

@ -241,6 +241,7 @@ object BuiltinCommands {
export,
boot,
initialize,
BasicCommands.multi,
act,
continuous,
flushFileTreeRepository

View File

@ -7,3 +7,15 @@
> checkStringValue bar
> ; setStringValue foo; setStringValue bar; setStringValue baz; checkStringValue baz
> setStringValue foo; setStringValue bar
> checkStringValue bar
> setStringValue foo; setStringValue bar; setStringValue baz
> checkStringValue baz
-> setStringValue foo; taskThatFails; setStringValue bar
> checkStringValue foo

View File

@ -8,6 +8,9 @@
> ~; setStringValue foo; setStringValue bar; checkStringValue bar
# no leading semicolon
> ~ setStringValue foo; setStringValue bar; checkStringValue bar
> ~ setStringValue foo
> checkStringValue foo