From 662804e4b0b1467b0216438755cb024720533fac Mon Sep 17 00:00:00 2001 From: moyiz <8603313+moyiz@users.noreply.github.com> Date: Sat, 17 Jan 2026 21:49:24 +0200 Subject: [PATCH] feat(parser): handle commit ids in tree URIs --- README.md | 6 +++ lua/git-dev/init.lua | 2 +- lua/git-dev/parser.lua | 40 ++++++++++---------- tests/parser_spec.lua | 84 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 9fcf8c7..6f4a4f8 100644 --- a/README.md +++ b/README.md @@ -438,18 +438,24 @@ parsed fields. - `https://github.com/` - `https://github.com/.git` - `https://github.com//tree/` + - `https://github.com//tree/` - `https://github.com//tree/` - `https://github.com//blob/` - `https://github.com//blob//` + - `https://github.com//blob/` + - `https://github.com//blob//` - `https://github.com//blob/` - `https://github.com//blob//` - GitLab - `https://gitlab.com/` - `https://gitlab.com/.git` - `https://gitlab.com//-/tree/` + - `https://gitlab.com//-/tree/` - `https://gitlab.com//-/tree/` - `https://gitlab.com//-/blob/` - `https://gitlab.com//-/blob//` + - `https://gitlab.com//-/blob/` + - `https://gitlab.com//-/blob//` - `https://gitlab.com//-/blob/` - `https://gitlab.com//-/blob//` - Gitea diff --git a/lua/git-dev/init.lua b/lua/git-dev/init.lua index 1972b00..908d4b2 100644 --- a/lua/git-dev/init.lua +++ b/lua/git-dev/init.lua @@ -229,7 +229,7 @@ M.open = function(repo, ref, opts) or parsed_repo.commit or parsed_repo.branch - if not branch and parsed_repo.full_blob then + if not branch then ui:print "Could not detect a ref in given URI, falling back to default." end diff --git a/lua/git-dev/parser.lua b/lua/git-dev/parser.lua index 8dc33a5..8278c36 100644 --- a/lua/git-dev/parser.lua +++ b/lua/git-dev/parser.lua @@ -29,6 +29,10 @@ local function is_git_bundle(file_path) return sig == "git\001\n" end +local function is_commit_id(text) + return text:find("^" .. ("%x"):rep(40) .. "$") +end + ---@class Parser ---@field gitcmd table ---@field base_uri_format string @@ -50,7 +54,6 @@ end ---@class GitDevParsedRepo ---@field repo_url string ----@field full_blob? string ---@field commit? string ---@field branch? string ---@field selected_path? string @@ -59,10 +62,10 @@ end -- Since branch / tag might include slashes, it is impossible to determine how -- to separate it from the optional trailing file path. `git ls-remote` is used -- to find the longest ref name that can be deducted from `text`. If none is --- found, it will be tested as a commit ID. If it is invalid as a commit, it --- will be notated as `full_blob`. Otherwise, it will be separated to `branch` --- and `selected_path`. If there are no slashes, it can be assumed that the --- full blob is actually a branch / tag name, and there is no trailed file path. +-- found, it will be treated as an optionally partial commit ID and the rest of +-- the blob will be treated as a selected path. If there are no slashes, it can +-- be assumed that the full blob is actually a branch / tag name, and there is +-- no trailed file path. function Parser:parse_full_blob(text, repo_url) if not text or text == "" then return {} @@ -90,18 +93,12 @@ function Parser:parse_full_blob(text, repo_url) end ref = new_ref end - -- No such ref, first part might still be a commit ID. + -- No such ref, fallback to a commit ID (or part of it). if not ref then - -- If the first part looks like a valid commit ID, it probably is. - -- TODO: Find a better way. The repository is not cloned yet. - if parts[1]:find("^" .. ("%x"):rep(40) .. "$") then - return { - commit = parts[1], - selected_path = vim.fn.join(vim.list_slice(parts, 2), "/"), - } - else - return { full_blob = text } - end + return { + commit = parts[1], + selected_path = vim.fn.join(vim.list_slice(parts, 2), "/"), + } end -- Generate a selected path and trim leading slash. @@ -114,9 +111,14 @@ end function Parser:parse_tree_or_full_blob(text, repo_url) local res = {} - local branch_or_tag = text:match "^/tree/(.*)$" - if branch_or_tag then - res.branch = branch_or_tag + local ref = text:match "^/tree/(.*)" + if ref and ref ~= "" then + local matches = self.gitcmd:list_refs_sync(repo_url, ref) + if #matches == 0 then + res.commit = ref + else + res.branch = ref + end else -- Full blob contains both the ref and the file path. -- Due to possible branch / tag names that contain `/`, the parser cannot diff --git a/tests/parser_spec.lua b/tests/parser_spec.lua index ec575eb..da4fea3 100644 --- a/tests/parser_spec.lua +++ b/tests/parser_spec.lua @@ -11,6 +11,9 @@ T.run = function() repo_url = "https://github.com/moyiz/git-dev.nvim.git", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/heads/main" }, + }, }, { url = "https://github.com/moyiz/git-dev.nvim/tree/url-parsing", @@ -19,6 +22,9 @@ T.run = function() repo_url = "https://github.com/moyiz/git-dev.nvim.git", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/heads/url-parsing" }, + }, }, { url = "https://github.com/moyiz/git-dev.nvim/blob", @@ -62,6 +68,9 @@ T.run = function() branch = "stable", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/heads/stable" }, + }, }, { url = "https://github.com/echasnovski/mini.nvim/tree/v0.12.0", @@ -70,30 +79,45 @@ T.run = function() branch = "v0.12.0", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/tags/v0.12.0" }, + }, }, { url = "https://github.com/echasnovski/mini.nvim/blob/main/README.md", expected = { repo_url = "https://github.com/echasnovski/mini.nvim.git", - full_blob = "main/README.md", + branch = "main", + selected_path = "README.md", type = "http", }, + remote_refs = { + { id = "1", ref = "refs/heads/main" }, + }, }, { url = "https://github.com/echasnovski/mini.nvim/blob/stable/README.md", expected = { repo_url = "https://github.com/echasnovski/mini.nvim.git", - full_blob = "stable/README.md", + branch = "stable", + selected_path = "README.md", type = "http", }, + remote_refs = { + { id = "1", ref = "refs/heads/stable" }, + }, }, { url = "https://github.com/echasnovski/mini.nvim/blob/main/lua/mini/basics.lua", expected = { repo_url = "https://github.com/echasnovski/mini.nvim.git", - full_blob = "main/lua/mini/basics.lua", + branch = "main", + selected_path = "lua/mini/basics.lua", type = "http", }, + remote_refs = { + { id = "1", ref = "refs/heads/main" }, + }, }, { url = "https://github.com/echasnovski/mini.nvim/blob/0cdf41afab4f13b7529d9965cff9c3d2d67b0bfb/lua/mini/statusline.lua", @@ -112,12 +136,61 @@ T.run = function() branch = "features/reuse-only", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/heads/features/reuse-only" }, + }, }, { url = "https://github.com/spack/spack/blob/features/reuse-only/.github/dependabot.yml", expected = { repo_url = "https://github.com/spack/spack.git", - full_blob = "features/reuse-only/.github/dependabot.yml", + branch = "features/reuse-only", + selected_path = ".github/dependabot.yml", + type = "http", + }, + remote_refs = { + { commit_id = "1", ref = "refs/heads/features/reuse-only" }, + }, + }, + { + url = "https://github.com/moyiz/git-dev.nvim/tree/d5f9302226852b80f58ef13e8353fda0cd78184e", + expected = { + repo_url = "https://github.com/moyiz/git-dev.nvim.git", + commit = "d5f9302226852b80f58ef13e8353fda0cd78184e", + type = "http", + }, + }, + { + url = "https://github.com/moyiz/git-dev.nvim/tree/d5f9302226852b8", + expected = { + repo_url = "https://github.com/moyiz/git-dev.nvim.git", + commit = "d5f9302226852b8", + type = "http", + }, + }, + { + url = "https://github.com/moyiz/git-dev.nvim/tree/d5f93022", + expected = { + repo_url = "https://github.com/moyiz/git-dev.nvim.git", + commit = "d5f93022", + type = "http", + }, + }, + { + url = "https://github.com/moyiz/git-dev.nvim/blob/d5f9302226852b80f58ef13e8353fda0cd78184e/.gitignore", + expected = { + repo_url = "https://github.com/moyiz/git-dev.nvim.git", + commit = "d5f9302226852b80f58ef13e8353fda0cd78184e", + selected_path = ".gitignore", + type = "http", + }, + }, + { + url = "https://github.com/moyiz/git-dev.nvim/blob/d5f9302226852/.gitignore", + expected = { + repo_url = "https://github.com/moyiz/git-dev.nvim.git", + commit = "d5f9302226852", + selected_path = ".gitignore", type = "http", }, }, @@ -160,6 +233,9 @@ T.run = function() branch = "1.1.0", type = "http", }, + remote_refs = { + { commit_id = "1", ref = "refs/tags/1.1.0" }, + }, }, { url = "https://gitlab.com/gitlab-org/code-creation/repository-x-ray/-/blob/010e6076637568b291b7563e089175130ce72369/cmd/scan/main.go",