def __call__(self, argv): arg_r = args.Reader(argv) arg = INIT_COMPLETION_SPEC.Parse(arg_r) var_names = arg_r.Rest() # Output variables to set for name in var_names: # Ironically we could complete these if name not in ['cur', 'prev', 'words', 'cword']: raise args.UsageError('Invalid output variable name %r' % name) #print(arg) # TODO: How does the user test a completion function programmatically? Set # COMP_ARGV? val = self.mem.GetVar('COMP_ARGV') if val.tag != value_e.StrArray: raise args.UsageError("COMP_ARGV should be an array") comp_argv = val.strs # These are the ones from COMP_WORDBREAKS that we care about. The rest occur # "outside" of words. break_chars = [':', '='] if arg.s: # implied break_chars.remove('=') # NOTE: The syntax is -n := and not -n : -n =. omit_chars = arg.n or '' for c in omit_chars: if c in break_chars: break_chars.remove(c) # argv adjusted according to 'break_chars'. adjusted_argv = [] for a in comp_argv: completion.AdjustArg(a, break_chars, adjusted_argv) if 'words' in var_names: state.SetArrayDynamic(self.mem, 'words', adjusted_argv) n = len(adjusted_argv) cur = adjusted_argv[-1] prev = '' if n < 2 else adjusted_argv[-2] if arg.s: if cur.startswith( '--') and '=' in cur: # Split into flag name and value prev, cur = cur.split('=', 1) split = 'true' else: split = 'false' # Do NOT set 'split' without -s. Caller might not have declared it. # Also does not respect var_names, because we don't need it. state.SetStringDynamic(self.mem, 'split', split) if 'cur' in var_names: state.SetStringDynamic(self.mem, 'cur', cur) if 'prev' in var_names: state.SetStringDynamic(self.mem, 'prev', prev) if 'cword' in var_names: # Same weird invariant after adjustment state.SetStringDynamic(self.mem, 'cword', str(n - 1)) return 0
def Read(argv, splitter, mem): arg, i = READ_SPEC.Parse(argv) names = argv[i:] if arg.n is not None: # read a certain number of bytes try: name = names[0] except IndexError: name = 'REPLY' # default variable name s = posix.read(sys.stdin.fileno(), arg.n) #log('read -n: %s = %s', name, s) state.SetLocalString(mem, name, s) # NOTE: Even if we don't get n bytes back, there is no error? return 0 if not names: names.append('REPLY') # leftover words assigned to the last name if arg.a: max_results = 0 # no max else: max_results = len(names) # We have to read more than one line if there is a line continuation (and # it's not -r). parts = [] join_next = False while True: line = ReadLineFromStdin() #log('LINE %r', line) if not line: # EOF status = 1 break if line.endswith('\n'): # strip trailing newline line = line[:-1] status = 0 else: # odd bash behavior: fail even if we can set variables. status = 1 spans = splitter.SplitForRead(line, not arg.r) done, join_next = _AppendParts(line, spans, max_results, join_next, parts) #log('PARTS %s continued %s', parts, continued) if done: break if arg.a: state.SetArrayDynamic(mem, arg.a, parts) else: for i in xrange(max_results): try: s = parts[i] except IndexError: s = '' # if there are too many variables #log('read: %s = %s', names[i], s) state.SetStringDynamic(mem, names[i], s) return status
def __call__(self, arg_vec): arg, i = READ_SPEC.ParseVec(arg_vec) names = arg_vec.strs[i:] if arg.n is not None: # read a certain number of bytes stdin = sys.stdin.fileno() try: name = names[0] except IndexError: name = 'REPLY' # default variable name s = "" if sys.stdin.isatty(): # set stdin to read in unbuffered mode orig_attrs = termios.tcgetattr(stdin) attrs = termios.tcgetattr(stdin) # disable canonical (buffered) mode # see `man termios` for an extended discussion attrs[3] &= ~termios.ICANON try: termios.tcsetattr(stdin, termios.TCSANOW, attrs) # posix.read always returns a single character in unbuffered mode while arg.n > 0: s += posix.read(stdin, 1) arg.n -= 1 finally: termios.tcsetattr(stdin, termios.TCSANOW, orig_attrs) else: s_len = 0 while arg.n > 0: buf = posix.read(stdin, arg.n) # EOF if buf == '': break arg.n -= len(buf) s += buf state.SetLocalString(self.mem, name, s) # NOTE: Even if we don't get n bytes back, there is no error? return 0 if not names: names.append('REPLY') # leftover words assigned to the last name if arg.a: max_results = 0 # no max else: max_results = len(names) # We have to read more than one line if there is a line continuation (and # it's not -r). parts = [] join_next = False while True: line = ReadLineFromStdin() #log('LINE %r', line) if not line: # EOF status = 1 break if line.endswith('\n'): # strip trailing newline line = line[:-1] status = 0 else: # odd bash behavior: fail even if we can set variables. status = 1 spans = self.splitter.SplitForRead(line, not arg.r) done, join_next = _AppendParts(line, spans, max_results, join_next, parts) #log('PARTS %s continued %s', parts, continued) if done: break if arg.a: state.SetArrayDynamic(self.mem, arg.a, parts) else: for i in xrange(max_results): try: s = parts[i] except IndexError: s = '' # if there are too many variables #log('read: %s = %s', names[i], s) state.SetStringDynamic(self.mem, names[i], s) return status