Skip to content

Commit

Permalink
feat: share Repo objects across buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
lewis6991 committed Jul 9, 2024
1 parent 220446c commit 2593efa
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 26 deletions.
4 changes: 2 additions & 2 deletions lua/gitsigns/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1284,8 +1284,8 @@ local function buildqflist(target)
end
end

local repo = git.Repo.new(assert(vim.loop.cwd()))
if not repos[repo.gitdir] then
local repo = git.Repo.get(assert(vim.loop.cwd()))
if repo and not repos[repo.gitdir] then
repos[repo.gitdir] = repo
end

Expand Down
1 change: 1 addition & 0 deletions lua/gitsigns/cache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ function CacheEntry:destroy()
if w and not w:is_closing() then
w:close()
end
self.git_obj.repo:unref()
end

---@type table<integer,Gitsigns.CacheEntry?>
Expand Down
15 changes: 8 additions & 7 deletions lua/gitsigns/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -360,21 +360,22 @@ function Obj.new(file, revision, encoding, gitdir, toplevel)
log.dprint('In git dir')
return nil
end
local self = setmetatable({}, { __index = Obj })

if not vim.startswith(file, '/') and toplevel then
file = toplevel .. util.path_sep .. file
end

local repo = Repo.get(util.dirname(file), gitdir, toplevel)
if not repo then
log.dprint('Not in git repo')
return
end

local self = setmetatable({}, { __index = Obj })
self.repo = repo
self.file = file
self.revision = util.norm_base(revision)
self.encoding = encoding
self.repo = Repo.new(util.dirname(file), gitdir, toplevel)

if not self.repo.gitdir then
log.dprint('Not in git repo')
return nil
end

-- When passing gitdir and toplevel, suppress stderr when resolving the file
local silent = gitdir ~= nil and toplevel ~= nil
Expand Down
65 changes: 51 additions & 14 deletions lua/gitsigns/git/repo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,11 @@ function M:update_abbrev_head()
end

--- @async
--- @param dir string
--- @param gitdir? string
--- @param toplevel? string
--- @private
--- @param info Gitsigns.RepoInfo
--- @return Gitsigns.Repo
function M.new(dir, gitdir, toplevel)
local function new(info)
local self = setmetatable({}, { __index = M })

local info = M.get_info(dir, gitdir, toplevel)
for k, v in
pairs(info --[[@as table<string,any>]])
do
Expand All @@ -112,10 +109,46 @@ function M.new(dir, gitdir, toplevel)
return self
end

--- @type table<string,[integer,Gitsigns.Repo]?>
local repo_cache = setmetatable({}, { __mode = 'v' })

--- @async
--- @param dir string
--- @param gitdir? string
--- @param toplevel? string
--- @return Gitsigns.Repo?
function M.get(dir, gitdir, toplevel)
local info = M.get_info(dir, gitdir, toplevel)
if not info then
return
end

gitdir = info.gitdir
if not repo_cache[gitdir] then
repo_cache[gitdir] = {1, new(info)}
else
local refcount = repo_cache[gitdir][1]
repo_cache[gitdir][1] = refcount + 1
end

return repo_cache[gitdir][2]
end

function M:unref()
local gitdir = self.gitdir
local refcount = repo_cache[gitdir][1]

This comment has been minimized.

Copy link
@mehalter

mehalter Jul 9, 2024

I am getting a nil value error on this when I close neovim.

attempt to index a nil value

I sorry I don't have much more details, I would sent the entire error log but it's too quick to go away when I'm closing the editor

This comment has been minimized.

Copy link
@lewis6991

lewis6991 Jul 9, 2024

Author Owner

Already fixed. GC was reclaiming the object first.

This comment has been minimized.

Copy link
@mehalter

mehalter Jul 9, 2024

Thanks so much for the incredibly quick fix 😄 I think 4 minutes is the fastest fix I've ever gotten on a bug resolution I've gotten before 😍

if refcount <= 1 then
repo_cache[gitdir] = nil
else
repo_cache[gitdir][1] = refcount - 1
end
end

local has_cygpath = jit and jit.os == 'Windows' and vim.fn.executable('cygpath') == 1

--- @param path? string
--- @return string?
--- @generic S
--- @param path S
--- @return S
local function normalize_path(path)
if path and has_cygpath and not uv.fs_stat(path) then
-- If on windows and path isn't recognizable as a file, try passing it
Expand Down Expand Up @@ -157,7 +190,7 @@ end
--- @param cwd string
--- @param gitdir? string
--- @param toplevel? string
--- @return Gitsigns.RepoInfo
--- @return Gitsigns.RepoInfo?
function M.get_info(cwd, gitdir, toplevel)
-- Does git rev-parse have --absolute-git-dir, added in 2.13:
-- https://public-inbox.org/git/20170203024829.8071-16-szeder.dev@gmail.com/
Expand All @@ -184,22 +217,26 @@ function M.get_info(cwd, gitdir, toplevel)
'HEAD',
})

local results = git_command(args, {
local stdout = git_command(args, {
ignore_error = true,
cwd = toplevel or cwd,
})

local toplevel_r = normalize_path(results[1])
local gitdir_r = normalize_path(results[2])
if not stdout[1] then
return
end

local toplevel_r = normalize_path(stdout[1])
local gitdir_r = normalize_path(stdout[2])

if gitdir_r and not has_abs_gd then
if not has_abs_gd then
gitdir_r = assert(uv.fs_realpath(gitdir_r))
end

return {
toplevel = toplevel_r,
gitdir = gitdir_r,
abbrev_head = process_abbrev_head(gitdir_r, results[3], cwd),
abbrev_head = process_abbrev_head(gitdir_r, stdout[3], cwd),
detached = toplevel_r and gitdir_r ~= toplevel_r .. '/.git',
}
end
Expand Down
3 changes: 0 additions & 3 deletions test/gitsigns_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ describe('gitsigns (with screen)', function()
np(
'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD'
),
np('run_job: git .* config user.name'),
n('new: Not in git repo'),
n('attach(1): Empty git obj'),
})
Expand All @@ -142,7 +141,6 @@ describe('gitsigns (with screen)', function()
np(
'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD'
),
np('run_job: git .* config user.name'),
n('new: Not in git repo'),
n('attach(1): Empty git obj'),
})
Expand Down Expand Up @@ -471,7 +469,6 @@ describe('gitsigns (with screen)', function()
np(
'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD'
),
np('run_job: git .* config user.name'),
np('run_job: git .* ls%-files .*'),
n('watch_gitdir(1): Watching git dir'),
}
Expand Down

0 comments on commit 2593efa

Please sign in to comment.