Skip to content

Commit 47d163f

Browse files
authored
fix: fix repository root detection (#232)
1 parent 69bafe6 commit 47d163f

File tree

2 files changed

+79
-45
lines changed

2 files changed

+79
-45
lines changed

lua/gitlinker/git.lua

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ end
4444
--- NOTE: async functions can't have optional parameters so wrap it into another function without '_'
4545
local _run_cmd = async.wrap(function(args, cwd, callback)
4646
local result = CmdResult:new()
47+
local logger = logging.get("gitlinker")
48+
logger:debug(string.format("|_run_cmd| args:%s, cwd:%s", vim.inspect(args), vim.inspect(cwd)))
4749

4850
spawn.run(args, {
4951
cwd = cwd,
@@ -70,10 +72,11 @@ local function run_cmd(args, cwd)
7072
end
7173

7274
--- @package
75+
--- @param cwd string?
7376
--- @return string[]|nil
74-
local function _get_remote()
77+
local function _get_remote(cwd)
7578
local args = { "git", "remote" }
76-
local result = run_cmd(args)
79+
local result = run_cmd(args, cwd)
7780
if type(result.stdout) ~= "table" or #result.stdout == 0 then
7881
result:print_err("fatal: git repo has no remote")
7982
return nil
@@ -87,11 +90,12 @@ local function _get_remote()
8790
end
8891

8992
--- @param remote string
93+
--- @param cwd string?
9094
--- @return string?
91-
local function get_remote_url(remote)
95+
local function get_remote_url(remote, cwd)
9296
assert(remote, "remote cannot be nil")
9397
local args = { "git", "remote", "get-url", remote }
94-
local result = run_cmd(args)
98+
local result = run_cmd(args, cwd)
9599
if not result:has_out() then
96100
result:print_err("fatal: failed to get remote url by remote '" .. remote .. "'")
97101
return nil
@@ -106,10 +110,11 @@ end
106110

107111
--- @package
108112
--- @param revspec string?
113+
--- @param cwd string?
109114
--- @return string?
110-
local function _get_rev(revspec)
115+
local function _get_rev(revspec, cwd)
111116
local args = { "git", "rev-parse", revspec }
112-
local result = run_cmd(args)
117+
local result = run_cmd(args, cwd)
113118
-- logger.debug(
114119
-- "|git._get_rev| running %s: %s (error:%s)",
115120
-- vim.inspect(args),
@@ -121,10 +126,11 @@ end
121126

122127
--- @package
123128
--- @param revspec string
129+
--- @param cwd string?
124130
--- @return string?
125-
local function _get_rev_name(revspec)
131+
local function _get_rev_name(revspec, cwd)
126132
local args = { "git", "rev-parse", "--abbrev-ref", revspec }
127-
local result = run_cmd(args)
133+
local result = run_cmd(args, cwd)
128134
if not result:has_out() then
129135
result:print_err("fatal: git branch has no remote")
130136
return nil
@@ -139,10 +145,11 @@ end
139145

140146
--- @param file string
141147
--- @param revspec string
148+
--- @param cwd string?
142149
--- @return boolean
143-
local function is_file_in_rev(file, revspec)
150+
local function is_file_in_rev(file, revspec, cwd)
144151
local args = { "git", "cat-file", "-e", revspec .. ":" .. file }
145-
local result = run_cmd(args)
152+
local result = run_cmd(args, cwd)
146153
if result:has_err() then
147154
result:print_err("fatal: '" .. file .. "' does not exist in remote '" .. revspec .. "'")
148155
return false
@@ -157,10 +164,11 @@ end
157164

158165
--- @param file string
159166
--- @param rev string
167+
--- @param cwd string?
160168
--- @return boolean
161-
local function file_has_changed(file, rev)
169+
local function file_has_changed(file, rev, cwd)
162170
local args = { "git", "diff", rev, "--", file }
163-
local result = run_cmd(args)
171+
local result = run_cmd(args, cwd)
164172
-- logger.debug(
165173
-- "|git.has_file_changed| running %s: %s",
166174
-- vim.inspect(args),
@@ -172,10 +180,11 @@ end
172180
--- @package
173181
--- @param revspec string
174182
--- @param remote string
183+
--- @param cwd string?
175184
--- @return boolean
176-
local function _is_rev_in_remote(revspec, remote)
185+
local function _is_rev_in_remote(revspec, remote, cwd)
177186
local args = { "git", "branch", "--remotes", "--contains", revspec }
178-
local result = run_cmd(args)
187+
local result = run_cmd(args, cwd)
179188
-- logger.debug(
180189
-- "|git._is_rev_in_remote| running %s: %s (error:%s)",
181190
-- vim.inspect(args),
@@ -193,10 +202,11 @@ end
193202

194203
--- @package
195204
--- @param remote string
205+
--- @param cwd string?
196206
--- @return boolean
197-
local function _has_remote_fetch_config(remote)
207+
local function _has_remote_fetch_config(remote, cwd)
198208
local args = { "git", "config", string.format("remote.%s.fetch", remote) }
199-
local result = run_cmd(args)
209+
local result = run_cmd(args, cwd)
200210
-- logger.debug(
201211
-- "|git._has_remote_fetch_config| running %s: %s (error:%s)",
202212
-- vim.inspect(args),
@@ -258,13 +268,14 @@ local function resolve_host(host)
258268
end
259269

260270
--- @param remote string
271+
--- @param cwd string?
261272
--- @return string?
262-
local function get_closest_remote_compatible_rev(remote)
273+
local function get_closest_remote_compatible_rev(remote, cwd)
263274
local logger = logging.get("gitlinker")
264275
assert(remote, "remote cannot be nil")
265276

266277
-- try upstream branch HEAD (a.k.a @{u})
267-
local upstream_rev = _get_rev("@{u}")
278+
local upstream_rev = _get_rev("@{u}", cwd)
268279
-- logger.debug(
269280
-- "|git.get_closest_remote_compatible_rev| running _get_rev:%s",
270281
-- vim.inspect(upstream_rev)
@@ -277,14 +288,14 @@ local function get_closest_remote_compatible_rev(remote)
277288

278289
-- try HEAD
279290
if remote_fetch_configured then
280-
if _is_rev_in_remote("HEAD", remote) then
281-
local head_rev = _get_rev("HEAD")
291+
if _is_rev_in_remote("HEAD", remote, cwd) then
292+
local head_rev = _get_rev("HEAD", cwd)
282293
if head_rev then
283294
return head_rev
284295
end
285296
end
286297
else
287-
local head_rev = _get_rev("HEAD")
298+
local head_rev = _get_rev("HEAD", cwd)
288299
if head_rev then
289300
return head_rev
290301
end
@@ -294,8 +305,8 @@ local function get_closest_remote_compatible_rev(remote)
294305
if remote_fetch_configured then
295306
for i = 1, 50 do
296307
local revspec = "HEAD~" .. i
297-
if _is_rev_in_remote(revspec, remote) then
298-
local rev = _get_rev(revspec)
308+
if _is_rev_in_remote(revspec, remote, cwd) then
309+
local rev = _get_rev(revspec, cwd)
299310
if rev then
300311
return rev
301312
end
@@ -304,15 +315,15 @@ local function get_closest_remote_compatible_rev(remote)
304315
else
305316
for i = 1, 50 do
306317
local revspec = "HEAD~" .. i
307-
local rev = _get_rev(revspec)
318+
local rev = _get_rev(revspec, cwd)
308319
if rev then
309320
return rev
310321
end
311322
end
312323
end
313324

314325
-- try remote HEAD
315-
local remote_rev = _get_rev(remote)
326+
local remote_rev = _get_rev(remote, cwd)
316327
if remote_rev then
317328
return remote_rev
318329
end
@@ -321,12 +332,11 @@ local function get_closest_remote_compatible_rev(remote)
321332
return nil
322333
end
323334

335+
--- @param cwd string?
324336
--- @return string?
325-
local function get_root()
326-
local buf_path = vim.api.nvim_buf_get_name(0)
327-
local buf_dir = vim.fn.fnamemodify(buf_path, ":p:h")
337+
local function get_root(cwd)
328338
local args = { "git", "rev-parse", "--show-toplevel" }
329-
local result = run_cmd(args, buf_dir)
339+
local result = run_cmd(args, cwd)
330340
-- logger.debug(
331341
-- "|git.get_root| buf_path:%s, buf_dir:%s, result:%s",
332342
-- vim.inspect(buf_path),
@@ -346,11 +356,12 @@ local function get_root()
346356
return result.stdout[1]
347357
end
348358

359+
--- @param cwd string?
349360
--- @return string?
350-
local function get_branch_remote()
361+
local function get_branch_remote(cwd)
351362
local logger = logging.get("gitlinker")
352363
-- origin/upstream
353-
local remotes = _get_remote()
364+
local remotes = _get_remote(cwd)
354365
if not remotes then
355366
return nil
356367
end
@@ -360,7 +371,7 @@ local function get_branch_remote()
360371
end
361372

362373
-- origin/linrongbin16/add-rule2
363-
local upstream_branch = _get_rev_name("@{u}")
374+
local upstream_branch = _get_rev_name("@{u}", cwd)
364375
if not upstream_branch then
365376
return nil
366377
end
@@ -393,11 +404,12 @@ local function get_branch_remote()
393404
end
394405

395406
--- @param remote string
407+
--- @param cwd string?
396408
--- @return string?
397-
local function get_default_branch(remote)
409+
local function get_default_branch(remote, cwd)
398410
local logger = logging.get("gitlinker")
399411
local args = { "git", "rev-parse", "--abbrev-ref", string.format("%s/HEAD", remote) }
400-
local result = run_cmd(args)
412+
local result = run_cmd(args, cwd)
401413
if type(result.stdout) ~= "table" or #result.stdout == 0 then
402414
return nil
403415
end
@@ -412,11 +424,12 @@ local function get_default_branch(remote)
412424
return splits[#splits]
413425
end
414426

427+
--- @param cwd string?
415428
--- @return string?
416-
local function get_current_branch()
429+
local function get_current_branch(cwd)
417430
local logger = logging.get("gitlinker")
418431
local args = { "git", "rev-parse", "--abbrev-ref", "HEAD" }
419-
local result = run_cmd(args)
432+
local result = run_cmd(args, cwd)
420433
if type(result.stdout) ~= "table" or #result.stdout == 0 then
421434
return nil
422435
end

lua/gitlinker/linker.lua

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,50 @@
11
local logging = require("gitlinker.commons.logging")
2+
local str = require("gitlinker.commons.str")
23
local git = require("gitlinker.git")
34
local path = require("gitlinker.path")
45
local giturlparser = require("gitlinker.giturlparser")
56
local async = require("gitlinker.commons.async")
67
local uri = require("gitlinker.commons.uri")
78

9+
--- @return string?
10+
local function _get_buf_dir()
11+
local logger = logging.get("gitlinker")
12+
local buf_path = vim.api.nvim_buf_get_name(0)
13+
local buf_dir = vim.fn.fnamemodify(buf_path, ":p:h")
14+
logger:debug(
15+
string.format(
16+
"|_get_buf_dir| buf_path:%s, buf_dir:%s",
17+
vim.inspect(buf_path),
18+
vim.inspect(buf_dir)
19+
)
20+
)
21+
if str.empty(buf_dir) or vim.fn.isdirectory(buf_dir or "") <= 0 then
22+
return nil
23+
end
24+
return buf_dir
25+
end
26+
827
--- @alias gitlinker.Linker {remote_url:string,protocol:string?,username:string?,password:string?,host:string,port:string?,org:string?,user:string?,repo:string,rev:string,file:string,lstart:integer,lend:integer,file_changed:boolean,default_branch:string?,current_branch:string?}
928
--- @param remote string?
1029
--- @return gitlinker.Linker?
1130
local function make_linker(remote)
1231
local logger = logging.get("gitlinker")
32+
local cwd = _get_buf_dir()
1333

14-
local root = git.get_root()
34+
local root = git.get_root(cwd)
1535
if not root then
1636
return nil
1737
end
1838

19-
remote = (type(remote) == "string" and string.len(remote) > 0) and remote
20-
or git.get_branch_remote()
39+
if str.empty(remote) then
40+
remote = git.get_branch_remote(cwd)
41+
end
2142
if not remote then
2243
return nil
2344
end
2445
-- logger.debug("|linker - Linker:make| remote:%s", vim.inspect(remote))
2546

26-
local remote_url = git.get_remote_url(remote)
47+
local remote_url = git.get_remote_url(remote, cwd)
2748
if not remote_url then
2849
return nil
2950
end
@@ -55,7 +76,7 @@ local function make_linker(remote)
5576
-- vim.inspect(remote_url)
5677
-- )
5778

58-
local rev = git.get_closest_remote_compatible_rev(remote)
79+
local rev = git.get_closest_remote_compatible_rev(remote, cwd)
5980
if not rev then
6081
return nil
6182
end
@@ -70,7 +91,7 @@ local function make_linker(remote)
7091
-- vim.inspect(buf_path_on_root)
7192
-- )
7293

73-
local file_in_rev_result = git.is_file_in_rev(buf_path_on_root, rev)
94+
local file_in_rev_result = git.is_file_in_rev(buf_path_on_root, rev, cwd)
7495
if not file_in_rev_result then
7596
return nil
7697
end
@@ -81,14 +102,14 @@ local function make_linker(remote)
81102

82103
async.scheduler()
83104
local buf_path_on_cwd = path.buffer_relpath() --[[@as string]]
84-
local file_changed = git.file_has_changed(buf_path_on_cwd, rev)
105+
local file_changed = git.file_has_changed(buf_path_on_cwd, rev, cwd)
85106
-- logger.debug(
86107
-- "|linker - Linker:make| buf_path_on_cwd:%s",
87108
-- vim.inspect(buf_path_on_cwd)
88109
-- )
89110

90-
local default_branch = git.get_default_branch(remote)
91-
local current_branch = git.get_current_branch()
111+
local default_branch = git.get_default_branch(remote, cwd)
112+
local current_branch = git.get_current_branch(cwd)
92113

93114
local o = {
94115
remote_url = remote_url,

0 commit comments

Comments
 (0)