diff options
Diffstat (limited to 'lua/clever_f/capabilities.lua')
| -rw-r--r-- | lua/clever_f/capabilities.lua | 154 |
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 |
