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!