Disabling and re-enabling groups of mappings

Hi all!

I’ve tried searching for an answer to this, but so far to no avail. (But maybe I haven’t found the right terminology yet…?)

Some background:

For a given filetype (like :set filetype=${SOME_LANGUAGE}), there’s different kinds of tasks that we want to do; for instance: debugging in a DAP session; git actions; or just browsing the code with LSP (with no intention of modifying the code). To better utilize the keyboard, I find myself wanting to define mappings specific to these contexts. E.g. for a DAP session, I basically never want to modify the code, so I’d like to do:

nnoremap r <Cmd>Debugger_Toggle_Display_of_Registers<cr>
nnoremap s <Cmd>Debugger_Step_Over<cr>
nnoremap S <Cmd>Debugger_Step_In<cr>

…etc. Of course, when that session is over, you’d like to go back to the usual meaning:

nunmap r
nunmap s
nunmap S

… but this gets tedious and error-prone when you have a lot of mappings and a lot of task-specific contexts.

One possible way to deal with this is to have a function that enables mappings that belong to the context of a task, e.g.:

fu! Activate_mapping_layer(layer)
  if a:layer == 'DAP'
      " mappings for a debugging session with DAP
  elseif a:layer == 'edit_LSP'
      " mappings for when we have LSP and we're making changes
  elseif a:layer == 'readonly_LSP'
      " mappings for when we're only reading/browsing code
  endif
endf

… and then, when you want to change context (e.g. from ‘DAP’ to ‘edit_LSP’), just delete all the buffer mappings with :mapclear <buffer> and then call Activate_mapping_layer() again with a different argument.

Unfortunately, this will also clear mappings from 3rd-party plugins (and if there is a way to re-establish those mappings, I haven’t found it yet, but maybe I missed something).

Ideally, what I want (I think) is a way to define groups or layers of mappings, and to disable and re-enable those layers as the context changes, and to do this without clobbering or clearing any mappings.
Right now, I’m not requesting a feature, because maybe there is a way to do this with nvim 0.6.0 that I haven’t found yet (?), but I think I want something like:

nnoremap r <Cmd>Something_else<cr>
" Currently, r maps to Something_else.

maplayer DAP
    nnoremap r <Cmd>Debugger_Toggle_Display_of_Registers<cr>
    nnoremap s <Cmd>Debugger_Step_Over<cr>
    " ...etc. Lotsa mappings.
maplayer END

" At this point, r would still be mapped to Something_else. 
" The command :maplayer would define a layer (with a name chosen 
" by the user, in this case "DAP"), but wouldn't activate it.

maplayer_enable DAP  
" Now r maps to Debugger_Toggle_Display_of_Registers (because we enabled
" DAP). The global mapping still exists, but it's currently shadowed by the
" DAP mapping.

maplayer_disable DAP
" Now r maps to Something_else again.

Ideally you could have multiple map-layers, and the most-recently-enabled layer would take precedence over all others. (Each layer would take precedence over the layers under it). Outside of an explicit layer definition, a mapping would belong to the global layer.

What do people think?

Is there currently a way to simulate this? If not, and if I were to take a stab at implementing it, what parts of the nvim src should I become familiar with?

Thanks in advance for any suggestions!

Sounds similar to https://github.com/neovim/neovim/issues/16313

1 Like

Ah, cool!

I didn’t see that thread before; glad to know I’m not the only one who wants something like this!