semi-idle-arpg/addons/godot_vim/remap.gd

179 lines
4.1 KiB
GDScript3
Raw Normal View History

2024-09-19 19:03:06 -06:00
class_name KeyRemap extends RefCounted
enum ApplyMode {
## Append this keybind to the end of the list
APPEND,
## Insert this keybind at the start of the list
PREPEND,
## Insert this keybind at the specified index
INSERT,
## Remove the specified keybind
REMOVE,
## Replace a keybind with this one
REPLACE,
}
const Constants = preload("res://addons/godot_vim/constants.gd")
const MODE = Constants.Mode
# Inner cmd
var inner: Dictionary = {}
var options: Dictionary = {"apply_mode": ApplyMode.APPEND}
func _init(keys: Array[String]):
assert(!keys.is_empty(), "cmd_keys cannot be empty")
inner = {"keys": keys}
## Returns self
func motion(motion_type: String, args: Dictionary = {}) -> KeyRemap:
var m: Dictionary = {"type": motion_type}
m.merge(args, true)
inner.motion = m
# Operator + Motion = OperatorMotion
if inner.get("type") == KeyMap.Operator:
inner.type = KeyMap.OperatorMotion
else:
inner.type = KeyMap.Motion
return self
## Returns self
func operator(operator_type: String, args: Dictionary = {}) -> KeyRemap:
var o: Dictionary = {"type": operator_type}
o.merge(args, true)
inner.operator = o
# Motion + Operator = OperatorMotion
if inner.get("type") == KeyMap.Motion:
inner.type = KeyMap.OperatorMotion
else:
inner.type = KeyMap.Operator
return self
## Returns self
func action(action_type: String, args: Dictionary = {}) -> KeyRemap:
var a: Dictionary = {"type": action_type}
a.merge(args, true)
inner.action = a
inner.type = KeyMap.Action
return self
## Returns self
func with_context(mode: MODE) -> KeyRemap:
inner["context"] = mode
return self
# `key_map` = KeyMap::key_map
func apply(key_map: Array[Dictionary]):
match options.get("apply_mode", ApplyMode.APPEND):
ApplyMode.APPEND:
key_map.append(inner)
ApplyMode.PREPEND:
var err: int = key_map.insert(0, inner)
if err != OK:
push_error("[Godot VIM] Failed to prepend keybind: %s" % error_string(err))
ApplyMode.INSERT:
var index: int = options.get("index", 0)
var err: int = key_map.insert(index, inner)
if err != OK:
push_error(
(
"[Godot VIM] Failed to insert keybind at index %s: %s"
% [index, error_string(err)]
)
)
ApplyMode.REMOVE:
var index: int = _find(key_map, inner)
if index == -1:
return
key_map.remove_at(index)
ApplyMode.REPLACE:
var constraints: Dictionary = {"keys": inner.get("keys", [])}
var index: int = _find(key_map, constraints)
if index == -1:
return
# print('replacing at index ', index)
key_map[index] = inner
#region Apply options
## Append this keybind to the end of the list
## Returns self
func append() -> KeyRemap:
options = {"apply_mode": ApplyMode.APPEND}
return self
## Insert this keybind at the start of the list
## Returns self
func prepend() -> KeyRemap:
options = {"apply_mode": ApplyMode.PREPEND}
return self
## Insert this keybind at the specified index
func insert_at(index: int) -> KeyRemap:
options = {
"apply_mode": ApplyMode.INSERT,
"index": index,
}
return self
## Removes the keybind from the list
## Returns self
func remove() -> KeyRemap:
options = {"apply_mode": ApplyMode.REMOVE}
return self
## Replaces the keybind from the list with this new one
## Returns self
func replace():
options = {"apply_mode": ApplyMode.REPLACE}
return self
#endregion
func _find(key_map: Array[Dictionary], constraints: Dictionary) -> int:
var keys: Array[String] = constraints.get("keys")
if keys == null:
push_error("[Godot VIM::KeyRemap::_find()] Failed to find keybind: keys not specified")
return -1
if keys.is_empty():
push_error("[Godot VIM::KeyRemap::_find()] Failed to find keybind: keys cannot be empty")
return -1
for i in key_map.size():
var cmd: Dictionary = key_map[i]
# Check keys
var m: KeyMap.KeyMatch = KeyMap.match_keys(cmd.keys, keys)
if m != KeyMap.KeyMatch.Full:
continue
# If types DON'T match (if specified, ofc), skip
if constraints.has("type") and constraints.type != cmd.type:
continue
# If contexts DON'T match (if specified, ofc), skip
if constraints.get("context", -1) != cmd.get("context", -1):
continue
return i
return -1