11

I want to remap <C-I> to print markdown * symbol around the previous word. For example:

# user actions inside <...>
some text typed in vim insert mode<cursor_position> <C-I>

# expected  vim output
some text typed in vim insert *mode*<cursor_position>

I am using the following line in my .vimrc for remapping

inoremap <C-i> <ESC>Bi*<ESC>ea*

Problem is, as per help :h i_CTRL-I, <C-I> in insert mode is already mapped to something and the mapping above doesn't work for me. Pressing <C-I> in insert mode leaves a <TAB> on editor.

<Tab> or CTRL-I Insert a tab. If the 'expandtab' option is on, the equivalent number of spaces is inserted (use CTRL-V to avoid the expansion; use CTRL-Q <Tab> if CTRL-V is mapped i_CTRL-Q). See also the 'smarttab' option and ins-expandtab.

  1. How do I make insert mode <C-I> mapping work?
  2. How can I override global vim key-mapping with my own key-mapping defined in .vimrc file?
Martin Tournoij
  • 62,054
  • 25
  • 192
  • 271
avimehenwal
  • 909
  • 9
  • 18
  • 1
    Very similar which explains some context: [Disable but keep <C->. The short version is that Tab is ctrl+i. Perhaps there are workarounds specific for Tab, so not quite a duplicate. – Martin Tournoij May 06 '18 at 18:27

2 Answers2

11

With a recent enough Vim binary, and for some terminals – including xterm and iterm2 if you enable the CSI u option – Vim can distinguish C-i from Tab.

You need at least the Vim patch 8.1.2134.

And you may need to add these lines in your vimrc:

let &t_TI = "\<Esc>[>4;2m"
let &t_TE = "\<Esc>[>4;m"

Unless your Vim binary also includes the patch 8.1.2194, in which case it should have been done automatically if Vim has properly detected it's running in xterm.


As a simple test, run this shell command:

vim -Nu NONE +'nno <C-i> :echom "C-i was pressed"<cr>' +'nno <tab> :echom "Tab was pressed"<cr>'

Then press Tab followed by C-i. The first keypress should log the message Tab was pressed, while the second one should log the message C-i was pressed (check out the output of :messages if you somehow missed the messages).

enter image description here

Make sure to install the Tab mapping after the C-i mapping; otherwise, the Tab mapping may be removed.


Vim can distinguish between many other keys; like C-a and C-S-a:

vim -Nu NONE +'nno <C-a> :echom "C-a was pressed"<cr>' +'nno <C-S-a> :echom "C-S-a was pressed"<cr>'

Here C- and S- stand for resp. the control and shift modifiers.

Or A-b and A-C-b:

vim -Nu NONE +'nno <A-b> :echom "A-b was pressed"<cr>' +'nno <A-C-b> :echom "A-C-b was pressed"<cr>'

Here A- stands for the Alt modifier.


For more info, see :h modifyOtherKeys.

user938271
  • 5,947
  • 1
  • 15
  • 24
  • 2
    This also works in iTerm2 by enabling the CSI u option https://iterm2.com/documentation-csiu.html – ruohola Jun 20 '20 at 17:55
  • Actually now it seems to need the 'Control sequences can enable modifyOtherKeys mode' option from iTerm2 -> Preferences -> Profiles -> Keys – ruohola Jan 09 '21 at 20:14
  • As mentioned here, to have a custom mapping for Tab and still use C-i for going forward in the jump list, we need to have an explicit mapping for C-i as well: nnoremap <C-i> <C-i> and then, for example: nmap <Tab> <c-^> – Matthias Braun Dec 29 '23 at 22:35
4

Short answer: you cannot.

Long answer: <C-i> being equivalent to <Tab> isn't a vim quirk or builtin. It's a quirk of how terminals represent characters (cf. https://bestasciitable.com).

You simply cannot avoid this fact. Now, it may be possible to force your mapping to take precedence over the tab-behavior of inserting tabs/spaces, but I haven't done much investigating there. I would recommend choosing another mapping.

D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65