in Sources/ArgumentParser/Usage/MessageInfo.swift [19:129]
init(error: Error, type: ParsableArguments.Type) {
var commandStack: [ParsableCommand.Type]
var parserError: ParserError? = nil
switch error {
case let e as CommandError:
commandStack = e.commandStack
parserError = e.parserError
// Exit early on built-in requests
switch e.parserError {
case .helpRequested:
self = .help(text: HelpGenerator(commandStack: e.commandStack).rendered())
return
case .dumpHelpRequested:
self = .help(text: DumpHelpGenerator(commandStack: e.commandStack).rendered())
return
case .versionRequested:
let versionString = commandStack
.map { $0.configuration.version }
.last(where: { !$0.isEmpty })
?? "Unspecified version"
self = .help(text: versionString)
return
case .completionScriptRequested(let shell):
do {
let completionsGenerator = try CompletionsGenerator(command: type.asCommand, shellName: shell)
self = .help(text: completionsGenerator.generateCompletionScript())
return
} catch {
self.init(error: error, type: type)
return
}
case .completionScriptCustomResponse(let output):
self = .help(text: output)
return
default:
break
}
case let e as ParserError:
// Send ParserErrors back through the CommandError path
self.init(error: CommandError(commandStack: [type.asCommand], parserError: e), type: type)
return
default:
commandStack = [type.asCommand]
// if the error wasn't one of our two Error types, wrap it as a userValidationError
// to be handled appropriately below
parserError = .userValidationError(error)
}
var usage = HelpGenerator(commandStack: commandStack).usageMessage()
let commandNames = commandStack.map { $0._commandName }.joined(separator: " ")
if let helpName = commandStack.getPrimaryHelpName() {
usage += "\n See '\(commandNames) \(helpName.synopsisString)' for more information."
}
// Parsing errors and user-thrown validation errors have the usage
// string attached. Other errors just get the error message.
if case .userValidationError(let error) = parserError {
switch error {
case let error as ValidationError:
self = .validation(message: error.message, usage: usage, help: "")
case let error as CleanExit:
switch error.base {
case .helpRequest(let command):
if let command = command {
commandStack = CommandParser(type.asCommand).commandStack(for: command)
}
self = .help(text: HelpGenerator(commandStack: commandStack).rendered())
case .dumpRequest(let command):
if let command = command {
commandStack = CommandParser(type.asCommand).commandStack(for: command)
}
self = .help(text: DumpHelpGenerator(commandStack: commandStack).rendered())
case .message(let message):
self = .help(text: message)
}
case let error as ExitCode:
self = .other(message: "", exitCode: error.rawValue)
case let error as LocalizedError where error.errorDescription != nil:
self = .other(message: error.errorDescription!, exitCode: EXIT_FAILURE)
default:
if Swift.type(of: error) is NSError.Type {
self = .other(message: error.localizedDescription, exitCode: EXIT_FAILURE)
} else {
self = .other(message: String(describing: error), exitCode: EXIT_FAILURE)
}
}
} else if let parserError = parserError {
let usage: String = {
guard case ParserError.noArguments = parserError else { return usage }
return "\n" + HelpGenerator(commandStack: [type.asCommand]).rendered()
}()
let argumentSet = ArgumentSet(commandStack.last!)
let message = argumentSet.errorDescription(error: parserError) ?? ""
let helpAbstract = argumentSet.helpDescription(error: parserError) ?? ""
self = .validation(message: message, usage: usage, help: helpAbstract)
} else {
self = .other(message: String(describing: error), exitCode: EXIT_FAILURE)
}
}