[2.x] fix: Fixes java++ tab completion (#8778)

Fixes #4310

Per review, the OOM comes from the version parser - token(StringBasic)
on the right side of || has no examples constraint. Move
.examples(knownVersions*) from the inner number parser to wrap the
entire || expression, so both alternatives are bounded.
This commit is contained in:
bitloi 2026-02-22 23:43:38 -05:00 committed by GitHub
parent c3a00771b3
commit 20f4a9c3b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 20 additions and 3 deletions

View File

@ -132,6 +132,9 @@ private[sbt] object CrossJava {
private case class SwitchTarget(version: Option[JavaVersion], home: Option[File], force: Boolean)
private case class SwitchJavaHome(target: SwitchTarget, verbose: Boolean, command: Option[String])
private[sbt] val JavaSwitchCommandCompletions =
Vector("-v", "compile", "test", "run", "clean", "console", "package")
private def switchParser(state: State): Parser[SwitchJavaHome] = {
import DefaultParsers.*
def versionAndCommand(spacePresent: Boolean) = {
@ -141,9 +144,9 @@ private[sbt] object CrossJava {
val knownVersions = javaHomes.keysIterator.map(_.numberStr).toVector
val version: Parser[SwitchTarget] =
(token(
(StringBasic <~ "@").? ~ ((NatBasic) ~ ("." ~> NatBasic).*)
.examples(knownVersions*) ~ "!".?
(StringBasic <~ "@").? ~ ((NatBasic) ~ ("." ~> NatBasic).*) ~ "!".?
) || token(StringBasic))
.examples(knownVersions*)
.map {
case Left(((vendor, (v1, vs)), bang)) =>
val force = bang.isDefined
@ -156,7 +159,10 @@ private[sbt] object CrossJava {
if (spacePresent) version
else version & spacedFirst(JavaSwitchCommand)
val verbose = Parser.opt(token(Space ~> "-v"))
val optionalCommand = Parser.opt(token(Space ~> matched(state.combinedParser)))
val optionalCommand =
Parser.opt(
token(Space ~> matched(state.combinedParser).examples(JavaSwitchCommandCompletions*))
)
(spacedVersion ~ verbose ~ optionalCommand).map { case v ~ verbose ~ command =>
SwitchJavaHome(v, verbose.isDefined, command)
}

View File

@ -242,4 +242,15 @@ class CrossJavaTest extends AnyFunSuite with Diagrams {
assert(version == "temurin@11.0.15")
}
}
test("java++ tab completion list is bounded (#4310)"):
val completions = CrossJava.JavaSwitchCommandCompletions
assert(completions.nonEmpty, "completion list must not be empty")
assert(
completions.size <= 20,
"completion list must stay small to avoid JLine 'Display all N possibilities?'"
)
assert(completions.contains("-v"), "completion list should suggest -v")
assert(completions.contains("compile"), "completion list should suggest compile")
assert(completions.contains("test"), "completion list should suggest test")
}