|
1 |
| -# [Lua Async Await](https://github.com./nvim-java/lua-async-await) |
| 1 | +# [Lua Async](https://github.com./nvim-java/lua-async) |
2 | 2 |
|
3 |
| -This is basically [ms-jpq/lua-async-await](https://github.com./ms-jpq/lua-async-await) but with Promise like error handling |
| 3 | +Synchronous like asynchronous for Lua. |
4 | 4 |
|
5 |
| -Refer the original repository for more comprehensive documentation on how all this works |
| 5 | +## What |
6 | 6 |
|
7 |
| -## Why? |
| 7 | +Take a look at before and after |
8 | 8 |
|
9 |
| -A Language Server command response contains two parameters. `error` & `response`. If the error is present |
10 |
| -then the error should be handled. |
11 |
| - |
12 |
| -Ex:- |
| 9 | +**Before:** |
13 | 10 |
|
14 | 11 | ```lua
|
15 |
| -self.client.request('workspace/executeCommand', cmd_info, function(err, res) |
| 12 | +client.request('workspace/executeCommand', cmd_info, function(err, res) |
16 | 13 | if err then
|
17 |
| - log.error(command .. ' failed! arguments: ', arguments, ' error: ', err) |
| 14 | + log.error(err) |
18 | 15 | else
|
19 |
| - log.debug(command .. ' success! response: ', res) |
| 16 | + log.debug(res) |
20 | 17 | end
|
21 | 18 | end, buffer)
|
22 | 19 | ```
|
23 | 20 |
|
24 |
| -Promises are fine but chaining is annoying specially when you don't have arrow function like |
25 |
| -syntactic sugar. Moreover, at the time of this is writing, Lua language server generics typing |
26 |
| -is so primitive and cannot handle `Promise<Something>` like types. |
| 21 | +**After:** |
27 | 22 |
|
28 |
| -So I wanted Promise like error handling but without Promises. |
| 23 | +```lua |
| 24 | +-- on error, statement will fail throwing an error just like any synchronous API |
| 25 | +local result = client.request('workspace/executeCommand', cmd_info, buffer) |
| 26 | +log.debug(result) |
| 27 | +``` |
29 | 28 |
|
30 |
| -## How to use |
| 29 | +## Why |
| 30 | + |
| 31 | +Well, callback creates callback hell. |
31 | 32 |
|
32 |
| -Assume following is the asynchronous API |
| 33 | +## How to use |
33 | 34 |
|
34 | 35 | ```lua
|
35 |
| -local function lsp_request(callback) |
| 36 | +local runner = require("async.runner") |
| 37 | +local wrap = require("async.wrap") |
| 38 | +local wait = require("async.waits.wait_with_error_handler") |
| 39 | + |
| 40 | +local function success_async(callback) |
36 | 41 | local timer = vim.loop.new_timer()
|
37 | 42 |
|
38 | 43 | assert(timer)
|
39 | 44 |
|
40 | 45 | timer:start(2000, 0, function()
|
41 | 46 | -- First parameter is the error
|
42 |
| - callback('something went wrong', nil) |
| 47 | + callback(nil, "hello world") |
43 | 48 | end)
|
44 | 49 | end
|
45 |
| -``` |
46 |
| - |
47 |
| -### When no error handler defined |
48 |
| - |
49 |
| -This is how you can call this asynchronous API without a callback |
50 | 50 |
|
51 |
| -```lua |
52 |
| -local M = require('sync') |
53 |
| - |
54 |
| -M.sync(function() |
55 |
| - local response = M.wait_handle_error(M.wrap(lsp_request)()) |
56 |
| -end).run() |
57 |
| -``` |
58 |
| - |
59 |
| -Result: |
60 |
| - |
61 |
| -``` |
62 |
| -Error executing luv callback: |
63 |
| -test6.lua:43: unhandled error test6.lua:105: something went wrong |
64 |
| -stack traceback: |
65 |
| - [C]: in function 'error' |
66 |
| - test6.lua:43: in function 'callback' |
67 |
| - test6.lua:130: in function <test6.lua:129> |
68 |
| -``` |
69 |
| - |
70 |
| -### When error handler is defined |
| 51 | +local function fail_async(callback) |
| 52 | + local timer = vim.loop.new_timer() |
71 | 53 |
|
72 |
| -```lua |
73 |
| -local M = require('sync') |
| 54 | + assert(timer) |
74 | 55 |
|
75 |
| -local main = M.sync(function() |
76 |
| - local response = M.wait_handle_error(M.wrap(lsp_request)()) |
77 |
| -end) |
78 |
| - .catch(function(err) |
79 |
| - print('error occurred ', err) |
| 56 | + timer:start(2000, 0, function() |
| 57 | + -- First parameter is the error |
| 58 | + callback("something went wrong", nil) |
80 | 59 | end)
|
81 |
| - .run() |
82 |
| -``` |
| 60 | +end |
83 | 61 |
|
84 |
| -Result: |
| 62 | +local function log(message) |
| 63 | + vim.print(os.date("%H:%M:%S") .. " " .. message) |
| 64 | +end |
85 | 65 |
|
86 |
| -``` |
87 |
| -error occurred test6.lua:105: something went wrong |
88 |
| -``` |
| 66 | +vim.cmd.messages("clear") |
89 | 67 |
|
90 |
| -### When nested |
| 68 | +local nested = runner(function() |
| 69 | + local success_sync = wrap(success_async) |
| 70 | + local fail_sync = wrap(fail_async) |
91 | 71 |
|
92 |
| -```lua |
93 |
| -local M = require('sync') |
| 72 | + local success_result = wait(success_sync()) |
| 73 | + -- here we get the result because there is no error |
| 74 | + log("success_result is: " .. success_result) |
94 | 75 |
|
95 |
| -local nested = M.sync(function() |
96 |
| - local response = M.wait_handle_error(M.wrap(lsp_request)()) |
| 76 | + -- following is going to fail and error will get caught by |
| 77 | + -- the parent runner function's 'catch' |
| 78 | + wait(fail_sync()) |
97 | 79 | end)
|
98 | 80 |
|
99 |
| -M.sync(function() |
100 |
| - M.wait_handle_error(nested.run) |
101 |
| -end) |
| 81 | +runner(function() |
| 82 | + log("starting the execution") |
| 83 | + -- just wait for nested runner to complete the execution |
| 84 | + wait(nested.run) |
| 85 | + end) |
102 | 86 | .catch(function(err)
|
103 |
| - print('parent error handler ' .. err) |
| 87 | + log("parent error handler " .. err) |
104 | 88 | end)
|
105 | 89 | .run()
|
106 | 90 | ```
|
107 |
| - |
108 |
| -Result: |
109 |
| - |
110 |
| -``` |
111 |
| -parent error handler test6.lua:105: test6.lua:105: something went wrong |
112 |
| -``` |
0 commit comments