diff options
-rw-r--r-- | changelog.md | 8 | ||||
-rw-r--r-- | lib/prelude.nim | 6 | ||||
-rw-r--r-- | lib/pure/parseopt.nim | 285 | ||||
-rw-r--r-- | tests/js/tstdlib_imports.nim | 2 | ||||
-rw-r--r-- | tests/test_nimscript.nims | 8 |
5 files changed, 165 insertions, 144 deletions
diff --git a/changelog.md b/changelog.md index 5adb15ff9..3e85d2d05 100644 --- a/changelog.md +++ b/changelog.md @@ -147,6 +147,14 @@ provided by the operating system. issues like https://github.com/nim-lang/Nim/issues/13063 (which affected error messages) 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 - `nimscript` now handles `except Exception as e`. diff --git a/lib/prelude.nim b/lib/prelude.nim index 4d8c7d7f0..e8f21fc99 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -16,8 +16,6 @@ ## Same as: ## ## .. code-block:: nim -## import os, strutils, times, parseutils, hashes, tables, sets, sequtils -## when not defined(js): import parseopt +## import os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt -import os, strutils, times, parseutils, hashes, tables, sets, sequtils -when not defined(js): import parseopt +import os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index e9e1e0e91..e79e53bd8 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -192,83 +192,94 @@ proc parseWord(s: string, i: int, w: var string, add(w, s[result]) inc(result) -when declared(os.paramCount): - # we cannot provide this for NimRtl creation on Posix, because we can't - # access the command line arguments then! - - proc initOptParser*(cmdline = "", shortNoVal: set[char] = {}, - longNoVal: seq[string] = @[]; - allowWhitespaceAfterColon = true): OptParser = - ## Initializes the command line parser. - ## - ## If ``cmdline == ""``, the real command line as provided by the - ## ``os`` module is retrieved instead. - ## - ## ``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] = {}, + longNoVal: seq[string] = @[]; + 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"]) - result.pos = 0 - result.idx = 0 - result.inShortState = false - result.shortNoVal = shortNoVal - result.longNoVal = longNoVal - result.allowWhitespaceAfterColon = allowWhitespaceAfterColon - if cmdline != "": - result.cmds = parseCmdLine(cmdline) + 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: + when declared(paramCount): + result.cmds = newSeq[string](paramCount()) + for i in countup(1, paramCount()): + result.cmds[i-1] = paramStr(i) else: - result.cmds = newSeq[string](os.paramCount()) - for i in countup(1, os.paramCount()): - result.cmds[i-1] = os.paramStr(i) + # we cannot provide this for NimRtl creation on Posix, because we can't + # access the command line arguments then! + doAssert false, "empty command line given but" & + " real command line is not accessible" - result.kind = cmdEnd - result.key = "" - result.val = "" + result.kind = cmdEnd + result.key = "" + result.val = "" - proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {}, - longNoVal: seq[string] = @[]; - allowWhitespaceAfterColon = true): OptParser = - ## Initializes the command line parser. - ## - ## If ``cmdline.len == 0``, the real command line as provided by the - ## ``os`` module is retrieved instead. Behavior of the other parameters - ## remains the same as in `initOptParser(string, ...) - ## <#initOptParser,string,set[char],seq[string]>`_. - ## - ## See also: - ## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_ - 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: seq[string], shortNoVal: set[char] = {}, + longNoVal: seq[string] = @[]; + allowWhitespaceAfterColon = true): OptParser = + ## Initializes the command line parser. + ## + ## If ``cmdline.len == 0``, 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. + ## Behavior of the other parameters remains the same as in + ## `initOptParser(string, ...) + ## <#initOptParser,string,set[char],seq[string]>`_. + ## + ## See also: + ## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_ + 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.len != 0: - result.cmds = newSeq[string](cmdline.len) - for i in 0..<cmdline.len: - result.cmds[i] = cmdline[i] + result.pos = 0 + result.idx = 0 + result.inShortState = false + result.shortNoVal = shortNoVal + result.longNoVal = longNoVal + result.allowWhitespaceAfterColon = allowWhitespaceAfterColon + if cmdline.len != 0: + result.cmds = newSeq[string](cmdline.len) + for i in 0..<cmdline.len: + 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: - result.cmds = newSeq[string](os.paramCount()) - for i in countup(1, os.paramCount()): - result.cmds[i-1] = os.paramStr(i) - result.kind = cmdEnd - result.key = "" - result.val = "" + # we cannot provide this for NimRtl creation on Posix, because we can't + # access the command line arguments then! + doAssert false, "empty command line given but" & + " real command line is not accessible" + result.kind = cmdEnd + result.key = "" + result.val = "" proc handleShortOption(p: var OptParser; cmd: string) = var i = p.pos @@ -366,23 +377,24 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = inc p.idx p.pos = 0 -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>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") - ## while true: - ## p.next() - ## if p.kind == cmdLongOption and p.key == "": # Look for "--" - ## break - ## else: continue - ## doAssert p.cmdLineRest == "foo.txt bar.txt" - result = p.cmds[p.idx .. ^1].quoteShellCommand +when declared(quoteShellCommand): + 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>`_ + ## + ## **Examples:** + ## + ## .. code-block:: + ## var p = initOptParser("--left -r:2 -- foo.txt bar.txt") + ## while true: + ## p.next() + ## if p.kind == cmdLongOption and p.key == "": # Look for "--" + ## break + ## else: continue + ## doAssert p.cmdLineRest == "foo.txt bar.txt" + result = p.cmds[p.idx .. ^1].quoteShellCommand proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} = ## 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 yield (p.kind, p.key, p.val) -when declared(initOptParser): - iterator getopt*(cmdline: seq[string] = commandLineParams(), - shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): - tuple[kind: CmdLineKind, key, val: string] = - ## Convenience iterator for iterating over command line arguments. - ## - ## This creates a new `OptParser<#OptParser>`_. If no command line - ## arguments are provided, the real command line as provided by the - ## ``os`` module is retrieved instead. - ## - ## ``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. - ## - ## There is no need to check for ``cmdEnd`` while iterating. - ## - ## See also: - ## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_ - ## - ## **Examples:** - ## - ## .. code-block:: - ## - ## # these are placeholders, of course - ## proc writeHelp() = discard - ## proc writeVersion() = discard - ## - ## var filename: string - ## let params = @["--left", "--debug:3", "-l", "-r:2"] - ## - ## for kind, key, val in getopt(params): - ## case kind - ## of cmdArgument: - ## filename = key - ## of cmdLongOption, cmdShortOption: - ## case key - ## of "help", "h": writeHelp() - ## of "version", "v": writeVersion() - ## of cmdEnd: assert(false) # cannot happen - ## if filename == "": - ## # no filename has been written, so we show the help - ## writeHelp() - var p = initOptParser(cmdline, shortNoVal = shortNoVal, - longNoVal = longNoVal) - while true: - next(p) - if p.kind == cmdEnd: break - yield (p.kind, p.key, p.val) +iterator getopt*(cmdline: seq[string] = @[], + shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): + tuple[kind: CmdLineKind, key, val: string] = + ## Convenience iterator for iterating over command line arguments. + ## + ## This creates a new `OptParser<#OptParser>`_. If no command line + ## arguments are provided, the real command line as provided by the + ## ``os`` module is retrieved instead. + ## + ## ``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. + ## + ## There is no need to check for ``cmdEnd`` while iterating. + ## + ## See also: + ## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_ + ## + ## **Examples:** + ## + ## .. code-block:: + ## + ## # these are placeholders, of course + ## proc writeHelp() = discard + ## proc writeVersion() = discard + ## + ## var filename: string + ## let params = @["--left", "--debug:3", "-l", "-r:2"] + ## + ## for kind, key, val in getopt(params): + ## case kind + ## of cmdArgument: + ## filename = key + ## of cmdLongOption, cmdShortOption: + ## case key + ## of "help", "h": writeHelp() + ## of "version", "v": writeVersion() + ## of cmdEnd: assert(false) # cannot happen + ## if filename == "": + ## # no filename has been written, so we show the help + ## writeHelp() + var p = initOptParser(cmdline, shortNoVal = shortNoVal, + longNoVal = longNoVal) + while true: + next(p) + if p.kind == cmdEnd: break + yield (p.kind, p.key, p.val) {.pop.} diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim index 7611b7dcb..6fe3772d3 100644 --- a/tests/js/tstdlib_imports.nim +++ b/tests/js/tstdlib_imports.nim @@ -46,7 +46,7 @@ import std/[ # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - # fails: parseopt + parseopt, # XML processing: xmltree, xmlparser, diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims index 9bfdff55e..2468699a4 100644 --- a/tests/test_nimscript.nims +++ b/tests/test_nimscript.nims @@ -48,7 +48,7 @@ import std/[ # Parsers: htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml, - # fails: parseopt + parseopt, # XML processing: xmltree, xmlparser, @@ -113,4 +113,8 @@ block: # cpDir, cpFile, dirExists, fileExists, mkDir, mvDir, mvFile, rmDir, rmF doAssert not dirExists(subDir) doAssert dirExists(subDir2) mvDir(subDir2, subDir) - rmDir(dname) \ No newline at end of file + rmDir(dname) + +block: + # check parseopt can get command line: + discard initOptParser() |