Skip to content

Commit

Permalink
feat(blame): support /blame url (#113)
Browse files Browse the repository at this point in the history
fear(bitbucket.org): support bitbucket.org via `src` router
  • Loading branch information
linrongbin16 committed Nov 15, 2023
1 parent 2cac1b7 commit 39acdb7
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 97 deletions.
34 changes: 28 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ A lua plugin for [Neovim](https://github.com/neovim/neovim) to generate sharable

Here's an example of git permalink: https://github.com/neovim/neovim/blob/2e156a3b7d7e25e56b03683cc6228c531f4c91ef/src/nvim/main.c#L137-L156.

Supported platforms are:

- [github.com](https://github.com/)
- [gitlab.com](https://gitlab.com/)
- [bitbucket.org](https://bitbucket.org/)

## Table of Contents

- [Break Changes & Updates](#break-changes--updates)
Expand All @@ -30,6 +36,7 @@ Here's an example of git permalink: https://github.com/neovim/neovim/blob/2e156a
- [Key Mappings](#key-mappings)
- [Vim Command](#vim-command)
- [Highlighting](#highlighting)
- [Blame](#blame)
- [Highlight Group](#highlight-group)
- [Development](#development)
- [Contribute](#contribute)
Expand All @@ -42,8 +49,7 @@ Here's an example of git permalink: https://github.com/neovim/neovim/blob/2e156a
- Windows support.
- Respect ssh config alias host.
- Add `?plain=1` for markdown files.
- Support `/blame` (by default is `/blob`, todo).
- Support column numbers (e.g. `#L152C2-L167C20`, todo).
- Support `/blame` (by default is `/blob`).
3. Improvements:
- Use stderr from git command as error message.
- Performant child process IO via `uv.spawn`.
Expand Down Expand Up @@ -115,7 +121,8 @@ These two operations are already defined in key mappings:
### Routers

- `require('gitlinker.routers').blob`: generate the `/blob` url, by default `link` API will use this router.
- `require('gitlinker.routers').blame` (todo): generate the `/blame` url.
- `require('gitlinker.routers').blame`: generate the `/blame` url.
- `require('gitlinker.routers').src`: generate the `/src` url (for [BitBucket.org](https://bitbucket.org/)).

### API

Expand Down Expand Up @@ -148,18 +155,33 @@ require('gitlinker').setup({

-- key mapping
mapping = {
-- copy git link to clipboard
["<leader>gl"] = {
-- copy git link to clipboard
action = require("gitlinker.actions").clipboard,
desc = "Copy git link to clipboard",
},
-- open git link in browser
["<leader>gL"] = {
-- open git link in browser
action = require("gitlinker.actions").system,
desc = "Open git link in browser",
},
},

-- different web sites use different urls, so we want to auto bind these routers
--
-- **note**:
-- auto bindings only work when `router=nil` in `link` API.
--
-- github.com: `/blob`
-- gitlab.com: `/blob`
-- bitbucket.org: `/src`
--
router_binding = {
["^github"] = require("gitlinker.routers").blob,
["^gitlab"] = require("gitlinker.routers").blob,
["^bitbucket"] = require("gitlinker.routers").src,
},

-- enable debug
debug = false,

Expand Down Expand Up @@ -233,7 +255,7 @@ hi link NvimGitLinkerHighlightTextObject Constant

> Also see [Highlight Group](#highlight-group).
### Blame (todo)
### Blame

To link to the `/blame` url, please specify the `router` option in `link` API:

Expand Down
43 changes: 34 additions & 9 deletions lua/gitlinker.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local logger = require("gitlinker.logger")
local Linker = require("gitlinker.linker").Linker
local linker = require("gitlinker.linker")
local highlight = require("gitlinker.highlight")
local deprecation = require("gitlinker.deprecation")

Expand All @@ -22,17 +22,30 @@ local Defaults = {
--- @type table<string, KeyMappingConfig>
mapping = {
["<leader>gl"] = {
router = require("gitlinker.routers").blob,
action = require("gitlinker.actions").clipboard,
desc = "Copy git link to clipboard",
},
["<leader>gL"] = {
router = require("gitlinker.routers").blob,
action = require("gitlinker.actions").system,
desc = "Open git link in browser",
},
},

-- different web sites use different urls, so we want to auto bind these routers
--
-- **note**:
-- auto bindings only work when `router=nil` in `link` API.
--
-- github.com: `/blob`
-- gitlab.com: `/blob`
-- bitbucket.org: `/src`
--
router_binding = {
["^github"] = require("gitlinker.routers").blob,
["^gitlab"] = require("gitlinker.routers").blob,
["^bitbucket"] = require("gitlinker.routers").src,
},

-- enable debug
--
--- @type boolean
Expand Down Expand Up @@ -130,17 +143,29 @@ local function link(opts)
local range = (type(opts.lstart) == "number" and type(opts.lend) == "number")
and { lstart = opts.lstart, lend = opts.lend }
or nil
local lk = Linker:make(range)
local lk = linker.make_linker(range)
if not lk then
return nil
end

local url = type(opts.router) == "function" and opts.router(lk)
or require("gitlinker.routers").blob(lk)
local router = opts.router
if router == nil then
if type(opts.router_binding) == "table" then
for pat, rout in pairs(opts.router_binding) do
if string.match(lk.host, pat) then
router = rout
break
end
end
end
router = router or require("gitlinker.routers").blob
end
local ok, url = pcall(router, lk)
logger.ensure(
type(url) == "string" and string.len(url) > 0,
"fatal: failed to generate permanent url from remote url:%s",
lk.remote_url
ok and type(url) == "string" and string.len(url) > 0,
"fatal: failed to generate permanent url from remote url (%s): %s",
vim.inspect(lk.remote_url),
vim.inspect(url)
)

if opts.action then
Expand Down
6 changes: 3 additions & 3 deletions lua/gitlinker/git.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
local logger = require("gitlinker.logger")
local spawn = require("gitlinker.spawn")

--- @class CmdResult
--- @class gitlinker.CmdResult
--- @field stdout string[]
--- @field stderr string[]
local CmdResult = {}

--- @return CmdResult
--- @return gitlinker.CmdResult
function CmdResult:new()
local o = {
stdout = {},
Expand Down Expand Up @@ -42,7 +42,7 @@ end
--- @package
--- @param args string[]
--- @param cwd string?
--- @return CmdResult
--- @return gitlinker.CmdResult
local function cmd(args, cwd)
local result = CmdResult:new()

Expand Down
2 changes: 1 addition & 1 deletion lua/gitlinker/highlight.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ end
local hl_namespace = "NvimGitLinker"

-- Highlights the text selected by the specified range.
--- @param range Range?
--- @param range gitlinker.Range?
M.show = function(range)
if not range then
return
Expand Down
26 changes: 7 additions & 19 deletions lua/gitlinker/linker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,6 @@ local path = require("gitlinker.path")
local logger = require("gitlinker.logger")
local utils = require("gitlinker.utils")

--- @class Linker
--- @field remote_url string e.g. git@github.com:linrongbin16/gitlinker.nvim.git
--- @field protocol "git"|"http"|"https"
--- @field host string
--- @field user string
--- @field repo string
--- @field rev string
--- @field file string
--- @field lstart integer
--- @field lend integer
--- @field file_changed boolean
local Linker = {}

-- example:
-- git@github.com:linrongbin16/gitlinker.nvim.git
-- https://github.com/linrongbin16/gitlinker.nvim.git
Expand Down Expand Up @@ -81,9 +68,10 @@ local function _parse_remote_url(remote_url)
return result
end

--- @param r Range?
--- @return Linker?
function Linker:make(r)
--- @alias gitlinker.Linker {remote_url:string,protocol:"git"|"http"|"https",host:string,user:string,repo:string,rev:string,file:string,lstart:integer,lend:integer,file_changed:boolean}
--- @param r gitlinker.Range?
--- @return gitlinker.Linker?
local function make_linker(r)
local root = git.get_root()
if not root then
return nil
Expand Down Expand Up @@ -141,7 +129,7 @@ function Linker:make(r)
-- )

if not range.is_range(r) then
r = range.Range:make()
r = range.make_range()
-- logger.debug("[linker - Linker:make] range:%s", vim.inspect(r))
end

Expand All @@ -160,13 +148,13 @@ function Linker:make(r)
file_changed = file_changed,
}

logger.debug("|linker.Linker:make| o:%s", vim.inspect(o))
logger.debug("|linker.make_linker| o:%s", vim.inspect(o))
return o
end

local M = {
_parse_remote_url = _parse_remote_url,
Linker = Linker,
make_linker = make_linker,
}

return M
33 changes: 6 additions & 27 deletions lua/gitlinker/range.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
--- @class Range
--- @field lstart integer
--- @field lend integer
local Range = {}

--- @param m string
--- @return boolean
local function _is_visual_mode(m)
Expand All @@ -12,8 +7,9 @@ local function _is_visual_mode(m)
or m == "\22"
end

--- @return Range
function Range:make()
--- @alias gitlinker.Range {lstart:integer,lend:integer,cstart:integer?,cend:integer?}
--- @return gitlinker.Range
local function make_range()
local m = vim.fn.mode()
local l1 = nil
local l2 = nil
Expand All @@ -34,37 +30,20 @@ function Range:make()
return o
end

--- @param r {lstart:integer?,lend:integer?}?
--- @return string?
local function stringify(r)
if type(r) ~= "table" then
return nil
end
if type(r.lstart) ~= "number" then
return nil
end
local builder = string.format([[#L%d]], r.lstart)
if type(r.lend) == "number" and r.lend > r.lstart then
builder = builder .. string.format([[-L%d]], r.lend)
end
return builder
end

--- @param r any?
--- @return boolean
local function is_range(r)
return type(r) == "table"
and type(r.lstart) == "number"
and type(r.lend) == "number"
and r.lstart >= 0
and r.lend >= 0
and type(r.lend) == "number"
and r.lend > 0
end

local M = {
Range = Range,
_is_visual_mode = _is_visual_mode,
is_range = is_range,
stringify = stringify,
make_range = make_range,
}

return M
Loading

0 comments on commit 39acdb7

Please sign in to comment.