Merge #29490 feat(vim.ui.open): configurable opener

This commit is contained in:
Justin M. Keyes 2024-09-16 03:21:40 -07:00 committed by GitHub
commit 549c00c791
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 46 additions and 11 deletions

View File

@ -2559,7 +2559,7 @@ vim.ui.input({opts}, {on_confirm}) *vim.ui.input()*
typed (it might be an empty string if nothing was typed (it might be an empty string if nothing was
entered), or `nil` if the user aborted the dialog. entered), or `nil` if the user aborted the dialog.
vim.ui.open({path}) *vim.ui.open()* vim.ui.open({path}, {opt}) *vim.ui.open()*
Opens `path` with the system default handler (macOS `open`, Windows Opens `path` with the system default handler (macOS `open`, Windows
`explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an `explorer.exe`, Linux `xdg-open`, …), or returns (but does not show) an
error message on failure. error message on failure.
@ -2570,6 +2570,8 @@ vim.ui.open({path}) *vim.ui.open()*
-- Asynchronous. -- Asynchronous.
vim.ui.open("https://neovim.io/") vim.ui.open("https://neovim.io/")
vim.ui.open("~/path/to/file") vim.ui.open("~/path/to/file")
-- Use the "osurl" command to handle the path or URL.
vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } })
-- Synchronous (wait until the process exits). -- Synchronous (wait until the process exits).
local cmd, err = vim.ui.open("$VIMRUNTIME") local cmd, err = vim.ui.open("$VIMRUNTIME")
if cmd then if cmd then
@ -2579,6 +2581,8 @@ vim.ui.open({path}) *vim.ui.open()*
Parameters: ~ Parameters: ~
• {path} (`string`) Path or URL to open • {path} (`string`) Path or URL to open
• {opt} (`{ cmd?: string[] }?`) Options
• cmd string[]|nil Command used to open the path or URL.
Return (multiple): ~ Return (multiple): ~
(`vim.SystemObj?`) Command object, or nil if not found. (`vim.SystemObj?`) Command object, or nil if not found.

View File

@ -194,7 +194,10 @@ TUI
UI UI
• TODO • |vim.ui.open()| (by default bound to |gx|) accepts an `opt.cmd` parameter
which controls the tool used to open the given path or URL. If you want to
globally set this, you can override vim.ui.open using the same approach
described at |vim.paste()|.
============================================================================== ==============================================================================
CHANGED FEATURES *news-changed* CHANGED FEATURES *news-changed*

View File

@ -117,6 +117,8 @@ end
--- -- Asynchronous. --- -- Asynchronous.
--- vim.ui.open("https://neovim.io/") --- vim.ui.open("https://neovim.io/")
--- vim.ui.open("~/path/to/file") --- vim.ui.open("~/path/to/file")
--- -- Use the "osurl" command to handle the path or URL.
--- vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } })
--- -- Synchronous (wait until the process exits). --- -- Synchronous (wait until the process exits).
--- local cmd, err = vim.ui.open("$VIMRUNTIME") --- local cmd, err = vim.ui.open("$VIMRUNTIME")
--- if cmd then --- if cmd then
@ -125,12 +127,14 @@ end
--- ``` --- ```
--- ---
---@param path string Path or URL to open ---@param path string Path or URL to open
---@param opt? { cmd?: string[] } Options
--- - cmd string[]|nil Command used to open the path or URL.
--- ---
---@return vim.SystemObj|nil # Command object, or nil if not found. ---@return vim.SystemObj|nil # Command object, or nil if not found.
---@return nil|string # Error message on failure, or nil on success. ---@return nil|string # Error message on failure, or nil on success.
--- ---
---@see |vim.system()| ---@see |vim.system()|
function M.open(path) function M.open(path, opt)
vim.validate({ vim.validate({
path = { path, 'string' }, path = { path, 'string' },
}) })
@ -139,12 +143,13 @@ function M.open(path)
path = vim.fs.normalize(path) path = vim.fs.normalize(path)
end end
local cmd --- @type string[] opt = opt or {}
local opts --- @type vim.SystemOpts local cmd ---@type string[]
local job_opt = { text = true, detach = true } --- @type vim.SystemOpts
opts = { text = true, detach = true } if opt.cmd then
cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { path })
if vim.fn.has('mac') == 1 then elseif vim.fn.has('mac') == 1 then
cmd = { 'open', path } cmd = { 'open', path }
elseif vim.fn.has('win32') == 1 then elseif vim.fn.has('win32') == 1 then
if vim.fn.executable('rundll32') == 1 then if vim.fn.executable('rundll32') == 1 then
@ -154,8 +159,8 @@ function M.open(path)
end end
elseif vim.fn.executable('xdg-open') == 1 then elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', path } cmd = { 'xdg-open', path }
opts.stdout = false job_opt.stdout = false
opts.stderr = false job_opt.stderr = false
elseif vim.fn.executable('wslview') == 1 then elseif vim.fn.executable('wslview') == 1 then
cmd = { 'wslview', path } cmd = { 'wslview', path }
elseif vim.fn.executable('explorer.exe') == 1 then elseif vim.fn.executable('explorer.exe') == 1 then
@ -164,7 +169,7 @@ function M.open(path)
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)' return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end end
return vim.system(cmd, opts), nil return vim.system(cmd, job_opt), nil
end end
--- Returns all URLs at cursor, if any. --- Returns all URLs at cursor, if any.

View File

@ -157,5 +157,28 @@ describe('vim.ui', function()
exec_lua [[local _, err = vim.ui.open('foo') ; return err]] exec_lua [[local _, err = vim.ui.open('foo') ; return err]]
) )
end) end)
it('opt.cmd #29490', function()
t.matches(
'ENOENT: no such file or directory',
t.pcall_err(exec_lua, function()
vim.ui.open('foo', { cmd = { 'non-existent-tool' } })
end)
)
eq(
{
code = 0,
signal = 0,
stderr = '',
stdout = 'arg1=arg1;arg2=https://example.com;',
},
exec_lua(function(cmd_)
local cmd, err = vim.ui.open('https://example.com', { cmd = cmd_ })
assert(cmd and not err)
return cmd:wait()
end, { n.testprg('printargs-test'), 'arg1' })
)
end)
end) end)
end) end)