diff --git a/runtime/plugin/net.lua b/runtime/plugin/net.lua index f088a8b58a..ac3700ee26 100644 --- a/runtime/plugin/net.lua +++ b/runtime/plugin/net.lua @@ -6,6 +6,32 @@ vim.g.loaded_nvim_net_plugin = true local augroup = vim.api.nvim_create_augroup('nvim.net.remotefile', {}) local url_patterns = { 'http://*', 'https://*' } +local archive_patterns = { + { suffix = '.tar.gz', kind = 'tar' }, + { suffix = '.tar.bz2', kind = 'tar' }, + { suffix = '.tar.xz', kind = 'tar' }, + { suffix = '.txz', kind = 'tar' }, + { suffix = '.tar', kind = 'tar' }, + { suffix = '.zip', kind = 'zip' }, +} + +---@param url string +---@return string +local function url_path(url) + return (url:gsub('[?#].*$', '')) +end + +---@param url string +---@return 'zip'|'tar'? +local function archive_type(url) + local path = url_path(url) + for _, pattern in ipairs(archive_patterns) do + if vim.endswith(path, pattern.suffix) then + return pattern.kind + end + end +end + vim.api.nvim_create_autocmd('BufReadCmd', { group = augroup, pattern = url_patterns, @@ -17,8 +43,36 @@ vim.api.nvim_create_autocmd('BufReadCmd', { end local url = ev.file + local archive_kind = archive_type(url) + vim.notify(('Fetching %s …'):format(url), vim.log.levels.INFO) + if archive_kind then + -- XXX: zipPlugin.vim, tarPlugin.vim don't work with non-file buffers. + local tmpfile = vim.fn.tempname() + + vim.net.request( + url, + { outpath = tmpfile }, + vim.schedule_wrap(function(err) + if err then + vim.notify(('Failed to fetch %s: %s'):format(url, err), vim.log.levels.ERROR) + return + end + + if archive_kind == 'zip' then + vim.fn['zip#Browse'](tmpfile) + else + vim.fn['tar#Browse'](tmpfile) + end + + vim.bo[ev.buf].modified = false + vim.notify(('Loaded %s'):format(url), vim.log.levels.INFO) + end) + ) + return + end + vim.net.request( url, { outbuf = ev.buf }, diff --git a/test/functional/lua/net_spec.lua b/test/functional/lua/net_spec.lua index 253f7c30d4..2057ce3331 100644 --- a/test/functional/lua/net_spec.lua +++ b/test/functional/lua/net_spec.lua @@ -113,4 +113,54 @@ describe('vim.net.request', function() t.eq(true, content[1]:find('Here') ~= nil) t.eq(true, content[2]:find('html') ~= nil) end) + + it('opens remote tar.gz URLs as tar archives', function() + t.skip(skip_integ, 'NVIM_TEST_INTEG not set: skipping network integration test') + + local rv = exec_lua([[ + vim.cmd('runtime! plugin/net.lua') + vim.cmd('runtime! plugin/tarPlugin.vim') + + vim.cmd('edit https://github.com/neovim/neovim/releases/download/nightly/nvim-macos-x86_64.tar.gz') + + vim.wait(2500, function() + return vim.bo.filetype == 'tar' or vim.b.tarfile ~= nil + end) + + return { + filetype = vim.bo.filetype, + modified = vim.bo.modified, + tarfile = vim.b.tarfile ~= nil, + } + ]]) + + t.eq('tar', rv.filetype) + t.eq(false, rv.modified) + t.eq(true, rv.tarfile) + end) + + it('opens remote zip URLs as zip archives', function() + t.skip(skip_integ, 'NVIM_TEST_INTEG not set: skipping network integration test') + + local rv = exec_lua([[ + vim.cmd('runtime! plugin/net.lua') + vim.cmd('runtime! plugin/zipPlugin.vim') + + vim.cmd('edit https://github.com/neovim/neovim/releases/download/nightly/nvim-win-arm64.zip') + + vim.wait(2500, function() + return vim.bo.filetype == 'zip' or vim.b.zipfile ~= nil + end) + + return { + filetype = vim.bo.filetype, + modified = vim.bo.modified, + zipfile = vim.b.zipfile ~= nil, + } + ]]) + + t.eq('zip', rv.filetype) + t.eq(false, rv.modified) + t.eq(true, rv.zipfile) + end) end)