package sbt.complete object JLineTest { import DefaultParsers._ val one = "blue" | "green" | "black" val two = token("color" ~> Space) ~> token(one) val three = token("color" ~> Space) ~> token(ID.examples("blue", "green", "black")) val four = token("color" ~> Space) ~> token(ID, "") val num = token(NatBasic) val five = (num ~ token("+" | "-") ~ num) <~ token('=') flatMap { case a ~ "+" ~ b => token((a+b).toString) case a ~ "-" ~ b => token((a-b).toString) } val parsers = Map("1" -> one, "2" -> two, "3" -> three, "4" -> four, "5" -> five) def main(args: Array[String]) { import jline.{ConsoleReader,Terminal} val reader = new ConsoleReader() Terminal.getTerminal.disableEcho() val parser = parsers(args(0)) JLineCompletion.installCustomCompletor(reader, parser) def loop() { val line = reader.readLine("> ") if(line ne null) { println("Result: " + apply(parser)(line).resultEmpty) loop() } } loop() } } import Parser._ import org.scalacheck._ object ParserTest extends Properties("Completing Parser") { import Parsers._ import DefaultParsers.matches val nested = (token("a1") ~ token("b2")) ~ "c3" val nestedDisplay = (token("a1", "") ~ token("b2", "")) ~ "c3" val spacePort = (token(Space) ~> Port) def p[T](f: T): T = { println(f); f } def checkSingle(in: String, expect: Completion)(expectDisplay: Completion = expect) = ( ("token '" + in + "'") |: checkOne(in, nested, expect)) && ( ("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay) ) def checkOne(in: String, parser: Parser[_], expect: Completion): Prop = completions(parser, in, 1) == Completions.single(expect) def checkAll(in: String, parser: Parser[_], expect: Completions): Prop = { val cs = completions(parser, in, 1) ("completions: " + cs) |: ("Expected: " + expect) |: ( (cs == expect): Prop) } def checkInvalid(in: String) = ( ("token '" + in + "'") |: checkInv(in, nested) ) && ( ("display '" + in + "'") |: checkInv(in, nestedDisplay) ) def checkInv(in: String, parser: Parser[_]): Prop = { val cs = completions(parser, in, 1) ("completions: " + cs) |: (( cs == Completions.nil): Prop) } property("nested tokens a") = checkSingle("", Completion.tokenStrict("","a1") )( Completion.displayStrict("")) property("nested tokens a1") = checkSingle("a", Completion.tokenStrict("a","1") )( Completion.displayStrict("")) property("nested tokens a inv") = checkInvalid("b") property("nested tokens b") = checkSingle("a1", Completion.tokenStrict("","b2") )( Completion.displayStrict("")) property("nested tokens b2") = checkSingle("a1b", Completion.tokenStrict("b","2") )( Completion.displayStrict("")) property("nested tokens b inv") = checkInvalid("a1a") property("nested tokens c") = checkSingle("a1b2", Completion.suggestStrict("c3") )() property("nested tokens c3") = checkSingle("a1b2c", Completion.suggestStrict("3"))() property("nested tokens c inv") = checkInvalid("a1b2a") property("suggest space") = checkOne("", spacePort, Completion.tokenStrict("", " ")) property("suggest port") = checkOne(" ", spacePort, Completion.displayStrict("") ) property("no suggest at end") = checkOne("asdf", "asdf", Completion.suggestStrict("")) property("no suggest at token end") = checkOne("asdf", token("asdf"), Completion.suggestStrict("")) property("empty suggest for examples") = checkOne("asdf", any.+.examples("asdf", "qwer"), Completion.suggestStrict("")) property("empty suggest for examples token") = checkOne("asdf", token(any.+.examples("asdf", "qwer")), Completion.suggestStrict("")) val colors = Set("blue", "green", "red") val base = (seen: Seq[String]) => token( ID examples (colors -- seen) ) val sep = token( Space ) val repeat = repeatDep( base, sep) def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) }) property("repeatDep no suggestions for bad input") = checkInv(".", repeat) property("repeatDep suggest all") = checkAll("", repeat, completionStrings(colors)) property("repeatDep suggest remaining two") = { val first = colors.toSeq.head checkAll(first + " ", repeat, completionStrings(colors - first)) } property("repeatDep suggest remaining one") = { val take = colors.toSeq.take(2) checkAll(take.mkString("", " ", " "), repeat, completionStrings(colors -- take)) } property("repeatDep requires at least one token") = !matches(repeat, "") property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head) property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" ")) } object ParserExample { val ws = charClass(_.isWhitespace)+ val notws = charClass(!_.isWhitespace)+ val name = token("test") val options = (ws ~> token("quick" | "failed" | "new") )* val include = (ws ~> token(examples(notws.string, Set("am", "is", "are", "was", "were") )) )* val t = name ~ options ~ include // Get completions for some different inputs println(completions(t, "te", 1)) println(completions(t, "test ",1)) println(completions(t, "test w", 1)) // Get the parsed result for different inputs println(apply(t)("te").resultEmpty) println(apply(t)("test").resultEmpty) println(apply(t)("test w").resultEmpty) println(apply(t)("test was were").resultEmpty) def run(n: Int) { val a = 'a'.id val aq = a.? val aqn = repeat(aq, min = n, max = n) val an = repeat(a, min = n, max = n) val ann = aqn ~ an def r = apply(ann)("a"*(n*2)).resultEmpty println(r.isValid) } def run2(n: Int) { val ab = "ab".?.* val r = apply(ab)("a"*n).resultEmpty println(r) } }