This commit is contained in:
Justin M. Keyes 2024-09-16 10:34:07 +00:00 committed by GitHub
commit ef5662544a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 68 additions and 53 deletions

View File

@ -97,37 +97,13 @@ do
--- Map |gx| to call |vim.ui.open| on the <cfile> at cursor. --- Map |gx| to call |vim.ui.open| on the <cfile> at cursor.
do do
local function do_open(uri)
local cmd, err = vim.ui.open(uri)
local rv = cmd and cmd:wait(1000) or nil
if cmd and rv and rv.code ~= 0 then
err = ('vim.ui.open: command %s (%d): %s'):format(
(rv.code == 124 and 'timeout' or 'failed'),
rv.code,
vim.inspect(cmd.cmd)
)
end
return err
end
local gx_desc = local gx_desc =
'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)' 'Opens filepath or URI under cursor with the system handler (file explorer, web browser, …)'
vim.keymap.set({ 'n' }, 'gx', function() vim.keymap.set({ 'n' }, 'gx', function()
for _, url in ipairs(require('vim.ui')._get_urls()) do vim.ui.open()
local err = do_open(url)
if err then
vim.notify(err, vim.log.levels.ERROR)
end
end
end, { desc = gx_desc }) end, { desc = gx_desc })
vim.keymap.set({ 'x' }, 'gx', function() vim.keymap.set({ 'x' }, 'gx', function()
local lines = vim.ui.open()
vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() })
-- Trim whitespace on each line and concatenate.
local err = do_open(table.concat(vim.iter(lines):map(vim.trim):totable()))
if err then
vim.notify(err, vim.log.levels.ERROR)
end
end, { desc = gx_desc }) end, { desc = gx_desc })
end end

View File

@ -126,7 +126,7 @@ end
--- end --- end
--- ``` --- ```
--- ---
---@param path string Path or URL to open ---@param path? string Path or URL to open, or `nil` to get path or URL at cursor.
---@param opt? { cmd?: string[] } Options ---@param opt? { cmd?: string[] } Options
--- - cmd string[]|nil Command used to open the path or URL. --- - cmd string[]|nil Command used to open the path or URL.
--- ---
@ -136,40 +136,79 @@ end
---@see |vim.system()| ---@see |vim.system()|
function M.open(path, opt) function M.open(path, opt)
vim.validate({ vim.validate({
path = { path, 'string' }, path = { path, 'string', true },
}) })
local is_uri = path:match('%w+:')
if not is_uri then
path = vim.fs.normalize(path)
end
opt = opt or {} opt = opt or {}
local cmd ---@type string[] local function do_open(uri)
local job_opt = { text = true, detach = true } --- @type vim.SystemOpts local cmd ---@type string[]
local job_opt = { text = true, detach = true } --- @type vim.SystemOpts
if opt.cmd then if opt.cmd then
cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { path }) cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { uri })
elseif vim.fn.has('mac') == 1 then elseif vim.fn.has('mac') == 1 then
cmd = { 'open', path } cmd = { 'open', uri }
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
cmd = { 'rundll32', 'url.dll,FileProtocolHandler', path } cmd = { 'rundll32', 'url.dll,FileProtocolHandler', uri }
else
return nil, 'vim.ui.open: rundll32 not found'
end
elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', uri }
job_opt.stdout = false
job_opt.stderr = false
elseif vim.fn.executable('wslview') == 1 then
cmd = { 'wslview', uri }
elseif vim.fn.executable('explorer.exe') == 1 then
cmd = { 'explorer.exe', uri }
else else
return nil, 'vim.ui.open: rundll32 not found' return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end end
elseif vim.fn.executable('xdg-open') == 1 then
cmd = { 'xdg-open', path } return vim.system(cmd, job_opt), nil
job_opt.stdout = false
job_opt.stderr = false
elseif vim.fn.executable('wslview') == 1 then
cmd = { 'wslview', path }
elseif vim.fn.executable('explorer.exe') == 1 then
cmd = { 'explorer.exe', path }
else
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end end
return vim.system(cmd, job_opt), nil local function do_open2(uri)
local cmd, err = do_open(uri)
-- wait() terminates the process if necessary (avoids stale processes), and allows us to show an
-- error message if needed.
local rv = cmd and cmd:wait(1000) or nil
if cmd and rv and rv.code ~= 0 then
err = ('vim.ui.open: command %s (%d): %s'):format(
(rv.code == 124 and 'timeout' or 'failed'),
rv.code,
vim.inspect(cmd.cmd)
)
end
return err
end
if path then
local is_uri = path:match('%w+:')
if not is_uri then
path = vim.fs.normalize(path)
end
return do_open(path)
else -- DWIM mode: get the URL or path from the cursor position, and show error.
local visual = not not vim.fn.mode():match('[vV\22]')
if visual then
local lines =
vim.fn.getregion(vim.fn.getpos('.'), vim.fn.getpos('v'), { type = vim.fn.mode() })
-- Trim whitespace on each line and concatenate.
local err = do_open2(table.concat(vim.iter(lines):map(vim.trim):totable()))
if err then
vim.notify(err, vim.log.levels.ERROR)
end
else
for _, url in ipairs(M._get_urls()) do
local err = do_open2(url)
if err then
vim.notify(err, vim.log.levels.ERROR)
end
end
end
end
end end
--- Returns all URLs at cursor, if any. --- Returns all URLs at cursor, if any.