4

I use Vim inside tmux, and have recently added the following to my .vimrc file:

" easy navigation
nnoremap <C-Left> :tabprevious
nnoremap <C-Right> :tabnext

But this seems to have no effect (I press CTRL+l or CTRL+Right and my cursor just moves as if I hadn't pressed CTRL at all). I am guessing that tmux is somehow responsible for this.

I tried adding each (not both) of the following lines to my .tmux.conf to no avail:

set -g default-terminal "xterm"
set-window-option -g xterm-keys on

Surely there's a simple way to pass these commands through to vim?

I read through this post:

How to get shift+arrows and ctrl+arrows working in Vim in tmux?

and tried adding the following to my .vimrc, also with no discernable effect:

if &term =~ '^screen'
    " tmux will send xterm-style keys when its xterm-keys option is on
    execute "set <xUp>=\e[1;*A"
    execute "set <xDown>=\e[1;*B"
    execute "set <xRight>=\e[1;*C"
    execute "set <xLeft>=\e[1;*D"
endif

I am running vim version 7.4

3 Answers 3

1

The recommended TERM setting for tmux is screen-256color and the snippet you added to your vimrc works only for a TERM that starts with screen so you can be sure that code block will never be executed if your TERM is xterm.

I've been successfully using that very snippet in the past on this machine, without set-window-option -g xterm-keys on, but for whatever reason it doesn't seem to work anymore for me (I didn't use tmux in the last three months). I wonder what's going on. An iTerm upgrade? A tmux upgrade?

Adding set-window-option -g xterm-keys on to my ~/.tmux.conf fixes the problem.

Anyway, you could directly map the raw sequences produced by <C-Left> and <C-Right> as a temporary workaround.

nnoremap <C-v><C-Left> :tabprevious<CR>

should give you something like:

nnoremap ^[[D :tabprevious<CR>
5
  • xterm-keys is not available since 2.4. | I'm not sure I understand how setting <xLeft> could help with mapping <C-Left>.
    – x-yuri
    Jan 8, 2022 at 9:39
  • Well, it certainly was available seven years ago, around the time the question was asked. If this solution doesn't work anymore, feel free to post a new updated question. As for <xLeft>, it is a hack introduced in a 7.x patch to help Vim recognise cursor keys+modifiers in some situations.
    – romainl
    Jan 8, 2022 at 9:53
  • I see, those fields are already in the vim's builtin xterm termcap entry. This part separates the key code from modifiers. Here the key code (w/o modifiers) is translated into its non-x* coutnerpart. Then vim looks for the keycode + the modifier in a table, ...
    – x-yuri
    Jan 8, 2022 at 14:28
  • ... and if found, the result can match the <...> key names. Under tmux TERM is supposedly different from xterm, as such those set's indeed might be needed. If it doesn't work for you, you can give me TERM, the key sequence and the escape sequence that don't work, and I'll try to figure it out. | About xterm-keys I didn't mean it wasn't needed back then. I just notified you in case you want to update your answer. AFAICU, it's not needed these days (the default).
    – x-yuri
    Jan 8, 2022 at 14:28
  • Well, thanks for the notification but I will leave the answer as-is and instead upvote yours.
    – romainl
    Jan 8, 2022 at 17:02
1

Unless you see the code (e.g. <C-Left>) you're using in the section "Terminal keys" of :set termcap, you can't use it right away.

The docs lists 3 ways to map a special key. First in Insert or Cmdline mode press Ctrl-K, then the key sequence you want to map (e.g. Ctrl-K Ctrl-Left). If it prints <...>, you can use that for the left-hand side of your mapping. Or else, prepend it with <Esc> (Ctrl-V Esc), or use Ctrl-V Ctrl-Left. For example, under tmux I get [1;5D for Ctrl-Left, and <Left> for Left. Which means that for Left I can use <Left>, and for Ctrl-Left I need ^[[1;5D (^[ should be one character, Ctrl-V Esc, and do note the trailing <CR>):

nnoremap ^[[1;5D <Cmd>tabprevious<CR>

Or (:h :set-termcap):

set <C-Left>=^[[1;5D
nnoremap <C-Left> <Cmd>tabprevious<CR>

If you work under different terminals you probably want the second approach:

if &term =~ '^screen'
    set <C-Left>=...
elseif &term =~ '^tmux'
    set <C-Left>=...
endif
nnoremap <C-Left> <Cmd>tabprevious<CR>

Some keys work with some terminals, but doesn't work with others (when they have no field in the corresponding terminfo entry). Let's take <S-Left>, for example. From :set termcap not under tmux (TERM=rxvt-unicode-256color) I can see that it resides in the t_#4 termcap field:

t_#4 <S-Left>    ^[[d

man terminfo says:

key_sleft                   kLFT      #4     shifted left-arrow
                                             key

Which means that the terminfo name is kLFT. Now let's see the value of this field for TERM=rxvt-unicode-256color (not under tmux), TERM=screen (under tmux) and TERM=tmux (which we might need later):

$ infocmp rxvt-unicode-256color | grep kLFT
    kLFT=\E[d, kNXT=\E[6$, kPRV=\E[5$, kRIT=\E[c, ka1=\EOw,

$ infocmp screen | grep kLFT

$ infocmp tmux | grep kLFT
    kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~,

It's missing in the screen terminfo entry. To resolve this:

if &term =~ '^screen'
    set <S-Left>=...
endif
nnoremap <S-Left> <Cmd>tabprevious<CR>

Or (with vim we must use termcap names):

if &term =~ '^screen'
    set t_#4=...
endif
nnoremap <S-Left> <Cmd>tabprevious<CR>

Alternatively, you can tell tmux to use its own terminfo entry:

set -g default-terminal tmux

On a side note, avoid using the <Esc> character if possible in your config (or generally in a text file). It's one character that looks like 2. If you e.g. copy it with a mouse, ^[ becomes 2 characters and this way it doesn't work. Particularly in the documentation you can find examples where ^[ is 2 characters, that you can't just copy. This sort of thing is easy to overlook.

And by the way, xterm-keys is not available since 2.4.

If it still doesn't work, tell me what you press and the escape sequence it produces (use Ctrl-V).

0

An alternative solution could be the following:

" Note:  Move to the next tab! By Questor
nnoremap <silent> <C-Up> :tabnext<cr>
inoremap <silent> <C-Up> <C-O>:tabnext<cr>
vnoremap <silent> <C-Up> :<C-U>tabnext<cr>v

" Note:  Move to the previous tab! By Questor
nnoremap <silent> <C-Down> :tabprevious<cr>
inoremap <silent> <C-Down> <C-O>:tabprevious<cr>
vnoremap <silent> <C-Down> :<C-U>tabprevious<cr>v

Works great for me!

See an example of use in https://github.com/eduardolucioac/groovim/blob/master/.vimrc

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .