-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathtag_manager.lua
209 lines (173 loc) · 4.83 KB
/
tag_manager.lua
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
local TagContainer = require("grapple.tag_container")
local Util = require("grapple.util")
---@class grapple.tag_manager
---@field state grapple.state
---@field containers table<string, grapple.tag_container>
local TagManager = {}
TagManager.__index = TagManager
---@param app grapple.app
---@param state grapple.state
---@return grapple.tag_manager
function TagManager:new(app, state)
return setmetatable({
app = app,
state = state,
containers = {},
}, self)
end
---@param opts grapple.options
---@return string[] errors
function TagManager:update_all(opts)
local errors = {}
for _, id in ipairs(vim.tbl_keys(self.containers)) do
local err = self:transaction(id, function(container)
return container:update(opts)
end)
if err then
table.insert(errors, err)
end
end
return errors
end
---@param id string
---@param callback fun(container: grapple.tag_container): string?
---@param opts? { sync?: boolean }
---@return string? error
function TagManager:transaction(id, callback, opts)
opts = vim.tbl_extend("keep", opts or {}, {
sync = true,
})
local container, err = self:load(id)
if not container then
return err
end
---@diagnostic disable-next-line: redefined-local
local err = callback(container)
if err then
return err
end
vim.api.nvim_exec_autocmds("User", {
pattern = "GrappleUpdate",
modeline = false,
})
if opts.sync then
---@diagnostic disable-next-line: redefined-local
local err = self:sync(id)
if err then
return err
end
end
return nil
end
---@alias grapple.tag_container_item { container: grapple.tag_container | nil, loaded: boolean}
---
---@return grapple.tag_container_item[]
function TagManager:list()
local list = {}
for _, id in ipairs(self.state:list()) do
---@type grapple.tag_container_item
local item = {
id = id,
container = self:get(id),
loaded = self:is_loaded(id),
}
table.insert(list, item)
end
return list
end
---@param id string
---@return grapple.tag_container | nil
function TagManager:get(id)
return self.containers[id]
end
---@param id string
---@return boolean
function TagManager:is_loaded(id)
return self.containers[id] ~= nil
end
---@param id string
---@return grapple.tag_container | nil, string? error
function TagManager:load(id)
if self:is_loaded(id) then
return self.containers[id], nil
end
if not self.state:exists(id) then
local container = TagContainer:new(id)
self.containers[id] = container
return container, nil
end
local tbl, err = self.state:read(id)
if err then
return nil, err
end
---@diagnostic disable-next-line: redefined-local
local container, err = TagContainer.from_table(tbl)
if not container then
return nil, err
end
self.containers[id] = container
return container, nil
end
---@param id string
function TagManager:unload(id)
self.containers[id] = nil
end
---@param id string
---@return string? error
function TagManager:reset(id)
self:unload(id)
if self.state:exists(id) then
local err = self.state:remove(id)
if err then
return err
end
end
end
---@param time_limit integer | string
---@return string[] | nil pruned, string? error
function TagManager:prune(time_limit)
vim.validate({
time_limit = { time_limit, { "number", "string" } },
})
local limit_sec
if type(time_limit) == "number" then
limit_sec = time_limit
elseif type(time_limit) == "string" then
local n, kind = string.match(time_limit, "^(%d+)(%S)$")
if not n or not kind then
return nil, string.format("Could not parse time limit: %s", time_limit)
end
n = assert(tonumber(n))
if kind == "d" then
limit_sec = n * 24 * 60 * 60
elseif kind == "h" then
limit_sec = n * 60 * 60
elseif kind == "m" then
limit_sec = n * 60
elseif kind == "s" then
limit_sec = n
else
return nil, string.format("Invalid time limit kind: %s", time_limit)
end
else
return nil, string.format("Invalid time limit: %s", vim.inspect(time_limit))
end
local pruned_ids, err = self.state:prune(limit_sec)
if not pruned_ids then
return nil, err
end
return pruned_ids, nil
end
---@param id string
---@return string? error
function TagManager:sync(id)
local container = self.containers[id]
if not container then
return string.format("no container for id: %s", id)
end
local err = self.state:write(id, container:into_table())
if err then
return err
end
end
return TagManager