Skip to content

fix(async): revert back to previous version 'async' module #258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ assignees: ""
3. how do you configure this plugin?

It's ...

4. What's your OS and Neovim version?

The OS is: Windows 10 x86_64 (Intel/AMD chip), MacOS M1 chip, Ubuntu/Fedora/Arch x86_64 (Intel/AMD chip), ...
The Neovim version (`nvim --version`) is: ...
8 changes: 3 additions & 5 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# Regression Test

## Platforms
## Test Platforms

- [ ] windows
- [ ] macOS
- [ ] linux

## Hosts
## Test Hosts

- [ ] Test on [github.com](https://github.com).
- [ ] Test on [gitlab.com](https://gitlab.com).
- [ ] Test on [bitbucket.org](https://bitbucket.org).
- [ ] Test on [codeberg.org](https://codeberg.org).
- [ ] Test on [git.samba.org](https://git.samba.org).

## Functions
## Test Functions

- [ ] Use `GitLink(!)` to copy git link (or open in browser).
- [ ] Use `GitLink(!) blame` to copy the `/blame` link (or open in browser).
Expand Down
12 changes: 6 additions & 6 deletions lua/gitlinker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
local num = require("gitlinker.commons.num")
local LogLevels = require("gitlinker.commons.logging").LogLevels
local logging = require("gitlinker.commons.logging")
local async = require("gitlinker.commons.async")

local async = require("gitlinker.async")
local configs = require("gitlinker.configs")
local range = require("gitlinker.range")
local linker = require("gitlinker.linker")
Expand Down Expand Up @@ -221,7 +221,7 @@
lk.rev = opts.rev
end

async.schedule()
async.scheduler()

Check warning on line 224 in lua/gitlinker.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker.lua#L224

Added line #L224 was not covered by tests
local ok, url = pcall(opts.router, lk, true)
-- logger:debug(
-- "|link| ok:%s, url:%s, router:%s",
Expand Down Expand Up @@ -273,7 +273,7 @@
end

--- @type fun(opts:{action:gitlinker.Action?,router:gitlinker.Router,lstart:integer,lend:integer,remote:string?,file:string?,rev:string?}):string?
local _sync_link = async.sync(1, _link)
local _void_link = async.void(_link)

--- @param args string?
--- @return {router_type:string,remote:string?,file:string?,rev:string?}
Expand Down Expand Up @@ -332,7 +332,7 @@
local lstart = math.min(r.lstart, r.lend, command_opts.line1, command_opts.line2)
local lend = math.max(r.lstart, r.lend, command_opts.line1, command_opts.line2)
local parsed = _parse_args(args)
_sync_link({
_void_link({

Check warning on line 335 in lua/gitlinker.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker.lua#L335

Added line #L335 was not covered by tests
action = command_opts.bang and require("gitlinker.actions").system
or require("gitlinker.actions").clipboard,
router = function(lk)
Expand Down Expand Up @@ -392,7 +392,7 @@
opts.lend = math.max(r.lstart, r.lend)
end

_sync_link({
_void_link({
action = opts.action,
router = opts.router,
lstart = opts.lstart,
Expand All @@ -408,7 +408,7 @@
local M = {
_url_template_engine = _url_template_engine,
_worker = _worker,
_sync_link = _sync_link,
_void_link = _void_link,
_router = _router,
_browse = _browse,
_blame = _blame,
Expand Down
239 changes: 239 additions & 0 deletions lua/gitlinker/async.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
---@diagnostic disable: luadoc-miss-module-name, undefined-doc-name
--- Small async library for Neovim plugins
--- @module async
-- Store all the async threads in a weak table so we don't prevent them from
-- being garbage collected
local handles = setmetatable({}, { __mode = "k" })
local M = {}
-- Note: coroutine.running() was changed between Lua 5.1 and 5.2:
-- - 5.1: Returns the running coroutine, or nil when called by the main thread.
-- - 5.2: Returns the running coroutine plus a boolean, true when the running
-- coroutine is the main one.
--
-- For LuaJIT, 5.2 behaviour is enabled with LUAJIT_ENABLE_LUA52COMPAT
--
-- We need to handle both.
--- Returns whether the current execution context is async.
---
--- @treturn boolean?
function M.running()
local current = coroutine.running()
if current and handles[current] then
return true
end
end
local function is_Async_T(handle)
if
handle
and type(handle) == "table"
and vim.is_callable(handle.cancel)
and vim.is_callable(handle.is_cancelled)

Check warning on line 30 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L29-L30

Added lines #L29 - L30 were not covered by tests
then
return true

Check warning on line 32 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L32

Added line #L32 was not covered by tests
end
end
local Async_T = {}
-- Analogous to uv.close
function Async_T:cancel(cb)
-- Cancel anything running on the event loop
if self._current and not self._current:is_cancelled() then
self._current:cancel(cb)

Check warning on line 40 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L39-L40

Added lines #L39 - L40 were not covered by tests
end
end
function Async_T.new(co)
local handle = setmetatable({}, { __index = Async_T })
handles[co] = handle
return handle
end
-- Analogous to uv.is_closing
function Async_T:is_cancelled()
return self._current and self._current:is_cancelled()

Check warning on line 50 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L50

Added line #L50 was not covered by tests
end
--- Run a function in an async context.
--- @tparam function func
--- @tparam function callback
--- @tparam any ... Arguments for func
--- @treturn async_t Handle
function M.run(func, callback, ...)
vim.validate({
func = { func, "function" },
callback = { callback, "function", true },
})
local co = coroutine.create(func)
local handle = Async_T.new(co)
local function step(...)
local ret = { coroutine.resume(co, ...) }
local ok = ret[1]
if not ok then
local err = ret[2]
error(
string.format("The coroutine failed with this message:\n%s\n%s", err, debug.traceback(co))
)
end
if coroutine.status(co) == "dead" then
if callback then
callback(unpack(ret, 4, table.maxn(ret)))

Check warning on line 75 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L75

Added line #L75 was not covered by tests
end
return
end
local nargs, fn = ret[2], ret[3]
local args = { select(4, unpack(ret)) }
assert(type(fn) == "function", "type error :: expected func")
args[nargs] = step
local r = fn(unpack(args, 1, nargs))
if is_Async_T(r) then
handle._current = r

Check warning on line 85 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L85

Added line #L85 was not covered by tests
end
end
step(...)
return handle
end
local function wait(argc, func, ...)
vim.validate({
argc = { argc, "number" },
func = { func, "function" },
})
-- Always run the wrapped functions in xpcall and re-raise the error in the
-- coroutine. This makes pcall work as normal.
local function pfunc(...)
local args = { ... }
local cb = args[argc]
args[argc] = function(...)
cb(true, ...)
end
xpcall(func, function(err)
cb(false, err, debug.traceback())
end, unpack(args, 1, argc))
end
local ret = { coroutine.yield(argc, pfunc, ...) }
local ok = ret[1]
if not ok then
local _, err, traceback = unpack(ret)
error(string.format("Wrapped function failed: %s\n%s", err, traceback))
end
return unpack(ret, 2, table.maxn(ret))
end
--- Wait on a callback style function
---
--- @tparam integer? argc The number of arguments of func.
--- @tparam function func callback style function to execute
--- @tparam any ... Arguments for func
function M.wait(...)
if type(select(1, ...)) == "number" then
return wait(...)
end
-- Assume argc is equal to the number of passed arguments.
return wait(select("#", ...) - 1, ...)

Check warning on line 126 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L126

Added line #L126 was not covered by tests
end
--- Use this to create a function which executes in an async context but
--- called from a non-async context. Inherently this cannot return anything
--- since it is non-blocking
--- @tparam function func
--- @tparam number argc The number of arguments of func. Defaults to 0
--- @tparam boolean strict Error when called in non-async context
--- @treturn function(...):async_t
function M.create(func, argc, strict)
vim.validate({

Check warning on line 136 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L136

Added line #L136 was not covered by tests
func = { func, "function" },
argc = { argc, "number", true },
})
argc = argc or 0

Check warning on line 140 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L140

Added line #L140 was not covered by tests
return function(...)
if M.running() then
if strict then
error("This function must run in a non-async context")

Check warning on line 144 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L142-L144

Added lines #L142 - L144 were not covered by tests
end
return func(...)

Check warning on line 146 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L146

Added line #L146 was not covered by tests
end
local callback = select(argc + 1, ...)
return M.run(func, callback, unpack({ ... }, 1, argc))

Check warning on line 149 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L148-L149

Added lines #L148 - L149 were not covered by tests
end
end
--- Create a function which executes in an async context but
--- called from a non-async context.
--- @tparam function func
--- @tparam boolean strict Error when called in non-async context
function M.void(func, strict)
vim.validate({ func = { func, "function" } })
return function(...)
if M.running() then
if strict then
error("This function must run in a non-async context")

Check warning on line 161 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L160-L161

Added lines #L160 - L161 were not covered by tests
end
return func(...)

Check warning on line 163 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L163

Added line #L163 was not covered by tests
end
return M.run(func, nil, ...)
end
end
--- Creates an async function with a callback style function.
---
--- @tparam function func A callback style function to be converted. The last argument must be the callback.
--- @tparam integer argc The number of arguments of func. Must be included.
--- @tparam boolean strict Error when called in non-async context
--- @treturn function Returns an async function
function M.wrap(func, argc, strict)
vim.validate({
argc = { argc, "number" },
})
return function(...)
if not M.running() then
if strict then
error("This function must run in an async context")

Check warning on line 181 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L180-L181

Added lines #L180 - L181 were not covered by tests
end
return func(...)

Check warning on line 183 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L183

Added line #L183 was not covered by tests
end
return M.wait(argc, func, ...)
end
end
--- Run a collection of async functions (`thunks`) concurrently and return when
--- all have finished.
--- @tparam function[] thunks
--- @tparam integer n Max number of thunks to run concurrently
--- @tparam function interrupt_check Function to abort thunks between calls
function M.join(thunks, n, interrupt_check)
local function run(finish)
if #thunks == 0 then
return finish()

Check warning on line 196 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L195-L196

Added lines #L195 - L196 were not covered by tests
end
local remaining = { select(n + 1, unpack(thunks)) }
local to_go = #thunks
local ret = {}

Check warning on line 200 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L198-L200

Added lines #L198 - L200 were not covered by tests
local function cb(...)
ret[#ret + 1] = { ... }
to_go = to_go - 1
if to_go == 0 then
finish(ret)
elseif not interrupt_check or not interrupt_check() then
if #remaining > 0 then
local next_task = table.remove(remaining)
next_task(cb)

Check warning on line 209 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L202-L209

Added lines #L202 - L209 were not covered by tests
end
end
end
for i = 1, math.min(n, #thunks) do
thunks[i](cb)

Check warning on line 214 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L213-L214

Added lines #L213 - L214 were not covered by tests
end
end
if not M.running() then
return run

Check warning on line 218 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L217-L218

Added lines #L217 - L218 were not covered by tests
end
return M.wait(1, false, run)

Check warning on line 220 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L220

Added line #L220 was not covered by tests
end
--- Partially applying arguments to an async function
--- @tparam function fn
--- @param ... arguments to apply to `fn`
function M.curry(fn, ...)
local args = { ... }
local nargs = select("#", ...)

Check warning on line 227 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L226-L227

Added lines #L226 - L227 were not covered by tests
return function(...)
local other = { ... }
for i = 1, select("#", ...) do
args[nargs + i] = other[i]

Check warning on line 231 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L229-L231

Added lines #L229 - L231 were not covered by tests
end
fn(unpack(args))

Check warning on line 233 in lua/gitlinker/async.lua

View check run for this annotation

Codecov / codecov/patch

lua/gitlinker/async.lua#L233

Added line #L233 was not covered by tests
end
end
--- An async function that when called will yield to the Neovim scheduler to be
--- able to call the neovim API.
M.scheduler = M.wrap(vim.schedule, 1, false)
return M
21 changes: 10 additions & 11 deletions lua/gitlinker/commons/fileio.lua → lua/gitlinker/commons/fio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function FileLineReader:open(filename, batchsize)
if type(handler) ~= "number" then
error(
string.format(
"|commons.fileio - FileLineReader:open| failed to fs_open file: %s",
"|commons.fio - FileLineReader:open| failed to fs_open file: %s",
vim.inspect(filename)
)
)
Expand All @@ -31,7 +31,7 @@ function FileLineReader:open(filename, batchsize)
if type(fstat) ~= "table" then
error(
string.format(
"|commons.fileio - FileLineReader:open| failed to fs_fstat file: %s",
"|commons.fio - FileLineReader:open| failed to fs_fstat file: %s",
vim.inspect(filename)
)
)
Expand Down Expand Up @@ -67,7 +67,7 @@ function FileLineReader:_read_chunk()
if read_err then
error(
string.format(
"|commons.fileio - FileLineReader:_read_chunk| failed to fs_read file: %s, read_error:%s, read_name:%s",
"|commons.fio - FileLineReader:_read_chunk| failed to fs_read file: %s, read_error:%s, read_name:%s",
vim.inspect(self.filename),
vim.inspect(read_err),
vim.inspect(read_name)
Expand Down Expand Up @@ -199,12 +199,12 @@ end
--- @alias commons.AsyncReadFileOnComplete fun(data:string?):any
--- @alias commons.AsyncReadFileOnError fun(step:string?,err:string?):any
--- @param filename string
--- @param on_complete commons.AsyncReadFileOnComplete
--- @param opts {trim:boolean?,on_error:commons.AsyncReadFileOnError?}?
M.asyncreadfile = function(filename, on_complete, opts)
opts = opts or { trim = false }
opts.trim = type(opts.trim) == "boolean" and opts.trim or false
--- @param opts {on_complete:commons.AsyncReadFileOnComplete,on_error:commons.AsyncReadFileOnError?,trim:boolean?}
M.asyncreadfile = function(filename, opts)
assert(type(opts) == "table")
assert(type(opts.on_complete) == "function")

opts.trim = type(opts.trim) == "boolean" and opts.trim or false
if type(opts.on_error) ~= "function" then
opts.on_error = function(step1, err1)
error(
Expand Down Expand Up @@ -240,11 +240,10 @@ M.asyncreadfile = function(filename, on_complete, opts)
uv.fs_close(fd --[[@as integer]], function(close_complete_err)
if opts.trim and type(data) == "string" then
local trimmed_data = vim.trim(data)
on_complete(trimmed_data)
opts.on_complete(trimmed_data)
else
on_complete(data)
opts.on_complete(data)
end

if close_complete_err then
opts.on_error("fs_close complete", close_complete_err)
end
Expand Down
2 changes: 1 addition & 1 deletion lua/gitlinker/commons/platform.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local os_name = uv.os_uname().sysname
local os_name_valid = type(os_name) == "string" and string.len(os_name) > 0

M.OS_NAME = os_name
M.IS_WINDOWS = os_name_valid and os_name:gmatch("Windows") ~= nil
M.IS_WINDOWS = os_name_valid and os_name:match("Windows") ~= nil
M.IS_MAC = os_name_valid and os_name:match("Darwin") ~= nil
M.IS_BSD = vim.fn.has("bsd") > 0
M.IS_LINUX = os_name_valid and os_name:match("Linux") ~= nil
Expand Down
Loading
Loading