keymap: changes and docs
* Prevent adding duplicate bindings * Clean reverse_map on overwrite or add direct * Added get_bindings to complement get_binding * Added doc comments for easier comprehension * Check if command is function on add_direct
This commit is contained in:
parent
2c968073e4
commit
b8ed4a43f6
|
@ -3,33 +3,111 @@ local command = require "core.command"
|
||||||
local config = require "core.config"
|
local config = require "core.config"
|
||||||
local keymap = {}
|
local keymap = {}
|
||||||
|
|
||||||
|
---@alias keymap.shortcut string
|
||||||
|
---@alias keymap.command string
|
||||||
|
---@alias keymap.modkey string
|
||||||
|
---@alias keymap.pressed boolean
|
||||||
|
---@alias keymap.map table<keymap.shortcut,keymap.command|keymap.command[]>
|
||||||
|
---@alias keymap.rmap table<keymap.command, keymap.shortcut|keymap.shortcut[]>
|
||||||
|
|
||||||
|
---Pressed status of mod keys.
|
||||||
|
---@type table<keymap.modkey, keymap.pressed>
|
||||||
keymap.modkeys = {}
|
keymap.modkeys = {}
|
||||||
|
|
||||||
|
---List of commands assigned to a shortcut been the key of the map the shortcut.
|
||||||
|
---@type keymap.map
|
||||||
keymap.map = {}
|
keymap.map = {}
|
||||||
|
|
||||||
|
---List of shortcuts assigned to a command been the key of the map the command.
|
||||||
|
---@type keymap.rmap
|
||||||
keymap.reverse_map = {}
|
keymap.reverse_map = {}
|
||||||
|
|
||||||
local macos = PLATFORM == "Mac OS X"
|
local macos = PLATFORM == "Mac OS X"
|
||||||
|
|
||||||
-- Thanks to mathewmariani, taken from his lite-macos github repository.
|
-- Thanks to mathewmariani, taken from his lite-macos github repository.
|
||||||
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic"))
|
local modkeys_os = require("core.modkeys-" .. (macos and "macos" or "generic"))
|
||||||
|
|
||||||
|
---@type table<keymap.modkey, keymap.modkey>
|
||||||
local modkey_map = modkeys_os.map
|
local modkey_map = modkeys_os.map
|
||||||
|
|
||||||
|
---@type keymap.modkey[]
|
||||||
local modkeys = modkeys_os.keys
|
local modkeys = modkeys_os.keys
|
||||||
|
|
||||||
local function key_to_stroke(k)
|
|
||||||
|
---Generates a stroke sequence including currently pressed mod keys.
|
||||||
|
---@param key string
|
||||||
|
---@return string
|
||||||
|
local function key_to_stroke(key)
|
||||||
local stroke = ""
|
local stroke = ""
|
||||||
for _, mk in ipairs(modkeys) do
|
for _, mk in ipairs(modkeys) do
|
||||||
if keymap.modkeys[mk] then
|
if keymap.modkeys[mk] then
|
||||||
stroke = stroke .. mk .. "+"
|
stroke = stroke .. mk .. "+"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return stroke .. k
|
return stroke .. key
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Remove the given value from an array associated to a key in a table.
|
||||||
|
---@param tbl table<string, string> The table containing the key
|
||||||
|
---@param k string The key containing the array
|
||||||
|
---@param v? string The value to remove from the array
|
||||||
|
local function remove_only(tbl, k, v)
|
||||||
|
if tbl[k] then
|
||||||
|
if v then
|
||||||
|
local j = 0
|
||||||
|
for i=1, #tbl[k] do
|
||||||
|
while tbl[k][i + j] == v do
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
tbl[k][i] = tbl[k][i + j]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tbl[k] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Removes from a keymap.map the bindings that are already registered.
|
||||||
|
---@param map keymap.map
|
||||||
|
local function remove_duplicates(map)
|
||||||
|
for stroke, commands in pairs(map) do
|
||||||
|
if type(commands) == "string" or type(commands) == "function" then
|
||||||
|
commands = { commands }
|
||||||
|
end
|
||||||
|
if keymap.map[stroke] then
|
||||||
|
for _, registered_cmd in ipairs(keymap.map[stroke]) do
|
||||||
|
local j = 0
|
||||||
|
for i=1, #commands do
|
||||||
|
while commands[i + j] == registered_cmd do
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
commands[i] = commands[i + j]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #commands < 1 then
|
||||||
|
map[stroke] = nil
|
||||||
|
else
|
||||||
|
map[stroke] = commands
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Add bindings by replacing commands that were previously assigned to a shortcut.
|
||||||
|
---@param map keymap.map
|
||||||
function keymap.add_direct(map)
|
function keymap.add_direct(map)
|
||||||
for stroke, commands in pairs(map) do
|
for stroke, commands in pairs(map) do
|
||||||
if type(commands) == "string" then
|
if type(commands) == "string" or type(commands) == "function" then
|
||||||
commands = { commands }
|
commands = { commands }
|
||||||
end
|
end
|
||||||
|
if keymap.map[stroke] then
|
||||||
|
for _, cmd in ipairs(keymap.map[stroke]) do
|
||||||
|
remove_only(keymap.reverse_map, cmd, stroke)
|
||||||
|
end
|
||||||
|
end
|
||||||
keymap.map[stroke] = commands
|
keymap.map[stroke] = commands
|
||||||
for _, cmd in ipairs(commands) do
|
for _, cmd in ipairs(commands) do
|
||||||
keymap.reverse_map[cmd] = keymap.reverse_map[cmd] or {}
|
keymap.reverse_map[cmd] = keymap.reverse_map[cmd] or {}
|
||||||
|
@ -38,15 +116,23 @@ function keymap.add_direct(map)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Adds bindings by appending commands to already registered shortcut or by
|
||||||
|
---replacing currently assigned commands if overwrite is specified.
|
||||||
|
---@param map keymap.map
|
||||||
|
---@param overwrite? boolean
|
||||||
function keymap.add(map, overwrite)
|
function keymap.add(map, overwrite)
|
||||||
|
remove_duplicates(map)
|
||||||
for stroke, commands in pairs(map) do
|
for stroke, commands in pairs(map) do
|
||||||
if macos then
|
if macos then
|
||||||
stroke = stroke:gsub("%f[%a]ctrl%f[%A]", "cmd")
|
stroke = stroke:gsub("%f[%a]ctrl%f[%A]", "cmd")
|
||||||
end
|
end
|
||||||
if type(commands) == "string" or type(commands) == "function" then
|
|
||||||
commands = { commands }
|
|
||||||
end
|
|
||||||
if overwrite then
|
if overwrite then
|
||||||
|
if keymap.map[stroke] then
|
||||||
|
for _, cmd in ipairs(keymap.map[stroke]) do
|
||||||
|
remove_only(keymap.reverse_map, cmd, stroke)
|
||||||
|
end
|
||||||
|
end
|
||||||
keymap.map[stroke] = commands
|
keymap.map[stroke] = commands
|
||||||
else
|
else
|
||||||
keymap.map[stroke] = keymap.map[stroke] or {}
|
keymap.map[stroke] = keymap.map[stroke] or {}
|
||||||
|
@ -62,35 +148,34 @@ function keymap.add(map, overwrite)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function remove_only(tbl, k, v)
|
---Unregisters the given shortcut and associated command.
|
||||||
for key, values in pairs(tbl) do
|
---@param shortcut string
|
||||||
if key == k then
|
---@param cmd string
|
||||||
if v then
|
function keymap.unbind(shortcut, cmd)
|
||||||
for i, value in ipairs(values) do
|
remove_only(keymap.map, shortcut, cmd)
|
||||||
if value == v then
|
remove_only(keymap.reverse_map, cmd, shortcut)
|
||||||
table.remove(values, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tbl[key] = nil
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function keymap.unbind(key, cmd)
|
|
||||||
remove_only(keymap.map, key, cmd)
|
|
||||||
remove_only(keymap.reverse_map, cmd, key)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Returns all the shortcuts associated to a command unpacked for easy assignment.
|
||||||
|
---@param cmd string
|
||||||
|
---@return ...
|
||||||
function keymap.get_binding(cmd)
|
function keymap.get_binding(cmd)
|
||||||
return table.unpack(keymap.reverse_map[cmd] or {})
|
return table.unpack(keymap.reverse_map[cmd] or {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
---Returns all the shortcuts associated to a command packed in a table.
|
||||||
|
---@param cmd string
|
||||||
|
---@return table<integer, string> | nil shortcuts
|
||||||
|
function keymap.get_bindings(cmd)
|
||||||
|
return keymap.reverse_map[cmd]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Events listening
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
function keymap.on_key_pressed(k, ...)
|
function keymap.on_key_pressed(k, ...)
|
||||||
local mk = modkey_map[k]
|
local mk = modkey_map[k]
|
||||||
if mk then
|
if mk then
|
||||||
|
@ -101,7 +186,7 @@ function keymap.on_key_pressed(k, ...)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local stroke = key_to_stroke(k)
|
local stroke = key_to_stroke(k)
|
||||||
local commands, performed = keymap.map[stroke]
|
local commands, performed = keymap.map[stroke], false
|
||||||
if commands then
|
if commands then
|
||||||
for _, cmd in ipairs(commands) do
|
for _, cmd in ipairs(commands) do
|
||||||
if type(cmd) == "function" then
|
if type(cmd) == "function" then
|
||||||
|
@ -143,6 +228,9 @@ function keymap.on_key_released(k)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
-- Register default bindings
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
if macos then
|
if macos then
|
||||||
local keymap_macos = require("core.keymap-macos")
|
local keymap_macos = require("core.keymap-macos")
|
||||||
keymap_macos(keymap)
|
keymap_macos(keymap)
|
||||||
|
|
Loading…
Reference in New Issue