Make parseopt available on all backends (#17009)

* Make parseopt available on all backends

* fix spaces

* fix getopt and update prelude

* no crazy unnecessary version checks, use doAssert
This commit is contained in:
hlaaftana 2021-02-13 11:05:40 +03:00 • committed by GitHub
commit fad8439b8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 144 deletions

View file

@ -147,6 +147,14 @@ provided by the operating system.
issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages) issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages)
for modules importing `std/wrapnils`. for modules importing `std/wrapnils`.
- `parseopt.initOptParser` has been made available and `parseopt` has been
added back to `prelude` for all backends. Previously `initOptParser` was
unavailable if the `os` module did not have `paramCount` or `paramStr`,
but the use of these in `initOptParser` were conditionally to the runtime
arguments passed to it, so `initOptParser` has been changed to raise
`ValueError` when the real command line is not available. `parseopt` was
previously excluded from `prelude` for JS, as it could not be imported.
## Language changes ## Language changes
- `nimscript` now handles `except Exception as e`. - `nimscript` now handles `except Exception as e`.

View file

@ -16,8 +16,6 @@
## Same as: ## Same as:
## ##
## .. code-block:: nim ## .. code-block:: nim
## import os, strutils, times, parseutils, hashes, tables, sets, sequtils ## import os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt
## when not defined(js): import parseopt
import os, strutils, times, parseutils, hashes, tables, sets, sequtils import os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt
when not defined(js): import parseopt

View file

