mirror of
https://github.com/folke/snacks.nvim
synced 2025-07-07 21:25:11 +00:00
This commit is contained in:
parent
42e3a25d95
commit
92da87c910
2 changed files with 61 additions and 23 deletions
|
@ -18,9 +18,11 @@ local defaults = {
|
|||
end
|
||||
vim.ui.open(url)
|
||||
end,
|
||||
---@type "repo" | "branch" | "file"
|
||||
what = "file", -- what to open. not all remotes support all types
|
||||
-- patterns to transform remotes to an actual URL
|
||||
-- stylua: ignore
|
||||
patterns = {
|
||||
remote_patterns = {
|
||||
{ "^(https?://.*)%.git$" , "%1" },
|
||||
{ "^git@(.+):(.+)%.git$" , "https://%1/%2" },
|
||||
{ "^git@(.+):(.+)$" , "https://%1/%2" },
|
||||
|
@ -34,48 +36,84 @@ local defaults = {
|
|||
{ ":%d+" , "" },
|
||||
{ "%.git$" , "" },
|
||||
},
|
||||
url_patterns = {
|
||||
["github.com"] = {
|
||||
branch = "/tree/{branch}",
|
||||
file = "/blob/{branch}/{file}#L{line}",
|
||||
},
|
||||
["gitlab.com"] = {
|
||||
branch = "/-/tree/{branch}",
|
||||
file = "/-/blob/{branch}/{file}#L{line}",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
---@private
|
||||
---@param remote string
|
||||
---@param opts? snacks.gitbrowse.Config
|
||||
function M.get_url(remote, opts)
|
||||
function M.get_repo(remote, opts)
|
||||
opts = Snacks.config.get("gitbrowse", defaults, opts)
|
||||
local ret = remote
|
||||
for _, pattern in ipairs(opts.patterns) do
|
||||
ret = ret:gsub(pattern[1], pattern[2])
|
||||
for _, pattern in ipairs(opts.remote_patterns) do
|
||||
ret = ret:gsub(pattern[1], pattern[2]) --[[@as string]]
|
||||
end
|
||||
return ret:find("https://") == 1 and ret or ("https://%s"):format(ret)
|
||||
end
|
||||
|
||||
---@param repo string
|
||||
---@param opts? snacks.gitbrowse.Config
|
||||
function M.get_url(repo, opts)
|
||||
opts = Snacks.config.get("gitbrowse", defaults, opts)
|
||||
for remote, patterns in pairs(opts.url_patterns) do
|
||||
if repo:find(remote) then
|
||||
return patterns[opts.what] and (repo .. patterns[opts.what]) or repo
|
||||
end
|
||||
end
|
||||
return repo
|
||||
end
|
||||
|
||||
---@param cmd string[]
|
||||
---@param err string
|
||||
local function system(cmd, err)
|
||||
local proc = vim.system(cmd, { text = true }):wait()
|
||||
if proc.code ~= 0 then
|
||||
Snacks.notify.error({ err, proc.stderr, proc.stdout }, { title = "Git Browse" })
|
||||
error(err)
|
||||
end
|
||||
return vim.split(vim.trim(proc.stdout), "\n")
|
||||
end
|
||||
|
||||
---@param opts? snacks.gitbrowse.Config
|
||||
function M.open(opts)
|
||||
opts = Snacks.config.get("gitbrowse", defaults, opts)
|
||||
local proc = vim.system({ "git", "remote", "-v" }, { text = true }):wait()
|
||||
if proc.code ~= 0 then
|
||||
return Snacks.notify.error("Failed to get git remotes", { title = "Git Browse" })
|
||||
end
|
||||
local lines = vim.split(proc.stdout, "\n")
|
||||
pcall(M._open, opts) -- errors are handled with notifications
|
||||
end
|
||||
|
||||
proc = vim.system({ "git", "rev-parse", "--abbrev-ref", "HEAD" }):wait()
|
||||
if proc.code ~= 0 then
|
||||
return Snacks.notify.error("Failed to get current branch", { title = "Git Browse" })
|
||||
end
|
||||
local branch = proc.stdout:gsub("\n", "")
|
||||
---@param opts? snacks.gitbrowse.Config
|
||||
function M._open(opts)
|
||||
opts = Snacks.config.get("gitbrowse", defaults, opts)
|
||||
local file = vim.api.nvim_buf_get_name(0) ---@type string?
|
||||
file = file and (vim.uv.fs_stat(file) or {}).type == "file" and vim.fs.normalize(file) or nil
|
||||
local cwd = file and vim.fn.fnamemodify(file, ":h") or vim.fn.getcwd()
|
||||
local fields = {
|
||||
branch = system({ "git", "-C", cwd, "rev-parse", "--abbrev-ref", "HEAD" }, "Failed to get current branch")[1],
|
||||
file = file and system({ "git", "-C", cwd, "ls-files", "--full-name", file }, "Failed to get git file path")[1],
|
||||
line = file and vim.fn.line("."),
|
||||
}
|
||||
opts.what = opts.what == "file" and not fields.file and "branch" or opts.what
|
||||
opts.what = opts.what == "branch" and not fields.branch and "repo" or opts.what
|
||||
|
||||
local remotes = {} ---@type {name:string, url:string}[]
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
for _, line in ipairs(system({ "git", "-C", cwd, "remote", "-v" }, "Failed to get git remotes")) do
|
||||
local name, remote = line:match("(%S+)%s+(%S+)%s+%(fetch%)")
|
||||
if name and remote then
|
||||
local url = M.get_url(remote, opts)
|
||||
if url:find("github") and branch and branch ~= "master" and branch ~= "main" then
|
||||
url = ("%s/tree/%s"):format(url, branch)
|
||||
end
|
||||
if url then
|
||||
local repo = M.get_repo(remote, opts)
|
||||
if repo then
|
||||
table.insert(remotes, {
|
||||
name = name,
|
||||
url = url,
|
||||
url = M.get_url(repo, opts):gsub("(%b{})", function(key)
|
||||
return fields[key:sub(2, -2)] or key
|
||||
end),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ local git_remotes_cases = {
|
|||
describe("util.lazygit", function()
|
||||
for remote, expected in pairs(git_remotes_cases) do
|
||||
it("should parse git remote " .. remote, function()
|
||||
local url = gitbrowse.get_url(remote)
|
||||
local url = gitbrowse.get_repo(remote)
|
||||
assert.are.equal(expected, url)
|
||||
end)
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue