Based upon my days and days of researching this, I may be seeking the impossible.
Situation
I have my
.bashrcnicely configured to either spawn a newtmuxon connect, or if one exists, attach to it.I always hit Ctrl+D to exit a shell session. It's burned into my muscle memory. Unlearning it after thirty years of systems administration is also asking the impossible.
I want to be able to detach from
tmuxusing just Ctrl+D, rather than having it kill my shell.
My imperfect approach
I can bind Ctrl+D to detach in .tmux.conf.
The problem is that I also have emacs key-bindings burned into my muscle memory, so when I start editing a command line, I'll hit Ctrl+D to employ the GNU readline 'delete char under cursor'. Instead, the tmux binding swallows the Ctrl+D, so I'm immediately detached. Same thing if I'm editing in emacs.
Another flawed approach
GNU readline will take the EOF on an empty line, and then exit the shell. So I've tried trapping exit in .bashrc instead:
trap "~/tmuxexit" EXIT
with the contents of tmuxexit being:
tmux detach-client -s main
Which initially seemed like it worked, as hitting Ctrl+D on an empty line would report:
[detached (from session main)]
But tmux ls reports no server running on […].
Do I seek the impossible?
Answer
I'm not sure if I crafted the simplest possible solution. This:
stty eof '^T'
bind '"\C-d": "\C-x\C-t\C-x\C-d"'
bind -x '"\C-x\C-t": _tmux_detach'
_tmux_detach() { [ -z "$READLINE_LINE" ] && tmux detach-client; }
bind '"\C-x\C-d": delete-char'
Explanation:
stty eof '^T'makes your terminal no longer send EOF at Ctrl+D. Now it's Ctrl+T. The new key combination will behave like the old one in readline, I mean it will exit the shell only if the line is empty. I deliberately chose Ctrl+T because it's very unlikely you will want to use its default binding (transpose characters) with an empty line.I thought that disabling EOF entirely (
stty eof undef) would work, but it turned out readline(?) still reacts to the previously defined combination (like Ctrl+D) and makes the shell register EOF if the line is empty.bind '"\C-d": "\C-x\C-t\C-x\C-d"'makes Ctrl+D "send" Ctrl+X, Ctrl+T and Ctrl+X, Ctrl+D. We will utilize the two sub-sequences separately.bind -x '"\C-x\C-t": _tmux_detach'– From now on Ctrl+X, Ctrl+T executes_tmux_detach…… which is a function that detaches
tmuxif the line ($READLINE_LINE) is empty.bind '"\C-x\C-d": delete-char'– From now on Ctrl+X, Ctrl+D deletes the character at point, like Ctrl+D usually does.
So Ctrl+D will work like this:
- if the line is not empty, the function is a no-op and
delete-chardoes its job; - if the line is empty, the function does its job and
delete-charis a no-op (it gets triggered but has nothing to do).
Notes:
READLINE_LINEwas introduced in Bash 4.0.- If you paste the code into your
~/.bashrc, you may want to improve it: check if the shell is insidetmuxbefore changing the behavior of Ctrl+D, so shells outside oftmuxare unaffected. - It's important that
_tmux_detachacts beforedelete-char. If you reverse the order then you will introduce a bug: Ctrl+D that deletes a solitary character will also detachtmux.
No comments:
Post a Comment