rm TaintedString for string; some proc -> func (#53)
* rm TaintedString for string; some proc -> func * procs which interact with macros in certain ways can't be funcs in Nim 1.2
This commit is contained in:
parent
d06f6187dc
commit
fc03a0c4e1
|
@ -338,7 +338,7 @@ Furthermore, you can extend the behavior of the library by providing
|
||||||
overloads such as:
|
overloads such as:
|
||||||
|
|
||||||
```nim
|
```nim
|
||||||
proc parseCmdArg*(T: type Foo, p: TaintedString): T =
|
proc parseCmdArg*(T: type Foo, p: string): T =
|
||||||
## This provides parsing and validation for fields having the `Foo` type.
|
## This provides parsing and validation for fields having the `Foo` type.
|
||||||
## You should raise `ConfigurationError` in case of detected problems.
|
## You should raise `ConfigurationError` in case of detected problems.
|
||||||
...
|
...
|
||||||
|
|
114
confutils.nim
114
confutils.nim
|
@ -60,7 +60,7 @@ const
|
||||||
confutils_description_width {.intdefine.} = 80
|
confutils_description_width {.intdefine.} = 80
|
||||||
confutils_narrow_terminal_width {.intdefine.} = 36
|
confutils_narrow_terminal_width {.intdefine.} = 36
|
||||||
|
|
||||||
proc getFieldName(caseField: NimNode): NimNode =
|
func getFieldName(caseField: NimNode): NimNode =
|
||||||
result = caseField
|
result = caseField
|
||||||
if result.kind == nnkIdentDefs: result = result[0]
|
if result.kind == nnkIdentDefs: result = result[0]
|
||||||
if result.kind == nnkPragmaExpr: result = result[0]
|
if result.kind == nnkPragmaExpr: result = result[0]
|
||||||
|
@ -390,7 +390,7 @@ func getNextArgIdx(cmd: CmdInfo, consumedArgIdx: int): int =
|
||||||
if cmd.opts[i].kind == Arg and cmd.opts[i].idx > consumedArgIdx:
|
if cmd.opts[i].kind == Arg and cmd.opts[i].idx > consumedArgIdx:
|
||||||
return cmd.opts[i].idx
|
return cmd.opts[i].idx
|
||||||
|
|
||||||
return -1
|
-1
|
||||||
|
|
||||||
proc noMoreArgsError(cmd: CmdInfo): string =
|
proc noMoreArgsError(cmd: CmdInfo): string =
|
||||||
result = if cmd.isSubCommand: "The command '$1'" % [cmd.name]
|
result = if cmd.isSubCommand: "The command '$1'" % [cmd.name]
|
||||||
|
@ -399,23 +399,23 @@ proc noMoreArgsError(cmd: CmdInfo): string =
|
||||||
if cmd.hasArgs: result.add " additional"
|
if cmd.hasArgs: result.add " additional"
|
||||||
result.add " arguments"
|
result.add " arguments"
|
||||||
|
|
||||||
proc findOpt(opts: openArray[OptInfo], name: string): OptInfo =
|
func findOpt(opts: openArray[OptInfo], name: string): OptInfo =
|
||||||
for opt in opts:
|
for opt in opts:
|
||||||
if cmpIgnoreStyle(opt.name, name) == 0 or
|
if cmpIgnoreStyle(opt.name, name) == 0 or
|
||||||
cmpIgnoreStyle(opt.abbr, name) == 0:
|
cmpIgnoreStyle(opt.abbr, name) == 0:
|
||||||
return opt
|
return opt
|
||||||
|
|
||||||
proc findOpt(activeCmds: openArray[CmdInfo], name: string): OptInfo =
|
func findOpt(activeCmds: openArray[CmdInfo], name: string): OptInfo =
|
||||||
for i in countdown(activeCmds.len - 1, 0):
|
for i in countdown(activeCmds.len - 1, 0):
|
||||||
let found = findOpt(activeCmds[i].opts, name)
|
let found = findOpt(activeCmds[i].opts, name)
|
||||||
if found != nil: return found
|
if found != nil: return found
|
||||||
|
|
||||||
proc findCmd(cmds: openArray[CmdInfo], name: string): CmdInfo =
|
func findCmd(cmds: openArray[CmdInfo], name: string): CmdInfo =
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
if cmpIgnoreStyle(cmd.name, name) == 0:
|
if cmpIgnoreStyle(cmd.name, name) == 0:
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
proc findSubCmd(cmd: CmdInfo, name: string): CmdInfo =
|
func findSubCmd(cmd: CmdInfo, name: string): CmdInfo =
|
||||||
let subCmdDiscriminator = cmd.getSubCmdDiscriminator
|
let subCmdDiscriminator = cmd.getSubCmdDiscriminator
|
||||||
if subCmdDiscriminator != nil:
|
if subCmdDiscriminator != nil:
|
||||||
let cmd = findCmd(subCmdDiscriminator.subCmds, name)
|
let cmd = findCmd(subCmdDiscriminator.subCmds, name)
|
||||||
|
@ -423,7 +423,7 @@ proc findSubCmd(cmd: CmdInfo, name: string): CmdInfo =
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
proc startsWithIgnoreStyle(s: string, prefix: string): bool =
|
func startsWithIgnoreStyle(s: string, prefix: string): bool =
|
||||||
# Similar in spirit to cmpIgnoreStyle, but compare only the prefix.
|
# Similar in spirit to cmpIgnoreStyle, but compare only the prefix.
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
|
@ -461,13 +461,13 @@ else:
|
||||||
template printCmdTree(cmd: CmdInfo) = discard
|
template printCmdTree(cmd: CmdInfo) = discard
|
||||||
|
|
||||||
# TODO remove the overloads here to get better "missing overload" error message
|
# TODO remove the overloads here to get better "missing overload" error message
|
||||||
proc parseCmdArg*(T: type InputDir, p: TaintedString): T =
|
proc parseCmdArg*(T: type InputDir, p: string): T =
|
||||||
if not dirExists(p.string):
|
if not dirExists(p.string):
|
||||||
raise newException(ValueError, "Directory doesn't exist")
|
raise newException(ValueError, "Directory doesn't exist")
|
||||||
|
|
||||||
result = T(p)
|
T(p)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type InputFile, p: TaintedString): T =
|
proc parseCmdArg*(T: type InputFile, p: string): T =
|
||||||
# TODO this is needed only because InputFile cannot be made
|
# TODO this is needed only because InputFile cannot be made
|
||||||
# an alias of TypedInputFile at the moment, because of a generics
|
# an alias of TypedInputFile at the moment, because of a generics
|
||||||
# caching issue
|
# caching issue
|
||||||
|
@ -481,10 +481,10 @@ proc parseCmdArg*(T: type InputFile, p: TaintedString): T =
|
||||||
except IOError:
|
except IOError:
|
||||||
raise newException(ValueError, "File not accessible")
|
raise newException(ValueError, "File not accessible")
|
||||||
|
|
||||||
result = T(p.string)
|
T(p.string)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type TypedInputFile, p: TaintedString): T =
|
proc parseCmdArg*(T: type TypedInputFile, p: string): T =
|
||||||
var path = p.string
|
var path = p
|
||||||
when T.defaultExt.len > 0:
|
when T.defaultExt.len > 0:
|
||||||
path = path.addFileExt(T.defaultExt)
|
path = path.addFileExt(T.defaultExt)
|
||||||
|
|
||||||
|
@ -498,59 +498,59 @@ proc parseCmdArg*(T: type TypedInputFile, p: TaintedString): T =
|
||||||
except IOError:
|
except IOError:
|
||||||
raise newException(ValueError, "File not accessible")
|
raise newException(ValueError, "File not accessible")
|
||||||
|
|
||||||
result = T(path)
|
T(path)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type[OutDir|OutFile|OutPath], p: TaintedString): T =
|
func parseCmdArg*(T: type[OutDir|OutFile|OutPath], p: string): T =
|
||||||
result = T(p)
|
T(p)
|
||||||
|
|
||||||
proc parseCmdArg*[T](_: type Option[T], s: TaintedString): Option[T] =
|
proc parseCmdArg*[T](_: type Option[T], s: string): Option[T] =
|
||||||
return some(parseCmdArg(T, s))
|
some(parseCmdArg(T, s))
|
||||||
|
|
||||||
template parseCmdArg*(T: type string, s: TaintedString): string =
|
template parseCmdArg*(T: type string, s: string): string =
|
||||||
string s
|
s
|
||||||
|
|
||||||
proc parseCmdArg*(T: type SomeSignedInt, s: TaintedString): T =
|
func parseCmdArg*(T: type SomeSignedInt, s: string): T =
|
||||||
T parseBiggestInt(string s)
|
T parseBiggestInt(string s)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type SomeUnsignedInt, s: TaintedString): T =
|
func parseCmdArg*(T: type SomeUnsignedInt, s: string): T =
|
||||||
T parseBiggestUInt(string s)
|
T parseBiggestUInt(string s)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type SomeFloat, p: TaintedString): T =
|
func parseCmdArg*(T: type SomeFloat, p: string): T =
|
||||||
result = parseFloat(p)
|
parseFloat(p)
|
||||||
|
|
||||||
proc parseCmdArg*(T: type bool, p: TaintedString): T =
|
func parseCmdArg*(T: type bool, p: string): T =
|
||||||
try:
|
try:
|
||||||
result = p.len == 0 or parseBool(p)
|
p.len == 0 or parseBool(p)
|
||||||
except CatchableError:
|
except CatchableError:
|
||||||
raise newException(ValueError, "'" & p.string & "' is not a valid boolean value. Supported values are on/off, yes/no, true/false or 1/0")
|
raise newException(ValueError, "'" & p.string & "' is not a valid boolean value. Supported values are on/off, yes/no, true/false or 1/0")
|
||||||
|
|
||||||
proc parseCmdArg*(T: type enum, s: TaintedString): T =
|
func parseCmdArg*(T: type enum, s: string): T =
|
||||||
parseEnum[T](string(s))
|
parseEnum[T](string(s))
|
||||||
|
|
||||||
proc parseCmdArgAux(T: type, s: TaintedString): T = # {.raises: [ValueError].} =
|
proc parseCmdArgAux(T: type, s: string): T = # {.raises: [ValueError].} =
|
||||||
# The parseCmdArg procs are allowed to raise only `ValueError`.
|
# The parseCmdArg procs are allowed to raise only `ValueError`.
|
||||||
# If you have provided your own specializations, please handle
|
# If you have provided your own specializations, please handle
|
||||||
# all other exception types.
|
# all other exception types.
|
||||||
mixin parseCmdArg
|
mixin parseCmdArg
|
||||||
parseCmdArg(T, s)
|
parseCmdArg(T, s)
|
||||||
|
|
||||||
proc completeCmdArg*(T: type enum, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type enum, val: string): seq[string] =
|
||||||
for e in low(T)..high(T):
|
for e in low(T)..high(T):
|
||||||
let as_str = $e
|
let as_str = $e
|
||||||
if startsWithIgnoreStyle(as_str, val):
|
if startsWithIgnoreStyle(as_str, val):
|
||||||
result.add($e)
|
result.add($e)
|
||||||
|
|
||||||
proc completeCmdArg*(T: type SomeNumber, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type SomeNumber, val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
proc completeCmdArg*(T: type bool, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type bool, val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
proc completeCmdArg*(T: type string, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type string, val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
proc completeCmdArg*(T: type[InputFile|TypedInputFile|InputDir|OutFile|OutDir|OutPath],
|
proc completeCmdArg*(T: type[InputFile|TypedInputFile|InputDir|OutFile|OutDir|OutPath],
|
||||||
val: TaintedString): seq[string] =
|
val: string): seq[string] =
|
||||||
when not defined(nimscript):
|
when not defined(nimscript):
|
||||||
let (dir, name, ext) = splitFile(val)
|
let (dir, name, ext) = splitFile(val)
|
||||||
let tail = name & ext
|
let tail = name & ext
|
||||||
|
@ -581,36 +581,36 @@ proc completeCmdArg*(T: type[InputFile|TypedInputFile|InputDir|OutFile|OutDir|Ou
|
||||||
except OSError:
|
except OSError:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc completeCmdArg*[T](_: type seq[T], val: TaintedString): seq[string] =
|
func completeCmdArg*[T](_: type seq[T], val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
proc completeCmdArg*[T](_: type Option[T], val: TaintedString): seq[string] =
|
proc completeCmdArg*[T](_: type Option[T], val: string): seq[string] =
|
||||||
mixin completeCmdArg
|
mixin completeCmdArg
|
||||||
return completeCmdArg(type(T), val)
|
return completeCmdArg(type(T), val)
|
||||||
|
|
||||||
proc completeCmdArgAux(T: type, val: TaintedString): seq[string] =
|
proc completeCmdArgAux(T: type, val: string): seq[string] =
|
||||||
mixin completeCmdArg
|
mixin completeCmdArg
|
||||||
return completeCmdArg(T, val)
|
return completeCmdArg(T, val)
|
||||||
|
|
||||||
template setField[T](loc: var T, val: Option[TaintedString], defaultVal: untyped) =
|
template setField[T](loc: var T, val: Option[string], defaultVal: untyped) =
|
||||||
type FieldType = type(loc)
|
type FieldType = type(loc)
|
||||||
loc = if isSome(val): parseCmdArgAux(FieldType, val.get)
|
loc = if isSome(val): parseCmdArgAux(FieldType, val.get)
|
||||||
else: FieldType(defaultVal)
|
else: FieldType(defaultVal)
|
||||||
|
|
||||||
template setField[T](loc: var seq[T], val: Option[TaintedString], defaultVal: untyped) =
|
template setField[T](loc: var seq[T], val: Option[string], defaultVal: untyped) =
|
||||||
if val.isSome:
|
if val.isSome:
|
||||||
loc.add parseCmdArgAux(type(loc[0]), val.get)
|
loc.add parseCmdArgAux(type(loc[0]), val.get)
|
||||||
else:
|
else:
|
||||||
type FieldType = type(loc)
|
type FieldType = type(loc)
|
||||||
loc = FieldType(defaultVal)
|
loc = FieldType(defaultVal)
|
||||||
|
|
||||||
proc makeDefaultValue*(T: type): T =
|
func makeDefaultValue*(T: type): T =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc requiresInput*(T: type): bool =
|
func requiresInput*(T: type): bool =
|
||||||
not ((T is seq) or (T is Option) or (T is bool))
|
not ((T is seq) or (T is Option) or (T is bool))
|
||||||
|
|
||||||
proc acceptsMultipleValues*(T: type): bool =
|
func acceptsMultipleValues*(T: type): bool =
|
||||||
T is seq
|
T is seq
|
||||||
|
|
||||||
template debugMacroResult(macroName: string) {.dirty.} =
|
template debugMacroResult(macroName: string) {.dirty.} =
|
||||||
|
@ -651,7 +651,7 @@ proc generateFieldSetters(RecordType: NimNode): NimNode =
|
||||||
newCall(bindSym"acceptsMultipleValues", fixedFieldType))
|
newCall(bindSym"acceptsMultipleValues", fixedFieldType))
|
||||||
|
|
||||||
result.add quote do:
|
result.add quote do:
|
||||||
proc `completerName`(val: TaintedString): seq[string] {.
|
proc `completerName`(val: string): seq[string] {.
|
||||||
nimcall
|
nimcall
|
||||||
gcsafe
|
gcsafe
|
||||||
sideEffect
|
sideEffect
|
||||||
|
@ -659,7 +659,7 @@ proc generateFieldSetters(RecordType: NimNode): NimNode =
|
||||||
.} =
|
.} =
|
||||||
return completeCmdArgAux(`fixedFieldType`, val)
|
return completeCmdArgAux(`fixedFieldType`, val)
|
||||||
|
|
||||||
proc `setterName`(`configVar`: var `RecordType`, val: Option[TaintedString]) {.
|
proc `setterName`(`configVar`: var `RecordType`, val: Option[string]) {.
|
||||||
nimcall
|
nimcall
|
||||||
gcsafe
|
gcsafe
|
||||||
sideEffect
|
sideEffect
|
||||||
|
@ -678,14 +678,14 @@ proc generateFieldSetters(RecordType: NimNode): NimNode =
|
||||||
result.add settersArray
|
result.add settersArray
|
||||||
debugMacroResult "Field Setters"
|
debugMacroResult "Field Setters"
|
||||||
|
|
||||||
proc checkDuplicate(cmd: CmdInfo, opt: OptInfo, fieldName: NimNode) =
|
func checkDuplicate(cmd: CmdInfo, opt: OptInfo, fieldName: NimNode) =
|
||||||
for x in cmd.opts:
|
for x in cmd.opts:
|
||||||
if opt.name == x.name:
|
if opt.name == x.name:
|
||||||
error "duplicate name detected: " & opt.name, fieldName
|
error "duplicate name detected: " & opt.name, fieldName
|
||||||
if opt.abbr.len > 0 and opt.abbr == x.abbr:
|
if opt.abbr.len > 0 and opt.abbr == x.abbr:
|
||||||
error "duplicate abbr detected: " & opt.abbr, fieldName
|
error "duplicate abbr detected: " & opt.abbr, fieldName
|
||||||
|
|
||||||
proc validPath(path: var seq[CmdInfo], parent, node: CmdInfo): bool =
|
func validPath(path: var seq[CmdInfo], parent, node: CmdInfo): bool =
|
||||||
for x in parent.opts:
|
for x in parent.opts:
|
||||||
if x.kind != Discriminator: continue
|
if x.kind != Discriminator: continue
|
||||||
for y in x.subCmds:
|
for y in x.subCmds:
|
||||||
|
@ -697,7 +697,7 @@ proc validPath(path: var seq[CmdInfo], parent, node: CmdInfo): bool =
|
||||||
return true
|
return true
|
||||||
false
|
false
|
||||||
|
|
||||||
proc findPath(parent, node: CmdInfo): seq[CmdInfo] =
|
func findPath(parent, node: CmdInfo): seq[CmdInfo] =
|
||||||
# find valid path from parent to node
|
# find valid path from parent to node
|
||||||
result = newSeq[CmdInfo]()
|
result = newSeq[CmdInfo]()
|
||||||
doAssert validPath(result, parent, node)
|
doAssert validPath(result, parent, node)
|
||||||
|
@ -878,7 +878,7 @@ proc loadImpl[C, SecondarySources](
|
||||||
|
|
||||||
let confAddr = addr result
|
let confAddr = addr result
|
||||||
|
|
||||||
template applySetter(setterIdx: int, cmdLineVal: TaintedString) =
|
template applySetter(setterIdx: int, cmdLineVal: string) =
|
||||||
try:
|
try:
|
||||||
fieldSetters[setterIdx][1](confAddr[], some(cmdLineVal))
|
fieldSetters[setterIdx][1](confAddr[], some(cmdLineVal))
|
||||||
inc fieldCounters[setterIdx]
|
inc fieldCounters[setterIdx]
|
||||||
|
@ -889,7 +889,7 @@ proc loadImpl[C, SecondarySources](
|
||||||
getCurrentExceptionMsg())
|
getCurrentExceptionMsg())
|
||||||
|
|
||||||
when hasCompletions:
|
when hasCompletions:
|
||||||
template getArgCompletions(opt: OptInfo, prefix: TaintedString): seq[string] =
|
template getArgCompletions(opt: OptInfo, prefix: string): seq[string] =
|
||||||
fieldSetters[opt.idx][2](prefix)
|
fieldSetters[opt.idx][2](prefix)
|
||||||
|
|
||||||
template required(opt: OptInfo): bool =
|
template required(opt: OptInfo): bool =
|
||||||
|
@ -897,8 +897,8 @@ proc loadImpl[C, SecondarySources](
|
||||||
|
|
||||||
template activateCmd(discriminator: OptInfo, activatedCmd: CmdInfo) =
|
template activateCmd(discriminator: OptInfo, activatedCmd: CmdInfo) =
|
||||||
let cmd = activatedCmd
|
let cmd = activatedCmd
|
||||||
applySetter(discriminator.idx, if cmd.desc.len > 0: TaintedString(cmd.desc)
|
applySetter(discriminator.idx, if cmd.desc.len > 0: cmd.desc
|
||||||
else: TaintedString(cmd.name))
|
else: cmd.name)
|
||||||
activeCmds.add cmd
|
activeCmds.add cmd
|
||||||
nextArgIdx = cmd.getNextArgIdx(-1)
|
nextArgIdx = cmd.getNextArgIdx(-1)
|
||||||
|
|
||||||
|
@ -1070,7 +1070,7 @@ proc loadImpl[C, SecondarySources](
|
||||||
# there is nothing left to do here.
|
# there is nothing left to do here.
|
||||||
discard
|
discard
|
||||||
elif opt.hasDefault:
|
elif opt.hasDefault:
|
||||||
fieldSetters[opt.idx][1](conf, none[TaintedString]())
|
fieldSetters[opt.idx][1](conf, none[string]())
|
||||||
elif opt.required:
|
elif opt.required:
|
||||||
fail "The required option '$1' was not specified" % [opt.name]
|
fail "The required option '$1' was not specified" % [opt.name]
|
||||||
|
|
||||||
|
@ -1092,7 +1092,7 @@ template load*(
|
||||||
copyrightBanner, printUsage, quitOnFailure,
|
copyrightBanner, printUsage, quitOnFailure,
|
||||||
secondarySourcesRef, secondarySources)
|
secondarySourcesRef, secondarySources)
|
||||||
|
|
||||||
proc defaults*(Configuration: type): Configuration =
|
func defaults*(Configuration: type): Configuration =
|
||||||
load(Configuration, cmdLine = @[], printUsage = false, quitOnFailure = false)
|
load(Configuration, cmdLine = @[], printUsage = false, quitOnFailure = false)
|
||||||
|
|
||||||
proc dispatchImpl(cliProcSym, cliArgs, loadArgs: NimNode): NimNode =
|
proc dispatchImpl(cliProcSym, cliArgs, loadArgs: NimNode): NimNode =
|
||||||
|
@ -1175,7 +1175,7 @@ macro cli*(args: varargs[untyped]): untyped =
|
||||||
|
|
||||||
debugMacroResult "CLI Code"
|
debugMacroResult "CLI Code"
|
||||||
|
|
||||||
proc load*(f: TypedInputFile): f.ContentType =
|
func load*(f: TypedInputFile): f.ContentType =
|
||||||
when f.Format is Unspecified or f.ContentType is Unspecified:
|
when f.Format is Unspecified or f.ContentType is Unspecified:
|
||||||
{.fatal: "To use `InputFile.load`, please specify the Format and ContentType of the file".}
|
{.fatal: "To use `InputFile.load`, please specify the Format and ContentType of the file".}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2018 Status Research & Development GmbH
|
# Copyright 2018-2022 Status Research & Development GmbH
|
||||||
# Parts taken from Nim's Runtime Library (c) Copyright 2015 Andreas Rumpf
|
# Parts taken from Nim's Runtime Library (c) Copyright 2015 Andreas Rumpf
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -17,11 +17,11 @@ type
|
||||||
cmds: seq[string]
|
cmds: seq[string]
|
||||||
idx: int
|
idx: int
|
||||||
kind*: CmdLineKind ## The detected command line token
|
kind*: CmdLineKind ## The detected command line token
|
||||||
key*, val*: TaintedString ## Key and value pair; the key is the option
|
key*, val*: string ## Key and value pair; the key is the option
|
||||||
## or the argument, and the value is not "" if
|
## or the argument, and the value is not "" if
|
||||||
## the option was given a value
|
## the option was given a value
|
||||||
|
|
||||||
proc parseWord(s: string, i: int, w: var string,
|
func parseWord(s: string, i: int, w: var string,
|
||||||
delim: set[char] = {'\t', ' '}): int =
|
delim: set[char] = {'\t', ' '}): int =
|
||||||
result = i
|
result = i
|
||||||
if result < s.len and s[result] == '\"':
|
if result < s.len and s[result] == '\"':
|
||||||
|
@ -37,7 +37,7 @@ proc parseWord(s: string, i: int, w: var string,
|
||||||
add(w, s[result])
|
add(w, s[result])
|
||||||
inc(result)
|
inc(result)
|
||||||
|
|
||||||
proc initOptParser*(cmds: seq[string], shortNoVal: set[char]={},
|
func initOptParser*(cmds: seq[string], shortNoVal: set[char]={},
|
||||||
longNoVal: seq[string] = @[];
|
longNoVal: seq[string] = @[];
|
||||||
allowWhitespaceAfterColon = true): OptParser =
|
allowWhitespaceAfterColon = true): OptParser =
|
||||||
result.pos = 0
|
result.pos = 0
|
||||||
|
@ -48,10 +48,10 @@ proc initOptParser*(cmds: seq[string], shortNoVal: set[char]={},
|
||||||
result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
|
result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
|
||||||
result.cmds = cmds
|
result.cmds = cmds
|
||||||
result.kind = cmdEnd
|
result.kind = cmdEnd
|
||||||
result.key = TaintedString""
|
result.key = ""
|
||||||
result.val = TaintedString""
|
result.val = ""
|
||||||
|
|
||||||
proc handleShortOption(p: var OptParser; cmd: string) =
|
func handleShortOption(p: var OptParser; cmd: string) =
|
||||||
var i = p.pos
|
var i = p.pos
|
||||||
p.kind = cmdShortOption
|
p.kind = cmdShortOption
|
||||||
if i < cmd.len:
|
if i < cmd.len:
|
||||||
|
@ -67,7 +67,7 @@ proc handleShortOption(p: var OptParser; cmd: string) =
|
||||||
inc(i)
|
inc(i)
|
||||||
p.inShortState = false
|
p.inShortState = false
|
||||||
while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i)
|
while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i)
|
||||||
p.val = TaintedString substr(cmd, i)
|
p.val = substr(cmd, i)
|
||||||
p.pos = 0
|
p.pos = 0
|
||||||
inc p.idx
|
inc p.idx
|
||||||
else:
|
else:
|
||||||
|
@ -77,7 +77,7 @@ proc handleShortOption(p: var OptParser; cmd: string) =
|
||||||
p.pos = 0
|
p.pos = 0
|
||||||
inc p.idx
|
inc p.idx
|
||||||
|
|
||||||
proc next*(p: var OptParser) =
|
func next*(p: var OptParser) =
|
||||||
## Parses the next token.
|
## Parses the next token.
|
||||||
##
|
##
|
||||||
## ``p.kind`` describes what kind of token has been parsed. ``p.key`` and
|
## ``p.kind`` describes what kind of token has been parsed. ``p.key`` and
|
||||||
|
@ -119,12 +119,12 @@ proc next*(p: var OptParser) =
|
||||||
inc p.idx
|
inc p.idx
|
||||||
i = 0
|
i = 0
|
||||||
if p.idx < p.cmds.len:
|
if p.idx < p.cmds.len:
|
||||||
p.val = TaintedString p.cmds[p.idx].substr(i)
|
p.val = p.cmds[p.idx].substr(i)
|
||||||
elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len:
|
elif len(p.longNoVal) > 0 and p.key notin p.longNoVal and p.idx+1 < p.cmds.len:
|
||||||
p.val = TaintedString p.cmds[p.idx+1]
|
p.val = p.cmds[p.idx+1]
|
||||||
inc p.idx
|
inc p.idx
|
||||||
else:
|
else:
|
||||||
p.val = TaintedString""
|
p.val = ""
|
||||||
inc p.idx
|
inc p.idx
|
||||||
p.pos = 0
|
p.pos = 0
|
||||||
else:
|
else:
|
||||||
|
@ -132,11 +132,11 @@ proc next*(p: var OptParser) =
|
||||||
handleShortOption(p, p.cmds[p.idx])
|
handleShortOption(p, p.cmds[p.idx])
|
||||||
else:
|
else:
|
||||||
p.kind = cmdArgument
|
p.kind = cmdArgument
|
||||||
p.key = TaintedString p.cmds[p.idx]
|
p.key = p.cmds[p.idx]
|
||||||
inc p.idx
|
inc p.idx
|
||||||
p.pos = 0
|
p.pos = 0
|
||||||
|
|
||||||
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedString] =
|
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: string] =
|
||||||
p.pos = 0
|
p.pos = 0
|
||||||
p.idx = 0
|
p.idx = 0
|
||||||
while true:
|
while true:
|
||||||
|
@ -146,7 +146,7 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, val: TaintedSt
|
||||||
|
|
||||||
iterator getopt*(cmds: seq[string],
|
iterator getopt*(cmds: seq[string],
|
||||||
shortNoVal: set[char]={}, longNoVal: seq[string] = @[]):
|
shortNoVal: set[char]={}, longNoVal: seq[string] = @[]):
|
||||||
tuple[kind: CmdLineKind, key, val: TaintedString] =
|
tuple[kind: CmdLineKind, key, val: string] =
|
||||||
var p = initOptParser(cmds, shortNoVal=shortNoVal, longNoVal=longNoVal)
|
var p = initOptParser(cmds, shortNoVal=shortNoVal, longNoVal=longNoVal)
|
||||||
while true:
|
while true:
|
||||||
next(p)
|
next(p)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
options
|
std/options
|
||||||
|
|
||||||
type
|
type
|
||||||
ConfigurationError* = object of CatchableError
|
ConfigurationError* = object of CatchableError
|
||||||
|
@ -21,15 +21,15 @@ type
|
||||||
SubCommandArgs* = distinct string
|
SubCommandArgs* = distinct string
|
||||||
|
|
||||||
Flag* = object
|
Flag* = object
|
||||||
name*: TaintedString
|
name*: string
|
||||||
|
|
||||||
FlagWithValue* = object
|
FlagWithValue* = object
|
||||||
name*: TaintedString
|
name*: string
|
||||||
value*: TaintedString
|
value*: string
|
||||||
|
|
||||||
FlagWithOptionalValue* = object
|
FlagWithOptionalValue* = object
|
||||||
name*: TaintedString
|
name*: string
|
||||||
value*: Option[TaintedString]
|
value*: Option[string]
|
||||||
|
|
||||||
Unspecified* = object
|
Unspecified* = object
|
||||||
Txt* = object
|
Txt* = object
|
||||||
|
@ -61,4 +61,3 @@ template implicitlySelectable* {.pragma.}
|
||||||
## to allow the value of the discriminator to be determined
|
## to allow the value of the discriminator to be determined
|
||||||
## implicitly when the user specifies any of the sub-options
|
## implicitly when the user specifies any of the sub-options
|
||||||
## that depend on the disciminator value.
|
## that depend on the disciminator value.
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ export stewNet
|
||||||
|
|
||||||
export ValidIpAddress
|
export ValidIpAddress
|
||||||
|
|
||||||
func parseCmdArg*(T: type ValidIpAddress, s: TaintedString): T =
|
func parseCmdArg*(T: type ValidIpAddress, s: string): T =
|
||||||
ValidIpAddress.init(string s)
|
ValidIpAddress.init(string s)
|
||||||
|
|
||||||
proc completeCmdArg*(T: type ValidIpAddress, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type ValidIpAddress, val: string): seq[string] =
|
||||||
# TODO: Maybe complete the local IP address?
|
# TODO: Maybe complete the local IP address?
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
func parseCmdArg*(T: type Port, s: TaintedString): T =
|
func parseCmdArg*(T: type Port, s: string): T =
|
||||||
template fail =
|
template fail =
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"The supplied port must be an integer value in the range 1-65535")
|
"The supplied port must be an integer value in the range 1-65535")
|
||||||
|
@ -25,6 +25,5 @@ func parseCmdArg*(T: type Port, s: TaintedString): T =
|
||||||
|
|
||||||
return Port(intVal)
|
return Port(intVal)
|
||||||
|
|
||||||
proc completeCmdArg*(T: type Port, val: TaintedString): seq[string] =
|
func completeCmdArg*(T: type Port, val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
|
|
|
@ -120,11 +120,11 @@ type
|
||||||
func defaultDataDir(conf: TestConf): string =
|
func defaultDataDir(conf: TestConf): string =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
func parseCmdArg*(T: type GraffitiBytes, input: TaintedString): T
|
func parseCmdArg*(T: type GraffitiBytes, input: string): T
|
||||||
{.raises: [ValueError, Defect].} =
|
{.raises: [ValueError, Defect].} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
func completeCmdArg*(T: type GraffitiBytes, input: TaintedString): seq[string] =
|
func completeCmdArg*(T: type GraffitiBytes, input: string): seq[string] =
|
||||||
@[]
|
@[]
|
||||||
|
|
||||||
func defaultAdminListenAddress*(conf: TestConf): ValidIpAddress =
|
func defaultAdminListenAddress*(conf: TestConf): ValidIpAddress =
|
||||||
|
|
|
@ -13,11 +13,11 @@ type
|
||||||
desc: "La2"
|
desc: "La2"
|
||||||
name: "la2" }: specialint.SInt
|
name: "la2" }: specialint.SInt
|
||||||
|
|
||||||
proc parseCmdArg(T: type specialint.SInt, p: TaintedString): T =
|
func parseCmdArg(T: type specialint.SInt, p: string): T =
|
||||||
parseInt(string p).T
|
parseInt(string p).T
|
||||||
|
|
||||||
proc completeCmdArg(T: type specialint.SInt, val: TaintedString): seq[string] =
|
func completeCmdArg(T: type specialint.SInt, val: string): seq[string] =
|
||||||
return @[]
|
@[]
|
||||||
|
|
||||||
suite "Qualified Ident":
|
suite "Qualified Ident":
|
||||||
test "Qualified Ident":
|
test "Qualified Ident":
|
||||||
|
|
Loading…
Reference in New Issue