mirror of
https://github.com/kristoferssolo/telescope-frecency.nvim.git
synced 2025-10-21 20:10:38 +00:00
* fix: get file lock forcibly When Neovim ends without removing file locks, it will fail to open frecency ever because file locks remain. This fix makes it remove file locks when all attempts fail forcibly. * test: avoid error in Windows In Windows, unclosed file cannot be removed, so close it before unlinking. * feat: retry to unlink when it fails
95 lines
2.4 KiB
Lua
95 lines
2.4 KiB
Lua
local async = require "plenary.async" --[[@as PlenaryAsync]]
|
|
local log = require "plenary.log"
|
|
|
|
---@class FrecencyFileLock
|
|
---@field base string
|
|
---@field config FrecencyFileLockConfig
|
|
---@field filename string
|
|
local FileLock = {}
|
|
|
|
---@class FrecencyFileLockConfig
|
|
---@field retry integer default: 5
|
|
---@field unlink_retry integer default: 5
|
|
---@field interval integer default: 500
|
|
|
|
---@param path string
|
|
---@param opts FrecencyFileLockConfig?
|
|
---@return FrecencyFileLock
|
|
FileLock.new = function(path, opts)
|
|
local config = vim.tbl_extend("force", { retry = 5, unlink_retry = 5, interval = 500 }, opts or {})
|
|
local self = setmetatable({ config = config }, { __index = FileLock })
|
|
self.filename = path .. ".lock"
|
|
return self
|
|
end
|
|
|
|
---@async
|
|
---@return string? err
|
|
function FileLock:get()
|
|
local count = 0
|
|
local unlink_count = 0
|
|
local err, fd
|
|
while true do
|
|
count = count + 1
|
|
err, fd = async.uv.fs_open(self.filename, "wx", tonumber("600", 8))
|
|
if not err then
|
|
break
|
|
end
|
|
async.util.sleep(self.config.interval)
|
|
if count >= self.config.retry then
|
|
log.debug(("file_lock get(): retry count reached. try to delete the lock file: %d"):format(count))
|
|
err = async.uv.fs_unlink(self.filename)
|
|
if err then
|
|
log.debug("file_lock get() failed: " .. err)
|
|
unlink_count = unlink_count + 1
|
|
if unlink_count >= self.config.unlink_retry then
|
|
log.error("file_lock get(): failed to unlink the lock file: " .. err)
|
|
return "failed to get lock"
|
|
end
|
|
end
|
|
end
|
|
log.debug(("file_lock get() retry: %d"):format(count))
|
|
end
|
|
err = async.uv.fs_close(fd)
|
|
if err then
|
|
log.debug("file_lock get() failed: " .. err)
|
|
return err
|
|
end
|
|
end
|
|
|
|
---@async
|
|
---@return string? err
|
|
function FileLock:release()
|
|
local err = async.uv.fs_stat(self.filename)
|
|
if err then
|
|
log.debug("file_lock release() not found: " .. err)
|
|
return "lock not found"
|
|
end
|
|
err = async.uv.fs_unlink(self.filename)
|
|
if err then
|
|
log.debug("file_lock release() unlink failed: " .. err)
|
|
return err
|
|
end
|
|
end
|
|
|
|
---@async
|
|
---@generic T
|
|
---@param f fun(): T
|
|
---@return string? err
|
|
---@return T
|
|
function FileLock:with(f)
|
|
local err = self:get()
|
|
if err then
|
|
return err, nil
|
|
end
|
|
local ok, result_or_err = pcall(f)
|
|
err = self:release()
|
|
if err then
|
|
return err, nil
|
|
elseif ok then
|
|
return nil, result_or_err
|
|
end
|
|
return result_or_err, nil
|
|
end
|
|
|
|
return FileLock
|