def _wizard(ns): env = builtins.__xonsh__.env shell = builtins.__xonsh__.shell.shell fname = env.get("XONSHRC")[-1] if ns.file is None else ns.file no_wiz = os.path.join(env.get("XONSH_CONFIG_DIR"), "no-wizard") w = make_xonfig_wizard(default_file=fname, confirm=ns.confirm, no_wizard_file=no_wiz) tempenv = {"PROMPT": "", "XONSH_STORE_STDOUT": False} pv = wiz.PromptVisitor(w, store_in_history=False, multiline=False) @contextlib.contextmanager def force_hide(): if env.get("XONSH_STORE_STDOUT") and hasattr(shell, "_force_hide"): orig, shell._force_hide = shell._force_hide, False yield shell._force_hide = orig else: yield with force_hide(), env.swap(tempenv): try: pv.visit() except (KeyboardInterrupt, Exception): print() print_exception()
def transform_command(src, show_diff=True): """Returns the results of firing the precommand handles.""" i = 0 limit = sys.getrecursionlimit() lst = "" raw = src while src != lst: lst = src srcs = events.on_transform_command.fire(cmd=src) for s in srcs: if s != lst: src = s break i += 1 if i == limit: print_exception( "Modifications to source input took more than " "the recursion limit number of iterations to " "converge." ) debug_level = builtins.__xonsh__.env.get("XONSH_DEBUG") if show_diff and debug_level > 1 and src != raw: sys.stderr.writelines( difflib.unified_diff( raw.splitlines(keepends=True), src.splitlines(keepends=True), fromfile="before precommand event", tofile="after precommand event", ) ) return src
def wait(self, timeout=None): """Runs the function and returns the result. Timeout argument only present for API compatibility. """ if self.f is None: return 0 env = builtins.__xonsh__.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") spec = self._wait_and_getattr("spec") # set file handles if self.stdin is None: stdin = None else: if isinstance(self.stdin, int): inbuf = io.open(self.stdin, "rb", -1) else: inbuf = self.stdin stdin = io.TextIOWrapper(inbuf, encoding=enc, errors=err) stdout = self._pick_buf(self.stdout, sys.stdout, enc, err) stderr = self._pick_buf(self.stderr, sys.stderr, enc, err) # run the actual function try: r = self.f(self.args, stdin, stdout, stderr, spec, spec.stack) except Exception: xt.print_exception() r = 1 self.returncode = parse_proxy_return(r, stdout, stderr) safe_flush(stdout) safe_flush(stderr) return self.returncode
def _get_prompt_tokens(self, env_name: str, prompt_name: str, **kwargs): env = builtins.__xonsh__.env # type:ignore p = env.get(env_name) if not p and "default" in kwargs: return kwargs.pop("default") try: p = self.prompt_formatter(template=p, threaded=env["ENABLE_ASYNC_PROMPT"], prompt_name=prompt_name) except Exception: # pylint: disable=broad-except print_exception() p, osc_tokens = remove_ansi_osc(p) if kwargs.get("handle_osc_tokens"): # handle OSC tokens for osc in osc_tokens: if osc[2:4] == "0;": env["TITLE"] = osc[4:-1] else: print(osc, file=sys.__stdout__, flush=True) toks = partial_color_tokenize(p) return tokenize_ansi(PygmentsTokens(toks))
def __init__(self, specs): """ Parameters ---------- specs : list of SubprocSpec Process specifications Attributes ---------- spec : SubprocSpec The last specification in specs proc : Popen-like The process in procs ended : bool Boolean for if the command has stopped executing. input : str A string of the standard input. output : str A string of the standard output. errors : str A string of the standard error. lines : list of str The output lines starttime : floats or None Pipeline start timestamp. """ self.starttime = None self.ended = False self.procs = [] self.specs = specs self.spec = specs[-1] self.captured = specs[-1].captured self.input = self._output = self.errors = self.endtime = None self._closed_handle_cache = {} self.lines = [] self._stderr_prefix = self._stderr_postfix = None self.term_pgid = None background = self.spec.background pipeline_group = None for spec in specs: if self.starttime is None: self.starttime = time.time() try: proc = spec.run(pipeline_group=pipeline_group) except Exception: xt.print_exception() self._return_terminal() self.proc = None return if (proc.pid and pipeline_group is None and not spec.is_proxy and self.captured != "object"): pipeline_group = proc.pid if update_fg_process_group(pipeline_group, background): self.term_pgid = pipeline_group self.procs.append(proc) self.proc = self.procs[-1]
def _failover_template_format(template): if callable(template): try: # Exceptions raises from function of producing $PROMPT # in user's xonshrc should not crash xonsh return template() except Exception: xt.print_exception() return "$ " return template
def _no_cache_field_value(self, field, field_value, **_): try: value = field_value() if callable(field_value) else field_value self.cache[field_value] = value except Exception: print("prompt: error: on field {!r}" "".format(field), file=sys.stderr) xt.print_exception() value = "{{BACKGROUND_RED}}{{ERROR:{}}}{{RESET}}".format(field) return value
def wrapper(*args, **kwargs): anchor = Path(os.getcwd()).anchor os.chdir(anchor) try: out = func(*args, **kwargs) finally: try: pwd = env.get("PWD", anchor) os.chdir(pwd) except (FileNotFoundError, NotADirectoryError): print_exception() newpath = _chdir_up(pwd) builtins.__xonsh__.env["PWD"] = newpath raise KeyboardInterrupt return out
def complete(self, prefix, line, begidx, endidx, ctx=None): """Complete the string, given a possible execution context. Parameters ---------- prefix : str The string to match line : str The line that prefix appears on. begidx : int The index in line that prefix starts on. endidx : int The index in line that prefix ends on. ctx : Iterable of str (ie dict, set, etc), optional Names in the current execution context. Returns ------- rtn : list of str Possible completions of prefix, sorted alphabetically. lprefix : int Length of the prefix to be replaced in the completion. """ ctx = ctx or {} for func in builtins.__xonsh__.completers.values(): try: out = func(prefix, line, begidx, endidx, ctx) except StopIteration: return set(), len(prefix) except Exception as e: print_exception( f"Completer {func.__name__} raises exception when get " f"(prefix={repr(prefix)}, line={repr(line)}, begidx={repr(begidx)}, endidx={repr(endidx)}):\n" f"{e}" ) return set(), len(prefix) if isinstance(out, cabc.Sequence): res, lprefix = out else: res = out lprefix = len(prefix) if res is not None and len(res) != 0: def sortkey(s): return s.lstrip(''''"''').lower() return tuple(sorted(res, key=sortkey)), lprefix return set(), lprefix
def xontribs_load(names, verbose=False): """Load xontribs from a list of names""" ctx = builtins.__xonsh__.ctx res = ExitCode.OK for name in names: if verbose: print("loading xontrib {0!r}".format(name)) try: update_context(name, ctx=ctx) except Exception: res = ExitCode.INIT_FAILED print_exception("Failed to load xontrib {}.".format(name)) if hasattr(update_context, "bad_imports"): res = ExitCode.NOT_FOUND prompt_xontrib_install(update_context.bad_imports) del update_context.bad_imports return res
def prompt(self): """Obtains the current prompt string.""" if self.need_more_lines: if self.mlprompt is None: try: self.mlprompt = multiline_prompt() except Exception: # pylint: disable=broad-except print_exception() self.mlprompt = "<multiline prompt error> " return self.mlprompt env = builtins.__xonsh__.env # pylint: disable=no-member p = env.get("PROMPT") try: p = self.prompt_formatter(p) except Exception: # pylint: disable=broad-except print_exception() self.settitle() return p
def default(self, line): """Implements code execution.""" line = line if line.endswith("\n") else line + "\n" src, code = self.push(line) if code is None: return events.on_precommand.fire(cmd=src) env = builtins.__xonsh__.env hist = builtins.__xonsh__.history # pylint: disable=no-member ts1 = None enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") tee = Tee(encoding=enc, errors=err) try: ts0 = time.time() run_compiled_code(code, self.ctx, None, "single") ts1 = time.time() if hist is not None and hist.last_cmd_rtn is None: hist.last_cmd_rtn = 0 # returncode for success except XonshError as e: print(e.args[0], file=sys.stderr) if hist is not None and hist.last_cmd_rtn is None: hist.last_cmd_rtn = 1 # return code for failure except Exception: # pylint: disable=broad-except print_exception() if hist is not None and hist.last_cmd_rtn is None: hist.last_cmd_rtn = 1 # return code for failure finally: ts1 = ts1 or time.time() tee_out = tee.getvalue() self._append_history(inp=src, ts=[ts0, ts1], tee_out=tee_out) self.accumulated_inputs += src if ( tee_out and env.get("XONSH_APPEND_NEWLINE") and not tee_out.endswith(os.linesep) ): print(os.linesep, end="") tee.close() self._fix_cwd() if builtins.__xonsh__.exit: # pylint: disable=no-member return True
def _xhj_get_history_files(sort=True, newest_first=False): """Find and return the history files. Optionally sort files by modify time. """ data_dir = builtins.__xonsh__.env.get("XONSH_DATA_DIR") data_dir = xt.expanduser_abs_path(data_dir) try: files = [ os.path.join(data_dir, f) for f in os.listdir(data_dir) if f.startswith("xonsh-") and f.endswith(".json") ] except OSError: files = [] if builtins.__xonsh__.env.get("XONSH_DEBUG"): xt.print_exception("Could not collect xonsh history files.") if sort: files.sort(key=lambda x: os.path.getmtime(x), reverse=newest_first) return files
def _push(self, line): """Pushes a line onto the buffer and compiles the code in a way that enables multiline input. """ code = None self.buffer.append(line) if self.need_more_lines: return None, code src = "".join(self.buffer) src = transform_command(src) try: code = self.execer.compile(src, mode="single", glbs=self.ctx, locs=None) self.reset_buffer() except Exception: # pylint: disable=broad-except self.reset_buffer() print_exception() return src, None return src, code
def ulimit(args, stdin, stdout, stderr): """An ulimit implementation""" rc, actions = _ul_parse_args(args, stderr) # could not parse arguments; message already printed to stderr if not rc: return 1 # args OK, but nothing to do; print help elif not actions: _ul_show_usage(stdout) return 0 # if there's more than one resource to be printed, use the long format long = len([a for a in actions if a[0] == _ul_show]) > 1 try: for fn, args in actions: fn(stdout=stdout, long=long, **args) return 0 except: print_exception() return 2
def compile(self, src): """Compiles source code and returns the (possibly modified) source and a valid code object. """ _cache = should_use_cache(self.execer, "single") if _cache: codefname = code_cache_name(src) cachefname = get_cache_filename(codefname, code=True) usecache, code = code_cache_check(cachefname) if usecache: self.reset_buffer() return src, code lincont = get_line_continuation() if src.endswith(lincont + "\n"): self.need_more_lines = True return src, None try: code = self.execer.compile(src, mode="single", glbs=self.ctx, locs=None) if _cache: update_cache(code, cachefname) self.reset_buffer() except SyntaxError: partial_string_info = check_for_partial_string(src) in_partial_string = ( partial_string_info[0] is not None and partial_string_info[1] is None ) if (src == "\n" or src.endswith("\n\n")) and not in_partial_string: self.reset_buffer() print_exception() return src, None self.need_more_lines = True code = None except Exception: # pylint: disable=broad-except self.reset_buffer() print_exception() code = None return src, code
def fire(self, **kwargs): """ Fires an event, calling registered handlers with the given arguments. A non-unique iterable of the results is returned. Each handler is called immediately. Exceptions are turned in to warnings. Parameters ---------- **kwargs : Keyword arguments to pass to each handler Returns ------- vals : iterable Return values of each handler. If multiple handlers return the same value, it will appear multiple times. """ vals = [] self._firing = True for handler in self._filterhandlers(self._handlers, **kwargs): try: rv = handler(**kwargs) except Exception: print_exception("Exception raised in event handler; ignored.") else: vals.append(rv) # clean up self._firing = False if self._delayed_adds is not None: self._handlers.update(self._delayed_adds) self._delayed_adds = None if self._delayed_discards is not None: self._handlers.difference_update(self._delayed_discards) self._delayed_discards = None return vals
def singleline(self, auto_suggest=None, enable_history_search=True, multiline=True, **kwargs): """Reads a single line of input from the shell. The store_in_history kwarg flags whether the input should be stored in PTK's in-memory history. """ events.on_pre_prompt_format.fire() env = builtins.__xonsh__.env mouse_support = env.get("MOUSE_SUPPORT") auto_suggest = auto_suggest if env.get("AUTO_SUGGEST") else None refresh_interval = env.get("PROMPT_REFRESH_INTERVAL") refresh_interval = refresh_interval if refresh_interval > 0 else None complete_in_thread = env.get("COMPLETION_IN_THREAD") completions_display = env.get("COMPLETIONS_DISPLAY") complete_style = self.completion_displays_to_styles[ completions_display] complete_while_typing = env.get("UPDATE_COMPLETIONS_ON_KEYPRESS") if complete_while_typing: # PTK requires history search to be none when completing while typing enable_history_search = False if HAS_PYGMENTS: self.styler.style_name = env.get("XONSH_COLOR_STYLE") completer = None if completions_display == "none" else self.pt_completer events.on_timingprobe.fire(name="on_pre_prompt_tokenize") get_bottom_toolbar_tokens = self.bottom_toolbar_tokens if env.get("UPDATE_PROMPT_ON_KEYPRESS"): get_prompt_tokens = self.prompt_tokens get_rprompt_tokens = self.rprompt_tokens else: get_prompt_tokens = self.prompt_tokens() get_rprompt_tokens = self.rprompt_tokens() if get_bottom_toolbar_tokens: get_bottom_toolbar_tokens = get_bottom_toolbar_tokens() events.on_timingprobe.fire(name="on_post_prompt_tokenize") if env.get("VI_MODE"): editing_mode = EditingMode.VI else: editing_mode = EditingMode.EMACS if env.get("XONSH_HISTORY_MATCH_ANYWHERE"): self.prompter.default_buffer._history_matches = MethodType( _cust_history_matches, self.prompter.default_buffer) elif (self.prompter.default_buffer._history_matches is not self._history_matches_orig): self.prompter.default_buffer._history_matches = self._history_matches_orig prompt_args = { "mouse_support": mouse_support, "auto_suggest": auto_suggest, "message": get_prompt_tokens, "rprompt": get_rprompt_tokens, "bottom_toolbar": get_bottom_toolbar_tokens, "completer": completer, "multiline": multiline, "editing_mode": editing_mode, "prompt_continuation": self.continuation_tokens, "enable_history_search": enable_history_search, "reserve_space_for_menu": 0, "key_bindings": self.key_bindings, "complete_style": complete_style, "complete_while_typing": complete_while_typing, "include_default_pygments_style": False, "refresh_interval": refresh_interval, "complete_in_thread": complete_in_thread, } if env.get("COLOR_INPUT"): events.on_timingprobe.fire(name="on_pre_prompt_style") if HAS_PYGMENTS: prompt_args["lexer"] = PygmentsLexer(pyghooks.XonshLexer) style = style_from_pygments_cls( pyghooks.xonsh_style_proxy(self.styler)) else: style = style_from_pygments_dict(DEFAULT_STYLE_DICT) prompt_args["style"] = style events.on_timingprobe.fire(name="on_post_prompt_style") style_overrides_env = env.get("PTK_STYLE_OVERRIDES") if style_overrides_env: try: style_overrides = Style.from_dict(style_overrides_env) prompt_args["style"] = merge_styles( [style, style_overrides]) except (AttributeError, TypeError, ValueError): print_exception() if env["ENABLE_ASYNC_PROMPT"]: # once the prompt is done, update it in background as each future is completed prompt_args["pre_run"] = self.prompt_formatter.start_update events.on_pre_prompt.fire() line = self.prompter.prompt(**prompt_args) events.on_post_prompt.fire() return line
def run(self): """Set up input/output streams and execute the child function in a new thread. This is part of the `threading.Thread` interface and should not be called directly. """ if self.f is None: return spec = self._wait_and_getattr("spec") last_in_pipeline = spec.last_in_pipeline if last_in_pipeline: capout = spec.captured_stdout # NOQA caperr = spec.captured_stderr # NOQA env = builtins.__xonsh__.env enc = env.get("XONSH_ENCODING") err = env.get("XONSH_ENCODING_ERRORS") if xp.ON_WINDOWS: if self.p2cread != -1: self.p2cread = xli.msvcrt.open_osfhandle( self.p2cread.Detach(), 0) if self.c2pwrite != -1: self.c2pwrite = xli.msvcrt.open_osfhandle( self.c2pwrite.Detach(), 0) if self.errwrite != -1: self.errwrite = xli.msvcrt.open_osfhandle( self.errwrite.Detach(), 0) # get stdin if self.stdin is None: sp_stdin = None elif self.p2cread != -1: sp_stdin = io.TextIOWrapper(io.open(self.p2cread, "rb", -1), encoding=enc, errors=err) else: sp_stdin = sys.stdin # stdout if self.c2pwrite != -1: sp_stdout = io.TextIOWrapper(io.open(self.c2pwrite, "wb", -1), encoding=enc, errors=err) else: sp_stdout = sys.stdout # stderr if self.errwrite == self.c2pwrite: sp_stderr = sp_stdout elif self.errwrite != -1: sp_stderr = io.TextIOWrapper(io.open(self.errwrite, "wb", -1), encoding=enc, errors=err) else: sp_stderr = sys.stderr # run the function itself try: with STDOUT_DISPATCHER.register( sp_stdout ), STDERR_DISPATCHER.register(sp_stderr), xt.redirect_stdout( STDOUT_DISPATCHER), xt.redirect_stderr(STDERR_DISPATCHER): r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec, spec.stack) except SystemExit as e: r = e.code if isinstance(e.code, int) else int(bool(e.code)) except OSError: status = still_writable(self.c2pwrite) and still_writable( self.errwrite) if status: # stdout and stderr are still writable, so error must # come from function itself. xt.print_exception() r = 1 else: # stdout and stderr are no longer writable, so error must # come from the fact that the next process in the pipeline # has closed the other side of the pipe. The function then # attempted to write to this side of the pipe anyway. This # is not truly an error and we should exit gracefully. r = 0 except Exception: xt.print_exception() r = 1 safe_flush(sp_stdout) safe_flush(sp_stderr) self.returncode = parse_proxy_return(r, sp_stdout, sp_stderr) if not last_in_pipeline and not xp.ON_WINDOWS: # mac requires us *not to* close the handles here while # windows requires us *to* close the handles here return # clean up # scopz: not sure why this is needed, but stdin cannot go here # and stdout & stderr must. handles = [self.stdout, self.stderr] for handle in handles: safe_fdclose(handle, cache=self._closed_handle_cache)
def _call(self, handler): try: handler(**self._kwargs) except Exception: print_exception("Exception raised in event handler; ignored.")