|
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