Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(parsing): fix git url parsing #195

Merged
merged 29 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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://[email protected]:linrongbin16/gitlinker.nvim.git`.
- The `myname` in `[email protected]: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:[email protected]:linrongbin16/gitlinker.nvim.git`.
- The `mypass` in `https://myname:[email protected]/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 `[email protected]: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://[email protected]/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
Loading