@ -192,83 +192,94 @@ proc parseWord(s: string, i: int, w: var string,
add(w, s[result]) add(w, s[result])
inc(result) inc(result)
when declared(os.paramCount): proc initOptParser*(cmdline = "", shortNoVal: set[char] = {},
# we cannot provide this for NimRtl creation on Posix, because we can't longNoVal: seq[string] = @[];
# access the command line arguments then! allowWhitespaceAfterColon = true): OptParser =
## Initializes the command line parser.
##
## If ``cmdline == ""``, the real command line as provided by the
## ``os`` module is retrieved instead if it is available. If the
## command line is not available, a `ValueError` will be raised.
##
## ``shortNoVal`` and ``longNoVal`` are used to specify which options
## do not take values. See the `documentation about these
## parameters<#shortnoval-and-longnoval>`_ for more information on
## how this affects parsing.
##
## See also:
## * `getopt iterator<#getopt.i,OptParser>`_
runnableExamples:
var p = initOptParser()
p = initOptParser("--left --debug:3 -l -r:2")
p = initOptParser("--left --debug:3 -l -r:2",
shortNoVal = {'l'}, longNoVal = @["left"])
proc initOptParser*(cmdline = "", shortNoVal: set[char] = {}, result.pos = 0
longNoVal: seq[string] = @[]; result.idx = 0
allowWhitespaceAfterColon = true): OptParser = result.inShortState = false
## Initializes the command line parser. result.shortNoVal = shortNoVal
## result.longNoVal = longNoVal
## If ``cmdline == ""``, the real command line as provided by the result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
## ``os`` module is retrieved instead. if cmdline != "":
## result.cmds = parseCmdLine(cmdline)
## ``shortNoVal`` and ``longNoVal`` are used to specify which options else:
## do not take values. See the `documentation about these when declared(paramCount):
## parameters<#shortnoval-and-longnoval>`_ for more information on result.cmds = newSeq[string](paramCount())
## how this affects parsing. for i in countup(1, paramCount()):
## result.cmds[i-1] = paramStr(i)
## See also:
## * `getopt iterator<#getopt.i,OptParser>`_
runnableExamples:
var p = initOptParser()
p = initOptParser("--left --debug:3 -l -r:2")
p = initOptParser("--left --debug:3 -l -r:2",
shortNoVal = {'l'}, longNoVal = @["left"])
result.pos = 0
result.idx = 0
result.inShortState = false
result.shortNoVal = shortNoVal
result.longNoVal = longNoVal
result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
if cmdline != "":
result.cmds = parseCmdLine(cmdline)
else: else:
result.cmds = newSeq[string](os.paramCount()) # we cannot provide this for NimRtl creation on Posix, because we can't
for i in countup(1, os.paramCount()): # access the command line arguments then!
result.cmds[i-1] = os.paramStr(i) doAssert false, "empty command line given but" &
" real command line is not accessible"
result.kind = cmdEnd result.kind = cmdEnd
result.key = "" result.key = ""
result.val = "" result.val = ""
proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {}, proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {},
longNoVal: seq[string] = @[]; longNoVal: seq[string] = @[];
allowWhitespaceAfterColon = true): OptParser = allowWhitespaceAfterColon = true): OptParser =
## Initializes the command line parser. ## Initializes the command line parser.
## ##
## If ``cmdline.len == 0``, the real command line as provided by the ## If ``cmdline.len == 0``, the real command line as provided by the
## ``os`` module is retrieved instead. Behavior of the other parameters ## ``os`` module is retrieved instead if it is available. If the
## remains the same as in `initOptParser(string, ...) ## command line is not available, a `ValueError` will be raised.
## <#initOptParser,string,set[char],seq[string]>`_. ## Behavior of the other parameters remains the same as in
## ## `initOptParser(string, ...)
## See also: ## <#initOptParser,string,set[char],seq[string]>`_.
## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_ ##
runnableExamples: ## See also:
var p = initOptParser() ## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_
p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"]) runnableExamples:
p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"], var p = initOptParser()
shortNoVal = {'l'}, longNoVal = @["left"]) p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"])
p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"],
shortNoVal = {'l'}, longNoVal = @["left"])
result.pos = 0 result.pos = 0
result.idx = 0 result.idx = 0
result.inShortState = false result.inShortState = false
result.shortNoVal = shortNoVal result.shortNoVal = shortNoVal
result.longNoVal = longNoVal result.longNoVal = longNoVal
result.allowWhitespaceAfterColon = allowWhitespaceAfterColon result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
if cmdline.len != 0: if cmdline.len != 0:
result.cmds = newSeq[string](cmdline.len) result.cmds = newSeq[string](cmdline.len)
for i in 0..<cmdline.len: for i in 0..<cmdline.len:
result.cmds[i] = cmdline[i] result.cmds[i] = cmdline[i]
else:
when declared(paramCount):
result.cmds = newSeq[string](paramCount())
for i in countup(1, paramCount()):
result.cmds[i-1] = paramStr(i)
else: else:
result.cmds = newSeq[string](os.paramCount()) # we cannot provide this for NimRtl creation on Posix, because we can't
for i in countup(1, os.paramCount()): # access the command line arguments then!
result.cmds[i-1] = os.paramStr(i) doAssert false, "empty command line given but" &
result.kind = cmdEnd " real command line is not accessible"
result.key = "" result.kind = cmdEnd
result.val = "" result.key = ""
result.val = ""
proc handleShortOption(p: var OptParser; cmd: string) = proc handleShortOption(p: var OptParser; cmd: string) =
var i = p.pos var i = p.pos
@ -366,23 +377,24 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
inc p.idx inc p.idx
p.pos = 0 p.pos = 0
proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo$1".} = when declared(quoteShellCommand):
## Retrieves the rest of the command line that has not been parsed yet. proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo$1".} =
## ## Retrieves the rest of the command line that has not been parsed yet.
## See also: ##
## * `remainingArgs proc<#remainingArgs,OptParser>`_ ## See also:
## ## * `remainingArgs proc<#remainingArgs,OptParser>`_
## **Examples:** ##
## ## **Examples:**
## .. code-block:: ##
## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") ## .. code-block::
## while true: ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt")
## p.next() ## while true:
## if p.kind == cmdLongOption and p.key == "": # Look for "--" ## p.next()
## break ## if p.kind == cmdLongOption and p.key == "": # Look for "--"
## else: continue ## break
## doAssert p.cmdLineRest == "foo.txt bar.txt" ## else: continue
result = p.cmds[p.idx .. ^1].quoteShellCommand ## doAssert p.cmdLineRest == "foo.txt bar.txt"
result = p.cmds[p.idx .. ^1].quoteShellCommand
proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} =
## Retrieves a sequence of the arguments that have not been parsed yet. ## Retrieves a sequence of the arguments that have not been parsed yet.
@ -442,54 +454,53 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key,
if p.kind == cmdEnd: break if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val) yield (p.kind, p.key, p.val)
when declared(initOptParser): iterator getopt*(cmdline: seq[string] = @[],
iterator getopt*(cmdline: seq[string] = commandLineParams(), shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]):
shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): tuple[kind: CmdLineKind, key, val: string] =
tuple[kind: CmdLineKind, key, val: string] = ## Convenience iterator for iterating over command line arguments.
## Convenience iterator for iterating over command line arguments. ##
## ## This creates a new `OptParser<#OptParser>`_. If no command line
## This creates a new `OptParser<#OptParser>`_. If no command line ## arguments are provided, the real command line as provided by the
## arguments are provided, the real command line as provided by the ## ``os`` module is retrieved instead.
## ``os`` module is retrieved instead. ##
## ## ``shortNoVal`` and ``longNoVal`` are used to specify which options
## ``shortNoVal`` and ``longNoVal`` are used to specify which options ## do not take values. See the `documentation about these
## do not take values. See the `documentation about these ## parameters<#shortnoval-and-longnoval>`_ for more information on
## parameters<#shortnoval-and-longnoval>`_ for more information on ## how this affects parsing.
## how this affects parsing. ##
## ## There is no need to check for ``cmdEnd`` while iterating.
## There is no need to check for ``cmdEnd`` while iterating. ##
## ## See also:
## See also: ## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_
## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_ ##
## ## **Examples:**
## **Examples:** ##
## ## .. code-block::
## .. code-block:: ##
## ## # these are placeholders, of course
## # these are placeholders, of course ## proc writeHelp() = discard
## proc writeHelp() = discard ## proc writeVersion() = discard
## proc writeVersion() = discard ##
## ## var filename: string
## var filename: string ## let params = @["--left", "--debug:3", "-l", "-r:2"]
## let params = @["--left", "--debug:3", "-l", "-r:2"] ##
## ## for kind, key, val in getopt(params):
## for kind, key, val in getopt(params): ## case kind
## case kind ## of cmdArgument:
## of cmdArgument: ## filename = key
## filename = key ## of cmdLongOption, cmdShortOption:
## of cmdLongOption, cmdShortOption: ## case key
## case key ## of "help", "h": writeHelp()
## of "help", "h": writeHelp() ## of "version", "v": writeVersion()
## of "version", "v": writeVersion() ## of cmdEnd: assert(false) # cannot happen
## of cmdEnd: assert(false) # cannot happen ## if filename == "":
## if filename == "": ## # no filename has been written, so we show the help
## # no filename has been written, so we show the help ## writeHelp()
## writeHelp() var p = initOptParser(cmdline, shortNoVal = shortNoVal,
var p = initOptParser(cmdline, shortNoVal = shortNoVal, longNoVal = longNoVal)
longNoVal = longNoVal) while true:
while true: next(p)
next(p) if p.kind == cmdEnd: break
if p.kind == cmdEnd: break yield (p.kind, p.key, p.val)
yield (p.kind, p.key, p.val)
{.pop.} {.pop.}

View file

@ -46,7 +46,7 @@ import std/[
# Parsers: # Parsers:
htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
# fails: parseopt parseopt,
# XML processing: # XML processing:
xmltree, xmlparser, xmltree, xmlparser,

View file

@ -48,7 +48,7 @@ import std/[
# Parsers: # Parsers:
htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
# fails: parseopt parseopt,
# XML processing: # XML processing:
xmltree, xmlparser, xmltree, xmlparser,
@ -114,3 +114,7 @@ block: # cpDir, cpFile, dirExists, fileExists, mkDir, mvDir, mvFile, rmDir, rmF
doAssert dirExists(subDir2) doAssert dirExists(subDir2)
mvDir(subDir2, subDir) mvDir(subDir2, subDir)
rmDir(dname) rmDir(dname)
block:
# check parseopt can get command line:
discard initOptParser()