Skip to content

Commit

Permalink
Merge pull request #13
Browse files Browse the repository at this point in the history
Extract port from uri
  • Loading branch information
ruifm authored Apr 27, 2021
2 parents 48ee2c8 + 48c0103 commit 17894da
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 147 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,18 @@ function that constructs the url and receives:
``` lua
url_data = {
host = "<host.tld>",
port = "3000" or nil,
repo = "<user/repo>",
file = "<path/to/file/from/repo/root>",
lstart = 42, -- the line start of the selected range / current line
lend 57, -- the line end of the selected range
}
```

`port` will always be `nil` except when the remote URI configured locally is
http(s) **and specifies a port** (e.g. `http://localhost:3000/user/repo.git`),
in which case the generated url permalink also needs the right port.

`lstart` and `lend` can be `nil` in case normal mode was used or
`opts.add_current_line_on_normal_mode = false`. Do not forget to check
for that in your callback.
Expand All @@ -145,11 +150,11 @@ it’s already builtin**, it’s just an example):
``` lua
callbacks = {
["github.com"] = function(url_data)
local url = "https://" .. url_data.host .. "/" .. url_data.repo .. "/blob/" ..
url_data.rev .. "/" .. url_data.file
local url = require"gitlinker.hosts".get_base_https_url(url_data) ..
url_data.repo .. "/blob/" .. url_data.rev .. "/" .. url_data.file
if url_data.lstart then
url = url .. "#L" .. url_data.lstart
if url_data.lend then url = url .. "-L" .. url_data.lend end
url = url .. "#L" .. url_data.lstart
if url_data.lend then url = url .. "-L" .. url_data.lend end
end
return url
end
Expand Down
13 changes: 9 additions & 4 deletions doc/gitlinker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,18 @@ function that constructs the url and receives:
>
url_data = {
host = "<host.tld>",
port = "3000" -- port number or nil,
repo = "<user/repo>",
file = "<path/to/file/from/repo/root>",
lstart = 42, -- the line start of the selected range / current line
lend 57, -- the line end of the selected range
}
<

`port` will always be `nil` except when the remote URI configured locally is
http(s) **and specifies a port** (e.g. `http://localhost:3000/user/repo.git`),
in which case the generated url permalink also needs the right port.

`lstart` and `lend` can be `nil` in case normal mode was used or
`opts.add_current_line_on_normal_mode = false`. Do not forget to check
for that in your callback.
Expand All @@ -138,11 +143,11 @@ it’s already builtin, it’s just an example):
>
callbacks = {
["github.com"] = function(url_data)
local url = "https://" .. url_data.host .. "/" .. url_data.repo .. "/blob/" ..
url_data.rev .. "/" .. url_data.file
local url = require"gitlinker.hosts".get_base_https_url(url_data) ..
url_data.repo .. "/blob/" .. url_data.rev .. "/" .. url_data.file
if url_data.lstart then
url = url .. "#L" .. url_data.lstart
if url_data.lend then url = url .. "-L" .. url_data.lend end
url = url .. "#L" .. url_data.lstart
if url_data.lend then url = url .. "-L" .. url_data.lend end
end
return url
end
Expand Down
3 changes: 2 additions & 1 deletion lua/gitlinker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ local function get_url_data(mode)
local remote = opts.remote or git.get_branch_remote()
if not remote then return nil end

local repo = git.get_repo(remote)
local repo = git.get_repo_data(remote)
if not repo or vim.tbl_isempty(repo) then return nil end

local buf_repo_path = buffer.get_relative_path(git.get_git_root())
Expand All @@ -57,6 +57,7 @@ local function get_url_data(mode)
return {
host = repo.host,
repo = repo.path,
port = repo.port,
rev = rev,
file = buf_repo_path,
lstart = range.lstart,
Expand Down
81 changes: 62 additions & 19 deletions lua/gitlinker/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -70,43 +70,86 @@ local function is_rev_in_remote(revspec, remote)
return is_in_remote
end

local function parse_uri(uri, errs)
local chars = "[_%-%w%.]+"
local pathChars = "[/_%-%w%.]+"
local chars = "[_%-%w%.]+"

-- strips the protocol (https://, git@, ssh://, etc)
local function strip_protocol(uri, errs)
local protocol_schema = chars .. "://"
local ssh_schema = chars .. "@"

-- strip the protocol (https://, git@, etc)
local stripped_uri = uri:match(protocol_schema .. "(.+)$") or
uri:match(ssh_schema .. "(.+)$")
if not stripped_uri then
table.insert(errs, string.format(
": remote uri '%s' uses an unsupported protocol format", uri))
return nil
end
return stripped_uri
end

-- strip '.git' at the end if it exists
stripped_uri = stripped_uri:match("(.+)%.git$") or stripped_uri
local function strip_dot_git(uri) return uri:match("(.+)%.git$") or uri end

local host_capture = '(' .. chars .. ")[:/].+$"
local path_capture = chars .. "[:/](" .. pathChars .. ")$"

local repo = {
host = stripped_uri:match(host_capture),
path = stripped_uri:match(path_capture)
}
local function strip_uri(uri, errs)
local stripped_uri = strip_protocol(uri, errs)
return strip_dot_git(stripped_uri)
end

if not repo.host then
local function parse_host(stripped_uri, errs)
local host_capture = '(' .. chars .. ")[:/].+$"
local host = stripped_uri:match(host_capture)
if not host then
table.insert(errs, string.format(
": cannot parse the hostname from uri '%s'", uri))
": cannot parse the hostname from uri '%s'", stripped_uri))
end
if not repo.path then
return host
end

local function parse_port(stripped_uri, host)
assert(host)
local port_capture = host .. ":([0-9]+)[:/].+$"
return stripped_uri:match(port_capture)
end

local function parse_repo_path(stripped_uri, host, port, errs)
assert(host)

local pathChars = "[/_%-%w%.]+"
-- base of path capture
local path_capture = "[:/](" .. pathChars .. ")$"

-- if port is specified, add it to the path capture
if port then path_capture = ':' .. port .. path_capture end

-- add parsed host to path capture
path_capture = host .. path_capture

-- parse repo path
local repo_path = stripped_uri:match(path_capture)
if not repo_path then
table.insert(errs, string.format(
": cannot parse the repo path from uri '%s'", uri))
": cannot parse the repo path from uri '%s'", stripped_uri))
return nil
end
return repo_path
end

return repo
local function parse_uri(uri, errs)
local stripped_uri = strip_uri(uri, errs)

local host = parse_host(stripped_uri, errs)
if not host then return nil end

local port = parse_port(stripped_uri, host)

local repo_path = parse_repo_path(stripped_uri, host, port, errs)
if not repo_path then return nil end

-- do not pass the port if it's NOT a http(s) uri since most likely the port
-- is just an ssh port, so it's irrelevant to the git permalink construction
-- (which is always an http url)
if not uri:match("https?://") then port = nil end

return {host = host, port = port, path = repo_path}
end

local function is_file_compatible_with_revspec(buf_repo_path, revspec, errs)
Expand Down Expand Up @@ -177,7 +220,7 @@ function M.get_closest_remote_compatible_rev(buf_repo_path, remote)
return nil
end

function M.get_repo(remote)
function M.get_repo_data(remote)
local errs = {
string.format("Failed to retrieve repo data for remote '%s'", remote)
}
Expand Down
Loading

0 comments on commit 17894da

Please sign in to comment.