4

I am experimenting with default key mappings and am considering remapping the g key entirely. But first I would like to turn off all the existing mappings that g has. For now I am using this kind of hack:

" disable all g maps
let g:netrw_nogx = 1 " allows disabling gx
let s:chars1 = map(range(char2nr('a'), char2nr('x')), 'nr2char(v:val)')
let s:chars2 = map(range(char2nr('A'), char2nr('Z')), 'nr2char(v:val)')
let s:chars = s:chars1 + s:chars2
let s:chars = s:chars+['0','1','2','3','4','5','6','7','8','9','+','-','=','_']
let s:chars = s:chars+['~','`','!','@','#','$','%','^','&','*','(',')','/','?']
let s:chars = s:chars+['[',']','{','}','\','\|',':',';','"',"'",'<',">",'.',',']

for char in s:chars
  execute 'noremap g' . char . ' <nop>'
endfor

But this is very messy and g<ctrl-_> maps are still left in.

Is there some cleaner way to accomplish this?

6
  • I think there is no better way other than to iterate over all combinations. Feb 27, 2018 at 7:55
  • Just out of curiosity: why do you need to remap all of these combinations to <nop>? Also, I agree with Christian that is probably the best way to do it.
    – statox
    Feb 27, 2018 at 12:09
  • 1
    Agree with @statox why not use unmap?
    – D. Ben Knoble
    Feb 27, 2018 at 12:25
  • 1
    @DavidBenKnoble I think what Karolis wants to do is to disable the built-in normal mode commands like gq, gU, etc while unmap would be useful to delete mappings created by the user. What I was wondering is, why does one need to disable all of these built-in commands?
    – statox
    Feb 27, 2018 at 12:32
  • @statox I am just experimenting with making (neo)vim maps more intuitive. For example my current experiment is to only use g prefix for "goto" commands. I.E. gg goes to top G goes to bottom, gf goes to file, gb and gB would traverse buffers, etc. No big reason to disable all g prefix maps, but it would help in a sense that I would be sure pressing g will put me into a goto context and would not do something else by accident. Feb 27, 2018 at 15:27

3 Answers 3

3

Suppressing the built-in g

Here's a mapping that will suppress all g-prefixed bindings, and only allow custom mappings that begin with g.

function! SuppressG()
  let c = nr2char(getchar())
  if maparg('g'.c, 'n') != ''
    return 'g'.c
  else
    return '\<Nop>'
  endif
endfunction

nnoremap <expr> g SuppressG()

The idea is to make a top-level mapping for g itself that then reads a single character from the keyboard. If a Normal mode mapping to g followed by the input character exists, return that. Otherwise, return <Nop>. It works with chords, too.

The effect is that when you haven't defined any other mappings beginning with g, all of Vim's built-in bindings beginning with g will do nothing. For example, ge, which normally moves backwards to the end of a word, would now be a no-op.

Creating a custom mapping

If you also defined a custom mapping to ge, then your mapping would take effect. Example:

nnoremap ge G

Now ge moves to the last line of the buffer, but all other g bindings still do nothing.

Restoring built-ins

You can also restore the g mappings you want to keep. For example:

nnoremap gg gg

This makes gg once again move to the first line of the buffer.

3
  • This works really well for "g" and "z" but for some reason I cannot figure out how to make it work for "ctrl". Maybe you have any tips? Aug 12, 2018 at 18:53
  • 1
    Ctrl itself isn't mappable, it's just part of a chord. Vim sees things like Ctrl+x as a single character.
    – tommcdo
    Sep 25, 2018 at 18:44
  • Does it gets called immediately? Not waiting for any longer combination that could surpass it?
    – eyal karni
    Oct 23, 2019 at 21:21
2

If your version of vim is recent enough, you could obtain all the mappings starting with g thanks to getcompletion('g', 'mapping').

However, you won't know the mode associated, you'd need to filter the list with mapcheck().

Of course, you won't obtain the default keybindings this way.

1
  • Presumably you'd need to do this in a VimEnter autocommand (to unmap mappings added by plugins)?
    – Rich
    Mar 8, 2018 at 15:02
2

A small generalization to tommcdo's excellent suggestion:

function! SuppressAllStartingWith(c1)
  let c2 = nr2char(getchar())
  if maparg(a:c1.c2, 'n') != ''
    return a:c1.c2
  else
    return '\<Nop>'
  endif
endfunction

Then you can use it like so:

nnoremap <expr> q SuppressAllStartingWith('q')
nnoremap <expr> z SuppressAllStartingWith('z')

As for motivation, in command mode I'm always fat-fingering 'z' when I'm heading for 'x', or 'q' when I'm heading for 'a', and I'm tired of that.

4
  • Welcome to Vi and Vim! Does this prevent you from recording macros q{letter} or using the fold and other z commands (zt, etc.)?
    – D. Ben Knoble
    Feb 12, 2021 at 15:18
  • Yes, it does. For certain of my editing jobs, I don't want any accidental keystrokes moving the cursor far away, or changing modes, or turning on anything. I just want local motions and text insert/delete, basically. This gets me partially there. If there's a WYSIWYG mode to vim, or a better way to achieve this, I'd love to hear about it.
    – Charles
    Feb 13, 2021 at 16:26
  • Vim is WYSIWYG if what you get is plain-text, so I don't follow that. But you could look at :help -y.
    – D. Ben Knoble
    Feb 13, 2021 at 19:37
  • I was using WYSIWG in the sense of what the nano editor gives you, i.e., exactly what -y gives you in vim, thanks for that tip. But what I'd like to achieve in vim is allowing editing commands that operate on the current line, or a few lines around it, and suppressing commands that take me to other parts of the file when I mistype them. So for example I never use z because I have no use for what it does, and when I accidentally hit it, I don't want what it does.
    – Charles
    Feb 15, 2021 at 15:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.