Added a -v/--validate option to fish_opt

This new flag causes fish_opt to generrate an option spec with !
(e.g. "fish_opt -s s -rv some code" will output "s=!some code").

Such validation scripts are not particular useful (they are highly limited as
they cannot access the values for other options, and must be quoted
appropriately so they can be passed to argparse). I merely added the option to
fish_opt so that it can now generate any valid option spec.
This commit is contained in:
Isaac Oscar Gariano
2025-08-03 10:07:08 +10:00
parent 007edac145
commit 944cfd181e
12 changed files with 133 additions and 14 deletions

View File

@@ -51,6 +51,7 @@ Scripting improvements
- ``argparse`` now allows specifying options that take multiple optional values by using ``=*`` in the option spec, the parsing of the option is the same as ones with optional values (i.e. ``=?``), but each successive use accumulates more values (or an empty string if no value), instead of replacing the previous value (i.e. it behaves similarly to ``=+``) (:issue:`8432`). In addition, ``fish_opt`` has been modified to support such options by using the ``--multiple-vals`` together with ``-o`` / ``--optional-val``; ``-m`` is also now acceptable as an abbreviation for ``--multiple-vals``.
- ``fish_opt`` no longer requires you give a short flag name when defining options, provided you give it a long flag name with more than one character.
- ``argparse`` option specifiers for long only options can now start with ``/``, allowing the definition of long options with a single letter (withouht the ``/``, an option with a single letter is always interpreted as a short flag). Due to this change, the ``--long-only`` option to ``fish_opt`` is now no longer necessary and is deprecated.
- ``fish_opt`` now has a ``-v`` / ``--validate`` option you can use to give a fish script to validate values of the option.
Interactive improvements
------------------------

View File

@@ -8,7 +8,7 @@ Synopsis
.. synopsis::
fish_opt [-s ALPHANUM] [-l LONG-NAME] [-ormd] [--long-only]
fish_opt [-s ALPHANUM] [-l LONG-NAME] [-ormd] [--long-only] [-v COMMAND OPTIONS ... ]
fish_opt --help
Description
@@ -40,6 +40,9 @@ The following ``argparse`` options are available:
The option and any values will be deleted from the ``$argv_opts`` variables set by ``argparse``
(as with other options, it will also be deleted from ``$argv``).
**-v** or **--validate** *COMMAND* *OPTION...*
This option must be the last one, and requires one of ``-o``, ``-r``, or ``-m``. All the remaining arguments are interpreted a fish script to run to validate the value of the argument, see ``argparse`` documentation for more details. Note that the interpretation of *COMMAND* *OPTION...* is similar to ``eval``, so you may need to quote or escape special characters *twice* if you want them to be interpreted literally when the validate script is run.
**-h** or **--help**
Displays help about using this command.
@@ -63,9 +66,16 @@ Same as above but with a second flag that requires a value:
::
set -l options (fish_opt -s h -l help)
set options $options (fish_opt -s m -l max --required-val)
set options $options (fish_opt -s m -l max -r)
argparse $options -- $argv
Same as above but the value of the second flag cannot be the empty string:
::
set -l options (fish_opt -s h -l help)
set options $options (fish_opt -s m -l max -rv test \$_flag_valu != "''")
argparse $options -- $argv
Same as above but with a third flag that can be given multiple times saving the value of each instance seen and only a long flag name (``--token``) is defined:
@@ -74,7 +84,7 @@ Same as above but with a third flag that can be given multiple times saving the
::
set -l options (fish_opt --short=h --long=help)
set options $options (fish_opt --short=m --long=max --required-val)
set options $options (fish_opt --short=m --long=max --required-val --validate test \$_flag_valu != "''")
set options $options (fish_opt --long=token --multiple-vals)
argparse $options -- $argv

View File

@@ -1939,6 +1939,9 @@ msgstr ""
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr ""
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr "%s: Ungültige Maske '%s'\\n"
@@ -1951,6 +1954,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr ""
@@ -25444,6 +25453,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -1935,6 +1935,9 @@ msgstr "%s: Expected 1, 2 or 3 arguments, got %d\\n"
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr "%s: Invalid mask “%s”\\n"
@@ -1947,6 +1950,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr "%s: The number of positions to skip must be a non-negative integer\\n"
@@ -25440,6 +25449,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -2036,6 +2036,9 @@ msgstr "%s : 1, 2 ou 3 arguments attendus, %d reçu(s)\\n"
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr "%s : Un argument attendu, %s reçu(s).\\n\\nRésumé :\\n\\t%svared%s VARIABLE\\n"
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr "%s : Masque '%s' invalide\\n"
@@ -2048,6 +2051,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr "%s : Le nombre de positions à passer doit être un entier naturel\\n"
@@ -25541,6 +25550,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -1931,6 +1931,9 @@ msgstr ""
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr ""
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr ""
@@ -1943,6 +1946,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr ""
@@ -25436,6 +25445,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -1936,6 +1936,9 @@ msgstr ""
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr ""
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr ""
@@ -1948,6 +1951,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr ""
@@ -25451,6 +25460,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -1932,6 +1932,9 @@ msgstr "%s: Förväntade 1, 2 eller 3 argument, fick %d\\n"
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr "%s: Förväntade exakt ett argument, fick %s\\n\\nSynopsis:\\n\\t%svared%s VARIABEL\\n"
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr "%s: Ogiltigt mask '%s'\\n"
@@ -1944,6 +1947,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr "%s: Antalet positioner att hoppa över måste vara ett positivt heltal\\n"
@@ -25439,6 +25448,9 @@ msgstr ""
msgid "First remove existing destination files"
msgstr ""
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr ""

