neovim
neovim copied to clipboard
feat(lua): add minimal vim.net.download wrapper using curl
This PR introduces a minimal vim.net.download() implementation as a simple wrapper around curl, following the approach suggested in this comment.
The goal is to start small and provide the foundational download functionality first and then add more advanced features (e.g. authentication, headers, proxy support) in future PRs.
This PR is related to issue #23232
Implementation
- Uses
vim.system()withcurlto perform the download. - Automatically adds --retry
, --location (follow redirects) and --output plus the URL. - Accepts an
optstable and an optionalon_exitcallback. - If you pass an
on_exitcallback, it runs in the background and invokeson_exit(err or nil)when done. - If no callback is given, it blocks until completion and returns
trueon success orfalse, errmsgon failure.
Proposed API Usage
-
Basic synchronous download:
local ok, err = vim.net.download("https://httpbingo.org/anything", "./anything.txt") if not ok then print("Download failed:", err) end -
Synchronous with custom options:
local ok, err = vim.net.download("https://httpbingo.org/anything", "./anything.txt", { verbose = true, retry = 5, } ) if ok then print("Done") else print("Error:", err) end -
Asynchronous with callback
vim.net.download("https://httpbingo.org/anything", "./anything.txt", { retry = 2 }, function(err) if err then print("Download failed:", err) else print("Download successful!") end end)
Next Steps
After initial feedback, the implementation can be extended incrementally, adding vim.net.request() or broader curl options support in follow-up PRs.
Needs docs and a news entry. It would help if the proposed API (for several representative use cases) was added to the PR description.
We should also add a health check for this (like we do for rg); see https://github.com/nvim-treesitter/nvim-treesitter/blob/e0d029bfdc1ea0da00356203b5afbe70ca9c74c1/lua/nvim-treesitter/health.lua#L87-L93
Here it's important to show the full version output, including all build flags (since there are severely gimped curl versions out there that can lead to hard to diagnose problems). We possibly want to also print all relevant environment variables that affect curl operations.
You need to add the new module to https://github.com/neovim/neovim/blob/59c45b22d9616cda448b3c3dddd3e9274c830ca3/src/gen/gen_vimdoc.lua#L135
You need to add the new module to
https://github.com/neovim/neovim/blob/59c45b22d9616cda448b3c3dddd3e9274c830ca3/src/gen/gen_vimdoc.lua#L135
Thank you! I’ve been struggling to get the docs right (embarrassingly).
On my side I still have pending
verboseflag (agree on this one for sure)retryflag (idem)
@clason Sorry to bother, but could you guide me a bit on the current CI issue? For some reason it's only failing on the test / ubuntu asan clang unittest unit tests...
Shouldn't something like this at least support a progress report and cancellation mechanism? Otherwise, plugin authors will end up reinventing a more functional version of this function anyway
As a plugin author, I don't need it. Let's keep this to MVP.
would it be possible to also introduce an auth flag via either to authenticate using either basic auth or via token ?
Either that or an option to provide extra arguments directly to curl
No, at least not in this PR. You can (and should) use environment variables for local configuration.
Reminder: This is meant to be a simple function mainly for the (internal!) purpose of downloading spell files, WASM parsers, and bootstrapping plugin managers. It is not meant to replace every vim.system call to curl, otherwise it'll end up with the exact same complexity and nothing is gained. So "advanced usage" like that is out of scope here and will require a manual vim.system call (which is easy enough). What exactly "advanced" means can be discussed, but not here -- this PR is strictly scoped to the minimal set of flags required for the stated purpose.
Hello, in the last push I implemented as per the feedback:
- async/sync behaviour based on the
on_exitargument along the corresponding functional tests - health check for env vars upper or lowercase as per curl documentation
I see that is failing on test/functional/terminal/tui_spec.lua for mac os intel, any help with that?
for the (internal!) purpose of downloading spell files, WASM parsers
Sorry if this is off-topic, but does that mean Nvim has plan to include the plugin nvim-treesitter by default?
As mentioned in https://github.com/neovim/neovim/pull/34140#issuecomment-2984316759 , I suggest starting with a vim.net.fetch() which, at first, might only do the basic "download" case, while keep the door open to expand it later.
The parameters of the proposed request() and download() already look nearly the same. So that suggests that we have a basic interface that allows future expansion. And they don't need to be separate functions.
I suggest starting with a vim.net.fetch() which, at first, might only do the basic "download" case, while keep the door open to expand it later.
But isn't that exactly what this PR does (modulo fetch vs. download) naming? I don't understand why you closed this.
Either this PR or https://github.com/neovim/neovim/pull/34140 should be closed. We don't need two separate interfaces until proven otherwise.
Either this PR or https://github.com/neovim/neovim/pull/34140 should be closed. We don't need two separate interfaces until proven otherwise.
Yes we do -- one high-level function for downloading stuff and one (possibly private) low-level function driving :e. I thought that was what you wanted?
I've said to "start with a basic download functionality", but I didn't mean to later add a different non-basic function. I meant that the function (vim.net.fetch()) is, initially, providing a simple feature, and later the same function can be expanded to do more complex things.
I don't think that's a good idea (that's exactly what killed the last attempt!) but will hold my peace from here on out. It's all yours.
Hi all, I'm closing this PR in favor of #34140, which consolidates download and fetch into a single vim.net.request() API. Thanks for the feedback here, please continue discussion over there!