aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/ui.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/ui.lua')
-rw-r--r--runtime/lua/vim/ui.lua94
1 files changed, 72 insertions, 22 deletions
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
index 99b9b78e2a..532decf5e9 100644
--- a/runtime/lua/vim/ui.lua
+++ b/runtime/lua/vim/ui.lua
@@ -117,6 +117,8 @@ end
--- -- Asynchronous.
--- vim.ui.open("https://neovim.io/")
--- 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).
--- local cmd, err = vim.ui.open("$VIMRUNTIME")
--- if cmd then
@@ -125,23 +127,29 @@ end
--- ```
---
---@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 nil|string # Error message on failure, or nil on success.
---
---@see |vim.system()|
-function M.open(path)
+function M.open(path, opt)
vim.validate({
path = { path, 'string' },
})
local is_uri = path:match('%w+:')
if not is_uri then
- path = vim.fn.expand(path)
+ path = vim.fs.normalize(path)
end
- local cmd --- @type string[]
+ opt = opt or {}
+ local cmd ---@type string[]
+ local job_opt = { text = true, detach = true } --- @type vim.SystemOpts
- if vim.fn.has('mac') == 1 then
+ if opt.cmd then
+ cmd = vim.list_extend(opt.cmd --[[@as string[] ]], { path })
+ elseif vim.fn.has('mac') == 1 then
cmd = { 'open', path }
elseif vim.fn.has('win32') == 1 then
if vim.fn.executable('rundll32') == 1 then
@@ -149,37 +157,79 @@ function M.open(path)
else
return nil, 'vim.ui.open: rundll32 not found'
end
+ elseif vim.fn.executable('xdg-open') == 1 then
+ cmd = { 'xdg-open', path }
+ 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 }
- elseif vim.fn.executable('xdg-open') == 1 then
- cmd = { 'xdg-open', path }
else
return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)'
end
- return vim.system(cmd, { text = true, detach = true }), nil
+ return vim.system(cmd, job_opt), nil
end
---- Gets the URL at cursor, if any.
-function M._get_url()
- if vim.bo.filetype == 'markdown' then
- local range = vim.api.nvim_win_get_cursor(0)
- vim.treesitter.get_parser():parse(range)
- -- marking the node as `markdown_inline` is required. Setting it to `markdown` does not
- -- work.
- local current_node = vim.treesitter.get_node { lang = 'markdown_inline' }
- while current_node do
- local type = current_node:type()
- if type == 'inline_link' or type == 'image' then
- local child = assert(current_node:named_child(1))
- return vim.treesitter.get_node_text(child, 0)
+--- Returns all URLs at cursor, if any.
+--- @return string[]
+function M._get_urls()
+ local urls = {} ---@type string[]
+
+ local bufnr = vim.api.nvim_get_current_buf()
+ local cursor = vim.api.nvim_win_get_cursor(0)
+ local row = cursor[1] - 1
+ local col = cursor[2]
+ local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, -1, { row, col }, { row, col }, {
+ details = true,
+ type = 'highlight',
+ overlap = true,
+ })
+ for _, v in ipairs(extmarks) do
+ local details = v[4]
+ if details and details.url then
+ urls[#urls + 1] = details.url
+ end
+ end
+
+ local highlighter = vim.treesitter.highlighter.active[bufnr]
+ if highlighter then
+ local range = { row, col, row, col }
+ local ltree = highlighter.tree:language_for_range(range)
+ local lang = ltree:lang()
+ local query = vim.treesitter.query.get(lang, 'highlights')
+ if query then
+ local tree = assert(ltree:tree_for_range(range))
+ for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1) do
+ for id, nodes in pairs(match) do
+ for _, node in ipairs(nodes) do
+ if vim.treesitter.node_contains(node, range) then
+ local url = metadata[id] and metadata[id].url
+ if url and match[url] then
+ for _, n in ipairs(match[url]) do
+ urls[#urls + 1] =
+ vim.treesitter.get_node_text(n, bufnr, { metadata = metadata[url] })
+ end
+ end
+ end
+ end
+ end
end
- current_node = current_node:parent()
end
end
- return vim.fn.expand('<cfile>')
+
+ if #urls == 0 then
+ -- If all else fails, use the filename under the cursor
+ table.insert(
+ urls,
+ vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function()
+ return vim.fn.expand('<cfile>')
+ end)
+ )
+ end
+
+ return urls
end
return M