Skip to content

Commit

Permalink
fix: properly complete subcommands for fish
Browse files Browse the repository at this point in the history
  • Loading branch information
branchvincent committed Aug 21, 2023
1 parent 7448f55 commit 8394f10
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 14 deletions.
1 change: 1 addition & 0 deletions news/357.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed subcommand completions for Fish.
48 changes: 38 additions & 10 deletions src/cleo/commands/completions_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,34 +249,62 @@ def sanitize(s: str) -> str:
# Commands + options
cmds = []
cmds_opts = []
cmds_names = []
namespaces = set()
for cmd in sorted(self.application.all().values(), key=lambda c: c.name or ""):
if cmd.hidden or not cmd.enabled or not cmd.name:
continue
command_name = shell_quote(cmd.name) if " " in cmd.name else cmd.name
cmds.append(
f"complete -c {script_name} -f -n '__fish{function}_no_subcommand' "
f"-a {command_name} -d '{sanitize(cmd.description)}'"
)
cmd_path = cmd.name.split(" ")
namespace = cmd_path[0]
cmd_name = cmd_path[-1] if " " in cmd.name else cmd.name

# We either have a command like `poetry add` or a nested (namespaced)
# command like `poetry cache clear`.
if len(cmd_path) == 1:
cmds.append(
f"complete -c {script_name} -f -n '__fish{function}_no_subcommand' "
f"-a {cmd_name} -d '{sanitize(cmd.description)}'"
)
condition = f"__fish_seen_subcommand_from {cmd_name}"
else:
# Complete the namespace first
if namespace not in namespaces:
cmds.append(
f"complete -c {script_name} -f -n "
f"'__fish{function}_no_subcommand' -a {namespace}"
)
# Now complete the command
subcmds = [
name.split(" ")[-1] for name in self.application.all(namespace)
]
cmds.append(
f"complete -c {script_name} -f -n '__fish_seen_subcommand_from "
f"{namespace}; and not __fish_seen_subcommand_from {' '.join(subcmds)}' " # noqa: E501
f"-a {cmd_name} -d '{sanitize(cmd.description)}'"
)
condition = (
f"__fish_seen_subcommand_from {namespace}; "
f"and __fish_seen_subcommand_from {cmd_name}"
)

cmds_opts += [
f"# {command_name}",
f"# {cmd.name}",
*[
f"complete -c {script_name} -A "
f"-n '__fish_seen_subcommand_from {sanitize(command_name)}' "
f"-n '{condition}' "
f"-l {opt.name} -d '{sanitize(opt.description)}'"
for opt in sorted(cmd.definition.options, key=lambda o: o.name)
],
"", # newline
]
cmds_names.append(command_name)
namespaces.add(namespace)

return TEMPLATES["fish"] % {
"script_name": script_name,
"function": function,
"opts": "\n".join(opts),
"cmds": "\n".join(cmds),
"cmds_opts": "\n".join(cmds_opts[:-1]), # trim trailing newline
"cmds_names": " ".join(cmds_names),
"cmds_names": " ".join(sorted(namespaces)),
}

def get_shell_type(self) -> str:
Expand Down
9 changes: 5 additions & 4 deletions tests/commands/completion/fixtures/fish.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function __fish_my_function_no_subcommand
for i in (commandline -opc)
if contains -- $i command:with:colons hello help list 'spaced command'
if contains -- $i command:with:colons hello help list spaced
return 1
end
end
Expand All @@ -21,7 +21,8 @@ complete -c script -f -n '__fish_my_function_no_subcommand' -a command:with:colo
complete -c script -f -n '__fish_my_function_no_subcommand' -a hello -d 'Complete me please.'
complete -c script -f -n '__fish_my_function_no_subcommand' -a help -d 'Displays help for a command.'
complete -c script -f -n '__fish_my_function_no_subcommand' -a list -d 'Lists commands.'
complete -c script -f -n '__fish_my_function_no_subcommand' -a 'spaced command' -d 'Command with space in name.'
complete -c script -f -n '__fish_my_function_no_subcommand' -a spaced
complete -c script -f -n '__fish_seen_subcommand_from spaced; and not __fish_seen_subcommand_from command' -a command -d 'Command with space in name.'

# command options

Expand All @@ -36,5 +37,5 @@ complete -c script -A -n '__fish_seen_subcommand_from hello' -l option-without-d

# list

# 'spaced command'
complete -c script -A -n '__fish_seen_subcommand_from \'spaced command\'' -l goodbye -d ''
# spaced command
complete -c script -A -n '__fish_seen_subcommand_from spaced; and __fish_seen_subcommand_from command' -l goodbye -d ''

0 comments on commit 8394f10

Please sign in to comment.