feat: Enable `attach()` to work with any buffer when given context data
* feat: Enable `attach()` to work with any buffer when given context data. * fix(test): Pattern escape file names when matching debug messages.
This commit is contained in:
parent
0d4fe37ba5
commit
ec4742a7ee
|
@ -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
|
||||
|
|
|
@ -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 = {}, }
|
||||
|
||||
|
||||
|
||||
|
@ -36,6 +36,16 @@ local M = {}
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local GitContext = M.GitContext
|
||||
|
||||
|
||||
function M.detach_all()
|
||||
for k, _ in pairs(cache) do
|
||||
M.detach(k)
|
||||
|
@ -186,7 +196,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')
|
||||
|
@ -209,33 +219,45 @@ 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
|
||||
|
||||
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
|
||||
if encoding == '' then
|
||||
encoding = 'utf-8'
|
||||
end
|
||||
local file
|
||||
local commit
|
||||
local gitdir_oap
|
||||
local toplevel_oap
|
||||
|
||||
local file_dir = util.dirname(file)
|
||||
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 not file_dir or not util.path_exists(file_dir) then
|
||||
dprint('Not a path')
|
||||
return
|
||||
if vim.bo[cbuf].buftype ~= '' then
|
||||
dprint('Non-normal buffer')
|
||||
return
|
||||
end
|
||||
|
||||
file, commit = get_buf_path(cbuf)
|
||||
local file_dir = util.dirname(file)
|
||||
|
||||
if not file_dir or not util.path_exists(file_dir) then
|
||||
dprint('Not a path')
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
|
@ -258,7 +280,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
|
||||
|
@ -283,7 +305,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),
|
||||
|
@ -318,8 +340,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 function setup_cli()
|
||||
|
@ -414,7 +451,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
|
||||
|
@ -423,9 +460,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',
|
||||
|
|
|
@ -290,7 +290,7 @@ function M.get_repo_info(path, cmd, gitdir, toplevel)
|
|||
local results = git_command(args, {
|
||||
command = cmd or 'git',
|
||||
suppress_stderr = true,
|
||||
cwd = path,
|
||||
cwd = toplevel or path,
|
||||
})
|
||||
|
||||
local ret = {
|
||||
|
|
|
@ -32,9 +32,19 @@ 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
|
||||
end
|
||||
|
||||
local GitContext = M.GitContext
|
||||
|
||||
--- Detach Gitsigns from all buffers it is attached to.
|
||||
function M.detach_all()
|
||||
for k, _ in pairs(cache as {integer:CacheEntry}) do
|
||||
|
@ -186,7 +196,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')
|
||||
|
@ -209,33 +219,45 @@ 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
|
||||
|
||||
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
|
||||
if encoding == '' then
|
||||
encoding = 'utf-8'
|
||||
end
|
||||
local file: string
|
||||
local commit: string
|
||||
local gitdir_oap: string
|
||||
local toplevel_oap: string
|
||||
|
||||
local file_dir = util.dirname(file)
|
||||
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 not file_dir or not util.path_exists(file_dir) then
|
||||
dprint('Not a path')
|
||||
return
|
||||
if vim.bo[cbuf].buftype ~= '' then
|
||||
dprint('Non-normal buffer')
|
||||
return
|
||||
end
|
||||
|
||||
file, commit = get_buf_path(cbuf)
|
||||
local file_dir = util.dirname(file)
|
||||
|
||||
if not file_dir or not util.path_exists(file_dir) then
|
||||
dprint('Not a path')
|
||||
return
|
||||
end
|
||||
|
||||
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
|
||||
|
@ -258,7 +280,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
|
||||
|
@ -283,7 +305,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),
|
||||
|
@ -318,8 +340,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 function setup_cli()
|
||||
|
@ -414,7 +451,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
|
||||
|
@ -423,9 +460,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',
|
||||
|
|
|
@ -290,7 +290,7 @@ function M.get_repo_info(path: string, cmd: string, gitdir: string, toplevel: st
|
|||
local results = git_command(args, {
|
||||
command = cmd or 'git',
|
||||
suppress_stderr = true,
|
||||
cwd = path
|
||||
cwd = toplevel or path,
|
||||
})
|
||||
|
||||
local ret: M.RepoInfo = {
|
||||
|
|
|
@ -55,7 +55,7 @@ describe('gitdir_watcher', function()
|
|||
'attach(1): Attaching (trigger=BufRead)',
|
||||
p"run_job: git .* config user.name",
|
||||
p"run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD",
|
||||
p('run_job: git .* ls%-files .* '..test_file),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file)),
|
||||
'watch_gitdir(1): Watching git dir',
|
||||
p'run_job: git .* show :0:dummy.txt',
|
||||
'update(1): updates: 1, jobs: 6',
|
||||
|
@ -70,10 +70,10 @@ describe('gitdir_watcher', function()
|
|||
match_debug_messages {
|
||||
'watcher_cb(1): Git dir update',
|
||||
p'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD',
|
||||
p('run_job: git .* ls%-files .* '..test_file),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file)),
|
||||
p'run_job: git .* diff %-%-name%-status %-C %-%-cached',
|
||||
'handle_moved(1): File moved to dummy.txt2',
|
||||
p('run_job: git .* ls%-files .* '..test_file2),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file2)),
|
||||
p'handle_moved%(1%): Renamed buffer 1 from .*/dummy.txt to .*/dummy.txt2',
|
||||
p'run_job: git .* show :0:dummy.txt2',
|
||||
'update(1): updates: 2, jobs: 11'
|
||||
|
@ -88,10 +88,10 @@ describe('gitdir_watcher', function()
|
|||
match_debug_messages {
|
||||
'watcher_cb(1): Git dir update',
|
||||
p'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD',
|
||||
p('run_job: git .* ls%-files .* '..test_file2),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file2)),
|
||||
p'run_job: git .* diff %-%-name%-status %-C %-%-cached',
|
||||
'handle_moved(1): File moved to dummy.txt3',
|
||||
p('run_job: git .* ls%-files .* '..test_file3),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file3)),
|
||||
p'handle_moved%(1%): Renamed buffer 1 from .*/dummy.txt2 to .*/dummy.txt3',
|
||||
p'run_job: git .* show :0:dummy.txt3',
|
||||
'update(1): updates: 3, jobs: 16'
|
||||
|
@ -106,11 +106,11 @@ describe('gitdir_watcher', function()
|
|||
match_debug_messages {
|
||||
'watcher_cb(1): Git dir update',
|
||||
p'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD',
|
||||
p('run_job: git .* ls%-files .* '..test_file3),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file3)),
|
||||
p'run_job: git .* diff %-%-name%-status %-C %-%-cached',
|
||||
p('run_job: git .* ls%-files .* '..test_file),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file)),
|
||||
'handle_moved(1): Moved file reset',
|
||||
p('run_job: git .* ls%-files .* '..test_file),
|
||||
p('run_job: git .* ls%-files .* '..helpers.pesc(test_file)),
|
||||
p'handle_moved%(1%): Renamed buffer 1 from .*/dummy.txt3 to .*/dummy.txt',
|
||||
p'run_job: git .* show :0:dummy.txt',
|
||||
'update(1): updates: 4, jobs: 22'
|
||||
|
|
|
@ -91,7 +91,7 @@ describe('gitsigns', function()
|
|||
'attach(1): Attaching (trigger=BufRead)',
|
||||
p'run_job: git .* config user.name',
|
||||
p'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD',
|
||||
p('run_job: git .* ls%-files %-%-stage %-%-others %-%-exclude%-standard %-%-eol '..test_file),
|
||||
p('run_job: git .* ls%-files %-%-stage %-%-others %-%-exclude%-standard %-%-eol '..helpers.pesc(test_file)),
|
||||
'watch_gitdir(1): Watching git dir',
|
||||
p'run_job: git .* show :0:dummy.txt',
|
||||
'update(1): updates: 1, jobs: 7'
|
||||
|
@ -201,7 +201,7 @@ describe('gitsigns', function()
|
|||
'attach(1): Attaching (trigger=BufNewFile)',
|
||||
p'run_job: git .* config user.name',
|
||||
p'run_job: git .* rev%-parse %-%-show%-toplevel %-%-absolute%-git%-dir %-%-abbrev%-ref HEAD',
|
||||
p('run_job: git .* ls%-files %-%-stage %-%-others %-%-exclude%-standard %-%-eol '..newfile),
|
||||
p('run_job: git .* ls%-files %-%-stage %-%-others %-%-exclude%-standard %-%-eol '..helpers.pesc(newfile)),
|
||||
'attach(1): Not a file',
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,15 @@ local test_file_text = {
|
|||
'content', 'doesn\'t', 'matter,', 'it', 'just', 'needs', 'to', 'be', 'static.'
|
||||
}
|
||||
|
||||
--- Escapes magic chars in |lua-patterns|.
|
||||
---
|
||||
---@see https://github.com/rxi/lume
|
||||
---@param s string String to escape
|
||||
---@return string %-escaped pattern string
|
||||
function M.pesc(s)
|
||||
return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1'))
|
||||
end
|
||||
|
||||
function M.git(args)
|
||||
system{"git", "-C", M.scratch, unpack(args)}
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue