@@ -77,7 +77,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
77
77
78
78
private inline val maxUsageLineLength = 120
79
79
80
- private var info : Info = _ // TODO remove this var
80
+ private var help : Help = _
81
81
82
82
private def getAliases (param : Parameter ): Seq [String ] =
83
83
param.annotations.collect{ case a : Alias => a }.flatMap(_.aliases)
@@ -107,27 +107,19 @@ final class newMain extends MainAnnotation[FromString, Any]:
107
107
getAliases(param).filter(name => ! nameIsValid(name) && ! shortNameIsValid(name))
108
108
109
109
def command (info : Info , args : Seq [String ]): Option [Seq [String ]] =
110
- this .info = info
110
+ help = new Help (info)
111
+ val canonicalNames = CanonicalNames (info)
111
112
112
113
val errors = new mutable.ArrayBuffer [String ]
113
114
114
115
def error (msg : String ): Unit = {
115
116
errors += msg
116
117
}
117
118
118
- val canonicalNames = CanonicalNames (info)
119
-
120
- val helpIsOverridden = canonicalNames.getName(helpArg).isDefined
121
- val shortHelpIsOverridden = canonicalNames.getShortName(shortHelpArg).isDefined
122
-
123
- val displayHelp =
124
- (! helpIsOverridden && args.contains(getNameWithMarker(helpArg))) ||
125
- (! shortHelpIsOverridden && args.contains(getNameWithMarker(shortHelpArg)))
126
-
127
- if displayHelp then
128
- usage()
119
+ if Help .hasHelpArg(canonicalNames, args) then
120
+ help.printUsage()
129
121
println()
130
- explain ()
122
+ help.printExplain ()
131
123
None
132
124
else
133
125
val (positionalArgs, byNameArgs, invalidByNameArgs) = {
@@ -212,94 +204,103 @@ final class newMain extends MainAnnotation[FromString, Any]:
212
204
213
205
if errors.nonEmpty then
214
206
for msg <- errors do println(s " Error: $msg" )
215
- usage ()
207
+ help.printUsage ()
216
208
None
217
209
else
218
210
Some (argStrings.flatten)
219
211
end if
220
212
end command
221
213
222
- private def usage (): Unit =
223
- def argsUsage : Seq [String ] =
224
- for (infos <- info.parameters)
225
- yield {
226
- val canonicalName = getNameWithMarker(infos.name)
227
- val shortNames = getShortNames(infos).map(getNameWithMarker)
228
- val alternativeNames = getAlternativeNames(infos).map(getNameWithMarker)
229
- val namesPrint = (canonicalName +: alternativeNames ++: shortNames).mkString(" [" , " | " , " ]" )
230
- val shortTypeName = infos.typeName.split('.' ).last
231
- if infos.isVarargs then s " [< $shortTypeName> [< $shortTypeName> [...]]] "
232
- else if infos.hasDefault then s " [ $namesPrint < $shortTypeName>] "
233
- else s " $namesPrint < $shortTypeName> "
234
- }
235
-
236
- def wrapArgumentUsages (argsUsage : Seq [String ], maxLength : Int ): Seq [String ] = {
237
- def recurse (args : Seq [String ], currentLine : String , acc : Vector [String ]): Seq [String ] =
238
- (args, currentLine) match {
239
- case (Nil , " " ) => acc
240
- case (Nil , l) => (acc :+ l)
241
- case (arg +: t, " " ) => recurse(t, arg, acc)
242
- case (arg +: t, l) if l.length + 1 + arg.length <= maxLength => recurse(t, s " $l $arg" , acc)
243
- case (arg +: t, l) => recurse(t, arg, acc :+ l)
214
+ private class Help (info : Info ):
215
+
216
+ def printUsage (): Unit =
217
+ def argsUsage : Seq [String ] =
218
+ for (infos <- info.parameters)
219
+ yield {
220
+ val canonicalName = getNameWithMarker(infos.name)
221
+ val shortNames = getShortNames(infos).map(getNameWithMarker)
222
+ val alternativeNames = getAlternativeNames(infos).map(getNameWithMarker)
223
+ val namesPrint = (canonicalName +: alternativeNames ++: shortNames).mkString(" [" , " | " , " ]" )
224
+ val shortTypeName = infos.typeName.split('.' ).last
225
+ if infos.isVarargs then s " [< $shortTypeName> [< $shortTypeName> [...]]] "
226
+ else if infos.hasDefault then s " [ $namesPrint < $shortTypeName>] "
227
+ else s " $namesPrint < $shortTypeName> "
244
228
}
245
229
246
- recurse(argsUsage, " " , Vector ()).toList
247
- }
230
+ def wrapArgumentUsages (argsUsage : Seq [String ], maxLength : Int ): Seq [String ] = {
231
+ def recurse (args : Seq [String ], currentLine : String , acc : Vector [String ]): Seq [String ] =
232
+ (args, currentLine) match {
233
+ case (Nil , " " ) => acc
234
+ case (Nil , l) => (acc :+ l)
235
+ case (arg +: t, " " ) => recurse(t, arg, acc)
236
+ case (arg +: t, l) if l.length + 1 + arg.length <= maxLength => recurse(t, s " $l $arg" , acc)
237
+ case (arg +: t, l) => recurse(t, arg, acc :+ l)
238
+ }
248
239
249
- val usageBeginning = s " Usage: ${info.name} "
250
- val argsOffset = usageBeginning.length
251
- val usages = wrapArgumentUsages(argsUsage, maxUsageLineLength - argsOffset)
240
+ recurse(argsUsage, " " , Vector ()).toList
241
+ }
252
242
253
- println(usageBeginning + usages.mkString(" \n " + " " * argsOffset))
254
- end usage
243
+ val printUsageBeginning = s " Usage: ${info.name} "
244
+ val argsOffset = printUsageBeginning.length
245
+ val printUsages = wrapArgumentUsages(argsUsage, maxUsageLineLength - argsOffset)
255
246
256
- private def explain () : Unit =
257
- inline def shiftLines ( s : Seq [ String ], shift : Int ) : String = s.map( " " * shift + _).mkString( " \n " )
247
+ println(printUsageBeginning + printUsages.mkString( " \n " + " " * argsOffset))
248
+ end printUsage
258
249
259
- def wrapLongLine (line : String , maxLength : Int ): List [String ] = {
260
- def recurse (s : String , acc : Vector [String ]): Seq [String ] =
261
- val lastSpace = s.trim.nn.lastIndexOf(' ' , maxLength)
262
- if ((s.length <= maxLength) || (lastSpace < 0 ))
263
- acc :+ s
264
- else {
265
- val (shortLine, rest) = s.splitAt(lastSpace)
266
- recurse(rest.trim.nn, acc :+ shortLine)
267
- }
250
+ def printExplain (): Unit =
251
+ def shiftLines (s : Seq [String ], shift : Int ): String = s.map(" " * shift + _).mkString(" \n " )
268
252
269
- recurse(line, Vector ()).toList
270
- }
253
+ def wrapLongLine (line : String , maxLength : Int ): List [String ] = {
254
+ def recurse (s : String , acc : Vector [String ]): Seq [String ] =
255
+ val lastSpace = s.trim.nn.lastIndexOf(' ' , maxLength)
256
+ if ((s.length <= maxLength) || (lastSpace < 0 ))
257
+ acc :+ s
258
+ else {
259
+ val (shortLine, rest) = s.splitAt(lastSpace)
260
+ recurse(rest.trim.nn, acc :+ shortLine)
261
+ }
271
262
272
- if (info.documentation.nonEmpty)
273
- println(wrapLongLine(info.documentation, maxUsageLineLength).mkString(" \n " ))
274
- if (info.parameters.nonEmpty) {
275
- val argNameShift = 2
276
- val argDocShift = argNameShift + 2
277
-
278
- println(" Arguments:" )
279
- for infos <- info.parameters do
280
- val canonicalName = getNameWithMarker(infos.name)
281
- val shortNames = getShortNames(infos).map(getNameWithMarker)
282
- val alternativeNames = getAlternativeNames(infos).map(getNameWithMarker)
283
- val otherNames = (alternativeNames ++: shortNames) match {
284
- case Seq () => " "
285
- case names => names.mkString(" (" , " , " , " ) " )
286
- }
287
- val argDoc = StringBuilder (" " * argNameShift)
288
- argDoc.append(s " $canonicalName $otherNames- ${infos.typeName.split('.' ).last}" )
289
- if infos.isVarargs then argDoc.append(" (vararg)" )
290
- else if infos.hasDefault then argDoc.append(" (optional)" )
291
-
292
- if (infos.documentation.nonEmpty) {
293
- val shiftedDoc =
294
- infos.documentation.split(" \n " ).nn
295
- .map(line => shiftLines(wrapLongLine(line.nn, maxUsageLineLength - argDocShift), argDocShift))
296
- .mkString(" \n " )
297
- argDoc.append(" \n " ).append(shiftedDoc)
298
- }
263
+ recurse(line, Vector ()).toList
264
+ }
299
265
300
- println(argDoc)
301
- }
302
- end explain
266
+ if (info.documentation.nonEmpty)
267
+ println(wrapLongLine(info.documentation, maxUsageLineLength).mkString(" \n " ))
268
+ if (info.parameters.nonEmpty) {
269
+ val argNameShift = 2
270
+ val argDocShift = argNameShift + 2
271
+
272
+ println(" Arguments:" )
273
+ for infos <- info.parameters do
274
+ val canonicalName = getNameWithMarker(infos.name)
275
+ val shortNames = getShortNames(infos).map(getNameWithMarker)
276
+ val alternativeNames = getAlternativeNames(infos).map(getNameWithMarker)
277
+ val otherNames = (alternativeNames ++: shortNames) match {
278
+ case Seq () => " "
279
+ case names => names.mkString(" (" , " , " , " ) " )
280
+ }
281
+ val argDoc = StringBuilder (" " * argNameShift)
282
+ argDoc.append(s " $canonicalName $otherNames- ${infos.typeName.split('.' ).last}" )
283
+ if infos.isVarargs then argDoc.append(" (vararg)" )
284
+ else if infos.hasDefault then argDoc.append(" (optional)" )
285
+
286
+ if (infos.documentation.nonEmpty) {
287
+ val shiftedDoc =
288
+ infos.documentation.split(" \n " ).nn
289
+ .map(line => shiftLines(wrapLongLine(line.nn, maxUsageLineLength - argDocShift), argDocShift))
290
+ .mkString(" \n " )
291
+ argDoc.append(" \n " ).append(shiftedDoc)
292
+ }
293
+
294
+ println(argDoc)
295
+ }
296
+ end printExplain
297
+
298
+ private object Help :
299
+ def hasHelpArg (canonicalNames : CanonicalNames , args : Seq [String ]): Boolean =
300
+ val helpIsOverridden = canonicalNames.getName(helpArg).isDefined
301
+ val shortHelpIsOverridden = canonicalNames.getShortName(shortHelpArg).isDefined
302
+ (! helpIsOverridden && args.contains(getNameWithMarker(helpArg))) ||
303
+ (! shortHelpIsOverridden && args.contains(getNameWithMarker(shortHelpArg)))
303
304
304
305
def argGetter [T ](param : Parameter , arg : String , defaultArgument : Option [() => T ])(using p : FromString [T ]): () => T = {
305
306
if arg.nonEmpty then parse[T ](param, arg)
@@ -330,7 +331,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
330
331
def run (execProgram : () => Any ): Unit = {
331
332
if parseErrors.nonEmpty then
332
333
for msg <- parseErrors do println(s " Error: $msg" )
333
- usage ()
334
+ help.printUsage ()
334
335
else
335
336
execProgram()
336
337
}
0 commit comments