Skip to content

Commit

Permalink
implement fish completion with metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
amy-lei committed Jul 10, 2020
1 parent 7957d9e commit 86ed365
Showing 1 changed file with 59 additions and 21 deletions.
80 changes: 59 additions & 21 deletions src/click/shell_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
for completion in $response; do
IFS=',' read type value <<< "$completion"
COMPREPLY+=($type)
COMPREPLY+=($value)
if [[ $type == 'dir' ]]; then
COMREPLY=()
# COMREPLY=()
compopt -o dirnames
elif [[ $type == 'file' ]]; then
COMREPLY=()
Expand Down Expand Up @@ -86,12 +88,31 @@
compdef %(complete_func)s %(script_names)s
"""

COMPLETION_SCRIPT_FISH = (
"complete --no-files --command %(script_names)s --arguments"
' "(env %(autocomplete_var)s=complete_fish'
" COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t)"
' %(script_names)s)"'
)

COMPLETION_SCRIPT_FISH = """
function %(complete_func)s_complete;
set -l response;
for value in (env %(autocomplete_var)s=complete_fish \
COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t) \
%(script_names)s);
set response $response $value;
end;
for completion in $response;
set -l metadata (string split "," $completion);
if test $metadata[1] = "dir";
__fish_complete_directories $metadata[2];
else if test $metadata[1] = "file";
__fish_complete_path $metadata[2];
else if test $metadata[1] = "none";
echo $metadata[2];
end;
end;
end;
complete --no-files --command %(script_names)s --arguments \
"(%(complete_func)s_complete)"
"""

_invalid_ident_char_re = re.compile(r"[^a-zA-Z0-9_]")

Expand Down Expand Up @@ -133,7 +154,15 @@ def source(self):
return COMPLETION_SCRIPT_BASH

def complete(self):
completions = do_completion(self.cli, self.prog_name)
cwords = split_arg_string(os.environ["COMP_WORDS"])
cword = int(os.environ["COMP_CWORD"])
args = cwords[1:cword]
try:
incomplete = cwords[cword]
except IndexError:
incomplete = ""

completions = do_complete(self.cli, self.prog_name, args, incomplete)
for item in completions:
echo(f"{item[0]},{item[1]}")

Expand All @@ -147,7 +176,15 @@ def source(self):
return COMPLETION_SCRIPT_ZSH

def complete(self):
completions = do_completion(self.cli, self.prog_name)
cwords = split_arg_string(os.environ["COMP_WORDS"])
cword = int(os.environ["COMP_CWORD"])
args = cwords[1:cword]
try:
incomplete = cwords[cword]
except IndexError:
incomplete = ""

completions = do_complete(self.cli, self.prog_name, args, incomplete)
for item in completions:
echo(item[1])
echo(item[2] if item[2] else "_")
Expand All @@ -162,25 +199,26 @@ def source(self):
return COMPLETION_SCRIPT_FISH

def complete(self):
completions = do_completion(self.cli, self.prog_name)
cwords = split_arg_string(os.environ["COMP_WORDS"])
incomplete = os.environ["COMP_CWORD"]
args = cwords[1:]

# Fish is weird in that a partially completed path is registered in
# both `COMP_WORDS` and `COMP_CWORD`.
if incomplete and args and args[-1] == incomplete:
args.pop()

completions = do_complete(self.cli, self.prog_name, args, incomplete)
for item in completions:
if item[2]:
echo(f"{item[1]}\t{item[2]}")
echo(f"{item[0]},{item[1]}\t{item[2]}")
else:
echo(item[1])
echo(f"{item[0]},{item[1]}")

return True


def do_completion(cli, prog_name):
cwords = split_arg_string(os.environ["COMP_WORDS"])
cword = int(os.environ["COMP_CWORD"])
args = cwords[1:cword]
try:
incomplete = cwords[cword]
except IndexError:
incomplete = ""

def do_complete(cli, prog_name, args, incomplete):
all_args = copy.deepcopy(args)
ctx = resolve_ctx(cli, prog_name, args)
if ctx is None:
Expand Down

0 comments on commit 86ed365

Please sign in to comment.