mirror of
https://github.com/lewis6991/gitsigns.nvim
synced 2024-09-16 14:34:09 +02:00
feat: add staging and update locks
This commit is contained in:
parent
58bd9e98d8
commit
e6e3c3a139
5 changed files with 71 additions and 11 deletions
|
@ -275,6 +275,11 @@ M.stage_hunk = mk_repeatable(async.create(2, function(range, opts)
|
|||
return
|
||||
end
|
||||
|
||||
if bcache:locked() then
|
||||
print('Error: busy')
|
||||
return
|
||||
end
|
||||
|
||||
if not util.path_exists(bcache.file) then
|
||||
print('Error: Cannot stage lines. Please add the file to the working tree.')
|
||||
return
|
||||
|
@ -294,7 +299,6 @@ M.stage_hunk = mk_repeatable(async.create(2, function(range, opts)
|
|||
end
|
||||
|
||||
bcache.git_obj:stage_hunks({ hunk }, invert)
|
||||
|
||||
table.insert(bcache.staged_diffs, hunk)
|
||||
|
||||
bcache:invalidate(true)
|
||||
|
@ -397,6 +401,11 @@ M.undo_stage_hunk = async.create(function()
|
|||
return
|
||||
end
|
||||
|
||||
if bcache:locked() then
|
||||
print('Error: busy')
|
||||
return
|
||||
end
|
||||
|
||||
local hunk = table.remove(bcache.staged_diffs)
|
||||
if not hunk then
|
||||
print('No hunks to undo')
|
||||
|
@ -419,6 +428,11 @@ M.stage_buffer = async.create(function()
|
|||
return
|
||||
end
|
||||
|
||||
if bcache:locked() then
|
||||
print('Error: busy')
|
||||
return
|
||||
end
|
||||
|
||||
-- Only process files with existing hunks
|
||||
local hunks = bcache.hunks
|
||||
if not hunks or #hunks == 0 then
|
||||
|
@ -454,6 +468,11 @@ M.reset_buffer_index = async.create(function()
|
|||
return
|
||||
end
|
||||
|
||||
if bcache:locked() then
|
||||
print('Error: busy')
|
||||
return
|
||||
end
|
||||
|
||||
-- `bcache.staged_diffs` won't contain staged changes outside of current
|
||||
-- neovim session so signs added from this unstage won't be complete They will
|
||||
-- however be fixed by gitdir watcher and properly updated We should implement
|
||||
|
@ -463,7 +482,6 @@ M.reset_buffer_index = async.create(function()
|
|||
bcache.staged_diffs = {}
|
||||
|
||||
bcache.git_obj:unstage_file()
|
||||
|
||||
bcache:invalidate(true)
|
||||
update(bufnr)
|
||||
end)
|
||||
|
|
|
@ -20,6 +20,8 @@ local M = {
|
|||
--- @field gitdir_watcher? uv.uv_fs_event_t
|
||||
--- @field git_obj Gitsigns.GitObj
|
||||
--- @field blame? table<integer,Gitsigns.BlameInfo?>
|
||||
---
|
||||
--- @field update_lock? true Update in progress
|
||||
local CacheEntry = M.CacheEntry
|
||||
|
||||
function CacheEntry:get_rev_bufname(rev, nofile)
|
||||
|
@ -30,6 +32,10 @@ function CacheEntry:get_rev_bufname(rev, nofile)
|
|||
return string.format('gitsigns://%s//%s:%s', self.git_obj.repo.gitdir, rev, self.git_obj.relpath)
|
||||
end
|
||||
|
||||
function CacheEntry:locked()
|
||||
return self.git_obj.lock or self.update_lock or false
|
||||
end
|
||||
|
||||
--- Invalidate any state dependent on the buffer content.
|
||||
--- If 'all' is passed, then invalidate everything.
|
||||
--- @param all? boolean
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
local log = require('gitsigns.debug.log')
|
||||
local async = require('gitsigns.async')
|
||||
local util = require('gitsigns.util')
|
||||
local Repo = require('gitsigns.git.repo')
|
||||
|
||||
|
@ -31,6 +32,8 @@ end
|
|||
--- @field orig_relpath? string Use for tracking moved files
|
||||
--- @field repo Gitsigns.Repo
|
||||
--- @field has_conflicts? boolean
|
||||
---
|
||||
--- @field lock? true
|
||||
local Obj = {}
|
||||
|
||||
M.Obj = Obj
|
||||
|
@ -61,12 +64,14 @@ function M.diff(file_cmp, file_buf, indent_heuristic, diff_algo)
|
|||
})
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param revision? string
|
||||
function Obj:update_revision(revision)
|
||||
self.revision = util.norm_base(revision)
|
||||
self:update()
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param update_relpath? boolean
|
||||
--- @param silent? boolean
|
||||
--- @return boolean
|
||||
|
@ -98,6 +103,7 @@ function Obj:from_tree()
|
|||
return self.revision and not vim.startswith(self.revision, ':')
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param file? string
|
||||
--- @param silent? boolean
|
||||
--- @return Gitsigns.FileInfo
|
||||
|
@ -110,6 +116,7 @@ function Obj:file_info(file, silent)
|
|||
end
|
||||
|
||||
--- @private
|
||||
--- @async
|
||||
--- Get information about files in the index and the working tree
|
||||
--- @param file? string
|
||||
--- @param silent? boolean
|
||||
|
@ -177,6 +184,7 @@ function Obj:file_info_index(file, silent)
|
|||
end
|
||||
|
||||
--- @private
|
||||
--- @async
|
||||
--- Get information about files in a certain revision
|
||||
--- @param file? string
|
||||
--- @param silent? boolean
|
||||
|
@ -213,6 +221,7 @@ function Obj:file_info_tree(file, silent)
|
|||
}
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param revision? string
|
||||
--- @return string[] stdout, string? stderr
|
||||
function Obj:get_show_text(revision)
|
||||
|
@ -251,11 +260,15 @@ local function autocmd_changed(file)
|
|||
end)
|
||||
end
|
||||
|
||||
--- @async
|
||||
function Obj:unstage_file()
|
||||
self.lock = true
|
||||
self.repo:command({ 'reset', self.file })
|
||||
self.lock = nil
|
||||
autocmd_changed(self.file)
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param lines string[]
|
||||
--- @param lnum? integer
|
||||
--- @param revision? string
|
||||
|
@ -265,28 +278,33 @@ function Obj:run_blame(lines, lnum, revision, opts)
|
|||
return require('gitsigns.git.blame').run_blame(self, lines, lnum, revision, opts)
|
||||
end
|
||||
|
||||
--- @param obj Gitsigns.GitObj
|
||||
local function ensure_file_in_index(obj)
|
||||
if obj.object_name and not obj.has_conflicts then
|
||||
--- @async
|
||||
--- @private
|
||||
function Obj:ensure_file_in_index()
|
||||
self.lock = true
|
||||
if self.object_name and not self.has_conflicts then
|
||||
return
|
||||
end
|
||||
|
||||
if not obj.object_name then
|
||||
if not self.object_name then
|
||||
-- If there is no object_name then it is not yet in the index so add it
|
||||
obj.repo:command({ 'add', '--intent-to-add', obj.file })
|
||||
self.repo:command({ 'add', '--intent-to-add', self.file })
|
||||
else
|
||||
-- Update the index with the common ancestor (stage 1) which is what bcache
|
||||
-- stores
|
||||
local info = string.format('%s,%s,%s', obj.mode_bits, obj.object_name, obj.relpath)
|
||||
obj.repo:command({ 'update-index', '--add', '--cacheinfo', info })
|
||||
local info = string.format('%s,%s,%s', self.mode_bits, self.object_name, self.relpath)
|
||||
self.repo:command({ 'update-index', '--add', '--cacheinfo', info })
|
||||
end
|
||||
|
||||
obj:update()
|
||||
self:update()
|
||||
self.lock = nil
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- Stage 'lines' as the entire contents of the file
|
||||
--- @param lines string[]
|
||||
function Obj:stage_lines(lines)
|
||||
self.lock = true
|
||||
local new_object = self.repo:command({
|
||||
'hash-object',
|
||||
'-w',
|
||||
|
@ -301,13 +319,20 @@ function Obj:stage_lines(lines)
|
|||
string.format('%s,%s,%s', self.mode_bits, new_object, self.relpath),
|
||||
})
|
||||
|
||||
self.lock = nil
|
||||
autocmd_changed(self.file)
|
||||
end
|
||||
|
||||
local sleep = async.wrap(2, function(duration, cb)
|
||||
vim.defer_fn(cb, duration)
|
||||
end)
|
||||
|
||||
--- @async
|
||||
--- @param hunks Gitsigns.Hunk.Hunk[]
|
||||
--- @param invert? boolean
|
||||
function Obj:stage_hunks(hunks, invert)
|
||||
ensure_file_in_index(self)
|
||||
self.lock = true
|
||||
self:ensure_file_in_index()
|
||||
|
||||
local patch = require('gitsigns.hunks').create_patch(self.relpath, hunks, self.mode_bits, invert)
|
||||
|
||||
|
@ -328,9 +353,15 @@ function Obj:stage_hunks(hunks, invert)
|
|||
stdin = patch,
|
||||
})
|
||||
|
||||
-- Staging operations cause IO of the git directory so wait some time
|
||||
-- for the changes to settle.
|
||||
sleep(100)
|
||||
|
||||
self.lock = nil
|
||||
autocmd_changed(self.file)
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @return string?
|
||||
function Obj:has_moved()
|
||||
local out = self.repo:command({ 'diff', '--name-status', '-C', '--cached' })
|
||||
|
@ -349,6 +380,7 @@ function Obj:has_moved()
|
|||
end
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- @param file string
|
||||
--- @param revision string?
|
||||
--- @param encoding string
|
||||
|
|
|
@ -81,6 +81,7 @@ local function iconv_supported(encoding)
|
|||
return true
|
||||
end
|
||||
|
||||
--- @async
|
||||
--- Get version of file in the index, return array lines
|
||||
--- @param object string
|
||||
--- @param encoding? string
|
||||
|
|
|
@ -448,6 +448,8 @@ M.update = throttle_by_id(function(bufnr)
|
|||
return
|
||||
end
|
||||
local bcache = assert(cache[bufnr])
|
||||
bcache.update_lock = true
|
||||
|
||||
local old_hunks, old_hunks_staged = bcache.hunks, bcache.hunks_staged
|
||||
bcache.hunks, bcache.hunks_staged = nil, nil
|
||||
|
||||
|
@ -505,6 +507,7 @@ M.update = throttle_by_id(function(bufnr)
|
|||
summary.head = git_obj.repo.abbrev_head
|
||||
Status:update(bufnr, summary)
|
||||
end
|
||||
bcache.update_lock = nil
|
||||
end, true)
|
||||
|
||||
--- @param bufnr integer
|
||||
|
|
Loading…
Reference in a new issue