Skip to content

Commit 4a55079

Browse files
committed
feat: prune tag containers based on ttl
1 parent df9dc16 commit 4a55079

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

lua/grapple.lua

+14
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,20 @@ function Grapple.reset(opts)
424424
end
425425
end
426426

427+
---@param opts { ttl: integer | string }
428+
---@return string[] | nil, string? error
429+
function Grapple.prune(opts)
430+
local App = require("grapple.app")
431+
local app = App.get()
432+
433+
local pruned_ids, err = app.tag_manager:prune(opts.ttl)
434+
if not pruned_ids then
435+
return nil, err
436+
end
437+
438+
return pruned_ids, nil
439+
end
440+
427441
---Create a user-defined scope
428442
---@param definition grapple.scope_definition
429443
---@return string? error

lua/grapple/state.lua

+47
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,53 @@ function State:remove(name)
8282
end
8383
end
8484

85+
---@return string[] | nil pruned, string? error, string? error_kind
86+
function State:prune(ttl_msec)
87+
local function current_time()
88+
local name = os.tmpname()
89+
local fd, err, err_kind = vim.loop.fs_open(name, "r", 438)
90+
if not fd then
91+
return nil, err, err_kind
92+
end
93+
94+
local stat, err, err_kind = vim.loop.fs_fstat(fd)
95+
if not stat then
96+
return nil, err, err_kind
97+
end
98+
99+
assert(vim.loop.fs_close(fd))
100+
assert(vim.loop.fs_unlink(name))
101+
102+
return stat.mtime.sec, nil, nil
103+
end
104+
105+
local now, err, err_kind = current_time()
106+
if not now then
107+
return nil, err, err_kind
108+
end
109+
110+
local pruned = {}
111+
112+
for name, _ in vim.fs.dir(self.save_dir) do
113+
local path = Path.join(self.save_dir, name)
114+
115+
---@diagnostic disable-next-line: redefined-local
116+
local stat, err, err_kind = vim.loop.fs_stat(path)
117+
if not stat then
118+
return err, err_kind
119+
end
120+
121+
local elapsed_msec = now - stat.mtime.sec
122+
if elapsed_msec > ttl_msec then
123+
name = path_decode(name)
124+
name = string.gsub(name, "%.json", "")
125+
table.insert(pruned, path_decode(name))
126+
end
127+
end
128+
129+
return pruned, nil, nil
130+
end
131+
85132
---@param name string
86133
---@return any decoded, string? error, string? error_kind
87134
function State:read(name)

lua/grapple/tag_manager.lua

+38
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,44 @@ function TagManager:reset(id)
152152
end
153153
end
154154

155+
---@param ttl integer | string
156+
---@return string[] | nil pruned, string? error
157+
function TagManager:prune(ttl)
158+
vim.validate({
159+
ttl = { ttl, { "number", "string" } },
160+
})
161+
162+
local ttl_msec
163+
if type(ttl) == "number" then
164+
ttl_msec = ttl
165+
elseif type(ttl) == "string" then
166+
local n, kind = string.match(ttl, "^(%d+)(%S)$")
167+
if not n or not kind then
168+
return nil, string.format("Could not parse time-to-live: %s", ttl)
169+
end
170+
171+
n = assert(tonumber(n))
172+
if kind == "d" then
173+
ttl_msec = n * 24 * 60 * 60 * 1000
174+
elseif kind == "h" then
175+
ttl_msec = n * 60 * 60 * 1000
176+
elseif kind == "m" then
177+
ttl_msec = n * 60 * 1000
178+
else
179+
return nil, string.format("Invalid time-to-live kind: %s", kind)
180+
end
181+
else
182+
return nil, string.format("Invalid time-to-live: %s", vim.inspect(ttl))
183+
end
184+
185+
local pruned_ids, err = self.state:prune(ttl_msec)
186+
if not pruned_ids then
187+
return nil, err
188+
end
189+
190+
return pruned_ids, nil
191+
end
192+
155193
---@param id string
156194
---@return string? error
157195
function TagManager:sync(id)

0 commit comments

Comments
 (0)