Add initial Layer implementation
parent
1501358320
commit
f84b0288e7
@ -0,0 +1,39 @@
|
||||
local libmodal = require('libmodal')
|
||||
|
||||
-- create a new layer.
|
||||
local layer = libmodal.Layer.new('FOO', {
|
||||
['n'] = { -- normal mode mappings
|
||||
['gg'] = { -- remap `gg`
|
||||
['rhs'] = 'G', -- map it to `G`
|
||||
['noremap'] = true, -- don't recursively map.
|
||||
},
|
||||
['G'] = { -- remap `G`
|
||||
['rhs'] = 'gg', -- map it to `gg`
|
||||
['noremap'] = true -- don't recursively map.
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
-- enter the `layer`.
|
||||
layer:enter()
|
||||
|
||||
-- add a global function for exiting the mode.
|
||||
function libmodal_layer_example_exit()
|
||||
layer:exit()
|
||||
end
|
||||
|
||||
-- Add an additional mapping for `z`.
|
||||
layer:map('n', 'z', 'gg', {['noremap'] = true})
|
||||
|
||||
-- add an additional mapping for `q`.
|
||||
layer:map(
|
||||
'n', 'q', ':lua libmodal_layer_example_exit()<CR>',
|
||||
{['noremap'] = true, ['silent'] = true}
|
||||
)
|
||||
|
||||
--[[ unmap `gg` and `G`. Notice they both return to their defaults,
|
||||
rather than just not doing anything anymore. ]]
|
||||
layer:unmap('n', 'gg')
|
||||
layer:unmap('n', 'G')
|
||||
|
||||
-- If you wish to only change the mappings of a layer temporarily, you should use another layer. `map` and `unmap` permanently add and remove from the layer's keymap.
|
@ -0,0 +1,254 @@
|
||||
--[[
|
||||
/*
|
||||
* IMPORTS
|
||||
*/
|
||||
--]]
|
||||
|
||||
local api = vim.api
|
||||
local classes = require('libmodal/src/classes')
|
||||
|
||||
--[[
|
||||
/*
|
||||
* MODULE
|
||||
*/
|
||||
--]]
|
||||
|
||||
local Layer = {}
|
||||
|
||||
local _BUFFER_CURRENT = 0
|
||||
local _RESTORED = nil
|
||||
|
||||
local function convertKeymap(keymapEntry)
|
||||
local lhs = keymapEntry.lhs
|
||||
keymapEntry.lhs = nil
|
||||
|
||||
return {lhs, keymapEntry}
|
||||
end
|
||||
|
||||
local function deconvertKeymap(convertedKeymap)
|
||||
local rhs = convertedKeymap.rhs
|
||||
convertedKeymap.rhs = nil
|
||||
|
||||
return {rhs, convertedKeymap}
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* META `Layer`
|
||||
*/
|
||||
--]]
|
||||
|
||||
local _metaLayer = classes.new({})
|
||||
|
||||
---------------------------
|
||||
--[[ SUMMARY:
|
||||
* Enter the `Layer`.
|
||||
* Only activates for the current buffer.
|
||||
]]
|
||||
---------------------------
|
||||
function _metaLayer:enter()
|
||||
-- add local aliases.
|
||||
local layerKeymap = self._keymap
|
||||
local priorKeymap = {}
|
||||
|
||||
--[[ iterate over the new mappings to both:
|
||||
1. Populate `priorKeymap`
|
||||
2. Map the `layerKeymap` to the buffer. ]]
|
||||
for mode, newMappings in pairs(layerKeymap) do
|
||||
-- if `mode` key has not yet been made for `priorKeymap`.
|
||||
if not priorKeymap[mode] then
|
||||
priorKeymap[mode] = {}
|
||||
end
|
||||
|
||||
-- store the previously mapped keys
|
||||
for _, bufMap in ipairs(api.nvim_buf_get_keymap(_BUFFER_CURRENT, mode)) do
|
||||
-- if the new mappings would overwrite this one
|
||||
if newMappings[bufMap.lhs] then
|
||||
-- remove values so that it is in line with `nvim_set_keymap`.
|
||||
local lhs, keymap = unpack(convertKeymap(bufMap))
|
||||
priorKeymap[mode][lhs] = keymap
|
||||
end
|
||||
end
|
||||
|
||||
-- add the new mappings
|
||||
for lhs, newMapping in pairs(newMappings) do
|
||||
local rhs, options = unpack(deconvertKeymap(newMapping))
|
||||
api.nvim_buf_set_keymap(_BUFFER_CURRENT, mode, lhs, rhs, options)
|
||||
end
|
||||
end
|
||||
|
||||
print(vim.inspect(priorKeymap))
|
||||
self._priorKeymap = priorKeymap
|
||||
end
|
||||
|
||||
--------------------------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Add a mapping to the mode.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `mode` => the mode that this mapping for.
|
||||
* `lhs` => the left hand side of the mapping.
|
||||
* `rhs` => the right hand side of the mapping.
|
||||
* `options` => options for the mapping.
|
||||
]]
|
||||
--[[ SEE ALSO:
|
||||
* `nvim_buf_set_keymap()`
|
||||
]]
|
||||
--------------------------------------------------------
|
||||
function _metaLayer:_mapToBuffer(mode, lhs, rhs, options)
|
||||
local priorKeymap = self._priorKeymap
|
||||
|
||||
if not priorKeymap then error(
|
||||
"You can't map to a buffer without activating the layer first."
|
||||
) end
|
||||
|
||||
if not priorKeymap[mode][lhs] then -- the mapping's state has not been saved.
|
||||
for _, bufMap in
|
||||
ipairs(api.nvim_buf_get_keymap(_BUFFER_CURRENT, mode))
|
||||
do -- check if it exists in the buffer
|
||||
if bufMap.lhs == lhs then -- add it to the undo list
|
||||
priorKeymap[mode][lhs] = unpack(convertKeymap(bufMap))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- map the `lhs` to `rhs` in `mode` with `options` for the current buffer.
|
||||
api.nvim_buf_set_keymap(_BUFFER_CURRENT, mode, lhs, rhs, options)
|
||||
end
|
||||
|
||||
------------------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Add a mapping to the mode.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `mode` => the mode that this mapping for.
|
||||
* `lhs` => the left hand side of the mapping.
|
||||
* `rhs` => the right hand side of the mapping.
|
||||
* `options` => options for the mapping.
|
||||
]]
|
||||
--[[ SEE ALSO:
|
||||
* `nvim_buf_set_keymap()`
|
||||
]]
|
||||
------------------------------------------------
|
||||
function _metaLayer:map(mode, lhs, rhs, options)
|
||||
if self._priorKeymap then -- the layer has been activated.
|
||||
self:_mapToBuffer(mode, lhs, rhs, options)
|
||||
end
|
||||
|
||||
-- add the new mapping to the keymap
|
||||
self._keymap[mode][lhs] = vim.tbl_extend('force',
|
||||
options, {['rhs'] = rhs}
|
||||
)
|
||||
print(vim.inspect(self._priorKeymap))
|
||||
end
|
||||
|
||||
----------------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Undo a mapping after `enter()`.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `mode` => the mode to map (e.g. `n`, `i`).
|
||||
* `lhs` => the mapping to undo.
|
||||
]]
|
||||
----------------------------------------------
|
||||
function _metaLayer:_unmapFromBuffer(mode, lhs)
|
||||
local priorKeymap = self._priorKeymap
|
||||
local priorMapping = self._priorKeymap[mode][lhs]
|
||||
|
||||
print('unmapping ' .. mode .. ':' .. lhs)
|
||||
|
||||
if not priorKeymap then error(
|
||||
"You can't undo a map from a buffer without activating the layer first."
|
||||
) end
|
||||
|
||||
if priorMapping then -- there is an older mapping to go back to.
|
||||
-- undo the mapping
|
||||
local rhs, deconvertedKeymap = unpack(deconvertKeymap(priorMapping))
|
||||
api.nvim_buf_set_keymap(_BUFFER_CURRENT, mode, lhs, rhs, deconvertedKeymap)
|
||||
|
||||
-- set the prior mapping as restored.
|
||||
priorKeymap[mode][lhs] = _RESTORED
|
||||
|
||||
print('reverted mapping')
|
||||
else
|
||||
-- just delete the buffer mapping.
|
||||
local noErrors, err = pcall(api.nvim_buf_del_keymap, _BUFFER_CURRENT, mode, lhs)
|
||||
|
||||
if not noErrors then print(err) end
|
||||
print('deleted mapping')
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Remove a mapping from the mode.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `mode` => the mode that this mapping for.
|
||||
* `lhs` => the left hand side of the mapping.
|
||||
]]
|
||||
--[[ SEE ALSO:
|
||||
* `nvim_buf_del_keymap()`
|
||||
]]
|
||||
------------------------------------
|
||||
function _metaLayer:unmap(mode, lhs)
|
||||
-- unmap for the buffer too, if the layer is activated.
|
||||
if self._priorKeymap then
|
||||
self:_unmapFromBuffer(mode, lhs)
|
||||
end
|
||||
|
||||
-- remove the mapping from the internal keymap
|
||||
self._keymap[mode][lhs] = _RESTORED
|
||||
end
|
||||
|
||||
--------------------------
|
||||
--[[ SUMMARY:
|
||||
* Exit the layer.
|
||||
]]
|
||||
--[[
|
||||
* This function is regenerated every time that `enter` is called,
|
||||
because what it must do depends on the state of Vim upon calling `enter()`.
|
||||
]]
|
||||
--------------------------
|
||||
function _metaLayer:exit()
|
||||
for mode, mappings in pairs(self._keymap) do
|
||||
for lhs, _ in pairs(mappings) do
|
||||
self:_unmapFromBuffer(mode, lhs)
|
||||
end
|
||||
end
|
||||
self._priorKeymap = _RESTORED
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* CLASS `Layer`
|
||||
*/
|
||||
--]]
|
||||
|
||||
-----------------------------------------------------
|
||||
--[[ SUMMARY:
|
||||
* Create a new `Layer` for `commands`, `mappings`, and `options`.
|
||||
]]
|
||||
--[[ PARAMS:
|
||||
* `name` => the name of the layer.
|
||||
* `mappings` => the list of user mappings to replace.
|
||||
]]
|
||||
--[[ RETURNS:
|
||||
* A new `Layer`.
|
||||
]]
|
||||
-----------------------------------------------------
|
||||
function Layer.new(name, mappings)
|
||||
return setmetatable(
|
||||
{['_keymap'] = mappings, ['name'] = name},
|
||||
_metaLayer
|
||||
)
|
||||
end
|
||||
|
||||
--[[
|
||||
/*
|
||||
* PUBLICIZE `Layer`
|
||||
*/
|
||||
--]]
|
||||
|
||||
return Layer
|
Loading…
Reference in New Issue