Numerous changes to setqflist
- Fix duplicate items appearing (#370) - Make setqflist/setloclist async again - setqflist('all') now also looks in the current working directory - Automatically open the quickfix/location list on completion - Make setloclist an alias of setqflist - Refactor git.tl so now there is a separate 'Repo' object to allows us to create git objects for a directory. Fixes #370
This commit is contained in:
parent
d11b627d5a
commit
a6d1574bab
|
@ -298,8 +298,9 @@ get_hunks({bufnr}) *gitsigns.get_hunks()*
|
|||
• `"start"`: Line number (1-based)
|
||||
• `"count"`: Line count
|
||||
|
||||
setqflist({target}) *gitsigns.setqflist()*
|
||||
Populate the quickfix list with hunks.
|
||||
setqflist({target}, {opts}) *gitsigns.setqflist()*
|
||||
Populate the quickfix list with hunks. Automatically opens the
|
||||
quickfix window.
|
||||
|
||||
Attributes: ~
|
||||
{async}
|
||||
|
@ -312,10 +313,23 @@ setqflist({target}) *gitsigns.setqflist()*
|
|||
number. `0` for current buffer (default).
|
||||
• `"attached"`: All attached buffers.
|
||||
• `"all"`: All modified files for each git
|
||||
directory of all attached buffers.
|
||||
directory of all attached buffers in addition
|
||||
to the current working directory.
|
||||
{opts} (table|nil):
|
||||
Additional options:
|
||||
• {use_location_list}: (boolean)
|
||||
Populate the location list instead of the
|
||||
quickfix list. Default to `false`.
|
||||
• {nr}: (integer)
|
||||
Window number or ID when using location list.
|
||||
Expand folds when navigating to a hunk which is
|
||||
inside a fold. Defaults to `0`.
|
||||
|
||||
setloclist({nr}, {target}) *gitsigns.setloclist()*
|
||||
Populate the location list with hunks.
|
||||
Populate the location list with hunks. Automatically opens the
|
||||
location list window.
|
||||
|
||||
Alias for: `setqflist({target}, { use_location_list = true, nr = {nr} }`
|
||||
|
||||
Attributes: ~
|
||||
{async}
|
||||
|
|
|
@ -53,7 +53,7 @@ local handle_moved = function(bufnr, bcache, old_relpath)
|
|||
end
|
||||
do_update = true
|
||||
elseif git_obj.orig_relpath then
|
||||
local orig_file = git_obj.toplevel .. util.path_sep .. git_obj.orig_relpath
|
||||
local orig_file = git_obj.repo.toplevel .. util.path_sep .. git_obj.orig_relpath
|
||||
if git_obj:file_info(orig_file) then
|
||||
dprintf('Moved file reset')
|
||||
git_obj.relpath = git_obj.orig_relpath
|
||||
|
@ -65,7 +65,7 @@ local handle_moved = function(bufnr, bcache, old_relpath)
|
|||
end
|
||||
|
||||
if do_update then
|
||||
git_obj.file = git_obj.toplevel .. util.path_sep .. git_obj.relpath
|
||||
git_obj.file = git_obj.repo.toplevel .. util.path_sep .. git_obj.relpath
|
||||
bcache.file = git_obj.file
|
||||
bcache.git_obj:update_file_info()
|
||||
scheduler()
|
||||
|
@ -97,10 +97,10 @@ local watch_index = function(bufnr, gitdir)
|
|||
|
||||
local git_obj = bcache.git_obj
|
||||
|
||||
git_obj:update_abbrev_head()
|
||||
git_obj.repo:update_abbrev_head()
|
||||
|
||||
scheduler()
|
||||
Status:update(bufnr, { head = git_obj.abbrev_head })
|
||||
Status:update(bufnr, { head = git_obj.repo.abbrev_head })
|
||||
|
||||
local was_tracked = git_obj.object_name ~= nil
|
||||
local old_relpath = git_obj.relpath
|
||||
|
@ -240,20 +240,21 @@ local attach0 = function(cbuf, aucmd)
|
|||
end
|
||||
|
||||
local git_obj = git.Obj.new(file)
|
||||
local repo = git_obj.repo
|
||||
|
||||
if not git_obj.gitdir then
|
||||
if not repo.gitdir then
|
||||
dprint('Not in git repo')
|
||||
return
|
||||
end
|
||||
|
||||
scheduler()
|
||||
Status:update(cbuf, {
|
||||
head = git_obj.abbrev_head,
|
||||
root = git_obj.toplevel,
|
||||
gitdir = git_obj.gitdir,
|
||||
head = repo.abbrev_head,
|
||||
root = repo.toplevel,
|
||||
gitdir = repo.gitdir,
|
||||
})
|
||||
|
||||
if vim.startswith(file, git_obj.gitdir .. util.path_sep) then
|
||||
if vim.startswith(file, repo.gitdir .. util.path_sep) then
|
||||
dprint('In non-standard git dir')
|
||||
return
|
||||
end
|
||||
|
@ -286,7 +287,7 @@ local attach0 = function(cbuf, aucmd)
|
|||
base = config.base,
|
||||
file = file,
|
||||
commit = commit,
|
||||
index_watcher = watch_index(cbuf, git_obj.gitdir),
|
||||
index_watcher = watch_index(cbuf, repo.gitdir),
|
||||
git_obj = git_obj,
|
||||
})
|
||||
|
||||
|
@ -413,8 +414,9 @@ local _update_cwd_head = function()
|
|||
local cwd = vim.fn.getcwd()
|
||||
local head
|
||||
for _, bcache in pairs(cache) do
|
||||
if bcache.git_obj.toplevel == cwd then
|
||||
head = bcache.git_obj.abbrev_head
|
||||
local repo = bcache.git_obj.repo
|
||||
if repo.toplevel == cwd then
|
||||
head = repo.abbrev_head
|
||||
break
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
local void = require('plenary.async.async').void
|
||||
local scheduler = require('plenary.async.util').scheduler
|
||||
local block_on = require('plenary.async.util').block_on
|
||||
|
||||
local Status = require("gitsigns.status")
|
||||
local config = require('gitsigns.config').config
|
||||
|
@ -28,7 +27,12 @@ local NavHunkOpts = {}
|
|||
|
||||
|
||||
|
||||
local M = {}
|
||||
local M = {QFListOpts = {}, }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -452,13 +456,13 @@ local function run_diff(a, b)
|
|||
return f(a, b, diff_opts.algorithm, diff_opts.indent_heuristic)
|
||||
end
|
||||
|
||||
local function get_blame_hunk(git_obj, info)
|
||||
local function get_blame_hunk(repo, info)
|
||||
local a = {}
|
||||
|
||||
if info.previous then
|
||||
a = git_obj:get_show_text(info.previous_sha .. ':' .. info.previous_filename)
|
||||
a = repo:get_show_text(info.previous_sha .. ':' .. info.previous_filename)
|
||||
end
|
||||
local b = git_obj:get_show_text(info.sha .. ':' .. info.filename)
|
||||
local b = repo:get_show_text(info.sha .. ':' .. info.filename)
|
||||
local hunks = run_diff(a, b)
|
||||
local hunk, i = gs_hunks.find_hunk(info.orig_lnum, hunks)
|
||||
return hunk, i, #hunks
|
||||
|
@ -516,7 +520,7 @@ M.blame_line = void(function(full)
|
|||
vim.list_extend(lines, commit_message)
|
||||
|
||||
if full then
|
||||
hunk, ihunk, nhunk = get_blame_hunk(bcache.git_obj, result)
|
||||
hunk, ihunk, nhunk = get_blame_hunk(bcache.git_obj.repo, result)
|
||||
end
|
||||
else
|
||||
lines[#lines + 1] = result.author
|
||||
|
@ -595,7 +599,7 @@ M.diffthis = void(function(base)
|
|||
local err
|
||||
local comp_obj = bcache:get_compare_obj(calc_base(base))
|
||||
if base then
|
||||
text, err = bcache.git_obj:get_show_text(comp_obj)
|
||||
text, err = bcache.git_obj.repo:get_show_text(comp_obj)
|
||||
if err then
|
||||
print(err)
|
||||
return
|
||||
|
@ -607,7 +611,7 @@ M.diffthis = void(function(base)
|
|||
|
||||
local ft = api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
|
||||
local bufname = string.format('gitsigns://%s/%s', bcache.git_obj.gitdir, comp_obj)
|
||||
local bufname = string.format('gitsigns://%s/%s', bcache.git_obj.repo.gitdir, comp_obj)
|
||||
|
||||
|
||||
vim.cmd("keepalt aboveleft vertical split " .. bufname)
|
||||
|
@ -647,54 +651,59 @@ local function buildqflist(target)
|
|||
local bufnr = target
|
||||
if not cache[bufnr] then return end
|
||||
hunks_to_qflist(bufnr, cache[bufnr].hunks, qflist)
|
||||
elseif target == 'attached' or target == 'all' then
|
||||
local gitdirs_done = {}
|
||||
elseif target == 'attached' then
|
||||
for bufnr, bcache in pairs(cache) do
|
||||
hunks_to_qflist(bufnr, bcache.hunks, qflist)
|
||||
end
|
||||
elseif target == 'all' then
|
||||
local repos = {}
|
||||
for _, bcache in pairs(cache) do
|
||||
local repo = bcache.git_obj.repo
|
||||
repos[repo] = true
|
||||
end
|
||||
|
||||
if target == 'all' then
|
||||
local git_obj = bcache.git_obj
|
||||
if not gitdirs_done[git_obj.gitdir] then
|
||||
for _, f in ipairs(git_obj:files_changed()) do
|
||||
local f_abs = git_obj.toplevel .. '/' .. f
|
||||
local stat = vim.loop.fs_stat(f_abs)
|
||||
if stat and stat.type == 'file' then
|
||||
local hunks = run_diff(
|
||||
git_obj:get_show_text(':0:' .. f),
|
||||
util.file_lines(f_abs))
|
||||
local repo = git.Repo.new(vim.fn.getcwd())
|
||||
repos[repo] = true
|
||||
|
||||
hunks_to_qflist(f_abs, hunks, qflist)
|
||||
end
|
||||
end
|
||||
for r, _ in pairs(repos) do
|
||||
for _, f in ipairs(r:files_changed()) do
|
||||
local f_abs = r.toplevel .. '/' .. f
|
||||
local stat = vim.loop.fs_stat(f_abs)
|
||||
if stat and stat.type == 'file' then
|
||||
local a = r:get_show_text(':0:' .. f)
|
||||
scheduler()
|
||||
local hunks = run_diff(a, util.file_lines(f_abs))
|
||||
hunks_to_qflist(f_abs, hunks, qflist)
|
||||
end
|
||||
gitdirs_done[git_obj.gitdir] = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return qflist
|
||||
end
|
||||
|
||||
M.setqflist = function(target)
|
||||
block_on(function()
|
||||
local qflist = buildqflist(target)
|
||||
scheduler()
|
||||
vim.fn.setqflist({}, ' ', {
|
||||
items = qflist,
|
||||
title = 'Hunks',
|
||||
})
|
||||
end)
|
||||
end
|
||||
M.setqflist = void(function(target, opts)
|
||||
opts = opts or {}
|
||||
local qfopts = {
|
||||
items = buildqflist(target),
|
||||
title = 'Hunks',
|
||||
}
|
||||
scheduler()
|
||||
if opts.use_location_list then
|
||||
local nr = opts.nr or 0
|
||||
vim.fn.setloclist(nr, {}, ' ', qfopts)
|
||||
vim.cmd([[lopen]])
|
||||
else
|
||||
vim.fn.setqflist({}, ' ', qfopts)
|
||||
vim.cmd([[copen]])
|
||||
end
|
||||
end)
|
||||
|
||||
M.setloclist = function(nr, target)
|
||||
block_on(function()
|
||||
nr = nr or 0
|
||||
local qflist = buildqflist(target)
|
||||
scheduler()
|
||||
vim.fn.setloclist(nr, {}, ' ', {
|
||||
items = qflist,
|
||||
title = 'Hunks',
|
||||
})
|
||||
end)
|
||||
M.setqflist(target, {
|
||||
nr = nr,
|
||||
use_location_list = true,
|
||||
})
|
||||
end
|
||||
|
||||
M.get_actions = function()
|
||||
|
|
|
@ -54,7 +54,7 @@ M.update = void(function()
|
|||
api.nvim_buf_set_extmark(bufnr, namespace, lnum - 1, 0, {
|
||||
id = 1,
|
||||
virt_text = config.current_line_blame_formatter(
|
||||
bcache.git_obj.username,
|
||||
bcache.git_obj.repo.username,
|
||||
result,
|
||||
config.current_line_blame_formatter_opts),
|
||||
|
||||
|
|
|
@ -21,7 +21,14 @@ local GJobSpec = {}
|
|||
|
||||
|
||||
|
||||
local M = {BlameInfo = {}, Version = {}, Obj = {}, }
|
||||
local M = {BlameInfo = {}, Version = {}, Repo = {}, Obj = {}, }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -87,6 +94,7 @@ local M = {BlameInfo = {}, Version = {}, Obj = {}, }
|
|||
|
||||
|
||||
local Obj = M.Obj
|
||||
local Repo = M.Repo
|
||||
|
||||
local function parse_version(version)
|
||||
assert(version:match('%d+%.%d+%.%w+'), 'Invalid git version: ' .. version)
|
||||
|
@ -216,16 +224,60 @@ end
|
|||
|
||||
|
||||
|
||||
Obj.command = function(self, args, spec)
|
||||
Repo.command = function(self, args, spec)
|
||||
spec = spec or {}
|
||||
spec.cwd = self.toplevel
|
||||
return M.command({ '--git-dir=' .. self.gitdir, unpack(args) }, spec)
|
||||
end
|
||||
|
||||
Obj.update_abbrev_head = function(self)
|
||||
Repo.files_changed = function(self)
|
||||
local results = self:command({ 'status', '--porcelain', '--ignore-submodules' })
|
||||
|
||||
local ret = {}
|
||||
for _, line in ipairs(results) do
|
||||
if line:sub(1, 2):match('^.M') then
|
||||
ret[#ret + 1] = line:sub(4, -1)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
Repo.get_show_text = function(self, object)
|
||||
return self:command({ 'show', object }, { supress_stderr = true })
|
||||
end
|
||||
|
||||
Repo.update_abbrev_head = function(self)
|
||||
_, _, self.abbrev_head = M.get_repo_info(self.toplevel)
|
||||
end
|
||||
|
||||
Repo.new = function(dir)
|
||||
local self = setmetatable({}, { __index = Repo })
|
||||
|
||||
self.username = M.command({ 'config', 'user.name' })[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head = M.get_repo_info(dir)
|
||||
|
||||
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(dir, os.getenv('HOME')) and
|
||||
#M.command({ 'ls-files', dir }, { command = 'yadm' }) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(dir, 'yadm')
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Obj.command = function(self, args, spec)
|
||||
return self.repo:command(args, spec)
|
||||
end
|
||||
|
||||
Obj.update_file_info = function(self)
|
||||
local old_object_name = self.object_name
|
||||
_, self.object_name, self.mode_bits, self.has_conflicts = self:file_info()
|
||||
|
@ -270,13 +322,8 @@ Obj.unstage_file = function(self)
|
|||
self:command({ 'reset', self.file })
|
||||
end
|
||||
|
||||
|
||||
Obj.get_show_text = function(self, object)
|
||||
return self:command({ 'show', object }, { supress_stderr = true })
|
||||
end
|
||||
|
||||
Obj.run_blame = function(self, lines, lnum)
|
||||
if not self.object_name or self.abbrev_head == '' then
|
||||
if not self.object_name or self.repo.abbrev_head == '' then
|
||||
|
||||
|
||||
|
||||
|
@ -356,43 +403,20 @@ Obj.has_moved = function(self)
|
|||
if orig_relpath == orig then
|
||||
self.orig_relpath = orig_relpath
|
||||
self.relpath = new
|
||||
self.file = self.toplevel .. '/' .. new
|
||||
self.file = self.repo.toplevel .. '/' .. new
|
||||
return new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Obj.files_changed = function(self)
|
||||
local results = self:command({ 'status', '--porcelain', '--ignore-submodules' })
|
||||
|
||||
local ret = {}
|
||||
for _, line in ipairs(results) do
|
||||
if line:sub(1, 2):match('^.M') then
|
||||
ret[#ret + 1] = line:sub(4, -1)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
Obj.new = function(file)
|
||||
local self = setmetatable({}, { __index = Obj })
|
||||
|
||||
self.file = file
|
||||
self.username = M.command({ 'config', 'user.name' })[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(util.dirname(file))
|
||||
self.repo = Repo.new(util.dirname(file))
|
||||
|
||||
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(file, os.getenv('HOME')) and
|
||||
#M.command({ 'ls-files', file }, { command = 'yadm' }) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(util.dirname(file), 'yadm')
|
||||
end
|
||||
end
|
||||
|
||||
if not self.gitdir then
|
||||
if not self.repo.gitdir then
|
||||
return self
|
||||
end
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ local update0 = function(bufnr, bcache)
|
|||
end
|
||||
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
bcache.compare_text = git_obj.repo:get_show_text(compare_object)
|
||||
end
|
||||
|
||||
bcache.hunks = run_diff(bcache.compare_text, buftext,
|
||||
|
@ -243,7 +243,7 @@ local update0 = function(bufnr, bcache)
|
|||
M.apply_win_signs(bufnr, bcache.pending_signs)
|
||||
end
|
||||
local summary = gs_hunks.get_summary(bcache.hunks)
|
||||
summary.head = git_obj.abbrev_head
|
||||
summary.head = git_obj.repo.abbrev_head
|
||||
Status:update(bufnr, summary)
|
||||
|
||||
update_cnt = update_cnt + 1
|
||||
|
|
|
@ -53,7 +53,7 @@ local handle_moved = function(bufnr: integer, bcache: CacheEntry, old_relpath: s
|
|||
end
|
||||
do_update = true
|
||||
elseif git_obj.orig_relpath then
|
||||
local orig_file = git_obj.toplevel..util.path_sep..git_obj.orig_relpath
|
||||
local orig_file = git_obj.repo.toplevel..util.path_sep..git_obj.orig_relpath
|
||||
if git_obj:file_info(orig_file) then
|
||||
dprintf('Moved file reset')
|
||||
git_obj.relpath = git_obj.orig_relpath
|
||||
|
@ -65,7 +65,7 @@ local handle_moved = function(bufnr: integer, bcache: CacheEntry, old_relpath: s
|
|||
end
|
||||
|
||||
if do_update then
|
||||
git_obj.file = git_obj.toplevel..util.path_sep..git_obj.relpath
|
||||
git_obj.file = git_obj.repo.toplevel..util.path_sep..git_obj.relpath
|
||||
bcache.file = git_obj.file
|
||||
bcache.git_obj:update_file_info()
|
||||
scheduler()
|
||||
|
@ -97,10 +97,10 @@ local watch_index = function(bufnr: integer, gitdir: string): uv.FSPollObj
|
|||
|
||||
local git_obj = bcache.git_obj
|
||||
|
||||
git_obj:update_abbrev_head()
|
||||
git_obj.repo:update_abbrev_head()
|
||||
|
||||
scheduler()
|
||||
Status:update(bufnr, { head = git_obj.abbrev_head})
|
||||
Status:update(bufnr, { head = git_obj.repo.abbrev_head})
|
||||
|
||||
local was_tracked = git_obj.object_name ~= nil
|
||||
local old_relpath = git_obj.relpath
|
||||
|
@ -240,20 +240,21 @@ local attach0 = function(cbuf: integer, aucmd: string)
|
|||
end
|
||||
|
||||
local git_obj = git.Obj.new(file)
|
||||
local repo = git_obj.repo
|
||||
|
||||
if not git_obj.gitdir then
|
||||
if not repo.gitdir then
|
||||
dprint('Not in git repo')
|
||||
return
|
||||
end
|
||||
|
||||
scheduler()
|
||||
Status:update(cbuf, {
|
||||
head = git_obj.abbrev_head,
|
||||
root = git_obj.toplevel,
|
||||
gitdir = git_obj.gitdir,
|
||||
head = repo.abbrev_head,
|
||||
root = repo.toplevel,
|
||||
gitdir = repo.gitdir,
|
||||
})
|
||||
|
||||
if vim.startswith(file, git_obj.gitdir..util.path_sep) then
|
||||
if vim.startswith(file, repo.gitdir..util.path_sep) then
|
||||
dprint('In non-standard git dir')
|
||||
return
|
||||
end
|
||||
|
@ -286,7 +287,7 @@ local attach0 = function(cbuf: integer, aucmd: string)
|
|||
base = config.base,
|
||||
file = file,
|
||||
commit = commit,
|
||||
index_watcher = watch_index(cbuf, git_obj.gitdir),
|
||||
index_watcher = watch_index(cbuf, repo.gitdir),
|
||||
git_obj = git_obj
|
||||
}
|
||||
|
||||
|
@ -413,8 +414,9 @@ local _update_cwd_head = function()
|
|||
local cwd = vim.fn.getcwd()
|
||||
local head: string
|
||||
for _, bcache in pairs(cache as {number:CacheEntry}) do
|
||||
if bcache.git_obj.toplevel == cwd then
|
||||
head = bcache.git_obj.abbrev_head
|
||||
local repo = bcache.git_obj.repo
|
||||
if repo.toplevel == cwd then
|
||||
head = repo.abbrev_head
|
||||
break
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
local void = require('plenary.async.async').void
|
||||
local scheduler = require('plenary.async.util').scheduler
|
||||
local block_on = require('plenary.async.util').block_on
|
||||
|
||||
local Status = require("gitsigns.status")
|
||||
local config = require('gitsigns.config').config
|
||||
|
@ -48,7 +47,12 @@ local record M
|
|||
reset_base : function(global: boolean)
|
||||
diffthis : function -- function(base: string)
|
||||
|
||||
setqflist : function(target:integer|string)
|
||||
record QFListOpts
|
||||
use_location_list: boolean
|
||||
nr: integer
|
||||
end
|
||||
|
||||
setqflist : function(target:integer|string, opts: QFListOpts, callback: function)
|
||||
setloclist : function(nr: integer, target:integer|string)
|
||||
|
||||
user_range : {integer, integer}
|
||||
|
@ -452,13 +456,13 @@ local function run_diff(a: {string}, b: {string}): {Hunk}
|
|||
return f(a, b, diff_opts.algorithm, diff_opts.indent_heuristic)
|
||||
end
|
||||
|
||||
local function get_blame_hunk(git_obj: git.Obj, info: git.BlameInfo): Hunk, integer, integer
|
||||
local function get_blame_hunk(repo: git.Repo, info: git.BlameInfo): Hunk, integer, integer
|
||||
local a = {}
|
||||
-- If no previous so sha of blame added the file
|
||||
if info.previous then
|
||||
a = git_obj:get_show_text(info.previous_sha..':'..info.previous_filename)
|
||||
a = repo:get_show_text(info.previous_sha..':'..info.previous_filename)
|
||||
end
|
||||
local b = git_obj:get_show_text(info.sha..':'..info.filename)
|
||||
local b = repo:get_show_text(info.sha..':'..info.filename)
|
||||
local hunks = run_diff(a, b)
|
||||
local hunk, i = gs_hunks.find_hunk(info.orig_lnum, hunks)
|
||||
return hunk, i, #hunks
|
||||
|
@ -516,7 +520,7 @@ M.blame_line = void(function(full: boolean)
|
|||
vim.list_extend(lines, commit_message)
|
||||
|
||||
if full then
|
||||
hunk, ihunk, nhunk = get_blame_hunk(bcache.git_obj, result)
|
||||
hunk, ihunk, nhunk = get_blame_hunk(bcache.git_obj.repo, result)
|
||||
end
|
||||
else
|
||||
lines[#lines+1] = result.author
|
||||
|
@ -595,7 +599,7 @@ M.diffthis = void(function(base: string)
|
|||
local err: string
|
||||
local comp_obj = bcache:get_compare_obj(calc_base(base))
|
||||
if base then
|
||||
text, err = bcache.git_obj:get_show_text(comp_obj)
|
||||
text, err = bcache.git_obj.repo:get_show_text(comp_obj)
|
||||
if err then
|
||||
print(err)
|
||||
return
|
||||
|
@ -607,7 +611,7 @@ M.diffthis = void(function(base: string)
|
|||
|
||||
local ft = api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
|
||||
local bufname = string.format('gitsigns://%s/%s', bcache.git_obj.gitdir, comp_obj)
|
||||
local bufname = string.format('gitsigns://%s/%s', bcache.git_obj.repo.gitdir, comp_obj)
|
||||
|
||||
-- TDOD lewis6991 (27/05/21): Respect 'vertical' in diffopt
|
||||
vim.cmd("keepalt aboveleft vertical split "..bufname)
|
||||
|
@ -647,54 +651,59 @@ local function buildqflist(target: integer|string): {vim.fn.QFItem}
|
|||
local bufnr = target as integer
|
||||
if not cache[bufnr] then return end
|
||||
hunks_to_qflist(bufnr, cache[bufnr].hunks, qflist)
|
||||
elseif target == 'attached' or target == 'all' then
|
||||
local gitdirs_done: {string:boolean} = {}
|
||||
elseif target == 'attached' then
|
||||
for bufnr, bcache in pairs(cache as {integer:CacheEntry}) do
|
||||
hunks_to_qflist(bufnr, bcache.hunks, qflist)
|
||||
end
|
||||
elseif target == 'all' then
|
||||
local repos: {git.Repo:boolean} = {}
|
||||
for _, bcache in pairs(cache as {integer:CacheEntry}) do
|
||||
local repo = bcache.git_obj.repo
|
||||
repos[repo] = true
|
||||
end
|
||||
|
||||
if target == 'all' then
|
||||
local git_obj = bcache.git_obj
|
||||
if not gitdirs_done[git_obj.gitdir] then
|
||||
for _, f in ipairs(git_obj:files_changed()) do
|
||||
local f_abs = git_obj.toplevel..'/'..f
|
||||
local stat = vim.loop.fs_stat(f_abs)
|
||||
if stat and stat.type == 'file' then
|
||||
local hunks = run_diff(
|
||||
git_obj:get_show_text(':0:'..f),
|
||||
util.file_lines(f_abs)
|
||||
)
|
||||
hunks_to_qflist(f_abs, hunks, qflist)
|
||||
end
|
||||
end
|
||||
local repo = git.Repo.new(vim.fn.getcwd())
|
||||
repos[repo] = true
|
||||
|
||||
for r, _ in pairs(repos) do
|
||||
for _, f in ipairs(r:files_changed()) do
|
||||
local f_abs = r.toplevel..'/'..f
|
||||
local stat = vim.loop.fs_stat(f_abs)
|
||||
if stat and stat.type == 'file' then
|
||||
local a = r:get_show_text(':0:'..f)
|
||||
scheduler()
|
||||
local hunks = run_diff(a, util.file_lines(f_abs))
|
||||
hunks_to_qflist(f_abs, hunks, qflist)
|
||||
end
|
||||
gitdirs_done[git_obj.gitdir] = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return qflist
|
||||
end
|
||||
|
||||
M.setqflist = function(target: integer|string)
|
||||
block_on(function()
|
||||
local qflist = buildqflist(target)
|
||||
scheduler()
|
||||
vim.fn.setqflist({}, ' ', {
|
||||
items = qflist,
|
||||
title = 'Hunks'
|
||||
})
|
||||
end)
|
||||
end
|
||||
M.setqflist = void(function(target: integer|string, opts: M.QFListOpts)
|
||||
opts = opts or {}
|
||||
local qfopts = {
|
||||
items = buildqflist(target),
|
||||
title = 'Hunks'
|
||||
}
|
||||
scheduler()
|
||||
if opts.use_location_list then
|
||||
local nr = opts.nr or 0
|
||||
vim.fn.setloclist(nr, {}, ' ', qfopts)
|
||||
vim.cmd[[lopen]]
|
||||
else
|
||||
vim.fn.setqflist({}, ' ', qfopts)
|
||||
vim.cmd[[copen]]
|
||||
end
|
||||
end)
|
||||
|
||||
M.setloclist = function(nr: integer, target: integer|string)
|
||||
block_on(function()
|
||||
nr = nr or 0
|
||||
local qflist = buildqflist(target)
|
||||
scheduler()
|
||||
vim.fn.setloclist(nr, {}, ' ', {
|
||||
items = qflist,
|
||||
title = 'Hunks'
|
||||
})
|
||||
end)
|
||||
M.setqflist(target, {
|
||||
nr = nr,
|
||||
use_location_list = true
|
||||
})
|
||||
end
|
||||
|
||||
M.get_actions = function(): {string:function}
|
||||
|
|
|
@ -54,7 +54,7 @@ M.update = void(function()
|
|||
api.nvim_buf_set_extmark(bufnr, namespace, lnum-1, 0, {
|
||||
id = 1,
|
||||
virt_text = config.current_line_blame_formatter(
|
||||
bcache.git_obj.username,
|
||||
bcache.git_obj.repo.username,
|
||||
result,
|
||||
config.current_line_blame_formatter_opts
|
||||
),
|
||||
|
|
|
@ -58,12 +58,22 @@ local record M
|
|||
get_repo_info: function(path: string, cmd: string): string,string,string
|
||||
command : function(args: {string}, spec: GJobSpec): {string}, string
|
||||
|
||||
record Repo
|
||||
toplevel : string
|
||||
gitdir : string
|
||||
abbrev_head: string
|
||||
username : string
|
||||
|
||||
command : function(Repo, {string}, GJobSpec): {string}, string
|
||||
files_changed : function(Repo): {string}
|
||||
get_show_text : function(Repo, string): {string}, string
|
||||
update_abbrev_head : function(Repo)
|
||||
new : function(string): Repo
|
||||
end
|
||||
|
||||
record Obj
|
||||
toplevel : string
|
||||
gitdir : string
|
||||
repo : Repo
|
||||
file : string
|
||||
abbrev_head : string
|
||||
username : string
|
||||
relpath : string
|
||||
orig_relpath : string -- Use for tracking moved files
|
||||
object_name : string
|
||||
|
@ -71,22 +81,20 @@ local record M
|
|||
has_conflicts : boolean
|
||||
|
||||
command : function(Obj, {string}, GJobSpec): {string}, string
|
||||
update_abbrev_head : function(Obj)
|
||||
update_file_info : function(Obj): boolean
|
||||
unstage_file : function(Obj, string, string)
|
||||
get_show_text : function(Obj, string): {string}, string
|
||||
run_blame : function(Obj, {string}, number): BlameInfo
|
||||
file_info : function(Obj, string): string, string, string, boolean
|
||||
ensure_file_in_index : function(Obj)
|
||||
stage_hunks : function(Obj, {Hunk}, boolean)
|
||||
has_moved : function(Obj): string
|
||||
files_changed : function(Obj): {string}
|
||||
new : function(string): Obj
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local Obj = M.Obj
|
||||
local Repo = M.Repo
|
||||
|
||||
local function parse_version(version: string): M.Version
|
||||
assert(version:match('%d+%.%d+%.%w+'), 'Invalid git version: '..version)
|
||||
|
@ -212,20 +220,64 @@ M.set_version = function(version: string)
|
|||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Git object methods
|
||||
-- Git repo object methods
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--- Run git command the with the objects gitdir and toplevel
|
||||
Obj.command = function(self: Obj, args: {string}, spec: GJobSpec): {string}, string
|
||||
Repo.command = function(self: Repo, args: {string}, spec: GJobSpec): {string}, string
|
||||
spec = spec or {}
|
||||
spec.cwd = self.toplevel
|
||||
return M.command({'--git-dir='..self.gitdir, unpack(args)}, spec)
|
||||
end
|
||||
|
||||
Obj.update_abbrev_head = function(self: Obj)
|
||||
Repo.files_changed = function(self: Repo): {string}
|
||||
local results = self:command({ 'status', '--porcelain', '--ignore-submodules' })
|
||||
|
||||
local ret: {string} = {}
|
||||
for _, line in ipairs(results) do
|
||||
if line:sub(1, 2):match('^.M') then
|
||||
ret[#ret+1] = line:sub(4, -1)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Get version of file in the index, return array lines
|
||||
Repo.get_show_text = function(self: Repo, object: string): {string}, string
|
||||
return self:command({'show', object}, {supress_stderr = true})
|
||||
end
|
||||
|
||||
Repo.update_abbrev_head = function(self: Repo)
|
||||
_, _, self.abbrev_head = M.get_repo_info(self.toplevel)
|
||||
end
|
||||
|
||||
Repo.new = function(dir: string): Repo
|
||||
local self = setmetatable({} as Repo, {__index = Repo})
|
||||
|
||||
self.username = M.command({'config', 'user.name'})[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head = M.get_repo_info(dir)
|
||||
|
||||
-- Try yadm
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(dir, os.getenv('HOME'))
|
||||
and #M.command({'ls-files', dir}, {command = 'yadm'}) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(dir, 'yadm')
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Git object methods
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--- Run git command the with the objects gitdir and toplevel
|
||||
Obj.command = function(self: Obj, args: {string}, spec: GJobSpec): {string}, string
|
||||
return self.repo:command(args, spec)
|
||||
end
|
||||
|
||||
Obj.update_file_info = function(self: Obj): boolean
|
||||
local old_object_name = self.object_name
|
||||
_, self.object_name, self.mode_bits, self.has_conflicts = self:file_info()
|
||||
|
@ -270,13 +322,8 @@ Obj.unstage_file = function(self: Obj)
|
|||
self:command{'reset', self.file }
|
||||
end
|
||||
|
||||
--- Get version of file in the index, return array lines
|
||||
Obj.get_show_text = function(self: Obj, object: string): {string}, string
|
||||
return self:command({'show', object}, { supress_stderr = true })
|
||||
end
|
||||
|
||||
Obj.run_blame = function(self: Obj, lines: {string}, lnum: number): M.BlameInfo
|
||||
if not self.object_name or self.abbrev_head == '' then
|
||||
if not self.object_name or self.repo.abbrev_head == '' then
|
||||
-- As we support attaching to untracked files we need to return something if
|
||||
-- the file isn't isn't tracked in git.
|
||||
-- If abbrev_head is empty, then assume the repo has no commits
|
||||
|
@ -356,43 +403,20 @@ Obj.has_moved = function(self: Obj): string
|
|||
if orig_relpath == orig then
|
||||
self.orig_relpath = orig_relpath
|
||||
self.relpath = new
|
||||
self.file = self.toplevel..'/'..new
|
||||
self.file = self.repo.toplevel..'/'..new
|
||||
return new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Obj.files_changed = function(self: Obj): {string}
|
||||
local results = self:command{'status', '--porcelain', '--ignore-submodules'}
|
||||
|
||||
local ret: {string} = {}
|
||||
for _, line in ipairs(results) do
|
||||
if line:sub(1, 2):match('^.M') then
|
||||
ret[#ret+1] = line:sub(4, -1)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
Obj.new = function(file: string): Obj
|
||||
local self = setmetatable({} as Obj, {__index = Obj})
|
||||
|
||||
self.file = file
|
||||
self.username = M.command({'config', 'user.name'})[1]
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(util.dirname(file))
|
||||
self.repo = Repo.new(util.dirname(file))
|
||||
|
||||
-- Try yadm
|
||||
if M.enable_yadm and not self.gitdir then
|
||||
if vim.startswith(file, os.getenv('HOME'))
|
||||
and #M.command({'ls-files', file}, {command = 'yadm'}) ~= 0 then
|
||||
self.toplevel, self.gitdir, self.abbrev_head =
|
||||
M.get_repo_info(util.dirname(file), 'yadm')
|
||||
end
|
||||
end
|
||||
|
||||
if not self.gitdir then
|
||||
if not self.repo.gitdir then
|
||||
return self
|
||||
end
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ local update0 = function(bufnr: integer, bcache: CacheEntry)
|
|||
end
|
||||
|
||||
if not bcache.compare_text or config._refresh_staged_on_update then
|
||||
bcache.compare_text = git_obj:get_show_text(compare_object)
|
||||
bcache.compare_text = git_obj.repo:get_show_text(compare_object)
|
||||
end
|
||||
|
||||
bcache.hunks = run_diff(bcache.compare_text, buftext,
|
||||
|
@ -243,7 +243,7 @@ local update0 = function(bufnr: integer, bcache: CacheEntry)
|
|||
M.apply_win_signs(bufnr, bcache.pending_signs)
|
||||
end
|
||||
local summary = gs_hunks.get_summary(bcache.hunks)
|
||||
summary.head = git_obj.abbrev_head
|
||||
summary.head = git_obj.repo.abbrev_head
|
||||
Status:update(bufnr, summary)
|
||||
|
||||
update_cnt = update_cnt + 1
|
||||
|
|
Loading…
Reference in New Issue