Skip to content

Commit

Permalink
feat(attach): Allow attaching to files out of repo
Browse files Browse the repository at this point in the history
This will allow to highlight usaved changes in buffer, even if file is not in the git repo.
This behaviour needs to be enabled by `attach_to_out_of_repo` config option (false by default).

Resolves lewis6991#164
  • Loading branch information
Supremist committed Apr 9, 2024
1 parent 1a50b94 commit 91a8fed
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 25 deletions.
5 changes: 5 additions & 0 deletions doc/gitsigns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,11 @@ attach_to_untracked *gitsigns-config-attach_to_untracked*

Attach to untracked files.

attach_to_out_of_repo *gitsigns-config-attach_to_out_of_repo*
Type: `boolean`, Default: `false`

Attach to files out of git repository to highlight unsaved changes.

update_debounce *gitsigns-config-update_debounce*
Type: `number`, Default: `100`

Expand Down
33 changes: 22 additions & 11 deletions lua/gitsigns/attach.lua
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ local function try_worktrees(_bufnr, file, encoding)

for _, wt in ipairs(config.worktrees) do
local git_obj = git.Obj.new(file, encoding, wt.gitdir, wt.toplevel)
if git_obj and git_obj.object_name then
if git_obj.repo.gitdir and git_obj.object_name then
dprintf('Using worktree %s', vim.inspect(wt))
return git_obj
end
Expand Down Expand Up @@ -289,21 +289,23 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)
gitdir_oap, toplevel_oap = on_attach_pre(cbuf)
end

if not ctx and git.in_git_dir(file) then
dprint('In git dir')
return
end

local git_obj = git.Obj.new(file, encoding, gitdir_oap, toplevel_oap)

if not git_obj and not ctx then
git_obj = try_worktrees(cbuf, file, encoding)
if not git_obj.repo.gitdir and not ctx then
git_obj = try_worktrees(cbuf, file, encoding) or git_obj
async.scheduler()
if not api.nvim_buf_is_valid(cbuf) then
return
end
end

if not git_obj then
dprint('Empty git obj')
return
end
local repo = git_obj.repo
local base = ctx and ctx.base or nil

async.scheduler()
if not api.nvim_buf_is_valid(cbuf) then
Expand All @@ -316,7 +318,16 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)
gitdir = repo.gitdir,
})

if vim.startswith(file, repo.gitdir .. util.path_sep) then
if not repo.gitdir then
if config.attach_to_out_of_repo then
base = 'FILE'
else
dprint('Not in git repo')
return
end
end

if repo.gitdir and vim.startswith(file, repo.gitdir .. util.path_sep) then
dprint('In non-standard git dir')
return
end
Expand All @@ -326,7 +337,7 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)
return
end

if not git_obj.relpath then
if repo.gitdir and not git_obj.relpath then
dprint('Cannot resolve file in repo')
return
end
Expand All @@ -350,13 +361,13 @@ local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd)

cache[cbuf] = gs_cache.new({
bufnr = cbuf,
base = ctx and ctx.base or config.base,
base = base or config.base,
file = file,
commit = commit,
git_obj = git_obj,
})

if config.watch_gitdir.enable then
if config.watch_gitdir.enable and repo.gitdir then
local watcher = require('gitsigns.watcher')
cache[cbuf].gitdir_watcher = watcher.watch_gitdir(cbuf, repo.gitdir)
end
Expand Down
9 changes: 9 additions & 0 deletions lua/gitsigns/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
--- @field preview_config table<string,any>
--- @field auto_attach boolean
--- @field attach_to_untracked boolean
--- @field attach_to_out_of_repo boolean
--- @field yadm { enable: boolean }
--- @field worktrees {toplevel: string, gitdir: string}[]
--- @field word_diff boolean
Expand Down Expand Up @@ -598,6 +599,14 @@ M.schema = {
]],
},

attach_to_out_of_repo = {
type = 'boolean',
default = false,
description = [[
Attach to files out of git repository to highlight unsaved changes.
]],
},

update_debounce = {
type = 'number',
default = 100,
Expand Down
11 changes: 3 additions & 8 deletions lua/gitsigns/git.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ local asystem = async.wrap(3, system)

--- @param file string
--- @return boolean
local function in_git_dir(file)
function M.in_git_dir(file)
for _, p in ipairs(vim.split(file, util.path_sep)) do
if p == '.git' then
return true
Expand Down Expand Up @@ -800,21 +800,16 @@ end
--- @param encoding string
--- @param gitdir string?
--- @param toplevel string?
--- @return Gitsigns.GitObj?
--- @return Gitsigns.GitObj
function Obj.new(file, encoding, gitdir, toplevel)
if in_git_dir(file) then
dprint('In git dir')
return nil
end
local self = setmetatable({}, { __index = Obj })

self.file = file
self.encoding = encoding
self.repo = Repo.new(util.dirname(file), gitdir, toplevel)

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

-- When passing gitdir and toplevel, suppress stderr when resolving the file
Expand Down
9 changes: 3 additions & 6 deletions test/gitsigns_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ describe('gitsigns (with screen)', function()
np(
'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD'
),
n('new: Not in git repo'),
n('attach(1): Empty git obj'),
n('attach(1): Not in git repo'),
})
command('Gitsigns clear_debug')

Expand All @@ -148,8 +147,7 @@ describe('gitsigns (with screen)', function()
np(
'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD'
),
n('new: Not in git repo'),
n('attach(1): Empty git obj'),
n('attach(1): Not in git repo'),
})
end)

Expand Down Expand Up @@ -182,8 +180,7 @@ describe('gitsigns (with screen)', function()

match_debug_messages({
'attach(1): Attaching (trigger=BufReadPost)',
n('new: In git dir'),
n('attach(1): Empty git obj'),
n('attach(1): In git dir'),
})
end)

Expand Down

0 comments on commit 91a8fed

Please sign in to comment.