CommandLine
CommandLine
Section titled “CommandLine”Canonical source:
protos/lib/cli/CommandLine.protosat locked revisione99b712ecf658a527b1fe82c8beba2c1286d8dc9.
// THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE ADAPTIVE PUBLIC LICENSE// ("LICENSE") AS FIRST COMPLETED BY: Guillermo Adrián Molina. ANY USE, PUBLIC// DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION OF, OR PREPARATION OF// DERIVATIVE WORKS BASED ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE// OF THIS LICENSE AND ITS TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF// THE LICENSE. "LICENSED WORK" AND "RECIPIENT" ARE DEFINED IN THE LICENSE. A COPY// OF THE LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.TXT" ACCOMPANYING// THE CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS// FILE, A COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE:// https://github.com/guillermomolina/protos//// Software distributed under the License is distributed on an "AS IS" basis,// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for// the specific language governing rights and limitations under the License.
//! Canonical inert command-line specification records.
/// Canonicalizes one option descriptor into a fresh frozen OptionSpec record.option: (descriptor) => { required: (name) => { descriptor.hasSlot(name).ifFalse(() => { fail() }) descriptor.slotValue(name) }
validateString: (value) => { String.recognizes(value).ifFalse(() => { fail() }) value }
validateNonEmptyString: (value) => { validateString(value) (value == "").ifTrue(() => { fail() }) value }
validateOptionalString: (value) => { (value === null).ifFalse(() => { validateString(value) }) value }
isAlpha: (octet) => { ((octet >= 65) && (octet <= 90)) || ((octet >= 97) && (octet <= 122)) }
isDigit: (octet) => { (octet >= 48) && (octet <= 57) }
validateLongName: (value) => { validateString(value) source: Encoding.UTF8.encode(value) (source.size() == 0).ifTrue(() => { fail() }) isAlpha(source[0]).ifFalse(() => { fail() }) index: 1 (() => index < source.size()).whileTrue() { octet: source[index] allowed: isAlpha(octet) || isDigit(octet) || (octet == 45) allowed.ifFalse(() => { fail() }) index = index + 1 } value }
validateShortName: (value) => { validateString(value) source: Encoding.UTF8.encode(value) (source.size() == 1).ifFalse(() => { fail() }) (isAlpha(source[0]) || isDigit(source[0])).ifFalse(() => { fail() }) value }
validateInteger: (value) => { Integer.recognizes(value).ifFalse(() => { fail() }) value }
keyValue: validateNonEmptyString(required("key")) longValue: required("long") shortValue: required("short") minValuesValue: validateInteger(required("minValues")) maxValuesValue: validateInteger(required("maxValues")) minOccurrencesValue: validateInteger(required("minOccurrences")) maxOccurrencesValue: required("maxOccurrences") valueNameValue: validateOptionalString(required("valueName")) helpValue: validateOptionalString(required("help"))
(longValue === null).ifFalse(() => { validateLongName(longValue) }) (shortValue === null).ifFalse(() => { validateShortName(shortValue) }) ((longValue === null) && (shortValue === null)).ifTrue(() => { fail() })
validValueCardinality: ((minValuesValue == 0) && (maxValuesValue == 0)) || ((minValuesValue == 1) && (maxValuesValue == 1)) validValueCardinality.ifFalse(() => { fail() })
(maxValuesValue == 0).ifTrue(() => { (valueNameValue === null).ifFalse(() => { fail() }) })
(maxValuesValue == 1).ifTrue(() => { (valueNameValue === null).ifTrue(() => { fail() }) validateNonEmptyString(valueNameValue) })
((minOccurrencesValue == 0) || (minOccurrencesValue == 1)).ifFalse(() => { fail() }) (maxOccurrencesValue === null).ifFalse(() => { validateInteger(maxOccurrencesValue) (maxOccurrencesValue == 1).ifFalse(() => { fail() }) })
canonical: { kind: "option" key: keyValue long: longValue short: shortValue minValues: minValuesValue maxValues: maxValuesValue minOccurrences: minOccurrencesValue maxOccurrences: maxOccurrencesValue valueName: valueNameValue help: helpValue }
canonical.freeze()}
/// Canonicalizes one positional descriptor into a fresh frozen PositionalSpec record.positional: (descriptor) => { required: (name) => { descriptor.hasSlot(name).ifFalse(() => { fail() }) descriptor.slotValue(name) }
validateString: (value) => { String.recognizes(value).ifFalse(() => { fail() }) value }
validateNonEmptyString: (value) => { validateString(value) (value == "").ifTrue(() => { fail() }) value }
validateOptionalString: (value) => { (value === null).ifFalse(() => { validateString(value) }) value }
validateInteger: (value) => { Integer.recognizes(value).ifFalse(() => { fail() }) value }
keyValue: validateNonEmptyString(required("key")) minOccurrencesValue: validateInteger(required("minOccurrences")) maxOccurrencesValue: required("maxOccurrences") valueNameValue: validateNonEmptyString(required("valueName")) helpValue: validateOptionalString(required("help"))
((minOccurrencesValue == 0) || (minOccurrencesValue == 1)).ifFalse(() => { fail() }) (maxOccurrencesValue === null).ifFalse(() => { validateInteger(maxOccurrencesValue) (maxOccurrencesValue == 1).ifFalse(() => { fail() }) })
canonical: { kind: "positional" key: keyValue minOccurrences: minOccurrencesValue maxOccurrences: maxOccurrencesValue valueName: valueNameValue help: helpValue }
canonical.freeze()}
/// Canonicalizes one command descriptor and its complete nested specification graph.command: (descriptor) => { validateString: (value) => { String.recognizes(value).ifFalse(() => { fail() }) value }
validateOptionalString: (value) => { (value === null).ifFalse(() => { validateString(value) }) value }
isAlpha: (octet) => { ((octet >= 65) && (octet <= 90)) || ((octet >= 97) && (octet <= 122)) }
isDigit: (octet) => { (octet >= 48) && (octet <= 57) }
validateCommandName: (value) => { validateString(value) source: Encoding.UTF8.encode(value) (source.size() == 0).ifTrue(() => { fail() }) isAlpha(source[0]).ifFalse(() => { fail() }) index: 1 (() => index < source.size()).whileTrue() { octet: source[index] allowed: isAlpha(octet) || isDigit(octet) || (octet == 45) allowed.ifFalse(() => { fail() }) index = index + 1 } value }
validateArray: (value) => { Array.recognizes(value).ifFalse(() => { fail() }) value }
// Active-path identities only: a descriptor leaves `visiting` when its own // canonicalization completes, so completed shared descriptors are reused. visiting: IdentityMap()
// Validates one command descriptor and canonicalizes its options and // positionals, returning an explicit heap frame suspended before its children. enterCommand: (candidate, parentFrame) => { visiting.containsKey(candidate).ifTrue(() => { fail() }) visiting[candidate] = true
required: (name) => { candidate.hasSlot(name).ifFalse(() => { fail() }) candidate.slotValue(name) }
nameValue: validateCommandName(required("name")) helpValue: validateOptionalString(required("help")) optionDescriptors: validateArray(required("options")) positionalDescriptors: validateArray(required("positionals")) subcommandDescriptors: validateArray(required("subcommands"))
canonicalOptions: Array(...optionDescriptors) optionKeys: Map() longNames: Map() shortNames: Map()
optionIndex: 0 optionDescriptors.each((entry) => { spec: option(entry)
optionKeys.containsKey(spec.key).ifTrue(() => { fail() }) optionKeys[spec.key] = true
(spec.long === null).ifFalse(() => { longNames.containsKey(spec.long).ifTrue(() => { fail() }) longNames[spec.long] = true })
(spec.short === null).ifFalse(() => { shortNames.containsKey(spec.short).ifTrue(() => { fail() }) shortNames[spec.short] = true })
canonicalOptions[optionIndex] = spec optionIndex = optionIndex + 1 }) canonicalOptions.freeze()
canonicalPositionals: Array(...positionalDescriptors) positionalKeys: Map() positionalIndex: 0 positionalDescriptors.each((entry) => { spec: positional(entry)
positionalKeys.containsKey(spec.key).ifTrue(() => { fail() }) positionalKeys[spec.key] = true
(spec.maxOccurrences === null).ifTrue(() => { ((positionalIndex + 1) == positionalDescriptors.size()).ifFalse(() => { fail() }) })
canonicalPositionals[positionalIndex] = spec positionalIndex = positionalIndex + 1 }) canonicalPositionals.freeze()
suspended: { parent: parentFrame candidate: candidate name: nameValue help: helpValue options: canonicalOptions positionals: canonicalPositionals subcommandDescriptors: subcommandDescriptors subcommands: Array(...subcommandDescriptors) subcommandNames: Map() childIndex: 0 } suspended }
// Completes a frame whose children are all canonicalized. exitCommand: (frame) => { frame.subcommands.freeze()
visiting.remove(frame.candidate)
canonical: { kind: "command" name: frame.name help: frame.help options: frame.options positionals: frame.positionals subcommands: frame.subcommands }
canonical.freeze() }
// Depth-first traversal over explicit linked frames keeps execution-stack // depth independent of command depth. Each child is canonicalized completely // before its parent's duplicate-name check, registration and storage. frame: enterCommand(descriptor, null) result: null (() => result === null).whileTrue() { (frame.childIndex < frame.subcommandDescriptors.size()).ifTrueIfFalse( () => { frame = enterCommand(frame.subcommandDescriptors[frame.childIndex], frame) }, () => { spec: exitCommand(frame) parentFrame: frame.parent (parentFrame === null).ifTrueIfFalse( () => { result = spec }, () => { parentFrame.subcommandNames.containsKey(spec.name).ifTrue(() => { fail() }) parentFrame.subcommandNames[spec.name] = true
parentFrame.subcommands[parentFrame.childIndex] = spec parentFrame.childIndex = parentFrame.childIndex + 1 frame = parentFrame } ) } ) } result}
/// Parses a canonical CommandSpec tree into a fresh frozen lossless result.////// Traversal follows D115 Candidate C-prime: the earliest feasible exact-child/// boundary, parent-minimum reservation, current-scope `--` escape and/// irreversible child scope transfer.parse: ((arrayBuilderFactory) => { (specification, suppliedArguments) => { validateArray: (value) => { Array.recognizes(value).ifFalse(() => { fail() }) value }
validateString: (value) => { String.recognizes(value).ifFalse(() => { fail() }) value }
specification.hasSlot("kind").ifFalse(() => { fail() }) (specification.slotValue("kind") == "command").ifFalse(() => { fail() })
spec: specification
validateArray(suppliedArguments) suppliedArguments.each((entry) => { validateString(entry) })
arguments: Array(...suppliedArguments) arguments.freeze()
newBuilder: () => { arrayBuilderFactory() }
appendBuilt: (builder, value) => { builder.append(value) }
finishBuilder: (builder) => { builder.finish() }
decodeRange: (source, start, end) => { buffer: Encoding.UTF8.encode("") cursor: start (() => cursor < end).whileTrue() { buffer.add(source[cursor]) cursor = cursor + 1 } Encoding.UTF8.decode(buffer) }
isAsciiLetter: (octet) => { ((octet >= 65) && (octet <= 90)) || ((octet >= 97) && (octet <= 122)) }
isAsciiDigit: (octet) => { (octet >= 48) && (octet <= 57) }
isShortOctet: (octet) => { isAsciiLetter(octet) || isAsciiDigit(octet) }
allocatePositionals: (scopeSpec, rawPositionals) => { requiredPositionals: 0 scopeSpec.positionals.each((positionalSpec) => { requiredPositionals = requiredPositionals + positionalSpec.minOccurrences })
(rawPositionals.size() < requiredPositionals).ifTrue(() => { fail() })
positionalBuilder: newBuilder() rawIndex: 0 laterMinimum: requiredPositionals
scopeSpec.positionals.each((positionalSpec) => { laterMinimum = laterMinimum - positionalSpec.minOccurrences
remaining: rawPositionals.size() - rawIndex consume: 0
(positionalSpec.maxOccurrences === null).ifTrue(() => { consume = remaining })
(positionalSpec.maxOccurrences === null).ifFalse(() => { (positionalSpec.minOccurrences == 1).ifTrue(() => { consume = 1 })
(positionalSpec.minOccurrences == 0).ifTrue(() => { (remaining > laterMinimum).ifTrue(() => { consume = 1 }) }) })
(consume < positionalSpec.minOccurrences).ifTrue(() => { fail() })
consumed: 0 (() => consumed < consume).whileTrue() { raw: rawPositionals[rawIndex] occurrence: { kind: "positionalOccurrence" key: positionalSpec.key value: raw.value tokenIndex: raw.tokenIndex } occurrence.freeze() appendBuilt(positionalBuilder, occurrence)
rawIndex = rawIndex + 1 consumed = consumed + 1 } })
(rawIndex == rawPositionals.size()).ifFalse(() => { fail() })
result: finishBuilder(positionalBuilder) result.freeze() }
parseScope: null parseScope = (scopeSpec, startIndex, commandTokenIndex) => { scopeSpec.hasSlot("kind").ifFalse(() => { fail() }) (scopeSpec.slotValue("kind") == "command").ifFalse(() => { fail() })
validateArray(scopeSpec.options) validateArray(scopeSpec.positionals) validateArray(scopeSpec.subcommands)
longOptions: Map() shortOptions: Map() occurrenceCounts: Map()
scopeSpec.options.each((optionSpec) => { occurrenceCounts[optionSpec.key] = 0
(optionSpec.long === null).ifFalse(() => { longOptions[optionSpec.long] = optionSpec })
(optionSpec.short === null).ifFalse(() => { shortOptions[optionSpec.short] = optionSpec }) })
childSpecs: Map() scopeSpec.subcommands.each((childSpec) => { childSpecs[childSpec.name] = childSpec })
requiredPositionals: 0 boundedMaximumPositionals: 0 unboundedPositionals: false
scopeSpec.positionals.each((positionalSpec) => { requiredPositionals = requiredPositionals + positionalSpec.minOccurrences
(positionalSpec.maxOccurrences === null).ifTrue(() => { unboundedPositionals = true })
(positionalSpec.maxOccurrences === null).ifFalse(() => { boundedMaximumPositionals = boundedMaximumPositionals + positionalSpec.maxOccurrences }) })
optionBuilder: newBuilder() rawPositionalBuilder: newBuilder() rawPositionalCount: 0
recordOption: ( optionSpec, spelling, tokenIndex, value, valueTokenIndex ) => { count: occurrenceCounts[optionSpec.key]
(optionSpec.maxOccurrences === null).ifFalse(() => { (count >= optionSpec.maxOccurrences).ifTrue(() => { fail() }) })
occurrenceCounts[optionSpec.key] = count + 1
occurrence: { kind: "optionOccurrence" key: optionSpec.key spelling: spelling tokenIndex: tokenIndex value: value valueTokenIndex: valueTokenIndex } occurrence.freeze() appendBuilt(optionBuilder, occurrence) }
recordRawPositional: (value, tokenIndex) => { appendBuilt( rawPositionalBuilder, { value: value tokenIndex: tokenIndex } ) rawPositionalCount = rawPositionalCount + 1 }
positionalPrefixFeasible: () => { feasible: rawPositionalCount >= requiredPositionals
((feasible) && (unboundedPositionals == false)).ifTrue(() => { (rawPositionalCount > boundedMaximumPositionals).ifTrue(() => { feasible = false }) })
feasible }
scanIndex: startIndex optionsEnabled: true endOfOptionsIndex: null selectedChild: null selectedChildIndex: null
(() => (scanIndex < arguments.size()) && (selectedChild === null) ).whileTrue() { token: arguments[scanIndex] source: Encoding.UTF8.encode(token) advance: 1 handled: false
optionsEnabled.ifTrue(() => { (token == "--").ifTrue(() => { endOfOptionsIndex = scanIndex optionsEnabled = false handled = true })
handled.ifFalse(() => { optionLike: false (source.size() > 0).ifTrue(() => { (source[0] == 45).ifTrue(() => { optionLike = true }) })
optionLike.ifTrue(() => { (source.size() == 1).ifTrue(() => { fail() })
longForm: source[1] == 45
longForm.ifTrue(() => { equalsIndex: -1 cursor: 2 (() => cursor < source.size()).whileTrue() { ( (equalsIndex < 0) && (source[cursor] == 61) ).ifTrue(() => { equalsIndex = cursor }) cursor = cursor + 1 }
nameEnd: source.size() (equalsIndex >= 0).ifTrue(() => { nameEnd = equalsIndex })
longName: decodeRange(source, 2, nameEnd) longOptions.containsKey(longName).ifFalse(() => { fail() })
optionSpec: longOptions[longName] spelling: "--" + optionSpec.long
(equalsIndex >= 0).ifTrue(() => { (optionSpec.maxValues == 1).ifFalse(() => { fail() })
value: decodeRange( source, equalsIndex + 1, source.size() ) recordOption( optionSpec, spelling, scanIndex, value, scanIndex ) })
(equalsIndex >= 0).ifFalse(() => { (optionSpec.maxValues == 1).ifTrue(() => { ( (scanIndex + 1) >= arguments.size() ).ifTrue(() => { fail() })
recordOption( optionSpec, spelling, scanIndex, arguments[scanIndex + 1], scanIndex + 1 ) advance = 2 })
(optionSpec.maxValues == 1).ifFalse(() => { recordOption( optionSpec, spelling, scanIndex, null, null ) }) })
handled = true })
longForm.ifFalse(() => { memberCount: source.size() - 1 cursor: 1
(() => cursor < source.size()).whileTrue() { octet: source[cursor] isShortOctet(octet).ifFalse(() => { fail() })
shortName: decodeRange( source, cursor, cursor + 1 ) shortOptions.containsKey(shortName).ifFalse(() => { fail() })
optionSpec: shortOptions[shortName] spelling: "-" + optionSpec.short
(memberCount > 1).ifTrue(() => { (optionSpec.maxValues == 0).ifFalse(() => { fail() }) recordOption( optionSpec, spelling, scanIndex, null, null ) })
(memberCount == 1).ifTrue(() => { (optionSpec.maxValues == 1).ifTrue(() => { ( (scanIndex + 1) >= arguments.size() ).ifTrue(() => { fail() })
recordOption( optionSpec, spelling, scanIndex, arguments[scanIndex + 1], scanIndex + 1 ) advance = 2 })
(optionSpec.maxValues == 1).ifFalse(() => { recordOption( optionSpec, spelling, scanIndex, null, null ) }) })
cursor = cursor + 1 }
handled = true }) })
optionLike.ifFalse(() => { childSpecs.containsKey(token).ifTrue(() => { positionalPrefixFeasible().ifTrue(() => { selectedChild = childSpecs[token] selectedChildIndex = scanIndex handled = true }) }) }) }) })
handled.ifFalse(() => { recordRawPositional(token, scanIndex) })
scanIndex = scanIndex + advance }
scopeSpec.options.each((optionSpec) => { ( occurrenceCounts[optionSpec.key] < optionSpec.minOccurrences ).ifTrue(() => { fail() }) })
rawPositionals: finishBuilder(rawPositionalBuilder) positionalOccurrences: allocatePositionals(scopeSpec, rawPositionals)
optionOccurrences: finishBuilder(optionBuilder) optionOccurrences.freeze()
childResult: null (selectedChild === null).ifFalse(() => { childResult = parseScope( selectedChild, scanIndex, selectedChildIndex ) })
commandResult: { kind: "commandResult" name: scopeSpec.name tokenIndex: commandTokenIndex endOfOptionsIndex: endOfOptionsIndex options: optionOccurrences positionals: positionalOccurrences subcommand: childResult } commandResult.freeze() }
commandResult: parseScope(spec, 0, null)
result: { kind: "parseResult" arguments: arguments command: commandResult } result.freeze() }})(_commandLineArrayBuilderFactory)
// The runtime-provisioned factory is captured privately above; it is not module surface.context.removeSlot("_commandLineArrayBuilderFactory")
/// Renders canonical pure help for one exact command path.////// D118 Candidate F-prime fixes deterministic unwrapped plain text with explicit/// path context and no terminal/output authority. D119 Candidate A-prime ensures/// every value-bearing canonical specification already carries a non-empty/// presentation valueName.renderHelp: (rootSpec, commandPath) => { validateArray: (value) => { Array.recognizes(value).ifFalse(() => { fail() }) value }
validateString: (value) => { String.recognizes(value).ifFalse(() => { fail() }) value }
rootSpec.hasSlot("kind").ifFalse(() => { fail() }) (rootSpec.slotValue("kind") == "command").ifFalse(() => { fail() })
validateArray(commandPath)
selectedSpec: rootSpec commandPath.each((segment) => { validateString(segment)
selectedChild: null selectedSpec.subcommands.each((childSpec) => { ( (selectedChild === null) && (childSpec.name == segment) ).ifTrue(() => { selectedChild = childSpec }) })
(selectedChild === null).ifTrue(() => { fail() })
selectedSpec = selectedChild })
output: Encoding.UTF8.encode("")
appendText: (text) => { source: Encoding.UTF8.encode(text) index: 0 (() => index < source.size()).whileTrue() { output.add(source[index]) index = index + 1 } }
optionUsageTerm: (optionSpec) => { spelling: "" (optionSpec.long === null).ifFalse(() => { spelling = "--" + optionSpec.long }) (optionSpec.long === null).ifTrue(() => { spelling = "-" + optionSpec.short })
(optionSpec.maxValues == 1).ifTrue(() => { spelling = spelling + " " + optionSpec.valueName })
spelling }
positionalTerm: (positionalSpec) => { rendered: positionalSpec.valueName
( (positionalSpec.minOccurrences == 0) && (positionalSpec.maxOccurrences == 1) ).ifTrue(() => { rendered = "[" + positionalSpec.valueName + "]" })
( (positionalSpec.minOccurrences == 0) && (positionalSpec.maxOccurrences === null) ).ifTrue(() => { rendered = "[" + positionalSpec.valueName + "]..." })
( (positionalSpec.minOccurrences == 1) && (positionalSpec.maxOccurrences === null) ).ifTrue(() => { rendered = positionalSpec.valueName + " [" + positionalSpec.valueName + "]..." })
rendered }
optionEntry: (optionSpec) => { rendered: ""
(optionSpec.short === null).ifFalse(() => { rendered = "-" + optionSpec.short })
(optionSpec.long === null).ifFalse(() => { (rendered == "").ifFalse(() => { rendered = rendered + ", " }) rendered = rendered + "--" + optionSpec.long })
(optionSpec.maxValues == 1).ifTrue(() => { rendered = rendered + " " + optionSpec.valueName })
( (optionSpec.minOccurrences == 1) && (optionSpec.maxOccurrences == 1) ).ifTrue(() => { rendered = rendered + " (required)" })
( (optionSpec.minOccurrences == 0) && (optionSpec.maxOccurrences === null) ).ifTrue(() => { rendered = rendered + " (repeatable)" })
( (optionSpec.minOccurrences == 1) && (optionSpec.maxOccurrences === null) ).ifTrue(() => { rendered = rendered + " (required, repeatable)" })
rendered }
appendDescription: (helpText) => { (helpText === null).ifFalse(() => { appendText("\n ") appendText(helpText) }) }
appendText("Usage: ") appendText(rootSpec.name)
commandPath.each((segment) => { appendText(" ") appendText(segment) })
hasOptionalOptions: false selectedSpec.options.each((optionSpec) => { (optionSpec.minOccurrences == 0).ifTrue(() => { hasOptionalOptions = true })
(optionSpec.minOccurrences == 1).ifTrue(() => { term: optionUsageTerm(optionSpec) appendText(" ") appendText(term)
(optionSpec.maxOccurrences === null).ifTrue(() => { appendText(" [") appendText(term) appendText("]...") }) }) })
hasOptionalOptions.ifTrue(() => { appendText(" [OPTIONS]") })
selectedSpec.positionals.each((positionalSpec) => { appendText(" ") appendText(positionalTerm(positionalSpec)) })
(selectedSpec.subcommands.size() > 0).ifTrue(() => { appendText(" [COMMAND]") })
(selectedSpec.help === null).ifFalse(() => { appendText("\n\n") appendText(selectedSpec.help) })
(selectedSpec.positionals.size() > 0).ifTrue(() => { appendText("\n\nArguments:") selectedSpec.positionals.each((positionalSpec) => { appendText("\n ") appendText(positionalTerm(positionalSpec)) appendDescription(positionalSpec.help) }) })
(selectedSpec.options.size() > 0).ifTrue(() => { appendText("\n\nOptions:") selectedSpec.options.each((optionSpec) => { appendText("\n ") appendText(optionEntry(optionSpec)) appendDescription(optionSpec.help) }) })
(selectedSpec.subcommands.size() > 0).ifTrue(() => { appendText("\n\nCommands:") selectedSpec.subcommands.each((childSpec) => { appendText("\n ") appendText(childSpec.name) appendDescription(childSpec.help) }) })
Encoding.UTF8.decode(output)}