Fish completions: fully support nested commands

This commit is contained in:
Paul Ouellette
2019-08-07 18:51:38 -04:00
parent abf07e978d
commit 0b081a1838
2 changed files with 132 additions and 35 deletions

View File

@@ -217,37 +217,84 @@ _comptest
it("generates correct fish completion script", function()
assert.equal([=[
function __fish_comptest_print_command
set -l cmdline (commandline -poc)
set -l cmd
set -e cmdline[1]
for arg in $cmdline
switch $arg
case help
set cmd $cmd help
break
case completion
set cmd $cmd completion
break
case install i
set cmd $cmd install
break
case admin
set cmd $cmd admin
set -e cmdline[1]
for arg in $cmdline
switch $arg
case help
set cmd $cmd help
break
case add
set cmd $cmd add
break
case remove
set cmd $cmd remove
break
end
end
break
end
end
echo "$cmd"
end
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'
function __fish_comptest_using_command
test (__fish_comptest_print_command) = "$argv"
and return 0
or return 1
end
function __fish_comptest_seen_command
string match -q "$argv*" (__fish_comptest_print_command)
and return 0
or return 1
end
complete -c comptest -n '__fish_comptest_using_command' -xa 'help' -d 'Show help for commands'
complete -c comptest -n '__fish_comptest_using_command' -xa 'completion' -d 'Output a shell completion script'
complete -c comptest -n '__fish_comptest_using_command' -xa 'install i' -d 'Install a rock'
complete -c comptest -n '__fish_comptest_using_command' -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_comptest_using_command help' -xa 'help completion install i admin'
complete -c comptest -n '__fish_comptest_seen_command 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_comptest_seen_command 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_comptest_seen_command install' -s h -l help -d 'Show this help message and exit'
complete -c comptest -n '__fish_comptest_seen_command install' -l deps-mode -xa 'all one order none'
complete -c comptest -n '__fish_comptest_seen_command install' -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_comptest_using_command admin' -xa 'help' -d 'Show help for commands'
complete -c comptest -n '__fish_comptest_using_command admin' -xa 'add' -d 'Add a rock to a server'
complete -c comptest -n '__fish_comptest_using_command admin' -xa 'remove' -d 'Remove a rock from a server'
complete -c comptest -n '__fish_comptest_seen_command 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_comptest_using_command admin help' -xa 'help add remove'
complete -c comptest -n '__fish_comptest_seen_command admin 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_comptest_seen_command admin 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'
complete -c comptest -n '__fish_comptest_seen_command admin remove' -s h -l help -d 'Show this help message and exit'
]=], get_output("completion fish"))
end)
end)

View File

@@ -584,12 +584,14 @@ function Option:_is_vararg()
return self._maxargs ~= self._minargs
end
function Parser:_get_fullname()
function Parser:_get_fullname(exclude_root)
local parent = self._parent
local buf = {self._name}
while parent do
table.insert(buf, 1, parent._name)
if not exclude_root or parent._parent then
table.insert(buf, 1, parent._name)
end
parent = parent._parent
end
@@ -1441,23 +1443,48 @@ local function fish_escape(string)
return string:gsub("[\\']", "\\%0")
end
function Parser:_fish_complete_help(buf, prefix)
function Parser:_fish_get_cmd(buf, indent)
if #self._commands == 0 then
return
end
table.insert(buf, (" "):rep(indent) .. "set -e cmdline[1]")
table.insert(buf, (" "):rep(indent) .. "for arg in $cmdline")
table.insert(buf, (" "):rep(indent + 4) .. "switch $arg")
for _, command in ipairs(self._commands) do
table.insert(buf, (" "):rep(indent + 8) .. "case " .. table.concat(command._aliases, " "))
table.insert(buf, (" "):rep(indent + 12) .. "set cmd $cmd " .. command._name)
command:_fish_get_cmd(buf, indent + 12)
table.insert(buf, (" "):rep(indent + 12) .. "break")
end
table.insert(buf, (" "):rep(indent + 4) .. "end")
table.insert(buf, (" "):rep(indent) .. "end")
end
function Parser:_fish_complete_help(buf, basename)
local prefix = "complete -c " .. basename
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)
local aliases = table.concat(command._aliases, " ")
local line
if self._parent then
line = ("%s -n '__fish_%s_using_command %s' -xa '%s'")
:format(prefix, basename, self:_get_fullname(true), aliases)
else
line = ("%s -n '__fish_%s_using_command' -xa '%s'"):format(prefix, basename, aliases)
end
if command._description then
line = ("%s -d '%s'"):format(line, fish_escape(get_short_description(command)))
end
table.insert(buf, line)
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())
local line = ("%s -n '__fish_%s_using_command %s' -xa '%s'")
:format(prefix, basename, self:_get_fullname(true), self._parent:_get_commands())
table.insert(buf, line)
end
@@ -1465,7 +1492,7 @@ function Parser:_fish_complete_help(buf, prefix)
local parts = {prefix}
if self._parent then
table.insert(parts, "-n '__fish_seen_subcommand_from " .. table.concat(self._aliases, " ") .. "'")
table.insert(parts, "-n '__fish_" .. basename .. "_seen_command " .. self:_get_fullname(true) .. "'")
end
for _, alias in ipairs(option._aliases) do
@@ -1490,7 +1517,7 @@ function Parser:_fish_complete_help(buf, prefix)
end
for _, command in ipairs(self._commands) do
command:_fish_complete_help(buf, prefix)
command:_fish_complete_help(buf, basename)
end
end
@@ -1498,8 +1525,31 @@ 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)
if #self._commands > 0 then
table.insert(buf, ([[
function __fish_%s_print_command
set -l cmdline (commandline -poc)
set -l cmd]]):format(self._basename))
self:_fish_get_cmd(buf, 4)
table.insert(buf, ([[
echo "$cmd"
end
function __fish_%s_using_command
test (__fish_%s_print_command) = "$argv"
and return 0
or return 1
end
function __fish_%s_seen_command
string match -q "$argv*" (__fish_%s_print_command)
and return 0
or return 1
end]]):format(self._basename, self._basename, self._basename, self._basename))
end
self:_fish_complete_help(buf, self._basename)
return table.concat(buf, "\n") .. "\n"
end