View File

@@ -1934,6 +1934,9 @@ msgstr "%s: 预期参数 1, 2 或 3, 获得 %d\\n"
msgid "%s: Expected exactly one argument, got %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgstr "%s: 需要精确的一条参数, 获得 %s.\\n\\nSynopsis:\\n\\t%svared%s VARIABLE\\n"
msgid "%s: Extra non-option arguments were provided\\n"
msgstr ""
msgid "%s: Invalid mask '%s'\\n"
msgstr "%s:无效的掩码'%s'\\n"
@@ -1946,6 +1949,12 @@ msgstr ""
msgid "%s: The --short flag must be a single character\\n"
msgstr ""
msgid "%s: The --validate flag requires subsequent arguments\\n"
msgstr ""
msgid "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\\n"
msgstr ""
msgid "%s: The number of positions to skip must be a non-negative integer\\n"
msgstr "%s:要跳过的位置数必须是非负整数\\n"
@@ -25439,6 +25448,9 @@ msgstr "要转换的第一个页面"
msgid "First remove existing destination files"
msgstr "首先删除已有目的文件"
msgid "Fish script to validate option values"
msgstr ""
msgid "Fish's release notes"
msgstr "fish的放行记录"

View File

@@ -11,3 +11,4 @@ complete --command fish_opt --short-option o --long-option optional-val -n $COND
complete --command fish_opt --short-option r --long-option required-val -n $CONDITION --description 'Require value'
complete --command fish_opt --short-option m --long-option multiple-vals --description 'Store all values'
complete --command fish_opt --short-option d --long-option delete --description 'Delete option from argv_opts'
complete --command fish_opt --short-option v --long-option validate --require-parameter --description 'Fish script to validate option values'

View File

@@ -1,6 +1,15 @@
# This is a helper function for `fish_opt`. It does some basic validation of the arguments.
function __fish_opt_validate_args --no-scope-shadowing
if set -q _flag_short && test 1 -ne (string length -- $_flag_short)
if not set -q _flag_validate && test (count $argv) -ne 0
printf (_ "%s: Extra non-option arguments were provided\n") fish_opt >&2
return 1
else if set -q _flag_validate && test (count $argv) -eq 0
printf (_ "%s: The --validate flag requires subsequent arguments\n") fish_opt >&2
return 1
else if set -q _flag_validate && not set -q _flag_multiple_vals && not set -q _flag_optional_val && not set -q _flag_required_val
printf (_ "%s: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag\n") fish_opt >&2
return 1
else if set -q _flag_short && test 1 -ne (string length -- $_flag_short)
printf (_ "%s: The --short flag must be a single character\n") fish_opt >&2
return 1
else if not set -q _flag_short && not set -q _flag_long
@@ -17,8 +26,8 @@ end
# The `fish_opt` command.
function fish_opt -d 'Produce an option specification suitable for use with `argparse`.'
set -l options h/help 's/short=' 'l/long=' d/delete o/optional-val r/required-val m/multiple-vals long-only
argparse -n fish_opt --max-args=0 --exclusive=r,o $options -- $argv
set -l options h/help 's/short=' 'l/long=' d/delete o/optional-val r/required-val m/multiple-vals long-only v/validate
argparse -n fish_opt --stop-nonopt --exclusive=r,o $options -- $argv
or return
if set -q _flag_help
@@ -26,7 +35,7 @@ function fish_opt -d 'Produce an option specification suitable for use with `arg
return 0
end
__fish_opt_validate_args
__fish_opt_validate_args $argv
or return
if not set -q _flag_short
@@ -53,5 +62,9 @@ function fish_opt -d 'Produce an option specification suitable for use with `arg
set opt_spec "$opt_spec&"
end
if set -q _flag_validate
set opt_spec "$opt_spec!$argv"
end
echo $opt_spec
end

View File

@@ -572,7 +572,17 @@ and echo unexpected status $status
# An unexpected arg not associated with a flag is an error
fish_opt -s h -l help hello
and echo unexpected status $status
#CHECKERR: fish_opt: expected <= 0 arguments; got 1
#CHECKERR: fish_opt: Extra non-option arguments were provided
# A -v / --validate without any arguments is an error
fish_opt -s h -l help -rv
and echo unexpected status $status
#CHECKERR: fish_opt: The --validate flag requires subsequent arguments
# A -v / --validate for boolean options is an error
fish_opt -s h -l help -v echo hello
and echo unexpected status $status
#CHECKERR: fish_opt: The --validate flag requires the --required-val, --optional-value, or --multiple-vals flag
# Now verify that valid combinations of options produces the correct output.
@@ -615,20 +625,20 @@ fish_opt --short h -l help --optional-val --long-only
or echo unexpected status $status
#CHECK: h-help=?
# Repeated val, short and long valid
fish_opt --short h -l help --multiple-vals
# Repeated val, short and long valid, with validate
fish_opt --short h -l help --multiple-vals --validate _validate_int --max 500
or echo unexpected status $status
#CHECK: h/help=+
#CHECK: h/help=+!_validate_int --max 500
# Repeated and optional val, short and long valid
fish_opt --short h -l help --optional-val -m
or echo unexpected status $status
#CHECK: h/help=*
# Repeated val and short
fish_opt -ml help --long-only
# Repeated val and short, with validate
fish_opt -ml help --long-only -v test \$_flag_value != "' '"
or echo unexpected status $status
#CHECK: /help=+
#CHECK: /help=+!test $_flag_value != ' '
# Repeated and optional val, short and long but short not valid
fish_opt --short h -l help --long-only -mo