Open gsavovski opened 8 years ago
Mapping meta does not work in the terminal because Vim cannot tell the difference between meta and esc. Neovim in the terminal works fine with meta maps (as well as <esc>
map), but it means that the opposite issue occurs: https://github.com/neovim/neovim/issues/2017
Hi @gsavovski,
I make Meta mappings work in my terminal by explicitly setting them on startup.
For example, if your terminal sends \033a
when you press <M-a>
on your
keyboard, you can teach vim this keystroke with:
execute "set <M-a>=\<Esc>a"
Therefore, to make <M-…>
work in a terminal that sends \033
:
" Timeout quickly on key codes to differentiate from normal <Esc>
set ttimeout ttimeoutlen=0
" Special named keys that cause problems when used literally
let namedkeys = { ' ': 'Space', '\': 'Bslash', '|': 'Bar', '<': 'lt' }
" Map Alt + ASCII printable chars
for n in range(0x20, 0x7e)
let char = nr2char(n)
let key = char
if has_key(namedkeys, char)
let char = namedkeys[char]
let key = '<' . char . '>'
endif
" Escaped Meta (i.e. not 8-bit mode)
" * Esc-[ is the CSI prefix (Control Sequence Introducer)
" * Esc-O is the SS3 prefix (Single Shift Select of G3 Character Set)
if char !=# '[' && char !=# 'O'
try
execute 'set <M-' . char . ">=\<Esc>" . key
catch
endtry
endif
endfor
unlet namedkeys n key char
I've always meant to package this bit of vim voodoo into a plugin, but never
got around to it. In fact, when I originally wrote vim-sexp, I had been using
this setup for so long that I forgot that <M-…>
does not work in vim by
default.
Hence https://github.com/tpope/vim-sexp-mappings-for-regular-people
:)
EDIT (removed discussion of binding <4-…>
, simplified code example):
@justinmk just brought up a good point: this will cause <Esc>
to behave
badly unless we set ttimeout
and ttimeoutlen
:
set ttimeout ttimeoutlen=0
Setting ttimeout{,len}
can have its own issues, but I don't find it to be a
problem in practice. You can increase ttimeoutlen
if you are using Vim over
an especially slow network connection.
In truth, none of this has personally never bothered me as I use <C-c>
in
place of <Esc>
.
Hope this helps!
Thanks for the reminder @justinmk!
@justinmk
Oops, forgot about that side effect. Appending my first post now...
Okay, I've updated my comment with discussion of ttimeout{,len}
.
It's surely a hack, but a serviceable one nonetheless.
@gsavovski
One more thing I forgot to mention: Meta mappings work by default in vim if you can configure your terminal to set the 8th bit on meta/alt.
Most terminals can be configured to do this, but often do not do it by default. I imagine iTerm has this option as well. IIRC, the default OS X Terminal also has this option.
Hi @justinmk
Thanks for the kind explanation.
I actually remembered that I never could use the Alt/Meta and Command keys since I didn’t have any mappings for them in vimrc.
Hi @guns,
Thanks for opening this new door :-)
I already had set in my iTerm2 that the left option
acts as (+Esc).
When I press any of the
-=} cat ^[H^[J^[K^[L
So I tried explicitly setting:
execute "set
The ASCII code for ‘^[‘ is ‘\094 \091’.
Then I just put your code snippet in my vimrc and it really worked. I can not even believe it :-) Thank you so much!
Few more questions bug me..
Why did the explicit setting I mention above didn’t work? Out of curiosity looking at your modifiers.vim code you have a lots of mappings using the arrow keys, what do you accomplish doing that? And lastly what do you mean by rarely used <4-…> mapping to be used as super? Is that the actual number 4?
Thanks again this is great :-)
By the way the plugin already worked great in MacVim but I'm much more of terminal user, therefore this is super exciting..
I already had set in my iTerm2 that the left option acts as (+Esc).
Sounds like turning this off might enable meta-sets-top-bit mode, which is really the best no-hack option if you just want to enable meta keys in your terminal. You should give it a try!
So I tried explicitly setting:
execute "set
=^[J" execute "set =^[K" execute "set =^[H" execute "set =^[L” The ASCII code for ‘^[‘ is ‘\094 \091’. … Why did the explicit setting I mention above didn’t work?
The ^[
is actually the standard printable representation for ASCII 033
(Escape). This character can be produced with the Escape key, or by pressing
<C-[>
. Actually, the first 32 unprintable ASCII control characters can be
produced by pressing Ctrl and the corresponding ASCII equivalent 0x40 up the
table:
Ctrl + @ (0x40) -> 0x00 (Other keys can send NUL; I like Ctrl + Space)
Ctrl + A (0x41) -> 0x01
Ctrl + B (0x42) -> 0x02
Ctrl + C (0x43) -> 0x03
…
Ctrl + _ (0x5f) -> 0x1f
Of course, we don't type Ctrl-Shift-C
when we want to send interrupt
through a terminal, so the actual key sent is upper cased when the Control
modifier is active. This convenience is why Ctrl-a
and Ctrl-Shift-a
are indistinguishable in most terminal programs. Lots of people find this
annoying, but I personally enjoy this feature.
Here is the relevant bit in vim:
https://github.com/vim/vim/blob/60cce2f/src/ascii.h#L40-L41
#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) /* '?' -> DEL, '@' -> ^@, etc. */
#define Meta(x) ((x) | 0x80)
Here we can also see why configuring your terminal to set the top bit when Meta is active makes Meta mappings work out of the box.
Then I just put your code snippet in my vimrc and it really worked. I can not even believe it :-)
I've edited my comment again to remove an errant debugging echo string()
, so
you may want to remove that from your vimrc.
You've convinced me to start work on packaging this up as a plugin since it
does not seem to be common knowledge. It is in the documentation, but it's
easy to miss: :help :set-termcap
.
Out of curiosity looking at your modifiers.vim code you have a lots of mappings using the arrow keys, what do you accomplish doing that?
It allows mapping Modifier + Arrow keys. I don't ever find myself touching the arrow keys, so it was mostly a way to experiment with setting key codes.
And lastly what do you mean by rarely used <4-…> mapping to be used as super? Is that the actual number 4?
Yes, the <4-
modifier is actually a mouse event modifier, but you can
bind it in regular mappings. For example, I configure my terminal to send
\033\007…
when I type Super + …
, then I map this sequence to produce the
corresponding <4-…>
:
execute "map <special> \<Esc>\<C-g>… <4-…>"
execute "map! <special> \<Esc>\<C-g>… <4-…>"
Now this <4-…>
key can represent Super + …
in your vimrc:
map <4-s> :<C-u>update<CR>
This is my favorite Vim hack, but it has the nasty side effect of borking
<Esc>
, which is why I retracted my discussion of it.
Like I mentioned before, I use Ctrl-C
as my escape anyway, so this does not
bother me.
I suspect there is a way to abuse the termcap key code system to accomplish the same without this downside. If I find one I'll report back here.
By the way the plugin already worked great in MacVim but I'm much more of terminal user, therefore this is super exciting..
Good to know. I compile vim with --disable-gui
, so I am very unfamiliar with
GUI vim builds.
Thanks for the great plugin.
I'm trying hard to get it to work on a mac in iterm2 with vim version 7.4.488. My .vimrc is pretty big so I'm eliminating any possible conflicts by using a plain vanila .vimrc with nothing in it but your plugin. None of the <M mappings work for me.
Am I missing some obvious thing specific to Mac. Anybody else has/had this issue?
I saw that there is a possibility to set your own mappings using the 'sexp-explicit-mappings' directive. But I like the default mappings so want to stick to those..
Thanks