Skip to content

Commit 6eb5f69

Browse files
committed
Display help eagerly
1 parent 9efd7ab commit 6eb5f69

File tree

1 file changed

+87
-85
lines changed

1 file changed

+87
-85
lines changed

library/src/scala/annotation/newMain.scala

+87-85
Original file line numberDiff line numberDiff line change
@@ -133,86 +133,6 @@ final class newMain extends MainAnnotation[FromString, Any]:
133133
val helpIsOverridden = namesToCanonicalName.exists((name, _) => name == helpArg)
134134
val shortHelpIsOverridden = shortNamesToCanonicalName.exists((name, _) => name == shortHelpArg)
135135

136-
val (positionalArgs, byNameArgs, invalidByNameArgs) = {
137-
def getCanonicalArgName(arg: String): Option[String] =
138-
if arg.startsWith(argMarker) && arg.length > argMarker.length then
139-
namesToCanonicalName.get(arg.drop(argMarker.length))
140-
else if arg.startsWith(shortArgMarker) && arg.length == shortArgMarker.length + 1 then
141-
shortNamesToCanonicalName.get(arg(shortArgMarker.length))
142-
else
143-
None
144-
145-
def isArgName(arg: String): Boolean =
146-
val isFullName = arg.startsWith(argMarker)
147-
val isShortName = arg.startsWith(shortArgMarker) && arg.length == shortArgMarker.length + 1 && shortNameIsValidChar(arg(shortArgMarker.length))
148-
isFullName || isShortName
149-
150-
def recurse(remainingArgs: Seq[String], pa: mutable.Queue[String], bna: Seq[(String, String)], ia: Seq[String]): (mutable.Queue[String], Seq[(String, String)], Seq[String]) =
151-
remainingArgs match {
152-
case Seq() =>
153-
(pa, bna, ia)
154-
case argName +: argValue +: rest if isArgName(argName) =>
155-
getCanonicalArgName(argName) match {
156-
case Some(canonicalName) => recurse(rest, pa, bna :+ (canonicalName -> argValue), ia)
157-
case None => recurse(rest, pa, bna, ia :+ argName)
158-
}
159-
case arg +: rest =>
160-
recurse(rest, pa :+ arg, bna, ia)
161-
}
162-
163-
val (pa, bna, ia) = recurse(args.toSeq, mutable.Queue.empty, Vector(), Vector())
164-
val nameToArgValues: Map[String, Seq[String]] = if bna.isEmpty then Map.empty else bna.groupMapReduce(_._1)(p => List(p._2))(_ ++ _)
165-
(pa, nameToArgValues, ia)
166-
}
167-
168-
val argStrings: Seq[Seq[String]] =
169-
for paramInfo <- info.parameters yield {
170-
if (paramInfo.isVarargs) {
171-
val byNameGetters = byNameArgs.getOrElse(paramInfo.name, Seq())
172-
val positionalGetters = positionalArgs.removeAll()
173-
// First take arguments passed by name, then those passed by position
174-
byNameGetters ++ positionalGetters
175-
} else {
176-
byNameArgs.get(paramInfo.name) match
177-
case Some(Nil) =>
178-
throw AssertionError(s"${paramInfo.name} present in byNameArgs, but it has no argument value")
179-
case Some(argValues) =>
180-
if argValues.length > 1 then
181-
// Do not accept multiple values
182-
// Remove this test to take last given argument
183-
error(s"more than one value for ${paramInfo.name}: ${argValues.mkString(", ")}")
184-
Nil
185-
else
186-
List(argValues.last)
187-
case None =>
188-
if positionalArgs.length > 0 then
189-
List(positionalArgs.dequeue())
190-
else if paramInfo.hasDefault then
191-
List("")
192-
else
193-
error(s"missing argument for ${paramInfo.name}")
194-
Nil
195-
}
196-
}
197-
198-
// Check aliases unicity
199-
val nameAndCanonicalName = info.parameters.flatMap {
200-
case paramInfo => (paramInfo.name +: getAlternativeNames(paramInfo) ++: getShortNames(paramInfo)).map(_ -> paramInfo.name)
201-
}
202-
val nameToCanonicalNames = nameAndCanonicalName.groupMap(_._1)(_._2)
203-
204-
for (name, canonicalNames) <- nameToCanonicalNames if canonicalNames.length > 1 do
205-
throw IllegalArgumentException(s"$name is used for multiple parameters: ${canonicalNames.mkString(", ")}")
206-
207-
// Check aliases validity
208-
val problematicNames = info.parameters.flatMap(getInvalidNames)
209-
if problematicNames.length > 0 then
210-
throw IllegalArgumentException(s"The following aliases are invalid: ${problematicNames.mkString(", ")}")
211-
212-
// Handle unused and invalid args
213-
for (remainingArg <- positionalArgs) error(s"unused argument: $remainingArg")
214-
for (invalidArg <- invalidByNameArgs) error(s"unknown argument name: $invalidArg")
215-
216136
val displayHelp =
217137
(!helpIsOverridden && args.contains(getNameWithMarker(helpArg))) ||
218138
(!shortHelpIsOverridden && args.contains(getNameWithMarker(shortHelpArg)))
@@ -222,12 +142,94 @@ final class newMain extends MainAnnotation[FromString, Any]:
222142
println()
223143
explain()
224144
None
225-
else if errors.nonEmpty then
226-
for msg <- errors do println(s"Error: $msg")
227-
usage()
228-
None
229145
else
230-
Some(argStrings.flatten)
146+
val (positionalArgs, byNameArgs, invalidByNameArgs) = {
147+
def getCanonicalArgName(arg: String): Option[String] =
148+
if arg.startsWith(argMarker) && arg.length > argMarker.length then
149+
namesToCanonicalName.get(arg.drop(argMarker.length))
150+
else if arg.startsWith(shortArgMarker) && arg.length == shortArgMarker.length + 1 then
151+
shortNamesToCanonicalName.get(arg(shortArgMarker.length))
152+
else
153+
None
154+
155+
def isArgName(arg: String): Boolean =
156+
val isFullName = arg.startsWith(argMarker)
157+
val isShortName = arg.startsWith(shortArgMarker) && arg.length == shortArgMarker.length + 1 && shortNameIsValidChar(arg(shortArgMarker.length))
158+
isFullName || isShortName
159+
160+
def recurse(remainingArgs: Seq[String], pa: mutable.Queue[String], bna: Seq[(String, String)], ia: Seq[String]): (mutable.Queue[String], Seq[(String, String)], Seq[String]) =
161+
remainingArgs match {
162+
case Seq() =>
163+
(pa, bna, ia)
164+
case argName +: argValue +: rest if isArgName(argName) =>
165+
getCanonicalArgName(argName) match {
166+
case Some(canonicalName) => recurse(rest, pa, bna :+ (canonicalName -> argValue), ia)
167+
case None => recurse(rest, pa, bna, ia :+ argName)
168+
}
169+
case arg +: rest =>
170+
recurse(rest, pa :+ arg, bna, ia)
171+
}
172+
173+
val (pa, bna, ia) = recurse(args.toSeq, mutable.Queue.empty, Vector(), Vector())
174+
val nameToArgValues: Map[String, Seq[String]] = if bna.isEmpty then Map.empty else bna.groupMapReduce(_._1)(p => List(p._2))(_ ++ _)
175+
(pa, nameToArgValues, ia)
176+
}
177+
178+
val argStrings: Seq[Seq[String]] =
179+
for paramInfo <- info.parameters yield {
180+
if (paramInfo.isVarargs) {
181+
val byNameGetters = byNameArgs.getOrElse(paramInfo.name, Seq())
182+
val positionalGetters = positionalArgs.removeAll()
183+
// First take arguments passed by name, then those passed by position
184+
byNameGetters ++ positionalGetters
185+
} else {
186+
byNameArgs.get(paramInfo.name) match
187+
case Some(Nil) =>
188+
throw AssertionError(s"${paramInfo.name} present in byNameArgs, but it has no argument value")
189+
case Some(argValues) =>
190+
if argValues.length > 1 then
191+
// Do not accept multiple values
192+
// Remove this test to take last given argument
193+
error(s"more than one value for ${paramInfo.name}: ${argValues.mkString(", ")}")
194+
Nil
195+
else
196+
List(argValues.last)
197+
case None =>
198+
if positionalArgs.length > 0 then
199+
List(positionalArgs.dequeue())
200+
else if paramInfo.hasDefault then
201+
List("")
202+
else
203+
error(s"missing argument for ${paramInfo.name}")
204+
Nil
205+
}
206+
}
207+
208+
// Check aliases unicity
209+
val nameAndCanonicalName = info.parameters.flatMap {
210+
case paramInfo => (paramInfo.name +: getAlternativeNames(paramInfo) ++: getShortNames(paramInfo)).map(_ -> paramInfo.name)
211+
}
212+
val nameToCanonicalNames = nameAndCanonicalName.groupMap(_._1)(_._2)
213+
214+
for (name, canonicalNames) <- nameToCanonicalNames if canonicalNames.length > 1 do
215+
throw IllegalArgumentException(s"$name is used for multiple parameters: ${canonicalNames.mkString(", ")}")
216+
217+
// Check aliases validity
218+
val problematicNames = info.parameters.flatMap(getInvalidNames)
219+
if problematicNames.length > 0 then
220+
throw IllegalArgumentException(s"The following aliases are invalid: ${problematicNames.mkString(", ")}")
221+
222+
// Handle unused and invalid args
223+
for (remainingArg <- positionalArgs) error(s"unused argument: $remainingArg")
224+
for (invalidArg <- invalidByNameArgs) error(s"unknown argument name: $invalidArg")
225+
226+
if errors.nonEmpty then
227+
for msg <- errors do println(s"Error: $msg")
228+
usage()
229+
None
230+
else
231+
Some(argStrings.flatten)
232+
end if
231233
end command
232234

233235
private def usage(): Unit =

0 commit comments

Comments
 (0)