Skip to content

Commit db97e66

Browse files
authored
feat: Added a Stream data structure (#412)
Implement stream data structures as a better way to pass results from long running async worker tasks.
1 parent 500d8b2 commit db97e66

23 files changed

+1282
-428
lines changed

.luarc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json",
33
"Lua.diagnostics.disable": [
44
"assign-type-mismatch",
5-
"cast-type-mismatch"
5+
"cast-type-mismatch",
6+
"missing-fields"
67
],
78
"workspace.checkThirdParty": false
89
}

Makefile

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
.PHONY: all
22
all: test
33

4+
TEST_PATH := $(if $(TEST_PATH),$(TEST_PATH),lua/diffview/tests/)
5+
export TEST_PATH
6+
7+
# Usage:
8+
# Run all tests:
9+
# $ make test
10+
#
11+
# Run tests for a specific path:
12+
# $ TEST_PATH=tests/some/path make test
413
.PHONY: test
514
test:
615
nvim --headless -i NONE -n -u scripts/minimal_init.lua -c \
7-
"PlenaryBustedDirectory tests/ { minimal_init = './scripts/minimal_init.lua' }"
16+
"PlenaryBustedDirectory $(TEST_PATH) { minimal_init = './scripts/minimal_init.lua' }"
817

918
.PHONY: clean
1019
clean:

lua/diffview/async.lua

+37-29
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ local DEFAULT_ERROR = "Unkown error."
88

99
local M = {}
1010

11-
---@private
11+
---@package
1212
---@type { [Future]: boolean }
1313
M._watching = setmetatable({}, { __mode = "k" })
1414

15-
---@private
15+
---@package
1616
---@type { [thread]: Future }
1717
M._handles = {}
1818

@@ -65,26 +65,34 @@ end
6565

6666
---@class Waitable : diffview.Object
6767
local Waitable = oop.create_class("Waitable")
68+
M.Waitable = Waitable
6869

6970
---@abstract
7071
---@return any ... # Any values returned by the waitable
7172
function Waitable:await() oop.abstract_stub() end
7273

73-
M.Waitable = Waitable
74+
---Schedule a callback to be invoked when this waitable has settled.
75+
---@param callback function
76+
function Waitable:finally(callback)
77+
(M.void(function()
78+
local ret = tbl_pack(M.await(self))
79+
callback(tbl_unpack(ret))
80+
end))()
81+
end
7482

7583
---@class Future : Waitable
7684
---@operator call : Future
77-
---@field private thread thread
78-
---@field private listeners Future[]
79-
---@field private parent? Future
80-
---@field private func? function
81-
---@field private return_values? any[]
82-
---@field private err? string
83-
---@field private kind AsyncKind
84-
---@field private started boolean
85-
---@field private awaiting_cb boolean
86-
---@field private done boolean
87-
---@field private has_raised boolean # `true` if this future has raised an error.
85+
---@field package thread thread
86+
---@field package listeners Future[]
87+
---@field package parent? Future
88+
---@field package func? function
89+
---@field package return_values? any[]
90+
---@field package err? string
91+
---@field package kind AsyncKind
92+
---@field package started boolean
93+
---@field package awaiting_cb boolean
94+
---@field package done boolean
95+
---@field package has_raised boolean # `true` if this future has raised an error.
8896
local Future = oop.create_class("Future", Waitable)
8997

9098
function Future:init(opt)
@@ -107,18 +115,18 @@ function Future:init(opt)
107115
self.has_raised = false
108116
end
109117

110-
---@private
118+
---@package
111119
---@return string
112120
function Future:__tostring()
113121
return dstring(self.thread)
114122
end
115123

116-
---@private
124+
---@package
117125
function Future:destroy()
118126
M._handles[self.thread] = nil
119127
end
120128

121-
---@private
129+
---@package
122130
---@param value boolean
123131
function Future:set_done(value)
124132
self.done = value
@@ -138,7 +146,7 @@ function Future:get_returned()
138146
return unpack(self.return_values, 2, table.maxn(self.return_values))
139147
end
140148

141-
---@private
149+
---@package
142150
---@param ... any
143151
function Future:dprint(...)
144152
if not DiffviewGlobal.logger then return end
@@ -149,7 +157,7 @@ function Future:dprint(...)
149157
end
150158
end
151159

152-
---@private
160+
---@package
153161
---@param ... any
154162
function Future:dprintf(...)
155163
self:dprint(fmt(...))
@@ -165,21 +173,21 @@ function Future:unwatch()
165173
M._watching[self] = nil
166174
end
167175

168-
---@private
176+
---@package
169177
---@return boolean
170178
function Future:is_watching()
171179
return not not M._watching[self]
172180
end
173181

174-
---@private
182+
---@package
175183
---@param force? boolean
176184
function Future:raise(force)
177185
if self.has_raised and not force then return end
178186
self.has_raised = true
179187
error(self.err)
180188
end
181189

182-
---@private
190+
---@package
183191
function Future:step(...)
184192
self:dprint("step")
185193
local ret = { coroutine.resume(self.thread, ...) }
@@ -217,7 +225,7 @@ function Future:step(...)
217225
end
218226
end
219227

220-
---@private
228+
---@package
221229
---@param ok boolean
222230
---@param ... any
223231
function Future:notify_all(ok, ...)
@@ -241,6 +249,7 @@ function Future:notify_all(ok, ...)
241249
end
242250
end
243251

252+
---@override
244253
---@return any ... # Return values
245254
function Future:await()
246255
if self.err then
@@ -302,7 +311,7 @@ function Future:await()
302311
return self:get_returned()
303312
end
304313

305-
---@private
314+
---@package
306315
---@return any ...
307316
function Future:toplevel_await()
308317
local ok, status
@@ -337,15 +346,13 @@ end
337346
---@field nparams? integer
338347
---@field args any[]
339348

340-
---@private
349+
---@package
341350
---@param func function
342351
---@param opt async._run.Opt
343352
function M._run(func, opt)
344-
---@diagnostic disable: invisible
345353
opt = opt or {}
346354

347355
local handle ---@type Future
348-
local wrapped_cb
349356
local use_err_handler = not not current_thread()
350357

351358
local function wrapped_func(...)
@@ -381,7 +388,7 @@ function M._run(func, opt)
381388
if opt.kind == "callback" then
382389
local cur_cb = opt.args[opt.nparams]
383390

384-
function wrapped_cb(...)
391+
local function wrapped_cb(...)
385392
handle:set_done(true)
386393
handle.return_values = { true, ... }
387394
if cur_cb then cur_cb(...) end
@@ -405,7 +412,6 @@ function M._run(func, opt)
405412
handle:step(tbl_unpack(opt.args))
406413

407414
return handle
408-
---@diagnostic enable: invisible
409415
end
410416

411417
---Create an async task for a function with no return values.
@@ -566,4 +572,6 @@ M.scheduler = M.wrap(function(fast_only, callback)
566572
vim.schedule(callback)
567573
end)
568574

575+
M.schedule_now = M.wrap(vim.schedule, 1)
576+
569577
return M

0 commit comments

Comments
 (0)