mirror of
https://github.com/neovim/neovim.git
synced 2026-09-11 08:31:03 +00:00
feat(net): vim.net.request(outbuf) writes response to buffer #36164
Problem:
Non-trivial to write output of vim.net.request to buffer. Requires extra
code in plugin/net.lua which can't be reused by other plugin authors.
```
vim.net.request('https://neovim.io', {}, function(err, res)
if not err then
local buf = vim.api.nvim_create_buf(true, false)
if res then
local lines = vim.split(res.body, '\n', { plain = true })
vim.api.nvim_buf_set_lines(buf, 0, -1, true, lines)
end
end
end)
```
Solution:
Accept an optional `outbuf` argument to indicate the buffer to write output
to, similar to `outpath`.
vim.net.request('https://neovim.io', { outbuf = buf })
Other fixes / followups:
- Make plugin/net.lua smaller
- Return objection with close() method
- vim.net.request.Opts class
- vim.validate single calls
- Use (''):format(...) instead of `..`
This commit is contained in:
committed by
GitHub
parent
7c3df3e2ea
commit
f29b3b5d45
@@ -1,23 +1,67 @@
|
||||
local M = {}
|
||||
|
||||
---@class vim.net.request.Opts
|
||||
---@inlinedoc
|
||||
---
|
||||
---Enables verbose output.
|
||||
---@field verbose? boolean
|
||||
---
|
||||
---Number of retries on transient failures (default: 3).
|
||||
---@field retry? integer
|
||||
---
|
||||
---File path to save the response body to.
|
||||
---@field outpath? string
|
||||
---
|
||||
---Buffer to save the response body to.
|
||||
---@field outbuf? integer
|
||||
|
||||
---@class vim.net.request.Response
|
||||
---
|
||||
---The HTTP body of the request
|
||||
---@field body string
|
||||
|
||||
--- Makes an HTTP GET request to the given URL (asynchronous).
|
||||
---
|
||||
--- This function operates in one mode:
|
||||
--- - Asynchronous (non-blocking): Returns immediately and passes the response object to the
|
||||
--- provided `on_response` handler on completion.
|
||||
--- This function is asynchronous (non-blocking), returning immediately and
|
||||
--- passing the response object to the optional `on_response` handler on
|
||||
--- completion.
|
||||
---
|
||||
--- Examples:
|
||||
--- ```lua
|
||||
--- -- Write response body to file
|
||||
--- vim.net.request('https://neovim.io/charter/', {
|
||||
--- outpath = 'vision.html',
|
||||
--- })
|
||||
---
|
||||
--- -- Process the response
|
||||
--- vim.net.request(
|
||||
--- 'https://api.github.com/repos/neovim/neovim',
|
||||
--- {},
|
||||
--- function (err, res)
|
||||
--- if err then return end
|
||||
--- local stars = vim.json.decode(res.body).stargazers_count
|
||||
--- vim.print(('Neovim currently has %d stars'):format(stars))
|
||||
--- end
|
||||
--- )
|
||||
---
|
||||
--- -- Write to both file and current buffer, but cancel it
|
||||
--- local job = vim.net.request('https://neovim.io/charter/', {
|
||||
--- outpath = 'vision.html',
|
||||
--- outbuf = 0,
|
||||
--- })
|
||||
--- job:close()
|
||||
--- ```
|
||||
---
|
||||
--- @param url string The URL for the request.
|
||||
--- @param opts? table Optional parameters:
|
||||
--- - `verbose` (boolean|nil): Enables verbose output.
|
||||
--- - `retry` (integer|nil): Number of retries on transient failures (default: 3).
|
||||
--- - `outpath` (string|nil): File path to save the response body to. If set, the `body` value in the Response Object will be `true` instead of the response body.
|
||||
--- @param on_response fun(err?: string, response?: { body: string|boolean }) Callback invoked on request
|
||||
--- completion. The `body` field in the response object contains the raw response data (text or binary).
|
||||
--- Called with (err, nil) on failure, or (nil, { body = string|boolean }) on success.
|
||||
--- @param opts? vim.net.request.Opts
|
||||
--- @param on_response? fun(err: string?, response: vim.net.request.Response?)
|
||||
--- Callback invoked on request completion. The `body` field in the response
|
||||
--- parameter contains the raw response data (text or binary).
|
||||
--- @return { close: fun() } # Table with method to cancel, similar to [vim.SystemObj].
|
||||
function M.request(url, opts, on_response)
|
||||
vim.validate('url', url, 'string')
|
||||
vim.validate('opts', opts, 'table', true)
|
||||
vim.validate('on_response', on_response, 'function')
|
||||
vim.validate('on_response', on_response, 'function', true)
|
||||
|
||||
opts = opts or {}
|
||||
local retry = opts.retry or 3
|
||||
@@ -37,19 +81,39 @@ function M.request(url, opts, on_response)
|
||||
|
||||
table.insert(args, url)
|
||||
|
||||
local function on_exit(res)
|
||||
local s = 'Request failed with exit code %d'
|
||||
local err_msg = res.code ~= 0
|
||||
and ((res.stderr ~= '' and res.stderr) or string.format(s, res.code))
|
||||
or nil
|
||||
local response = res.code == 0 and { body = opts.outpath and true or res.stdout } or nil
|
||||
local job = vim.system(args, {}, function(res)
|
||||
---@type string?, vim.net.request.Response?
|
||||
local err, response = nil, nil
|
||||
if res.signal ~= 0 then
|
||||
err = ('Request killed with signal %d'):format(res.signal)
|
||||
elseif res.code ~= 0 then
|
||||
err = res.stderr ~= '' and res.stderr or ('Request failed with exit code %d'):format(res.code)
|
||||
else
|
||||
if not (opts.outpath or opts.outbuf) then
|
||||
response = {
|
||||
body = res.stdout --[[@as string]],
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- nvim_buf_is_loaded and nvim_buf_set_lines are not allowed in fast context
|
||||
vim.schedule(function()
|
||||
if res.code == 0 and opts.outbuf and vim.api.nvim_buf_is_loaded(opts.outbuf) then
|
||||
local lines = vim.split(res.stdout, '\n', { plain = true })
|
||||
vim.api.nvim_buf_set_lines(opts.outbuf, 0, -1, true, lines)
|
||||
end
|
||||
end)
|
||||
|
||||
if on_response then
|
||||
on_response(err_msg, response)
|
||||
on_response(err, response)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
vim.system(args, {}, on_exit)
|
||||
return {
|
||||
close = function()
|
||||
job:kill('sigint')
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user