mirror of
https://github.com/TangentFoxy/argparse.git
synced 2025-07-27 18:42:20 +00:00
Merge remote-tracking branch 'luarocks/refs/pull/2/head'
This commit is contained in:
1
LICENSE
1
LICENSE
@@ -1,6 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 - 2018 Peter Melnichenko
|
||||
2019 Paul Ouellette
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
78
docsrc/completions.rst
Normal file
78
docsrc/completions.rst
Normal file
@@ -0,0 +1,78 @@
|
||||
Shell completions
|
||||
=================
|
||||
|
||||
Argparse can generate shell completion scripts for
|
||||
`Bash <https://www.gnu.org/software/bash/>`_, `Zsh <https://www.zsh.org/>`_, and
|
||||
`Fish <https://fishshell.com/>`_.
|
||||
The completion scripts support completing options, commands, and argument
|
||||
choices.
|
||||
|
||||
The Parser methods ``:get_bash_complete()``, ``:get_zsh_complete()``, and
|
||||
``:get_fish_complete()`` return completion scripts as a string.
|
||||
|
||||
Adding a completion option or command
|
||||
-------------------------------------
|
||||
|
||||
A ``--completion`` option can be added to a parser using the
|
||||
``:add_complete([value])`` method. The optional ``value`` argument is a string
|
||||
or table used to configure the option (by calling the option with ``value``).
|
||||
|
||||
.. code-block:: lua
|
||||
:linenos:
|
||||
|
||||
local parser = argparse()
|
||||
:add_complete()
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ lua script.lua -h
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Usage: script.lua [-h] [--completion {bash,zsh,fish}]
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit.
|
||||
--completion {bash,zsh,fish}
|
||||
Output a shell completion script for the specified shell.
|
||||
|
||||
A similar ``completion`` command can be added to a parser using the
|
||||
``:add_complete_command([value])`` method.
|
||||
|
||||
Using completions
|
||||
-----------------
|
||||
|
||||
Bash
|
||||
^^^^
|
||||
|
||||
Save the generated completion script at
|
||||
``/usr/share/bash-completion/completions/script.lua`` or
|
||||
``~/.local/share/bash-completion/completions/script.lua``.
|
||||
|
||||
Alternatively, add the following line to the ``~/.bashrc``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
source <(script.lua --completion bash)
|
||||
|
||||
Zsh
|
||||
^^^
|
||||
|
||||
Save the completion script in the ``/usr/share/zsh/site-functions/`` directory
|
||||
or any directory in the ``$fpath``. The file name should be an underscore
|
||||
followed by the program name. A new directory can be added to to the ``$fpath``
|
||||
by adding e.g. ``fpath=(~/.zfunc $fpath)`` in the ``~/.zshrc`` before
|
||||
``compinit``.
|
||||
|
||||
Fish
|
||||
^^^^
|
||||
|
||||
Save the completion script at
|
||||
``/usr/share/fish/vendor_completions.d/script.lua.fish`` or
|
||||
``~/.config/fish/completions/script.lua.fish``.
|
||||
|
||||
Alternatively, add the following line to the file ``~/.config/fish/config.fish``:
|
||||
|
||||
.. code-block:: fish
|
||||
|
||||
script.lua --completion fish | source
|
@@ -13,6 +13,7 @@ Contents:
|
||||
defaults
|
||||
callbacks
|
||||
messages
|
||||
completions
|
||||
misc
|
||||
|
||||
This is a tutorial for `argparse <https://github.com/mpeterv/argparse>`_, a feature-rich command line parser for Lua.
|
||||
|
222
spec/completion_spec.lua
Normal file
222
spec/completion_spec.lua
Normal file
@@ -0,0 +1,222 @@
|
||||
local script = "./spec/comptest"
|
||||
local script_cmd = "lua"
|
||||
|
||||
if package.loaded["luacov.runner"] then
|
||||
script_cmd = script_cmd .. " -lluacov"
|
||||
end
|
||||
|
||||
script_cmd = script_cmd .. " " .. script
|
||||
|
||||
local function get_output(args)
|
||||
local handler = io.popen(script_cmd .. " " .. args .. " 2>&1", "r")
|
||||
local output = handler:read("*a")
|
||||
handler:close()
|
||||
return output
|
||||
end
|
||||
|
||||
describe("tests related to generation of shell completion scripts", function()
|
||||
it("generates correct bash completion script", function()
|
||||
assert.equal([=[
|
||||
_comptest() {
|
||||
local IFS=$' \t\n'
|
||||
local cur prev cmd opts arg
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
cmd="comptest"
|
||||
opts="-h --help --completion -v --verbose -f --files"
|
||||
|
||||
case "$prev" in
|
||||
--completion)
|
||||
COMPREPLY=($(compgen -W "bash zsh fish" -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
-f|--files)
|
||||
COMPREPLY=($(compgen -f "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
for arg in ${COMP_WORDS[@]:1}; do
|
||||
case "$arg" in
|
||||
completion)
|
||||
cmd="completion"
|
||||
break
|
||||
;;
|
||||
install|i)
|
||||
cmd="install"
|
||||
break
|
||||
;;
|
||||
admin)
|
||||
cmd="admin"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$cmd" in
|
||||
comptest)
|
||||
COMPREPLY=($(compgen -W "help completion install i admin" -- "$cur"))
|
||||
;;
|
||||
completion)
|
||||
opts="$opts -h --help"
|
||||
;;
|
||||
install)
|
||||
case "$prev" in
|
||||
--deps-mode)
|
||||
COMPREPLY=($(compgen -W "all one order none" -- "$cur"))
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
opts="$opts -h --help --deps-mode --no-doc"
|
||||
;;
|
||||
admin)
|
||||
opts="$opts -h --help"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$cur" = -* ]]; then
|
||||
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _comptest -o bashdefault -o default comptest
|
||||
]=], get_output("completion bash"))
|
||||
end)
|
||||
|
||||
it("generates correct zsh completion script", function()
|
||||
assert.equal([=[
|
||||
#compdef comptest
|
||||
|
||||
_comptest() {
|
||||
local context state state_descr line
|
||||
typeset -A opt_args
|
||||
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
"--completion[Output a shell completion script for the specified shell]: :(bash zsh fish)" \
|
||||
"*"{-v,--verbose}"[Set the verbosity level]" \
|
||||
{-f,--files}"[A description with illegal \"' characters]:*: :_files" \
|
||||
": :_comptest_cmds" \
|
||||
"*:: :->args" \
|
||||
&& return 0
|
||||
|
||||
case $words[1] in
|
||||
help)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :(help completion install i admin)" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
completion)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :(bash zsh fish)" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
install|i)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
"--deps-mode: :(all one order none)" \
|
||||
"--no-doc[Install without documentation]" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
admin)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :_comptest_admin_cmds" \
|
||||
"*:: :->args" \
|
||||
&& return 0
|
||||
|
||||
case $words[1] in
|
||||
help)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :(help add remove)" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
add)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :_files" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
remove)
|
||||
_arguments -s -S \
|
||||
{-h,--help}"[Show this help message and exit]" \
|
||||
": :_files" \
|
||||
&& return 0
|
||||
;;
|
||||
|
||||
esac
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_comptest_cmds() {
|
||||
local -a commands=(
|
||||
"help:Show help for commands"
|
||||
"completion:Output a shell completion script"
|
||||
{install,i}":Install a rock"
|
||||
"admin:Rock server administration interface"
|
||||
)
|
||||
_describe "command" commands
|
||||
}
|
||||
|
||||
_comptest_admin_cmds() {
|
||||
local -a commands=(
|
||||
"help:Show help for commands"
|
||||
"add:Add a rock to a server"
|
||||
"remove:Remove a rock from a server"
|
||||
)
|
||||
_describe "command" commands
|
||||
}
|
||||
|
||||
_comptest
|
||||
]=], get_output("completion zsh"))
|
||||
end)
|
||||
|
||||
it("generates correct fish completion script", function()
|
||||
assert.equal([=[
|
||||
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'help' -d 'Show help for commands'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'completion' -d 'Output a shell completion script'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'install' -d 'Install a rock'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'i' -d 'Install a rock'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'admin' -d 'Rock server administration interface'
|
||||
complete -c comptest -s h -l help -d 'Show this help message and exit'
|
||||
complete -c comptest -l completion -xa 'bash zsh fish' -d 'Output a shell completion script for the specified shell'
|
||||
complete -c comptest -s v -l verbose -d 'Set the verbosity level'
|
||||
complete -c comptest -s f -l files -r -d 'A description with illegal "\' characters'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from help' -xa 'help completion install i admin'
|
||||
complete -c comptest -n '__fish_seen_subcommand_from help' -s h -l help -d 'Show this help message and exit'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from completion' -s h -l help -d 'Show this help message and exit'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from install i' -s h -l help -d 'Show this help message and exit'
|
||||
complete -c comptest -n '__fish_seen_subcommand_from install i' -l deps-mode -xa 'all one order none'
|
||||
complete -c comptest -n '__fish_seen_subcommand_from install i' -l no-doc -d 'Install without documentation'
|
||||
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'help' -d 'Show help for commands'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'add' -d 'Add a rock to a server'
|
||||
complete -c comptest -n '__fish_use_subcommand' -xa 'remove' -d 'Remove a rock from a server'
|
||||
complete -c comptest -n '__fish_seen_subcommand_from admin' -s h -l help -d 'Show this help message and exit'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from help' -xa 'help add remove'
|
||||
complete -c comptest -n '__fish_seen_subcommand_from help' -s h -l help -d 'Show this help message and exit'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from add' -s h -l help -d 'Show this help message and exit'
|
||||
|
||||
complete -c comptest -n '__fish_seen_subcommand_from remove' -s h -l help -d 'Show this help message and exit'
|
||||
]=], get_output("completion fish"))
|
||||
end)
|
||||
end)
|
39
spec/comptest
Executable file
39
spec/comptest
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
local argparse = require "argparse"
|
||||
|
||||
local parser = argparse()
|
||||
:add_help_command()
|
||||
:add_complete_command()
|
||||
:add_complete()
|
||||
|
||||
parser:flag "-v --verbose"
|
||||
:description "Set the verbosity level."
|
||||
:count "*"
|
||||
|
||||
parser:option "-f --files"
|
||||
:description "A description with illegal \"' characters."
|
||||
:args "+"
|
||||
|
||||
local install = parser:command "install i"
|
||||
:description "Install a rock."
|
||||
|
||||
install:option "--deps-mode"
|
||||
:choices {"all", "one", "order", "none"}
|
||||
|
||||
install:flag "--no-doc"
|
||||
:description "Install without documentation."
|
||||
|
||||
local admin = parser:command "admin"
|
||||
:description "Rock server administration interface."
|
||||
:add_help_command()
|
||||
|
||||
local admin_add = admin:command "add"
|
||||
:description "Add a rock to a server."
|
||||
admin_add:argument "rock"
|
||||
|
||||
local admin_remove = admin:command "remove"
|
||||
:description "Remove a rock from a server."
|
||||
admin_remove:argument "rock"
|
||||
|
||||
parser:parse()
|
412
src/argparse.lua
412
src/argparse.lua
@@ -1,6 +1,7 @@
|
||||
-- The MIT License (MIT)
|
||||
|
||||
-- Copyright (c) 2013 - 2018 Peter Melnichenko
|
||||
-- 2019 Paul Ouellette
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
-- this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -1080,9 +1081,420 @@ function Parser:add_help_command(value)
|
||||
help "help"
|
||||
end
|
||||
|
||||
help._is_help_command = true
|
||||
return self
|
||||
end
|
||||
|
||||
function Parser:_is_shell_safe()
|
||||
if self._basename then
|
||||
if self._basename:find("[^%w_%-%+%.]") then
|
||||
return false
|
||||
end
|
||||
else
|
||||
for _, alias in ipairs(self._aliases) do
|
||||
if alias:find("[^%w_%-%+%.]") then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, option in ipairs(self._options) do
|
||||
for _, alias in ipairs(option._aliases) do
|
||||
if alias:find("[^%w_%-%+%.]") then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if option._choices then
|
||||
for _, choice in ipairs(option._choices) do
|
||||
if choice:find("[%s'\"]") then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, argument in ipairs(self._arguments) do
|
||||
if argument._choices then
|
||||
for _, choice in ipairs(argument._choices) do
|
||||
if choice:find("[%s'\"]") then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, command in ipairs(self._commands) do
|
||||
if not command:_is_shell_safe() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Parser:add_complete(value)
|
||||
if value then
|
||||
assert(type(value) == "string" or type(value) == "table",
|
||||
("bad argument #1 to 'add_complete' (string or table expected, got %s)"):format(type(value)))
|
||||
end
|
||||
|
||||
local complete = self:option()
|
||||
:description "Output a shell completion script for the specified shell."
|
||||
:args(1)
|
||||
:choices {"bash", "zsh", "fish"}
|
||||
:action(function(_, _, shell)
|
||||
io.write(self["get_" .. shell .. "_complete"](self))
|
||||
os.exit(0)
|
||||
end)
|
||||
|
||||
if value then
|
||||
complete = complete(value)
|
||||
end
|
||||
|
||||
if not complete._name then
|
||||
complete "--completion"
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function Parser:add_complete_command(value)
|
||||
if value then
|
||||
assert(type(value) == "string" or type(value) == "table",
|
||||
("bad argument #1 to 'add_complete_command' (string or table expected, got %s)"):format(type(value)))
|
||||
end
|
||||
|
||||
local complete = self:command()
|
||||
:description "Output a shell completion script."
|
||||
complete:argument "shell"
|
||||
:description "The shell to output a completion script for."
|
||||
:choices {"bash", "zsh", "fish"}
|
||||
:action(function(_, _, shell)
|
||||
io.write(self["get_" .. shell .. "_complete"](self))
|
||||
os.exit(0)
|
||||
end)
|
||||
|
||||
if value then
|
||||
complete = complete(value)
|
||||
end
|
||||
|
||||
if not complete._name then
|
||||
complete "completion"
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
local function base_name(pathname)
|
||||
return pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") or pathname
|
||||
end
|
||||
|
||||
local function get_short_description(element)
|
||||
local short = element:_get_description():match("^(.-)%.%s")
|
||||
return short or element:_get_description():match("^(.-)%.?$")
|
||||
end
|
||||
|
||||
function Parser:_get_options()
|
||||
local options = {}
|
||||
for _, option in ipairs(self._options) do
|
||||
for _, alias in ipairs(option._aliases) do
|
||||
table.insert(options, alias)
|
||||
end
|
||||
end
|
||||
return table.concat(options, " ")
|
||||
end
|
||||
|
||||
function Parser:_get_commands()
|
||||
local commands = {}
|
||||
for _, command in ipairs(self._commands) do
|
||||
for _, alias in ipairs(command._aliases) do
|
||||
table.insert(commands, alias)
|
||||
end
|
||||
end
|
||||
return table.concat(commands, " ")
|
||||
end
|
||||
|
||||
function Parser:_bash_option_args(buf, indent)
|
||||
local opts = {}
|
||||
for _, option in ipairs(self._options) do
|
||||
if option._choices or option._minargs > 0 then
|
||||
local compreply
|
||||
if option._choices then
|
||||
compreply = 'COMPREPLY=($(compgen -W "' .. table.concat(option._choices, " ") .. '" -- "$cur"))'
|
||||
else
|
||||
compreply = 'COMPREPLY=($(compgen -f "$cur"))'
|
||||
end
|
||||
table.insert(opts, (" "):rep(indent + 4) .. table.concat(option._aliases, "|") .. ")")
|
||||
table.insert(opts, (" "):rep(indent + 8) .. compreply)
|
||||
table.insert(opts, (" "):rep(indent + 8) .. "return 0")
|
||||
table.insert(opts, (" "):rep(indent + 8) .. ";;")
|
||||
end
|
||||
end
|
||||
|
||||
if #opts > 0 then
|
||||
table.insert(buf, (" "):rep(indent) .. 'case "$prev" in')
|
||||
table.insert(buf, table.concat(opts, "\n"))
|
||||
table.insert(buf, (" "):rep(indent) .. "esac\n")
|
||||
end
|
||||
end
|
||||
|
||||
function Parser:_bash_get_cmd(buf)
|
||||
local cmds = {}
|
||||
for _, command in ipairs(self._commands) do
|
||||
if not command._is_help_command then
|
||||
table.insert(cmds, (" "):rep(12) .. table.concat(command._aliases, "|") .. ")")
|
||||
table.insert(cmds, (" "):rep(16) .. 'cmd="' .. command._name .. '"')
|
||||
table.insert(cmds, (" "):rep(16) .. "break")
|
||||
table.insert(cmds, (" "):rep(16) .. ";;")
|
||||
end
|
||||
end
|
||||
|
||||
if #cmds > 0 then
|
||||
table.insert(buf, (" "):rep(4) .. "for arg in ${COMP_WORDS[@]:1}; do")
|
||||
table.insert(buf, (" "):rep(8) .. 'case "$arg" in')
|
||||
table.insert(buf, table.concat(cmds, "\n"))
|
||||
table.insert(buf, (" "):rep(8) .. "esac")
|
||||
table.insert(buf, (" "):rep(4) .. "done\n")
|
||||
end
|
||||
end
|
||||
|
||||
function Parser:_bash_cmd_completions(buf)
|
||||
local subcmds = {}
|
||||
for _, command in ipairs(self._commands) do
|
||||
if #command._options > 0 and not command._is_help_command then
|
||||
table.insert(subcmds, (" "):rep(8) .. command._name .. ")")
|
||||
command:_bash_option_args(subcmds, 12)
|
||||
table.insert(subcmds, (" "):rep(12) .. 'opts="$opts ' .. command:_get_options() .. '"')
|
||||
table.insert(subcmds, (" "):rep(12) .. ";;")
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(buf, (" "):rep(4) .. 'case "$cmd" in')
|
||||
table.insert(buf, (" "):rep(8) .. self._basename .. ")")
|
||||
table.insert(buf, (" "):rep(12) .. 'COMPREPLY=($(compgen -W "' .. self:_get_commands() .. '" -- "$cur"))')
|
||||
table.insert(buf, (" "):rep(12) .. ";;")
|
||||
if #subcmds > 0 then
|
||||
table.insert(buf, table.concat(subcmds, "\n"))
|
||||
end
|
||||
table.insert(buf, (" "):rep(4) .. "esac\n")
|
||||
end
|
||||
|
||||
function Parser:get_bash_complete()
|
||||
self._basename = base_name(self._name)
|
||||
assert(self:_is_shell_safe())
|
||||
local buf = {([[
|
||||
_%s() {
|
||||
local IFS=$' \t\n'
|
||||
local cur prev cmd opts arg
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
cmd="%s"
|
||||
opts="%s"
|
||||
]]):format(self._basename, self._basename, self:_get_options())}
|
||||
|
||||
self:_bash_option_args(buf, 4)
|
||||
self:_bash_get_cmd(buf)
|
||||
if #self._commands > 0 then
|
||||
self:_bash_cmd_completions(buf)
|
||||
end
|
||||
|
||||
table.insert(buf, ([=[
|
||||
if [[ "$cur" = -* ]]; then
|
||||
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _%s -o bashdefault -o default %s
|
||||
]=]):format(self._basename, self._basename))
|
||||
|
||||
return table.concat(buf, "\n")
|
||||
end
|
||||
|
||||
function Parser:_zsh_arguments(buf, cmd_name, indent)
|
||||
table.insert(buf, (" "):rep(indent) .. "_arguments -s -S \\")
|
||||
|
||||
for _, option in ipairs(self._options) do
|
||||
local line = {}
|
||||
if #option._aliases > 1 then
|
||||
if option._maxcount > 1 then
|
||||
table.insert(line, '"*"')
|
||||
end
|
||||
table.insert(line, "{" .. table.concat(option._aliases, ",") .. '}"')
|
||||
else
|
||||
table.insert(line, '"')
|
||||
if option._maxcount > 1 then
|
||||
table.insert(line, "*")
|
||||
end
|
||||
table.insert(line, option._name)
|
||||
end
|
||||
if option._description then
|
||||
local description = get_short_description(option):gsub('["%]:]', "\\%0")
|
||||
table.insert(line, "[" .. description .. "]")
|
||||
end
|
||||
if option._maxargs == math.huge then
|
||||
table.insert(line, ":*")
|
||||
end
|
||||
if option._choices then
|
||||
table.insert(line, ": :(" .. table.concat(option._choices, " ") .. ")")
|
||||
elseif option._maxargs > 0 then
|
||||
table.insert(line, ": :_files")
|
||||
end
|
||||
table.insert(line, '"')
|
||||
|
||||
table.insert(buf, (" "):rep(indent + 2) .. table.concat(line) .. " \\")
|
||||
end
|
||||
|
||||
if self._is_help_command then
|
||||
table.insert(buf, (" "):rep(indent + 2) .. '": :(' .. self._parent:_get_commands() .. ')" \\')
|
||||
else
|
||||
for _, argument in ipairs(self._arguments) do
|
||||
local spec
|
||||
if argument._choices then
|
||||
spec = ": :(" .. table.concat(argument._choices, " ") .. ")"
|
||||
else
|
||||
spec = ": :_files"
|
||||
end
|
||||
if argument._maxargs == math.huge then
|
||||
table.insert(buf, (" "):rep(indent + 2) .. '"*' .. spec .. '" \\')
|
||||
break
|
||||
end
|
||||
for _ = 1, argument._maxargs do
|
||||
table.insert(buf, (" "):rep(indent + 2) .. '"' .. spec .. '" \\')
|
||||
end
|
||||
end
|
||||
|
||||
if #self._commands > 0 then
|
||||
table.insert(buf, (" "):rep(indent + 2) .. '": :_' .. cmd_name .. '_cmds" \\')
|
||||
table.insert(buf, (" "):rep(indent + 2) .. '"*:: :->args" \\')
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(buf, (" "):rep(indent + 2) .. "&& return 0")
|
||||
end
|
||||
|
||||
function Parser:_zsh_cmds(buf, cmd_name)
|
||||
table.insert(buf, "\n_" .. cmd_name .. "_cmds() {")
|
||||
table.insert(buf, " local -a commands=(")
|
||||
|
||||
for _, command in ipairs(self._commands) do
|
||||
local line = {}
|
||||
if #command._aliases > 1 then
|
||||
table.insert(line, "{" .. table.concat(command._aliases, ",") .. '}"')
|
||||
else
|
||||
table.insert(line, '"' .. command._name)
|
||||
end
|
||||
if command._description then
|
||||
table.insert(line, ":" .. get_short_description(command):gsub('["]', "\\%0"))
|
||||
end
|
||||
table.insert(buf, " " .. table.concat(line) .. '"')
|
||||
end
|
||||
|
||||
table.insert(buf, ' )\n _describe "command" commands\n}')
|
||||
end
|
||||
|
||||
function Parser:_zsh_complete_help(buf, cmds_buf, cmd_name, indent)
|
||||
if #self._commands == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
self:_zsh_cmds(cmds_buf, cmd_name)
|
||||
table.insert(buf, "\n" .. (" "):rep(indent) .. "case $words[1] in")
|
||||
|
||||
for _, command in ipairs(self._commands) do
|
||||
local name = cmd_name .. "_" .. command._name
|
||||
table.insert(buf, (" "):rep(indent + 2) .. table.concat(command._aliases, "|") .. ")")
|
||||
command:_zsh_arguments(buf, name, indent + 4)
|
||||
command:_zsh_complete_help(buf, cmds_buf, name, indent + 4)
|
||||
table.insert(buf, (" "):rep(indent + 4) .. ";;\n")
|
||||
end
|
||||
|
||||
table.insert(buf, (" "):rep(indent) .. "esac")
|
||||
end
|
||||
|
||||
function Parser:get_zsh_complete()
|
||||
self._basename = base_name(self._name)
|
||||
assert(self:_is_shell_safe())
|
||||
local buf = {("#compdef %s\n"):format(self._basename)}
|
||||
local cmds_buf = {}
|
||||
table.insert(buf, "_" .. self._basename .. "() {")
|
||||
if #self._commands > 0 then
|
||||
table.insert(buf, " local context state state_descr line")
|
||||
table.insert(buf, " typeset -A opt_args\n")
|
||||
end
|
||||
self:_zsh_arguments(buf, self._basename, 2)
|
||||
self:_zsh_complete_help(buf, cmds_buf, self._basename, 2)
|
||||
table.insert(buf, "\n return 1")
|
||||
table.insert(buf, "}")
|
||||
|
||||
local result = table.concat(buf, "\n")
|
||||
if #cmds_buf > 0 then
|
||||
result = result .. "\n" .. table.concat(cmds_buf, "\n")
|
||||
end
|
||||
return result .. "\n\n_" .. self._basename .. "\n"
|
||||
end
|
||||
|
||||
local function fish_escape(string)
|
||||
return string:gsub("[\\']", "\\%0")
|
||||
end
|
||||
|
||||
function Parser:_fish_complete_help(buf, prefix)
|
||||
table.insert(buf, "")
|
||||
|
||||
for _, command in ipairs(self._commands) do
|
||||
for _, alias in ipairs(command._aliases) do
|
||||
local line = ("%s -n '__fish_use_subcommand' -xa '%s'"):format(prefix, alias)
|
||||
if command._description then
|
||||
line = ("%s -d '%s'"):format(line, fish_escape(get_short_description(command)))
|
||||
end
|
||||
table.insert(buf, line)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if self._is_help_command then
|
||||
local line = ("%s -n '__fish_seen_subcommand_from %s' -xa '%s'")
|
||||
:format(prefix, table.concat(self._aliases, " "), self._parent:_get_commands())
|
||||
table.insert(buf, line)
|
||||
end
|
||||
|
||||
for _, option in ipairs(self._options) do
|
||||
local parts = {prefix}
|
||||
|
||||
if self._parent then
|
||||
table.insert(parts, "-n '__fish_seen_subcommand_from " .. table.concat(self._aliases, " ") .. "'")
|
||||
end
|
||||
|
||||
for _, alias in ipairs(option._aliases) do
|
||||
if alias:match("^%-.$") then
|
||||
table.insert(parts, "-s " .. alias:sub(2))
|
||||
elseif alias:match("^%-%-.+") then
|
||||
table.insert(parts, "-l " .. alias:sub(3))
|
||||
end
|
||||
end
|
||||
|
||||
if option._choices then
|
||||
table.insert(parts, "-xa '" .. table.concat(option._choices, " ") .. "'")
|
||||
elseif option._minargs > 0 then
|
||||
table.insert(parts, "-r")
|
||||
end
|
||||
|
||||
if option._description then
|
||||
table.insert(parts, "-d '" .. fish_escape(get_short_description(option)) .. "'")
|
||||
end
|
||||
|
||||
table.insert(buf, table.concat(parts, " "))
|
||||
end
|
||||
|
||||
for _, command in ipairs(self._commands) do
|
||||
command:_fish_complete_help(buf, prefix)
|
||||
end
|
||||
end
|
||||
|
||||
function Parser:get_fish_complete()
|
||||
self._basename = base_name(self._name)
|
||||
assert(self:_is_shell_safe())
|
||||
local buf = {}
|
||||
local prefix = "complete -c " .. self._basename
|
||||
self:_fish_complete_help(buf, prefix)
|
||||
return table.concat(buf, "\n") .. "\n"
|
||||
end
|
||||
|
||||
local function get_tip(context, wrong_name)
|
||||
local context_pool = {}
|
||||
local possible_name
|
||||
|
Reference in New Issue
Block a user