Skip to content

Commit 8293bee

Browse files
committed
feat: add type annotations for plenary.async
1 parent f5b6991 commit 8293bee

File tree

11 files changed

+145
-54
lines changed

11 files changed

+145
-54
lines changed

lua/plenary/async/api.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
local util = require "plenary.async.util"
22

3+
---@alias PlenaryAsyncApi table<string, PlenaryAsyncFunction>
4+
5+
---@type PlenaryAsyncApi
36
return setmetatable({}, {
47
__index = function(t, k)
58
return function(...)

lua/plenary/async/async.lua

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,20 @@ local errors = require "plenary.errors"
44
local traceback_error = errors.traceback_error
55
local f = require "plenary.functional"
66

7+
---@class PlenaryAsyncAsync
78
local M = {}
89

10+
---@param fn any
11+
---@return boolean
912
local function is_callable(fn)
1013
return type(fn) == "function" or (type(fn) == "table" and type(getmetatable(fn)["__call"]) == "function")
1114
end
1215

1316
---because we can't store varargs
17+
---@param step function
18+
---@param thread thread
19+
---@param callback? function
20+
---@param ... any
1421
local function callback_or_next(step, thread, callback, ...)
1522
local stat = f.first(...)
1623

@@ -33,12 +40,12 @@ local function callback_or_next(step, thread, callback, ...)
3340
end
3441

3542
---Executes a future with a callback when it is done
36-
---@param async_function Future: the future to execute
37-
---@param callback function: the callback to call when done
38-
local execute = function(async_function, callback, ...)
39-
assert(is_callable(async_function), "type error :: expected func")
43+
---@param func function the future to execute
44+
---@param callback? function the callback to call when done
45+
local execute = function(func, callback, ...)
46+
assert(is_callable(func), "type error :: expected func")
4047

41-
local thread = co.create(async_function)
48+
local thread = co.create(func)
4249

4350
local step
4451
step = function(...)
@@ -48,31 +55,41 @@ local execute = function(async_function, callback, ...)
4855
step(...)
4956
end
5057

58+
---A function including async logic
59+
---@alias PlenaryAsyncFunction async fun(...): ...
60+
5161
local add_leaf_function
5262
do
5363
---A table to store all leaf async functions
64+
---@type table<PlenaryAsyncFunction, integer>
5465
_PlenaryLeafTable = setmetatable({}, {
5566
__mode = "k",
5667
})
5768

69+
---@param async_func PlenaryAsyncFunction
70+
---@param argc integer
5871
add_leaf_function = function(async_func, argc)
5972
assert(_PlenaryLeafTable[async_func] == nil, "Async function should not already be in the table")
6073
_PlenaryLeafTable[async_func] = argc
6174
end
6275

76+
---@param async_func PlenaryAsyncFunction
77+
---@return boolean
6378
function M.is_leaf_function(async_func)
6479
return _PlenaryLeafTable[async_func] ~= nil
6580
end
6681

82+
---@param async_func PlenaryAsyncFunction
83+
---@return integer
6784
function M.get_leaf_function_argc(async_func)
6885
return _PlenaryLeafTable[async_func]
6986
end
7087
end
7188

7289
---Creates an async function with a callback style function.
73-
---@param func function: A callback style function to be converted. The last argument must be the callback.
74-
---@param argc number: The number of arguments of func. Must be included.
75-
---@return function: Returns an async function
90+
---@param func function A callback style function to be converted. The last argument must be the callback.
91+
---@param argc integer The number of arguments of func. Must be included.
92+
---@return PlenaryAsyncFunction leaf Returns an leaf
7693
M.wrap = function(func, argc)
7794
if not is_callable(func) then
7895
traceback_error("type error :: expected func, got " .. type(func))
@@ -82,6 +99,7 @@ M.wrap = function(func, argc)
8299
traceback_error("type error :: expected number, got " .. type(argc))
83100
end
84101

102+
---@type PlenaryAsyncFunction
85103
local function leaf(...)
86104
local nargs = select("#", ...)
87105

@@ -99,13 +117,13 @@ end
99117

100118
---Use this to either run a future concurrently and then do something else
101119
---or use it to run a future with a callback in a non async context
102-
---@param async_function function
120+
---@param func PlenaryAsyncFunction|function
103121
---@param callback function
104-
M.run = function(async_function, callback)
105-
if M.is_leaf_function(async_function) then
106-
async_function(callback)
122+
M.run = function(func, callback)
123+
if M.is_leaf_function(func) then
124+
func(callback)
107125
else
108-
execute(async_function, callback)
126+
execute(func, callback)
109127
end
110128
end
111129

lua/plenary/async/control.lua

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@ local a = require "plenary.async.async"
22
local Deque = require("plenary.async.structs").Deque
33
local tbl = require "plenary.tbl"
44

5+
---@class PlenaryAsyncControl
56
local M = {}
67

8+
---@class PlenaryAsyncCondvar
9+
---@field handles (fun(): nil)[]
710
local Condvar = {}
811
Condvar.__index = Condvar
912

10-
---@class Condvar
11-
---@return Condvar
13+
---@return PlenaryAsyncCondvar
1214
function Condvar.new()
1315
return setmetatable({ handles = {} }, Condvar)
1416
end
1517

1618
---`blocks` the thread until a notification is received
19+
---@param self PlenaryAsyncCondvar
20+
---@param callback fun(): nil
1721
Condvar.wait = a.wrap(function(self, callback)
1822
-- not calling the callback will block the coroutine
1923
table.insert(self.handles, callback)
20-
end, 2)
24+
end, 2) --[[@as async fun(): nil]]
2125

2226
---notify everyone that is waiting on this Condvar
2327
function Condvar:notify_all()
@@ -52,12 +56,14 @@ end
5256

5357
M.Condvar = Condvar
5458

59+
---@class PlenaryAsyncSemaphore
60+
---@field handles (fun(permit: PlenaryAsyncPermit): nil)[]
61+
---@field permits integer
5562
local Semaphore = {}
5663
Semaphore.__index = Semaphore
5764

58-
---@class Semaphore
59-
---@param initial_permits number: the number of permits that it can give out
60-
---@return Semaphore
65+
---@param initial_permits integer the number of permits that it can give out
66+
---@return PlenaryAsyncSemaphore
6167
function Semaphore.new(initial_permits)
6268
vim.validate {
6369
initial_permits = {
@@ -79,6 +85,8 @@ end
7985
---permit:forget()
8086
---when a permit can be acquired returns it
8187
---call permit:forget() to forget the permit
88+
---@param self PlenaryAsyncSemaphore
89+
---@param callback fun(permit: PlenaryAsyncPermit): nil
8290
Semaphore.acquire = a.wrap(function(self, callback)
8391
if self.permits > 0 then
8492
self.permits = self.permits - 1
@@ -87,8 +95,10 @@ Semaphore.acquire = a.wrap(function(self, callback)
8795
return
8896
end
8997

98+
---@class PlenaryAsyncPermit
9099
local permit = {}
91100

101+
---@param self_permit PlenaryAsyncPermit
92102
permit.forget = function(self_permit)
93103
self.permits = self.permits + 1
94104

@@ -99,16 +109,17 @@ Semaphore.acquire = a.wrap(function(self, callback)
99109
end
100110

101111
callback(permit)
102-
end, 2)
112+
end, 2) --[[@as async fun(self: PlenaryAsyncSemaphore): PlenaryAsyncPermit]]
103113

104114
M.Semaphore = Semaphore
105115

116+
---@class PlenaryAsyncControlChannel
106117
M.channel = {}
107118

108119
---Creates a oneshot channel
109120
---returns a sender and receiver function
110121
---the sender is not async while the receiver is
111-
---@return function, function
122+
---@return fun(...): nil tx, async fun(): ... rx
112123
M.channel.oneshot = function()
113124
local val = nil
114125
local saved_callback = nil
@@ -147,20 +158,26 @@ M.channel.oneshot = function()
147158
if is_single then
148159
return callback(val)
149160
else
150-
return callback(tbl.unpack(val))
161+
return callback(tbl.unpack(val --[[@as table]]))
151162
end
152163
else
153164
saved_callback = callback
154165
end
155-
end, 1)
166+
end, 1) --[[@as async fun(): ...]]
156167

157168
return sender, receiver
158169
end
159170

171+
---@class PlenaryAsyncCounterTx
172+
---@field send fun(): nil
173+
174+
---@class PlenaryAsyncCounterRx
175+
---@field recv async fun(): nil
176+
---@field last async fun(): nil
177+
160178
---A counter channel.
161179
---Basically a channel that you want to use only to notify and not to send any actual values.
162-
---@return function: sender
163-
---@return function: receiver
180+
---@return PlenaryAsyncCounterTx tx, PlenaryAsyncCounterRx rx
164181
M.channel.counter = function()
165182
local counter = 0
166183
local condvar = Condvar.new()
@@ -191,9 +208,15 @@ M.channel.counter = function()
191208
return Sender, Receiver
192209
end
193210

211+
---@class PlenaryAsyncMpscTx
212+
---@field send fun(...: any): nil
213+
214+
---@class PlenaryAsyncMpscRx
215+
---@field recv async fun(): ...
216+
---@field last async fun(): ...
217+
194218
---A multiple producer single consumer channel
195-
---@return table
196-
---@return table
219+
---@return PlenaryAsyncMpscTx, PlenaryAsyncMpscRx
197220
M.channel.mpsc = function()
198221
local deque = Deque.new()
199222
local condvar = Condvar.new()

lua/plenary/async/init.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ local lookups = {
1212
control = "plenary.async.control",
1313
}
1414

15+
---@class PlenaryAsync: PlenaryAsyncAsync
16+
---@field api PlenaryAsyncApi
17+
---@field control PlenaryAsyncControl
18+
---@field lsp PlenaryAsyncLsp
19+
---@field tests PlenaryAsyncTests
20+
---@field util PlenaryAsyncUtil
21+
---@field uv PlenaryAsyncUv
1522
local exports = setmetatable(require "plenary.async.async", {
1623
__index = function(t, k)
1724
local require_path = lookups[k]

lua/plenary/async/lsp.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
11
local a = require "plenary.async.async"
22

3+
---@class PlenaryAsyncLsp
34
local M = {}
45

6+
---@alias ClientRequestIds table<integer, integer>
7+
58
---This will be deprecated because the callback can be called multiple times.
69
---This will give a coroutine error because the coroutine will be resumed multiple times.
710
---Please use buf_request_all instead.
11+
---@type async fun(bufnr: integer, method: string, params?: table, handler?: lsp.Handler): ClientRequestIds, function
812
M.buf_request = a.wrap(vim.lsp.buf_request, 4)
913

14+
---@alias BufRequestAllHandler fun(results: table<integer, { error: lsp.ResponseError, result: any }>)
15+
16+
---Sends an async request for all active clients attached to the buffer and executes the `handler`
17+
---callback with the combined result.
18+
---
19+
---* param bufnr (integer) Buffer handle, or 0 for current.
20+
---* param method (string) LSP method name
21+
---* param params (table|nil) Parameters to send to the server
22+
---* param handler fun(results: table<integer, {error: lsp.ResponseError, result: any}>) (function)
23+
--- Handler called after all requests are completed. Server results are passed as
24+
--- a `client_id:result` map.
25+
---* return function cancel Function that cancels all requests.
26+
---@type async fun(bufnr: integer, method: string, params?: table, handler: BufRequestAllHandler): function
1027
M.buf_request_all = a.wrap(vim.lsp.buf_request_all, 4)
1128

1229
return M

lua/plenary/async/structs.lua

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
---@class PlenaryAsyncStructs
12
local M = {}
23

4+
---A double ended queue
5+
---@class PlenaryDeque
6+
---@field first integer
7+
---@field last integer
8+
---@field [integer] any
39
local Deque = {}
410
Deque.__index = Deque
511

6-
---@class Deque
7-
---A double ended queue
8-
---
9-
---@return Deque
12+
---@return PlenaryDeque
1013
function Deque.new()
1114
-- the indexes are created with an offset so that the indices are consequtive
1215
-- otherwise, when both pushleft and pushright are used, the indices will have a 1 length hole in the middle
@@ -62,13 +65,13 @@ function Deque:is_empty()
6265
end
6366

6467
---returns the number of elements of the deque
65-
---@return number
68+
---@return integer
6669
function Deque:len()
6770
return self.last - self.first + 1
6871
end
6972

7073
---returns and iterator of the indices and values starting from the left
71-
---@return function
74+
---@return fun(): integer?, any?
7275
function Deque:ipairs_left()
7376
local i = self.first
7477

@@ -85,7 +88,7 @@ function Deque:ipairs_left()
8588
end
8689

8790
---returns and iterator of the indices and values starting from the right
88-
---@return function
91+
---@return fun(): integer?, any?
8992
function Deque:ipairs_right()
9093
local i = self.last
9194

lua/plenary/async/tests.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
local util = require "plenary.async.util"
22

3+
---@class PlenaryAsyncTests
34
local M = {}
45

6+
---@param s string
7+
---@param async_func PlenaryAsyncFunction
58
M.describe = function(s, async_func)
69
describe(s, async_func)
710
end
811

12+
---@param s string
13+
---@param async_func PlenaryAsyncFunction
914
M.it = function(s, async_func)
1015
it(s, util.will_block(async_func, tonumber(vim.env.PLENARY_TEST_TIMEOUT)))
1116
end
1217

18+
---@param async_func PlenaryAsyncFunction
1319
M.pending = function(async_func)
1420
pending(async_func)
1521
end
1622

23+
---@param async_func PlenaryAsyncFunction
1724
M.before_each = function(async_func)
1825
before_each(util.will_block(async_func))
1926
end
2027

28+
---@param async_func PlenaryAsyncFunction
2129
M.after_each = function(async_func)
2230
after_each(util.will_block(async_func))
2331
end

0 commit comments

Comments
 (0)