5

How can I disable all user mappings only for current buffer in vim? I've tried :mapclear but it removed mappings for all buffers.

2
  • if there is a global mapping xxx, do you also need to have xxx disabled for the current buffer?
    – doraemon
    Commented Nov 1, 2018 at 9:53
  • @LiuSha Yep, all mappings if possible.
    – Jian
    Commented Nov 1, 2018 at 15:33

3 Answers 3

2

You might be looking for <buffer> argument.

This argument ensures that the command or the mapping will be effective only in the local buffer rather than the global buffer.

To clear all the user-mapping in the local buffer, :mapclear <buffer> should be used.

For more information, look at :h :map-<buffer>

3
  • You might misunderstand my question. The <buffer> argument is for removing local buffer mappings, but what I want to do is remove all mappings temporarily for the current buffer.
    – Jian
    Commented Jan 20, 2018 at 10:35
  • @theJian.. I'm looking up for this as well and ended up here. have you solved this? Commented Oct 31, 2018 at 12:32
  • @JohnFredFadrigalan Unfortunately no, this snippet is the temporary solution I've used. gist.github.com/theJian/beb8519127b9209f644197a09620d939
    – Jian
    Commented Nov 1, 2018 at 8:41
2

Here is the temporary solution I've found so far.

let lowercase = 'abcdefghijklmnopqrstuvwxyz'
let uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
let numbers = '0123456789'
let punctuation = "<>`@#~!\"$%^&/()=+*-_.,;:?\\\'{}[] " " and space
for str in [lowercase, uppercase, numbers, punctuation]
    for key in split(str, '\zs')
        execute printf("noremap <silent> <buffer> <nowait> %s :call DO_SOMETHING_OR_NOTHING<cr>", key)
    endfor
endfor

Basically this snippet will remap all the normal mappings for local buffer.

1
  • how about the <f1>-<f12> mappings
    – doraemon
    Commented Nov 1, 2018 at 9:55
2

The problem can be easily solved now if your vim version is >= 9.0, since you can get all the mappings through the maplist() function and set new mappings by calling the mapset() function. You just need to do some buffer-local mappings by remapping each previously mapped key sequence to itself.

for mapitem in maplist()
    call mapset(mapitem->extend(#{expr: 0, noremap: 1, rhs: mapitem.lhs, buffer: 1, silent: 1}))
endfor

The following script can also preserve the previously defined buffer-local mappings and will not overwrite them. If you are confused about the code, see :h maplist(), :h mapset(), :h filter(), :h map(), :h lambda, etc.

let bufmapsave = maplist()->filter('v:val.buffer == 1')
for mapitem in map(
    \ maplist()->filter('v:val.buffer == 0'),
    \ {_, val -> val->extend(#{expr: 0, noremap: 1, rhs: val.lhs, buffer: 1, silent: 1})})
    call mapset(mapitem)
endfor
for mapitem in bufmapsave
    call mapset(mapitem)
endfor

I've also worked out a solution for lower vim versions. We can use the execute() function (or the :redir command), which stringifies the output of a command. The mappings whose attr starts with @, *@ or &@ are buffer-local mappings (see :h map-listing). See :h execute(), :h :redir, :h split(), :h :let-unpack, :h expr-=~, :h add(), :h index(), etc. for more help.

let bufmapsave = []
let mapitems = []
for mapitem in split(execute('map | map!'), '\n\+')
    let [mapmode, lhs, attr; _] = split(mapitem, '\s\+', 1)
    if attr =~ '^[*&]\?@'
        call add(bufmapsave, lhs)
    else
        call add(mapitems, [mapmode, lhs])
    endif
endfor
for mapitem in mapitems
    let [mapmode, lhs] = mapitem
    if index(bufmapsave, lhs) == -1
        let mapcmd = mapmode == '!' ? 'noremap!' : (mapmode . 'noremap')
        silent exec mapcmd . ' <buffer> <silent> ' . lhs . ' ' . lhs
    endif
endfor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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