def complete_base(context: CompletionContext): """If the line is empty, complete based on valid commands, python names, and paths. If we are completing the first argument, complete based on valid commands and python names. """ out: tp.Set[Completion] = set() if context.command is None or context.command.arg_index != 0: # don't do unnecessary completions return out # get and unpack python completions python_comps = complete_python(context) or set() if isinstance(python_comps, cabc.Sequence): python_comps, python_comps_len = python_comps # type: ignore out.update(apply_lprefix(python_comps, python_comps_len)) else: out.update(python_comps) # add command completions out.update(complete_command(context.command)) # add paths, if needed if not context.command.prefix: path_comps, path_comp_len = contextual_complete_path(context.command, cdpath=False) out.update(apply_lprefix(path_comps, path_comp_len)) return out
def _format_completion( completion, completion_context, completing_contextual_command: bool, lprefix: int, custom_lprefix: bool, ) -> tp.Tuple[Completion, int]: if ( completing_contextual_command and completion_context.command.is_after_closing_quote ): """ The cursor is appending to a closed string literal, i.e. cursor at the end of ``ls "/usr/"``. 1. The closing quote will be appended to all completions. I.e the completion ``/usr/bin`` will turn into ``/usr/bin"`` To prevent this behavior, a completer can return a ``RichCompletion`` with ``append_closing_quote=False``. 2. If not specified, lprefix will cover the closing prefix. I.e for ``ls "/usr/"``, the default lprefix will be 6 to include the closing quote. To prevent this behavior, a completer can return a different lprefix or specify it inside ``RichCompletion``. """ closing_quote = completion_context.command.closing_quote if not custom_lprefix: lprefix += len(closing_quote) if closing_quote: if isinstance(completion, RichCompletion): if completion.append_closing_quote: completion = completion.replace( value=completion.value + closing_quote ) else: completion = completion + closing_quote completion = list(apply_lprefix([completion], lprefix))[0] if ( isinstance(completion, RichCompletion) and completion.append_space and not completion.value.endswith(" ") ): # append spaces AFTER appending closing quote completion = completion.replace(value=completion.value + " ") return completion, lprefix
def complete_from_context(self, completion_context, old_completer_args=None): lprefix = 0 completions = set() for func in builtins.__xonsh__.completers.values(): try: if is_contextual_completer(func): if completion_context is None: continue out = func(completion_context) else: if old_completer_args is None: continue out = func(*old_completer_args) except StopIteration: # completer requested to stop collecting completions break except Exception as e: print_exception( f"Completer {func.__name__} raises exception when gets " f"old_args={old_completer_args[:-1]} / completion_context={completion_context!r}:\n" f"{e}" ) continue completing_contextual_command = ( is_contextual_completer(func) and completion_context is not None and completion_context.command is not None ) if isinstance(out, cabc.Sequence): res, lprefix = out custom_lprefix = True else: res = out custom_lprefix = False if completing_contextual_command: lprefix = len(completion_context.command.prefix) elif old_completer_args is not None: lprefix = len(old_completer_args[0]) else: lprefix = 0 if res is None or len(res) == 0: continue if ( completing_contextual_command and completion_context.command.is_after_closing_quote ): """ The cursor is appending to a closed string literal, i.e. cursor at the end of ``ls "/usr/"``. 1. The closing quote will be appended to all completions. I.e the completion ``/usr/bin`` will turn into ``/usr/bin"`` To prevent this behavior, a completer can return a ``RichCompletion`` with ``append_closing_quote=False``. 2. If not specified, lprefix will cover the closing prefix. I.e for ``ls "/usr/"``, the default lprefix will be 6 to include the closing quote. To prevent this behavior, a completer can return a different lprefix or specify it inside ``RichCompletion``. """ closing_quote = completion_context.command.closing_quote if not custom_lprefix: lprefix += len(closing_quote) def append_closing_quote(completion: Completion): if isinstance(completion, RichCompletion): if completion.append_closing_quote: return completion.replace( value=completion.value + closing_quote ) return completion return completion + closing_quote res = map(append_closing_quote, res) completions.update(apply_lprefix(res, lprefix)) if is_exclusive_completer(func): # we got completions for an exclusive completer break # append spaces AFTER appending closing quote def append_space(comp: Completion): if ( isinstance(comp, RichCompletion) and comp.append_space and not comp.value.endswith(" ") ): return comp.replace(value=comp.value + " ") return comp completions = map(append_space, completions) def sortkey(s): return s.lstrip(''''"''').lower() # the last completer's lprefix is returned. other lprefix values are inside the RichCompletions. return tuple(sorted(completions, key=sortkey)), lprefix