Skip to content

Commit

Permalink
[completion] Properly implement the "124 protocol" for lazy loading.
Browse files Browse the repository at this point in the history
I manually tested it with osh-unit.bash and 'zz'.  This could use an
automated test.

Remove the old, broken implementation.
  • Loading branch information
Andy Chu committed Jan 22, 2019
1 parent 4502115 commit 6dc0f4d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 22 deletions.
47 changes: 27 additions & 20 deletions core/completion.py
Expand Up @@ -815,9 +815,8 @@ def LastColForWord(w):
n = len(partial_argv)

# TODO: Form prefix for RootCompleter to add to user_spec candidates

if n == 0:
# should never get this because of Lit_CompDummy?
# We should never get this because of Lit_CompDummy.
raise AssertionError
elif n == 1:
# First
Expand All @@ -843,8 +842,28 @@ def LastColForWord(w):
self.comp_state.current_opts = comp_opts
self.comp_state.currently_completing = True
try:
for entry in self._PostProcess(comp_opts, user_spec, comp):
yield entry
done = False
while not done:
try:
for entry in self._PostProcess(comp_opts, user_spec, comp):
yield entry
except _RetryCompletion as e:
debug_f.log('Got 124, trying again ...')

n = len(partial_argv)
# Get another user_spec. The ShellFuncAction may have 'sourced' code
# and run 'complete' to mutate comp_lookup, and we want to get that
# new entry.
if n == 0:
raise AssertionError
elif n == 1:
# First
comp_opts, user_spec = self.comp_lookup.GetFirstSpec()
else:
comp_opts, user_spec = self.comp_lookup.GetSpecForName(
partial_argv[0])
else:
done = True # exhausted candidates without getting a retry
finally:
self.comp_state.currently_completing = False

Expand Down Expand Up @@ -933,22 +952,10 @@ def _GetNextCompletion(self, state):

assert self.comp_iter is not None, self.comp_iter

done = False
while not done:
#self.debug_f.log('comp_iter.next()')
try:
next_completion = self.comp_iter.next()
done = True
except _RetryCompletion:
# TODO: Is it OK to retry here? Shouldn't we retry in
# RootCompleter, after we already know the words? That seems to run
# into some problems with Python generators and exceptions.
# I kind of want the 'g.send()' pattern to "prime the generator",
# revealing the first exception.
pass
except StopIteration:
next_completion = None # sentinel?
done = True
try:
next_completion = self.comp_iter.next()
except StopIteration:
next_completion = None # signals the end

return next_completion

Expand Down
18 changes: 16 additions & 2 deletions testdata/completion/osh-unit.bash
Expand Up @@ -114,7 +114,8 @@ complete_optdynamic() {
}
complete -F complete_optdynamic optdynamic

complete_files() {
files_func() { argv "$@"; }
complete_files_func() {
local first=$1
local cur=$2
local prev=$3
Expand All @@ -124,7 +125,7 @@ complete_files() {
}
# everything else completes files
#complete -D -A file
complete -F complete_files -D # messes up trailing slashes
complete -F complete_files_func files_func # messes up trailing slashes

# Check trailing backslashes for the 'fileuser' command
# Hm somehow it knows to distinguish. Gah.
Expand Down Expand Up @@ -178,6 +179,19 @@ complete_F_runtime_error() {
}
complete -F complete_F_runtime_error F_runtime_error

#
# Test out the "124" protocol for lazy loading of completions.
#

# https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html
_completion_loader()
{
# If the file exists, we will return 124 and reload it.
# TODO: It would be nice to have a debug_f builtin to trace this!
. "testdata/completion/${1}_completion.bash" >/dev/null 2>&1 && return 124
}
complete -D -F _completion_loader

#
# Unit tests use this
#
Expand Down
7 changes: 7 additions & 0 deletions testdata/completion/zz_completion.bash
@@ -0,0 +1,7 @@
# Testing out the "124 protocol" with a dummy 'zz' command.

_zz() {
COMPREPLY=(z1 z2 z3)
}

complete -F _zz zz

0 comments on commit 6dc0f4d

Please sign in to comment.