Search code examples
rvimx11tmuxgnu-screen

keyboard IO broken after reattach to tmux/screen


After reattaching a screen or tmux session over ssh, I commonly encounter two issues:

  • vim tab completion is broken. :e <Tab> produces :e ^I instead of suggesting files. Same for tags (:tj). Closing and re-opening vim fixes this, but at the cost of losing vim state.
  • R cannot produce graphics. I have X11 forwarding (ssh -X -Y) enabled. Closing and re-opening does not help.

I cannot deliberately reproduce the problem by closing my ssh window and re-attaching. Problem is usually observed after long periods without network connectivity between reattaching, and usually detaching is abrupt (loss of network connectivity).


Solution

  • Vim tab completion:

    This is an issue with screen/tmux's terminal emulator. If tabs work in your shell (e.g. bash), that's likely to the shell's credit; it knew to map the control sequence for you while vim did not. Presumably, you could fix this in vim in a similar manner, but then you'd run into the issue in some other interactive program.

    I can't speak to tmux, but for screen, you should look to update your ~/.screenrc. Mine, copied from the default that ships with Redhat (which I no longer use...), includes this:

    #xterm understands both im/ic and doesn't have a status line.
    #Note: Do not specify im and ic in the real termcap/info file as
    #some programs (e.g. vi) will not work anymore.
    termcap  xterm hs@:cs=\E[%i%d;%dr:im=\E[4h:ei=\E[4l
    terminfo xterm hs@:cs=\E[%i%p1%d;%p2%dr:im=\E[4h:ei=\E[4l
    

    Heed that comment, it may indicate your issue.

    Another reference to vi, which may or may not have come from Redhat's screenrc, is:

    # Yet another hack:
    # Prepend/append register [/] to the paste if ^a^] is pressed.
    # This lets me have autoindent mode in vi.
    register [ "\033:se noai\015a"
    register ] "\033:se ai\015a"
    bind ^] paste [.]
    

    Hopefully one or both of these will help, or else I've pointed you in the right direction to research what you need to correct your screen/tmux terminal emulation. Perhaps the answers to screen, vimrc, and bashrc over at LinuxQuestions.org can help further.


    X11 Forwarding:

    When you first launch screen, the $DISPLAY is inherited. For example, I take advantage of this on my TV server; I launch screen locally (DISPLAY=localhost:0), then when I connect to it over SSH, anything I do regarding X pops up on the TV. Obviously, this is not at all your use case; I'm just trying to educate you on how it works so you can understand the solution.

    If you are reconnecting to a screen/tmux session launched by an old SSH connection, you may luck out and have it connected to the same X display (SSH defaults to localhost:10.0 and then increments each time it finds a collision), but that doesn't sound like it's happening for you. (The "localhost" part is optional, as is the ".0" part. Those shouldn't matter for your purposes. DISPLAY=:10 is the same as DISPLAY=localhost:10.0)

    Before you connect to your screen/tmux session, take a look at your $DISPLAY.

    $ echo $DISPLAY
    localhost:10.0
    

    Then, log into screen/tmux and set the $DISPLAY to what you saw before.

    $ screen -r
    $ export DISPLAY=localhost:10.0
    

    I don't think either screen or tmux are smart enough to go any farther than this (think of my TV server example; this isn't always desired, and asking screen/tmux to test the $DISPLAY and then act contingent on its availability is a bit much), so you have to do this manually.

    (This may be annoying if you're like me and add screen -r >/dev/null 2>&1 in your ~/.bashrc. I don't run into this issue because I try to avoid X11 forwarding whenever possible due to its being slow as molasses and of course not surviving SSH disconnections.)