1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
local M = {}
M.read_methods = {
text = { "read_text" },
buffer = { "read_buffer", "read_window" },
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" },
highlight_groups = { "read_highlight_group" },
}
M.effect_methods = {
movement = { "apply_cursor", "apply_selection", "set_operator_inclusive" },
configuration = { "write_configuration" },
input = { "read_input" },
folds = { "open_fold" },
prompt = { "show_prompt" },
redraw = { "redraw" },
diagnostics = { "emit_diagnostic" },
highlights = {
"define_highlight_group",
"create_highlight",
"remove_highlight",
},
cursor_presentation = {
"supports_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
|