def Matches(self, comp): # TODO: Delete COMPREPLY here? It doesn't seem to be defined in bash by # default. argv, comp_words = comp.GetApiInput() state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', comp_words) state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(comp.index)) state.SetGlobalString(self.ex.mem, 'COMP_LINE', comp.line) state.SetGlobalString(self.ex.mem, 'COMP_POINT', str(comp.end)) 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() # Lame: 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, words, index, prefix): # TODO: # - Set COMP_CWORD etc. in ex.mem -- in the global namespace I guess # - Then parse the reply here # This is like a stack code: # for word in words: # self.ex.PushString(word) # self.ex.PushString('COMP_WORDS') # self.ex.MakeArray() # self.ex.PushString(str(index)) # self.ex.PushString('COMP_CWORD') # TODO: Get the name instead! # self.ex.PushString(self.func_name) # self.ex.Call() # call wit no arguments # self.ex.PushString('COMP_REPLY') # How does this one work? # reply = [] # self.ex.GetArray(reply) state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', words) state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(index)) self.ex.RunFunc(self.func, []) # call with no arguments # Should be COMP_REPLY to follow naming convention! Lame. val = state.GetGlobal(self.ex.mem, 'COMPREPLY') if val.tag == value_e.Undef: log('COMPREPLY not defined') return if val.tag != value_e.StrArray: log('ERROR: COMPREPLY should be an array, got %s', val) return reply = val.strs print('REPLY', reply) #reply = ['g1', 'g2', 'h1', 'i1'] for name in sorted(reply): if name.startswith(prefix): yield name + ' ' # full word
def Matches(self, comp): # type: (Api) -> List[str] # Have to clear the response every time. TODO: Reuse the object? state.SetGlobalArray(self.cmd_ev.mem, 'COMPREPLY', []) # New completions should use COMP_ARGV, a construct specific to OSH> state.SetGlobalArray(self.cmd_ev.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.cmd_ev.mem, 'COMP_WORDS', comp_words) state.SetGlobalString(self.cmd_ev.mem, 'COMP_CWORD', str(comp_cword)) state.SetGlobalString(self.cmd_ev.mem, 'COMP_LINE', comp.line) state.SetGlobalString(self.cmd_ev.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.cmd_ev.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.cmd_ev.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. stderr_line('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