I’ve been using Xonsh, a shell that combines a shell REPL with a Python REPL, for years now. I’ve also been using Emacs for years, but I was never able to marry the two in a satisfactory way. But finally, after being frustrated for long enough, I solved the puzzle. This article is written to help like one or two other people on this world who use both Emacs and Xonsh.
vterm, probably the best terminal
emulator in Emacs, requires some shell-side configuration to make a shell
integrate cleanly into Emacs. Specifically, an improved clear
experience and
directory- and prompt-tracking. vterm can also do message passing, but I’m not
very interested in running Elisp in my terminal emulator—I have the rest of
Emacs for that.
The idea is to print some invisible/hidden strings to the terminal that vterm
can subsequently read, but that the user is unbothered by. The code to achieve
this in .xonshrc
is:
# You can modify this however you want.
$PROMPT = "{env_name}🐚 {BOLD_GREEN}{user}{RESET} {BOLD_BLUE}{cwd_base}{RESET}{branch_color}{curr_branch: {}}{RESET} {BOLD_BLUE}{prompt_end}{RESET} "
def _vterm_printf(text):
def _term_is(value):
return $TERM.split("-")[0] == value
if ${...}.get("TMUX") and (_term_is("tmux") or _term_is("screen")):
return $(printf r"\ePtmux;\e\e]%s\007\e\\" @(text))
elif _term_is("screen"):
return $(printf r"\eP\e]%s\007\e\\" @(text))
else:
return $(printf r"\e]%s\e\\" @(text))
def _vterm_prompt_end():
return _vterm_printf("51;A{user}@{hostname}:{cwd}")
if ${...}.get("INSIDE_EMACS"):
$SHELL_TYPE = "readline"
def _clear(args, stdin=None):
print(_vterm_printf("51;Evterm-clear-scrollback"), end="")
tput clear @(args)
aliases["clear"] = _clear
$PROMPT += _vterm_prompt_end()
One important thing to note is that this only works in readline
mode.
prompt-toolkit is
much fancier, but for reasons that are unknown to me, modifying $PROMPT
as
above does not produce the desired result. I’ve also considered monkey-patching
print_color
as a work-around, but there exists no xonsh.built_ins.XSH.shell
inside of .xonshrc
to monkey-patch.
After implementing the above code in .xonshrc
, you can do the following things
in vterm:
C-c C-p
andC-c C-n
(vterm-[previous,next]-prompt
) move back and forth between prompts.C-x C-f
(find-file
) starts in the CWD of the shell.- When clearing, old data is removed from the buffer.
And that’s it. I’ll see about upstreaming some of this knowledge to vterm some day soon after some more hacking/testing.