Skip to content

Commit

Permalink
fix(parsing): fix git url parsing (#195)
Browse files Browse the repository at this point in the history
  • Loading branch information
linrongbin16 authored Jan 8, 2024
1 parent c6aaef1 commit ab44bb7
Show file tree
Hide file tree
Showing 13 changed files with 755 additions and 444 deletions.
14 changes: 0 additions & 14 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
# For New Use Cases

1. What's the output of `git remote get-url origin`?

It's ...

2. what's the expect git host url you want to generate?

It's ...

3. how do you configure this plugin?

It's ...

# Regression Test

## Platforms
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ jobs:
cp ~/.commons.nvim/version.txt ./lua/gitlinker/commons/version.txt
cd ./lua/gitlinker/commons
find . -type f -name '*.lua' -exec sed -i 's/require("commons/require("gitlinker.commons/g' {} \;
- name: Install giturlparser.lua
if: ${{ github.ref != 'refs/heads/master' }}
shell: bash
run: |
echo "pwd"
echo $PWD
git clone --depth=1 https://github.com/linrongbin16/giturlparser.lua.git ~/.giturlparser.lua
cp ~/.giturlparser.lua/src/giturlparser.lua ./lua/gitlinker/giturlparser.lua
- uses: stefanzweifel/git-auto-commit-action@v4
if: ${{ github.ref != 'refs/heads/master' }}
with:
Expand Down
7 changes: 5 additions & 2 deletions .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ globals = { "vim", "describe", "before_each", "it", "assert" }
max_line_length = 500
unused = false
unused_args = false
exclude_files =
{ "lua/gitlinker/commons/_system.lua", "lua/gitlinker/commons/_json.lua" }
exclude_files = {
"lua/gitlinker/commons/_system.lua",
"lua/gitlinker/commons/_json.lua",
"lua/gitlinker/giturlparser.lua",
}
1 change: 1 addition & 0 deletions .luacov
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ modules = {

exclude = {
"lua/gitlinker/commons/*.lua",
"lua/gitlinker/giturlparser.lua",
}
2 changes: 2 additions & 0 deletions .styluaignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lua/gitlinker/giturlparser.lua
lua/gitlinker/commons/*.lua
153 changes: 91 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ PRs are welcomed for other git host websites!
- [Highlighting](#highlighting)
- [Self-host Git Hosts](#self-host-git-hosts)
- [Fully Customize Urls](#fully-customize-urls)
- [GitWeb](#gitweb)
- [Create Your Own Router](#create-your-own-router)
- [Highlight Group](#highlight-group)
- [Development](#development)
Expand Down Expand Up @@ -185,31 +184,31 @@ require('gitlinker').setup({
browse = {
-- example: https://github.com/linrongbin16/gitlinker.nvim/blob/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#L3-L4
["^github%.com"] = "https://github.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blob/"
.. "{_A.REV}/"
.. "{_A.FILE}?plain=1" -- '?plain=1'
.. "#L{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and ('-L' .. _A.LEND) or '')}",
-- example: https://gitlab.com/linrongbin16/gitlinker.nvim/blob/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#L3-L4
["^gitlab%.com"] = "https://gitlab.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blob/"
.. "{_A.REV}/"
.. "{_A.FILE}"
.. "#L{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and ('-L' .. _A.LEND) or '')}",
-- example: https://bitbucket.org/linrongbin16/gitlinker.nvim/src/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#lines-3:4
-- example: https://bitbucket.org/linrongbin16/gitlinker.nvim/src/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#L3-L4
["^bitbucket%.org"] = "https://bitbucket.org/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/src/"
.. "{_A.REV}/"
.. "{_A.FILE}"
.. "#lines-{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and (':' .. _A.LEND) or '')}",
-- example: https://codeberg.org/linrongbin16/gitlinker.nvim/src/commit/a570f22ff833447ee0c58268b3bae4f7197a8ad8/LICENSE#L5-L6
["^codeberg%.org"] = "https://codeberg.org/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/src/commit/"
.. "{_A.REV}/"
.. "{_A.FILE}?display=source" -- '?display=source'
Expand All @@ -219,7 +218,7 @@ require('gitlinker').setup({
-- main repo: https://git.samba.org/?p=samba.git;a=blob;f=wscript;hb=83e8971c0f1c1db8c3574f83107190ac1ac23db0#l6
-- dev repo: https://git.samba.org/?p=bbaumbach/samba.git;a=blob;f=wscript;hb=8de348e9d025d336a7985a9025fe08b7096c0394#l7
["^git%.samba%.org"] = "https://git.samba.org/?p="
.. "{string.len(_A.USER) > 0 and (_A.USER .. '/') or ''}" -- 'p=samba.git;' or 'p=bbaumbach/samba.git;'
.. "{string.len(_A.ORG) > 0 and (_A.ORG .. '/') or ''}" -- 'p=samba.git;' or 'p=bbaumbach/samba.git;'
.. "{_A.REPO .. '.git'};a=blob;"
.. "f={_A.FILE};"
.. "hb={_A.REV}"
Expand All @@ -228,31 +227,31 @@ require('gitlinker').setup({
blame = {
-- example: https://github.com/linrongbin16/gitlinker.nvim/blame/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#L3-L4
["^github%.com"] = "https://github.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blame/"
.. "{_A.REV}/"
.. "{_A.FILE}?plain=1" -- '?plain=1'
.. "#L{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and ('-L' .. _A.LEND) or '')}",
-- example: https://gitlab.com/linrongbin16/gitlinker.nvim/blame/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#L3-L4
["^gitlab%.com"] = "https://gitlab.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blame/"
.. "{_A.REV}/"
.. "{_A.FILE}"
.. "#L{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and ('-L' .. _A.LEND) or '')}",
-- example: https://bitbucket.org/linrongbin16/gitlinker.nvim/annotate/9679445c7a24783d27063cd65f525f02def5f128/lua/gitlinker.lua#lines-3:4
["^bitbucket%.org"] = "https://bitbucket.org/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/annotate/"
.. "{_A.REV}/"
.. "{_A.FILE}"
.. "#lines-{_A.LSTART}"
.. "{(_A.LEND > _A.LSTART and (':' .. _A.LEND) or '')}",
-- example: https://codeberg.org/linrongbin16/gitlinker.nvim/blame/commit/a570f22ff833447ee0c58268b3bae4f7197a8ad8/LICENSE#L5-L6
["^codeberg%.org"] = "https://codeberg.org/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blame/commit/"
.. "{_A.REV}/"
.. "{_A.FILE}?display=source" -- '?display=source'
Expand Down Expand Up @@ -323,17 +322,59 @@ You can directly use below builtin APIs:

### Fully Customize Urls

> [!NOTE]
>
> Please refer to [Git Protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols) and [giturlparser](https://github.com/linrongbin16/giturlparser.lua?tab=readme-ov-file#features) for better understanding git url.
To fully customize url generation, please refer to the implementation of [routers.lua](https://github.com/linrongbin16/gitlinker.nvim/blob/master/lua/gitlinker/routers.lua), a router is simply construct the url string from below components:

- `protocol`: `git@`, `ssh://git@`, `https`, etc.
- `host`: `github.com`, `gitlab.com`, `bitbucket.org`, etc.
- `user`: `linrongbin16` (for this plugin), `neovim` (for [neovim](https://github.com/neovim/neovim)), etc.
- `repo`: `gitlinker.nvim.git`, `neovim.git`, etc.
- `rev`: git commit, e.g. `dbf3922382576391fbe50b36c55066c1768b08b6`.
- `default_branch`: git default branch, `master`, `main`, etc, retrieved from `git rev-parse --abbrev-ref origin/HEAD`.
- `current_branch`: git current branch, `feat-router-types`, etc, retrieved from `git rev-parse --abbrev-ref HEAD`.
- `file`: file name, e.g. `lua/gitlinker/routers.lua`.
- `lstart`/`lend`: start/end line numbers, e.g. `#L37-L156`.
- `protocol`: The component before `://` delimiter. For example:
- The `https` in `https://github.com`.
- The `ssh` in `ssh://github.com`.
- `username`: Optional component after `protocol`, before host name separated by `@`. For example:
- The `git` in `ssh://git@github.com:linrongbin16/gitlinker.nvim.git`.
- The `myname` in `myname@github.com:linrongbin16/gitlinker.nvim.git` (**Note:** the `ssh://` in ssh protocol can be omitted).
- `password`: Optional component after `username` separated by `:`, before `host` name separated by `@`. For example:
- The `mypass` in `ssh://myname:mypass@github.com:linrongbin16/gitlinker.nvim.git`.
- The `mypass` in `https://myname:mypass@github.com/linrongbin16/gitlinker.nvim.git`.
- `host`: The first component after `protocol` (and optional `username`, `password`). For example:
- The `github.com` in `https://github.com/linrongbin16/gitlinker.nvim` (**Note:** for http/https, `host` ends with `/`).
- The `127.0.0.1` in `ssh://127.0.0.1:linrongbin16/gitlinker.nvim` (**Note:** for ssh, `host` ends with `:`, and cannot have the following `port` component).
- `port`: Optional component after `host` separated by `:` (**Note:** ssh protocol cannot have `port` component). For example:
- The `22` in `https://github.com:22/linrongbin16/gitlinker.nvim`.
- The `123456` in `https://127.0.0.1:123456/linrongbin16/gitlinker.nvim`.
- `path`: All the left parts after `host` (and optional `port`). For example:
- `/linrongbin16/gitlinker.nvim.git` in `https://github.com/linrongbin16/gitlinker.nvim.git`.
- `linrongbin16/gitlinker.nvim.git` in `git@github.com:linrongbin16/gitlinker.nvim.git`.
- `rev`: Git commit. For example:
- The `a009dacda96756a8c418ff5fa689999b148639f6` in `https://github.com/linrongbin16/gitlinker.nvim/blob/a009dacda96756a8c418ff5fa689999b148639f6/lua/gitlinker/git.lua?plain=1#L3`.
- `file`: Relative file path. For example:
- `lua/gitlinker/routers.lua` in `https://github.com/linrongbin16/gitlinker.nvim/blob/master/lua/gitlinker/routers.lua`.
- `lstart`/`lend`: Start/end line numbers. For example:
- `3`/`13` in `https://github.com/linrongbin16/gitlinker.nvim/blob/master/lua/gitlinker/routers.lua#L3-L13`.

There're also 2 sugar components derived from `path`:

- `repo`: The last part after the last slash (`/`) in `path`, with around slashes been removed. For example:
- `gitlinker.nvim.git` in `https://github.com/linrongbin16/gitlinker.nvim`.
- `neovim.git` in `https://github.com/neovim/neovim.git`.
- `org`: (Optional) all the other parts before `repo` in `path`, with around slashes been removed. For example:
- `linrongbin16` in `https://github.com/linrongbin16/gitlinker.nvim.git`.
- `path/to/the` in `https://github.com/path/to/the/repo.git`.

> [!NOTE]
>
> The `org` component can be empty when the `path` only contains 1 slash (`/`), for example:
>
> - `ssh://git@host.xyz/repo.git`.
There're also 2 branch components:

- `default_branch`: Default branch retrieved from `git rev-parse --abbrev-ref origin/HEAD`. For example:
- `master` in `https://github.com/ruifm/gitlinker.nvim/blob/master/lua/gitlinker/routers.lua#L37-L156`.
- `main` in `https://github.com/linrongbin16/commons.nvim/blob/main/lua/commons/uv.lua`.
- `current_branch`: Current branch retrieved from `git rev-parse --abbrev-ref HEAD`. For example:
- `feat-router-types`

For example you can customize the line numbers in form `?&line=1&lines-count=2` like this:

Expand All @@ -347,21 +388,21 @@ end
--- @param lk gitlinker.Linker
local function your_router(lk)
local builder = "https://"
-- host: 'github.com', 'gitlab.com', 'bitbucket.org'
-- host
builder = builder .. lk.host .. "/"
-- user: 'linrongbin16', 'neovim'
builder = builder .. lk.user .. "/"
-- repo: 'gitlinker.nvim.git', 'neovim'
-- org
builder = builder .. lk.org .. "/"
-- repo
builder = builder
.. (string_endswith(lk.repo, ".git") and lk.repo:sub(1, #lk.repo - 4) or lk.repo)
.. "/"
-- rev: git commit, e.g. 'e605210941057849491cca4d7f44c0e09f363a69'
-- rev
builder = lk.rev .. "/"
-- file: 'lua/gitlinker/logger.lua'
-- file
builder = builder
.. lk.file
.. (string_endswith(lk.file, ".md") and "?plain=1" or "")
-- line range: start line number, end line number
-- line range
builder = builder .. string.format("&lines=%d", lk.lstart)
if lk.lend > lk.lstart then
builder = builder
Expand All @@ -388,7 +429,7 @@ require("gitlinker").setup({
router = {
browse = {
["^github%.your%.host"] = "https://github.your.host/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blob/"
.. "{_A.REV}/"
.. "{_A.FILE}"
Expand All @@ -403,39 +444,27 @@ The template string use curly braces `{}` to contains lua scripts, and evaluate

The available variables are the same with the `lk` parameter passing to hook functions, but in upper case, and with the `_A.` prefix:

- `_A.PROTOCOL`: `git@`, `ssh://git@`, `https`, etc.
- `_A.HOST`: `github.com`, `gitlab.com`, `bitbucket.org`, etc.
- `_A.USER`: `linrongbin16` (for this plugin), `neovim` (for [neovim](https://github.com/neovim/neovim)), etc.
- `_A.REPO`: `gitlinker.nvim`, `neovim`, etc.
- **Note:** for easier writing, the `.git` suffix is been removed.
- `_A.REV`: git commit, e.g. `dbf3922382576391fbe50b36c55066c1768b08b6`.
- `_A.DEFAULT_BRANCH`: git default branch, `master`, `main`, etc, retrieved from `git rev-parse --abbrev-ref origin/HEAD`.
- `_A.CURRENT_BRANCH`: git current branch, `feat-router-types`, etc, retrieved from `git rev-parse --abbrev-ref HEAD`.
- `_A.PROTOCOL`
- `_A.USERNAME`
- `_A.PASSWORD`
- `_A.HOST`
- `_A.PORT`
- `_A.PATH`
- `_A.REV`
- `_A.DEFAULT_BRANCH`
- `_A.CURRENT_BRANCH`
- `_A.FILE`: file name, e.g. `lua/gitlinker/routers.lua`.
- `_A.LSTART`/`_A.LEND`: start/end line numbers, e.g. `#L37-L156`.

### GitWeb
The 2 sugar components derived from `path` are:

For [GitWeb](https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb), there're two types of urls: the main repository and the user's dev repository. For example on [git.samba.org](https://git.samba.org/):

```bash
# main repo
https://git.samba.org/samba.git (`git remote get-url origin`)
https://git.samba.org/?p=samba.git;a=blob;f=wscript;hb=83e8971c0f1c1db8c3574f83107190ac1ac23db0#l7
| | | | | |
protocol host repo file rev line number

# user's dev repo
https://git.samba.org/bbaumbach/samba.git (`git remote get-url origin`)
https://git.samba.org/?p=bbaumbach/samba.git;a=blob;f=wscript;hb=8de348e9d025d336a7985a9025fe08b7096c0394#l7
| | | | | | |
protocol host user repo file rev line number
```
- `_A.ORG`
- `_A.REPO` - **Note:** for easier writing, the `.git` suffix is been removed.

The difference is: the main repo doesn't have the `user` component, it's just `https://git.samba.org/?p=samba.git`. To support such case, `user` and `repo` components have a little bit different when facing the main repo:
The 2 branch components are:

- `lk.user` (`_A.USER`): the value is `` (empty string).
- `lk.repo`: the value is `samba.git`, for `_A.REPO` the value is `samba` (the `.git` suffix is been removed for easier writing url template).
- `_A.DEFAULT_BRANCH`
- `_A.CURRENT_BRANCH`

### Create Your Own Router

Expand All @@ -446,7 +475,7 @@ require("gitlinker").setup({
router = {
default_branch = {
["^github%.com"] = "https://github.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blob/"
.. "{_A.DEFAULT_BRANCH}/" -- always 'master'/'main' branch
.. "{_A.FILE}?plain=1" -- '?plain=1'
Expand All @@ -455,7 +484,7 @@ require("gitlinker").setup({
},
current_branch = {
["^github%.com"] = "https://github.com/"
.. "{_A.USER}/"
.. "{_A.ORG}/"
.. "{_A.REPO}/blob/"
.. "{_A.CURRENT_BRANCH}/" -- always current branch
.. "{_A.FILE}?plain=1" -- '?plain=1'
Expand All @@ -466,13 +495,13 @@ require("gitlinker").setup({
})
```

Then use it just like `blame`:
Then use it just like `browse`:

```vim
GitLink default_branch " copy default branch to clipboard
GitLink! default_branch " open default branch in browser
GitLink current_branch " copy current branch to clipboard
GitLink! current_branch " open current branch in browser
GitLink default_branch
GitLink! default_branch
GitLink current_branch
GitLink! current_branch
```

## Highlight Group
Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ coverage:
threshold: 90%
ignore:
- "lua/gitlinker/commons/*.lua"
- "lua/gitlinker/giturlparser.lua"
Loading

0 comments on commit ab44bb7

Please sign in to comment.