summaryrefslogtreecommitdiff
path: root/lua/clever_f/capabilities.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/clever_f/capabilities.lua')
-rw-r--r--lua/clever_f/capabilities.lua154
1 files changed, 154 insertions, 0 deletions
diff --git a/lua/clever_f/capabilities.lua b/lua/clever_f/capabilities.lua
new file mode 100644
index 0000000..77ce130
--- /dev/null
+++ b/lua/clever_f/capabilities.lua
@@ -0,0 +1,154 @@
+local M = {}
+
+M.read_methods = {
+ text = { "read_text" },
+ cursor = { "read_cursor" },
+ mode = { "read_mode", "read_pending_operator" },
+ selection = { "read_selection" },
+ count = { "read_count" },
+ configuration = { "read_configuration", "configuration_present" },
+ encoding = { "read_encoding" },
+ macro_state = { "read_macro_state" },
+ fold_state = { "read_fold_state" },
+ time = { "read_time_ms" },
+}
+
+M.effect_methods = {
+ movement = { "apply_cursor", "apply_selection", "set_operator_inclusive" },
+ input = { "read_input" },
+ folds = { "open_fold" },
+ prompt = { "show_prompt" },
+ redraw = { "redraw" },
+ diagnostics = { "emit_diagnostic" },
+ highlights = { "create_highlight", "remove_highlight" },
+ cursor_presentation = {
+ "suppress_cursor_presentation",
+ "restore_cursor_presentation",
+ },
+ timers = { "supports_timers", "start_timer", "stop_timer" },
+ events = {
+ "register_events",
+ "remove_event_registration",
+ "deliver_event",
+ "begin_action_transition",
+ "commit_action_transition",
+ },
+ mappings = { "register_action", "register_mapping" },
+ dot_repeat = { "register_dot_repeat" },
+}
+
+local function collect_methods(groups)
+ local result = {}
+ local group_names = {}
+ for group_name in pairs(groups) do
+ group_names[#group_names + 1] = group_name
+ end
+ table.sort(group_names)
+ for _, group_name in ipairs(group_names) do
+ for _, method_name in ipairs(groups[group_name]) do
+ result[#result + 1] = method_name
+ end
+ end
+ return result
+end
+
+local all_methods = collect_methods(M.read_methods)
+for _, method_name in ipairs(collect_methods(M.effect_methods)) do
+ all_methods[#all_methods + 1] = method_name
+end
+table.sort(all_methods)
+
+function M.required_methods()
+ local result = {}
+ for index = 1, #all_methods do
+ result[index] = all_methods[index]
+ end
+ return result
+end
+
+function M.missing_methods(host)
+ local missing = {}
+ for _, method_name in ipairs(all_methods) do
+ if type(host) ~= "table" or type(host[method_name]) ~= "function" then
+ missing[#missing + 1] = method_name
+ end
+ end
+ return missing
+end
+
+function M.assert_implements(host)
+ local missing = M.missing_methods(host)
+ if #missing > 0 then
+ error("host is missing semantic capabilities: " .. table.concat(missing, ", "), 2)
+ end
+ return host
+end
+
+local EventQueue = {}
+EventQueue.__index = EventQueue
+M.EventQueue = EventQueue
+
+function EventQueue.new(deliver)
+ if type(deliver) ~= "function" then
+ error("event delivery must be a function", 2)
+ end
+ return setmetatable({
+ _deliver = deliver,
+ _active_token = nil,
+ _pending = {},
+ _next_token = 1,
+ }, EventQueue)
+end
+
+function EventQueue:begin_transition()
+ if self._active_token ~= nil then
+ error("an action transition is already active", 2)
+ end
+ local token = "action-transition-" .. tostring(self._next_token)
+ self._next_token = self._next_token + 1
+ self._active_token = token
+ self._pending = {}
+ return token
+end
+
+function EventQueue:is_transition_active()
+ return self._active_token ~= nil
+end
+
+function EventQueue:pending_count()
+ return #self._pending
+end
+
+function EventQueue:emit(name, payload)
+ if type(name) ~= "string" or name == "" then
+ error("event name must be a nonempty string", 2)
+ end
+ if self._active_token ~= nil then
+ self._pending[#self._pending + 1] = {
+ name = name,
+ payload = payload,
+ }
+ return false
+ end
+ self._deliver(name, payload)
+ return true
+end
+
+function EventQueue:commit_transition(token)
+ if self._active_token == nil then
+ error("no action transition is active", 2)
+ end
+ if token ~= self._active_token then
+ error("action transition token does not match", 2)
+ end
+
+ local pending = self._pending
+ self._active_token = nil
+ self._pending = {}
+ for index = 1, #pending do
+ local event = pending[index]
+ self._deliver(event.name, event.payload)
+ end
+end
+
+return M