From a9c89bcbf69a3d0ef47f324a47ff6eb482467e70 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 11:55:20 +0200 Subject: fix(gx): allow `@` in url This will make `gx` work for links for the form https://hachyderm.io/@neovim. --- runtime/lua/vim/ui.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 99b9b78e2a..f168da4955 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -179,7 +179,13 @@ function M._get_url() current_node = current_node:parent() end end - return vim.fn.expand('') + + local old_isfname = vim.o.isfname + vim.cmd [[set isfname+=@-@]] + local url = vim.fn.expand('') + vim.o.isfname = old_isfname + + return url end return M -- cgit From aa6b9c677d83d76d448c3bb0973bf8d14bfdf922 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 8 Jun 2024 21:40:18 +0200 Subject: refactor: use `vim._with` where possible This mostly means replacing `nvim_buf_call` and `nvim_win_call` with `vim._with`. --- runtime/lua/vim/ui.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index f168da4955..ec5c5c5ba0 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -180,10 +180,9 @@ function M._get_url() end end - local old_isfname = vim.o.isfname - vim.cmd [[set isfname+=@-@]] - local url = vim.fn.expand('') - vim.o.isfname = old_isfname + local url = vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function() + return vim.fn.expand('') + end) return url end -- cgit From 487f44a6c14f83a4f80a4d03a4a8c16ad690927a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 9 Jul 2024 19:17:50 +0800 Subject: fix(lua): change some vim.fn.expand() to vim.fs.normalize() (#29583) Unlike vim.fn.expand(), vim.fs.normalize() doesn't expand wildcards. --- runtime/lua/vim/ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index ec5c5c5ba0..79638a044a 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -136,7 +136,7 @@ function M.open(path) }) 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[] -- cgit From 65a703e06063c85c3dd5fdb3ad4e1207a622ef30 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 12 Aug 2024 01:03:48 -0600 Subject: fix(lua): ignore stdout and stderr for xdg-open Ref #19724 Fix #29932 --- runtime/lua/vim/ui.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 79638a044a..dccdbf32cc 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -140,6 +140,9 @@ function M.open(path) end local cmd --- @type string[] + local opts --- @type vim.SystemOpts + + opts = { text = true, detach = true } if vim.fn.has('mac') == 1 then cmd = { 'open', path } @@ -155,11 +158,13 @@ function M.open(path) cmd = { 'explorer.exe', path } elseif vim.fn.executable('xdg-open') == 1 then cmd = { 'xdg-open', path } + opts.stdout = false + opts.stderr = false 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, opts), nil end --- Gets the URL at cursor, if any. -- cgit From 9762c5e3406cab8152d8dd161c0178965d841676 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 31 Aug 2024 19:56:20 -0500 Subject: feat(ui): gx: use url extmark attribute and tree-sitter directive (#30192) Use the "url" extmark attribute as well as the "url" tree-sitter metadata key to determine if the cursor is over something Nvim considers a URL. --- runtime/lua/vim/ui.lua | 70 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 18 deletions(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index dccdbf32cc..b831a4f23e 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -167,29 +167,63 @@ function M.open(path) return vim.system(cmd, opts), 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 = {} + + 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.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 = ltree:tree_for_range(range) + for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1, { all = true }) 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[url]) + end + end + end + end + end end - current_node = current_node:parent() end end - local url = vim._with({ go = { isfname = vim.o.isfname .. ',@-@' } }, function() - return vim.fn.expand('') - end) + 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('') + end) + ) + end - return url + return urls end return M -- cgit From 318c0415d5b10b44fee4afa06994734f1beb7e71 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 1 Sep 2024 12:15:02 -0500 Subject: fix(ui): correctly pass metadata to get_node_text #30222 Fixes: #30220 --- runtime/lua/vim/ui.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index b831a4f23e..c2b19e92c0 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -170,7 +170,7 @@ end --- Returns all URLs at cursor, if any. --- @return string[] function M._get_urls() - local urls = {} + local urls = {} ---@type string[] local bufnr = vim.api.nvim_get_current_buf() local cursor = vim.api.nvim_win_get_cursor(0) @@ -183,7 +183,7 @@ function M._get_urls() }) for _, v in ipairs(extmarks) do local details = v[4] - if details.url then + if details and details.url then urls[#urls + 1] = details.url end end @@ -195,7 +195,7 @@ function M._get_urls() local lang = ltree:lang() local query = vim.treesitter.query.get(lang, 'highlights') if query then - local tree = ltree:tree_for_range(range) + local tree = assert(ltree:tree_for_range(range)) for _, match, metadata in query:iter_matches(tree:root(), bufnr, row, row + 1, { all = true }) do for id, nodes in pairs(match) do for _, node in ipairs(nodes) do @@ -203,7 +203,8 @@ function M._get_urls() 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[url]) + urls[#urls + 1] = + vim.treesitter.get_node_text(n, bufnr, { metadata = metadata[url] }) end end end -- cgit From 6913c5e1d975a11262d08b3339d50b579e6b6bb8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:01:53 -0500 Subject: feat(treesitter)!: default to correct behavior for quantified captures (#30193) For context, see https://github.com/neovim/neovim/pull/24738. Before that PR, Nvim did not correctly handle captures with quantifiers. That PR made the correct behavior opt-in to minimize breaking changes, with the intention that the correct behavior would eventually become the default. Users can still opt-in to the old (incorrect) behavior for now, but this option will eventually be removed completely. BREAKING CHANGE: Any plugin which uses `Query:iter_matches()` must update their call sites to expect an array of nodes in the `match` table, rather than a single node. --- runtime/lua/vim/ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index c2b19e92c0..2d3b828ea1 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -196,7 +196,7 @@ function M._get_urls() 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, { all = true }) do + 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 -- cgit From d338ec9cb299ca300e732da643616121361006cf Mon Sep 17 00:00:00 2001 From: Yi Ming Date: Sun, 8 Sep 2024 05:14:37 +0800 Subject: fix(vim.ui.open): prefer xdg-open on WSL #30302 xdg-open is usually not installed in WSL. But if the user deliberately installs it, presumably they want to prioritize it. --- runtime/lua/vim/ui.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 2d3b828ea1..3617e1d702 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -152,14 +152,14 @@ function M.open(path) else return nil, 'vim.ui.open: rundll32 not found' end - 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 } opts.stdout = false opts.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 -- cgit From 3f15e57b2614c7849c5bbc1f32c7bd90f2a917b6 Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Wed, 26 Jun 2024 14:59:46 +0200 Subject: feat(vim.ui): configurable "gx" / vim.ui.open() tool Problem: User cannot configure the tool used by `vim.ui.open` (or `gx`). With netrw this was supported by `g:netrw_browsex_viewer`. Solution: Introduce `opts.cmd`. Users that want to set this globally can monkey-patch `vim.ui.open` in the same way described at `:help vim.paste()`. Fixes https://github.com/neovim/neovim/issues/29488 Co-authored-by: Justin M. Keyes --- runtime/lua/vim/ui.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/ui.lua') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 3617e1d702..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,12 +127,14 @@ 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' }, }) @@ -139,12 +143,13 @@ function M.open(path) path = vim.fs.normalize(path) end - local cmd --- @type string[] - local opts --- @type vim.SystemOpts + opt = opt or {} + local cmd ---@type string[] + local job_opt = { text = true, detach = true } --- @type vim.SystemOpts - opts = { text = true, detach = true } - - 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 @@ -154,8 +159,8 @@ function M.open(path) end elseif vim.fn.executable('xdg-open') == 1 then cmd = { 'xdg-open', path } - opts.stdout = false - opts.stderr = false + 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 @@ -164,7 +169,7 @@ function M.open(path) return nil, 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)' end - return vim.system(cmd, opts), nil + return vim.system(cmd, job_opt), nil end --- Returns all URLs at cursor, if any. -- cgit