diff --git a/doc/gitsigns.txt b/doc/gitsigns.txt index 930e0eeef..c3fb23b19 100644 --- a/doc/gitsigns.txt +++ b/doc/gitsigns.txt @@ -102,7 +102,7 @@ setup({cfg}) *gitsigns.setup()* {cfg} Table object containing configuration for Gitsigns. See |gitsigns-usage| for more details. -attach({bufnr}) *gitsigns.attach()* +attach({bufnr}, {ctx}) *gitsigns.attach()* Attach Gitsigns to the buffer. Attributes: ~ @@ -110,6 +110,21 @@ attach({bufnr}) *gitsigns.attach()* Parameters: ~ {bufnr} (number): Buffer number + {ctx} (table|nil): + Git context data that may optionally be used to attach to any + buffer that represents a real git object. + • {file}: (string) + Path to the file represented by the buffer, relative to the + top-level. + • {toplevel}: (string) + Path to the top-level of the parent git repository. + • {gitdir}: (string) + Path to the git directory of the parent git repository + (typically the ".git/" directory). + • {commit}: (string) + The git revision that the file belongs to. + • {base}: (string|nil) + The git revision that the file should be compared to. detach({bufnr}) *gitsigns.detach()* Detach Gitsigns from the buffer {bufnr}. If {bufnr} is not diff --git a/lua/gitsigns.lua b/lua/gitsigns.lua index 291f4f1db..c7af58319 100644 --- a/lua/gitsigns.lua +++ b/lua/gitsigns.lua @@ -28,7 +28,7 @@ local api = vim.api local uv = vim.loop local current_buf = api.nvim_get_current_buf -local M = {} +local M = {GitContext = {}, } @@ -39,6 +39,16 @@ local M = {} + + + + + + + +local GitContext = M.GitContext + + M.detach_all = function() for k, _ in pairs(cache) do M.detach(k) @@ -187,7 +197,7 @@ end -local attach_throttled = throttle_by_id(function(cbuf, aucmd) +local attach_throttled = throttle_by_id(function(cbuf, ctx, aucmd) local __FUNC__ = 'attach' if vimgrep_running then dprint('attaching is disabled') @@ -210,30 +220,42 @@ local attach_throttled = throttle_by_id(function(cbuf, aucmd) return end - if api.nvim_buf_line_count(cbuf) > config.max_file_length then - dprint('Exceeds max_file_length') - return - end + local encoding = vim.bo[cbuf].fileencoding + local file + local commit + local gitdir_oap + local toplevel_oap + + if ctx then + gitdir_oap = ctx.gitdir + toplevel_oap = ctx.toplevel + file = ctx.toplevel .. util.path_sep .. ctx.file + commit = ctx.commit + else + if api.nvim_buf_line_count(cbuf) > config.max_file_length then + dprint('Exceeds max_file_length') + return + end - if vim.bo[cbuf].buftype ~= '' then - dprint('Non-normal buffer') - return - end + if vim.bo[cbuf].buftype ~= '' then + dprint('Non-normal buffer') + return + end - local file, commit = get_buf_path(cbuf) - local encoding = vim.bo[cbuf].fileencoding + file, commit = get_buf_path(cbuf) + local file_dir = util.dirname(file) - local file_dir = util.dirname(file) + if not file_dir or not util.path_exists(file_dir) then + dprint('Not a path') + return + end - if not file_dir or not util.path_exists(file_dir) then - dprint('Not a path') - return + gitdir_oap, toplevel_oap = on_attach_pre(cbuf) end - local gitdir_oap, toplevel_oap = on_attach_pre(cbuf) local git_obj = git.Obj.new(file, encoding, gitdir_oap, toplevel_oap) - if not git_obj then + if not git_obj and not ctx then git_obj = try_worktrees(cbuf, file, encoding) scheduler() end @@ -256,7 +278,7 @@ local attach_throttled = throttle_by_id(function(cbuf, aucmd) return end - if not util.path_exists(file) or uv.fs_stat(file).type == 'directory' then + if not ctx and (not util.path_exists(file) or uv.fs_stat(file).type == 'directory') then dprint('Not a file') return end @@ -281,7 +303,7 @@ local attach_throttled = throttle_by_id(function(cbuf, aucmd) end cache[cbuf] = CacheEntry.new({ - base = config.base, + base = ctx and ctx.base or config.base, file = file, commit = commit, gitdir_watcher = manager.watch_gitdir(cbuf, repo.gitdir), @@ -316,8 +338,23 @@ end) -M.attach = void(function(bufnr, _trigger) - attach_throttled(bufnr or current_buf(), _trigger) + + + + + + + + + + + + + + + +M.attach = void(function(bufnr, ctx, _trigger) + attach_throttled(bufnr or current_buf(), ctx, _trigger) end) local M0 = M @@ -490,7 +527,7 @@ M.setup = void(function(cfg) for _, buf in ipairs(api.nvim_list_bufs()) do if api.nvim_buf_is_loaded(buf) and api.nvim_buf_get_name(buf) ~= '' then - M.attach(buf, 'setup') + M.attach(buf, nil, 'setup') scheduler() end end @@ -499,9 +536,9 @@ M.setup = void(function(cfg) autocmd('VimLeavePre', M.detach_all) autocmd('ColorScheme', hl.setup_highlights) - autocmd('BufRead', wrap_func(M.attach, nil, 'BufRead')) - autocmd('BufNewFile', wrap_func(M.attach, nil, 'BufNewFile')) - autocmd('BufWritePost', wrap_func(M.attach, nil, 'BufWritePost')) + autocmd('BufRead', wrap_func(M.attach, nil, nil, 'BufRead')) + autocmd('BufNewFile', wrap_func(M.attach, nil, nil, 'BufNewFile')) + autocmd('BufWritePost', wrap_func(M.attach, nil, nil, 'BufWritePost')) autocmd('OptionSet', { pattern = 'fileformat', diff --git a/lua/gitsigns/async.lua b/lua/gitsigns/async.lua index 99cd27277..251d2aede 100644 --- a/lua/gitsigns/async.lua +++ b/lua/gitsigns/async.lua @@ -16,6 +16,7 @@ + local M = {} diff --git a/lua/gitsigns/debounce.lua b/lua/gitsigns/debounce.lua index 3b1224998..89c393a02 100644 --- a/lua/gitsigns/debounce.lua +++ b/lua/gitsigns/debounce.lua @@ -12,6 +12,7 @@ local M = {} + function M.debounce_trailing(ms, fn) local timer = uv.new_timer(true) return function(...) diff --git a/teal/gitsigns.tl b/teal/gitsigns.tl index e6fa1b474..d72686dd1 100644 --- a/teal/gitsigns.tl +++ b/teal/gitsigns.tl @@ -32,12 +32,22 @@ local record M setup : function(cfg: Config) detach : function(bufnr: integer, _keep_signs: boolean) detach_all : function() - attach : function(cbuf: integer, trigger: string) + attach : function(cbuf: integer, ctx: GitContext, trigger: string) + + record GitContext + toplevel: string + gitdir: string + file: string + commit: string + base: string + end -- Exposed for tests parse_fugitive_uri: function(name: string): string, string end +local GitContext = M.GitContext + --- Detach Gitsigns from all buffers it is attached to. M.detach_all = function() for k, _ in pairs(cache as {integer:CacheEntry}) do @@ -187,7 +197,7 @@ end -- Ensure attaches cannot be interleaved. -- Since attaches are asynchronous we need to make sure an attach isn't -- performed whilst another one is in progress. -local attach_throttled = throttle_by_id(function(cbuf: integer, aucmd: string) +local attach_throttled = throttle_by_id(function(cbuf: integer, ctx: GitContext, aucmd: string) local __FUNC__ = 'attach' if vimgrep_running then dprint('attaching is disabled') @@ -210,30 +220,42 @@ local attach_throttled = throttle_by_id(function(cbuf: integer, aucmd: string) return end - if api.nvim_buf_line_count(cbuf) > config.max_file_length then - dprint('Exceeds max_file_length') - return - end + local encoding = vim.bo[cbuf].fileencoding + local file: string + local commit: string + local gitdir_oap: string + local toplevel_oap: string + + if ctx then + gitdir_oap = ctx.gitdir + toplevel_oap = ctx.toplevel + file = ctx.toplevel .. util.path_sep .. ctx.file + commit = ctx.commit + else + if api.nvim_buf_line_count(cbuf) > config.max_file_length then + dprint('Exceeds max_file_length') + return + end - if vim.bo[cbuf].buftype ~= '' then - dprint('Non-normal buffer') - return - end + if vim.bo[cbuf].buftype ~= '' then + dprint('Non-normal buffer') + return + end - local file, commit = get_buf_path(cbuf) - local encoding = vim.bo[cbuf].fileencoding + file, commit = get_buf_path(cbuf) + local file_dir = util.dirname(file) - local file_dir = util.dirname(file) + if not file_dir or not util.path_exists(file_dir) then + dprint('Not a path') + return + end - if not file_dir or not util.path_exists(file_dir) then - dprint('Not a path') - return + gitdir_oap, toplevel_oap = on_attach_pre(cbuf) end - local gitdir_oap, toplevel_oap = on_attach_pre(cbuf) local git_obj = git.Obj.new(file, encoding, gitdir_oap, toplevel_oap) - if not git_obj then + if not git_obj and not ctx then git_obj = try_worktrees(cbuf, file, encoding) scheduler() end @@ -256,7 +278,7 @@ local attach_throttled = throttle_by_id(function(cbuf: integer, aucmd: string) return end - if not util.path_exists(file) or uv.fs_stat(file).type == 'directory' then + if not ctx and (not util.path_exists(file) or uv.fs_stat(file).type == 'directory') then dprint('Not a file') return end @@ -281,7 +303,7 @@ local attach_throttled = throttle_by_id(function(cbuf: integer, aucmd: string) end cache[cbuf] = CacheEntry.new { - base = config.base, + base = ctx and ctx.base or config.base, file = file, commit = commit, gitdir_watcher = manager.watch_gitdir(cbuf, repo.gitdir), @@ -316,8 +338,23 @@ end) --- --- Parameters: ~ --- {bufnr} (number): Buffer number -M.attach = void(function(bufnr: integer, _trigger: string) - attach_throttled(bufnr or current_buf(), _trigger) +--- {ctx} (table|nil): +--- Git context data that may optionally be used to attach to any +--- buffer that represents a real git object. +--- • {file}: (string) +--- Path to the file represented by the buffer, relative to the +--- top-level. +--- • {toplevel}: (string) +--- Path to the top-level of the parent git repository. +--- • {gitdir}: (string) +--- Path to the git directory of the parent git repository +--- (typically the ".git/" directory). +--- • {commit}: (string) +--- The git revision that the file belongs to. +--- • {base}: (string|nil) +--- The git revision that the file should be compared to. +M.attach = void(function(bufnr: integer, ctx: GitContext, _trigger: string) + attach_throttled(bufnr or current_buf(), ctx, _trigger) end) local M0 = M as {string:function} @@ -490,7 +527,7 @@ M.setup = void(function(cfg: Config) for _, buf in ipairs(api.nvim_list_bufs()) do if api.nvim_buf_is_loaded(buf) and api.nvim_buf_get_name(buf) ~= '' then - M.attach(buf, 'setup') + M.attach(buf, nil, 'setup') scheduler() end end @@ -499,9 +536,9 @@ M.setup = void(function(cfg: Config) autocmd('VimLeavePre' , M.detach_all) autocmd('ColorScheme' , hl.setup_highlights) - autocmd('BufRead' , wrap_func(M.attach, nil, 'BufRead')) - autocmd('BufNewFile' , wrap_func(M.attach, nil, 'BufNewFile')) - autocmd('BufWritePost', wrap_func(M.attach, nil, 'BufWritePost')) + autocmd('BufRead' , wrap_func(M.attach, nil, nil, 'BufRead')) + autocmd('BufNewFile' , wrap_func(M.attach, nil, nil, 'BufNewFile')) + autocmd('BufWritePost', wrap_func(M.attach, nil, nil, 'BufWritePost')) autocmd('OptionSet', { pattern = 'fileformat', diff --git a/teal/gitsigns/async.tl b/teal/gitsigns/async.tl index 655b63fed..f41f5d97f 100644 --- a/teal/gitsigns/async.tl +++ b/teal/gitsigns/async.tl @@ -4,6 +4,7 @@ local record Async void: function (function() ): function() void: function (function(A1) ): function(A1) void: function(function(A1,A2)): function(A1,A2) + void: function(function(A1,A2,A3)): function(A1,A2,A3) void: function(function(A1,A2,A3,A4): R1): function(A1,A2,A3,A4): R1 void: function(function(A1,A2,A3,A4,A5): R1): function(A1,A2,A3,A4,A5): R1 void: function(function(A1,A2,A3,A4)): function(A1,A2,A3,A4) diff --git a/teal/gitsigns/debounce.tl b/teal/gitsigns/debounce.tl index 34d7c00f7..fb93504cd 100644 --- a/teal/gitsigns/debounce.tl +++ b/teal/gitsigns/debounce.tl @@ -3,6 +3,7 @@ local uv = require('gitsigns.uv') local record M throttle_by_id: function (fn: function(T1 ), schedule: boolean): function(T1) throttle_by_id: function(fn: function(T1,T2), schedule: boolean): function(T1,T2) + throttle_by_id: function(fn: function(T1,T2,T3), schedule: boolean): function(T1,T2,T3) debounce_trailing: function(ms: number, fn: function(T1,T2), schedule: boolean): function(T1,T2) end