def Matches(self, comp): # Have to clear the response every time. TODO: Reuse the object? state.SetGlobalArray(self.ex.mem, 'COMPREPLY', []) # New completions should use COMP_ARGV, a construct specific to OSH> state.SetGlobalArray(self.ex.mem, 'COMP_ARGV', comp.partial_argv) # Old completions may use COMP_WORDS. It is split by : and = to emulate # bash's behavior. # More commonly, they will call _init_completion and use the 'words' output # of that, ignoring COMP_WORDS. comp_words = [] for a in comp.partial_argv: AdjustArg(a, [':', '='], comp_words) if comp.index == -1: # cmopgen comp_cword = comp.index else: comp_cword = len(comp_words) - 1 # weird invariant state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', comp_words) state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(comp_cword)) state.SetGlobalString(self.ex.mem, 'COMP_LINE', comp.line) state.SetGlobalString(self.ex.mem, 'COMP_POINT', str(comp.end)) argv = [comp.first, comp.to_complete, comp.prev] self.log('Running completion function %r with arguments %s', self.func.name, argv) status = self.ex.RunFuncForCompletion(self.func, argv) if status == 124: self.log('Got status 124 from %r', self.func.name) raise _RetryCompletion() # Read the response. We set it above, so this error would only happen if # the user unset it. # NOTE: 'COMP_REPLY' would follow the naming convention! val = state.GetGlobal(self.ex.mem, 'COMPREPLY') if val.tag == value_e.Undef: util.error('Ran function %s but COMPREPLY was not defined', self.func.name) return [] if val.tag != value_e.StrArray: log('ERROR: COMPREPLY should be an array, got %s', val) return [] self.log('COMPREPLY %s', val) # Return this all at once so we don't have a generator. COMPREPLY happens # all at once anyway. return val.strs
def Matches(self, comp): # Have to clear the response every time. TODO: Reuse the object? state.SetGlobalArray(self.ex.mem, 'COMPREPLY', []) # New completions should use COMP_ARGV, a construct specific to OSH> state.SetGlobalArray(self.ex.mem, 'COMP_ARGV', comp.partial_argv) # Old completions may use COMP_WORDS. It is split by : and = to emulate # bash's behavior. # More commonly, they will call _init_completion and use the 'words' output # of that, ignoring COMP_WORDS. comp_words = [] for a in comp.partial_argv: AdjustArg(a, [':', '='], comp_words) if comp.index == -1: # cmopgen comp_cword = comp.index else: comp_cword = len(comp_words) - 1 # weird invariant state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', comp_words) state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(comp_cword)) state.SetGlobalString(self.ex.mem, 'COMP_LINE', comp.line) state.SetGlobalString(self.ex.mem, 'COMP_POINT', str(comp.end)) argv = [comp.first, comp.to_complete, comp.prev] self.log('Running completion function %r with arguments %s', self.func.name, argv) self.comp_lookup.ClearCommandsChanged() status = self.ex.RunFuncForCompletion(self.func, argv) commands_changed = self.comp_lookup.GetCommandsChanged() self.log('comp.first %s, commands_changed: %s', comp.first, commands_changed) if status == 124: cmd = os_path.basename(comp.first) if cmd in commands_changed: self.log('Got status 124 from %r and %s commands changed', self.func.name, commands_changed) raise _RetryCompletion() else: # This happens with my own completion scripts. bash doesn't show an # error. self.log( "Function %r returned 124, but the completion spec for %r wasn't " "changed", self.func.name, cmd) return [] # Read the response. # NOTE: 'COMP_REPLY' would follow the naming convention! val = state.GetGlobal(self.ex.mem, 'COMPREPLY') if val.tag == value_e.Undef: # We set it above, so this error would only happen if the user unset it. # Not changing it means there were no completions. # TODO: This writes over the command line; it would be better to use an # error object. ui.Stderr('osh: Ran function %r but COMPREPLY was unset', self.func.name) return [] if val.tag != value_e.MaybeStrArray: log('ERROR: COMPREPLY should be an array, got %s', val) return [] self.log('COMPREPLY %s', val) # Return this all at once so we don't have a generator. COMPREPLY happens # all at once anyway. return val.strs