Skip to content

Commit 508f28e

Browse files
committed
fix(ProjectDiffScreen): Stay at next hunk/file after staging
- Hunk operations now stay at same index (the next hunk) - File operations now go to next file in order, not first file
1 parent 83d3850 commit 508f28e

1 file changed

Lines changed: 103 additions & 23 deletions

File tree

  • lua/vgit/features/screens/ProjectDiffScreen

lua/vgit/features/screens/ProjectDiffScreen/init.lua

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function ProjectDiffScreen:stage_hunk()
9393
if entry.type ~= 'unstaged' then return end
9494

9595
loop.free_textlock()
96-
local hunk = self.diff_view:get_hunk_under_cursor()
96+
local hunk, hunk_index = self.diff_view:get_hunk_under_cursor()
9797
if not hunk then return end
9898

9999
local filename = entry.status.filename
@@ -128,6 +128,19 @@ function ProjectDiffScreen:stage_hunk()
128128
end
129129
end
130130
end)
131+
132+
-- If still on the same file, stay at same hunk index position
133+
local new_entry = self.model:get_entry()
134+
if new_entry
135+
and new_entry.type == 'unstaged'
136+
and new_entry.status.filename == filename then
137+
local diff = self.model:get_diff()
138+
if diff and diff.marks and #diff.marks > 0 then
139+
local target = math.min(hunk_index, #diff.marks)
140+
local hunk_alignment = project_diff_preview_setting:get('hunk_alignment')
141+
self.diff_view:move_to_hunk(target, hunk_alignment)
142+
end
143+
end
131144
end
132145

133146
function ProjectDiffScreen:unstage_hunk()
@@ -136,7 +149,7 @@ function ProjectDiffScreen:unstage_hunk()
136149
if entry.type ~= 'staged' then return end
137150

138151
loop.free_textlock()
139-
local hunk = self.diff_view:get_hunk_under_cursor()
152+
local hunk, hunk_index = self.diff_view:get_hunk_under_cursor()
140153
if not hunk then return end
141154

142155
local filename = entry.status.filename
@@ -171,6 +184,19 @@ function ProjectDiffScreen:unstage_hunk()
171184
end
172185
end
173186
end)
187+
188+
-- If still on the same file, stay at same hunk index position
189+
local new_entry = self.model:get_entry()
190+
if new_entry
191+
and new_entry.type == 'staged'
192+
and new_entry.status.filename == filename then
193+
local diff = self.model:get_diff()
194+
if diff and diff.marks and #diff.marks > 0 then
195+
local target = math.min(hunk_index, #diff.marks)
196+
local hunk_alignment = project_diff_preview_setting:get('hunk_alignment')
197+
self.diff_view:move_to_hunk(target, hunk_alignment)
198+
end
199+
end
174200
end
175201

176202
function ProjectDiffScreen:reset_hunk()
@@ -179,7 +205,7 @@ function ProjectDiffScreen:reset_hunk()
179205
if entry.type ~= 'unstaged' then return end
180206

181207
loop.free_textlock()
182-
local hunk = self.diff_view:get_hunk_under_cursor()
208+
local hunk, hunk_index = self.diff_view:get_hunk_under_cursor()
183209
if not hunk then return end
184210

185211
local filename = entry.status.filename
@@ -218,6 +244,19 @@ function ProjectDiffScreen:reset_hunk()
218244
end
219245
end
220246
end)
247+
248+
-- If still on the same file, stay at same hunk index position
249+
local new_entry = self.model:get_entry()
250+
if new_entry
251+
and new_entry.type == 'unstaged'
252+
and new_entry.status.filename == filename then
253+
local diff = self.model:get_diff()
254+
if diff and diff.marks and #diff.marks > 0 then
255+
local target = math.min(hunk_index, #diff.marks)
256+
local hunk_alignment = project_diff_preview_setting:get('hunk_alignment')
257+
self.diff_view:move_to_hunk(target, hunk_alignment)
258+
end
259+
end
221260
end
222261

223262
function ProjectDiffScreen:stage_file()
@@ -227,24 +266,45 @@ function ProjectDiffScreen:stage_file()
227266

228267
loop.free_textlock()
229268
local filename = entry.status.filename
269+
270+
-- Find the next unstaged file after this one (before staging)
271+
local next_unstaged_filename = nil
272+
local found_current = false
273+
self.status_list_view:each_status(function(status, entry_type)
274+
if entry_type == 'unstaged' or entry_type == 'unmerged' then
275+
if found_current and not next_unstaged_filename then
276+
next_unstaged_filename = status.filename
277+
end
278+
if status.filename == filename then
279+
found_current = true
280+
end
281+
end
282+
end)
283+
230284
local _, err = self.model:stage_file(filename)
231285
if err then
232286
console.debug.error(err)
233287
return
234288
end
235289

236290
self:render(function()
237-
local has_unstaged = false
238-
self.status_list_view:each_status(function(status)
239-
if status:is_staged() then
240-
has_unstaged = true
291+
if next_unstaged_filename then
292+
-- Go to the next unstaged file
293+
self:move_to(function(status, entry_type)
294+
return status.filename == next_unstaged_filename
295+
and (entry_type == 'unstaged' or entry_type == 'unmerged')
296+
end)
297+
else
298+
-- No next unstaged file - try first unstaged, then staged version
299+
local found = self:move_to(function(_, entry_type)
300+
return entry_type == 'unstaged' or entry_type == 'unmerged'
301+
end)
302+
if not found then
303+
self:move_to(function(status)
304+
return status.filename == filename
305+
end)
241306
end
242-
end)
243-
244-
self:move_to(function(status)
245-
if has_unstaged then return status:is_unstaged() == true end
246-
return status.filename == entry.status.filename
247-
end)
307+
end
248308
end)
249309
end
250310

@@ -255,24 +315,44 @@ function ProjectDiffScreen:unstage_file()
255315

256316
loop.free_textlock()
257317
local filename = entry.status.filename
318+
319+
-- Find the next staged file after this one (before unstaging)
320+
local next_staged_filename = nil
321+
local found_current = false
322+
self.status_list_view:each_status(function(status, entry_type)
323+
if entry_type == 'staged' then
324+
if found_current and not next_staged_filename then
325+
next_staged_filename = status.filename
326+
end
327+
if status.filename == filename then
328+
found_current = true
329+
end
330+
end
331+
end)
332+
258333
local _, err = self.model:unstage_file(filename)
259334
if err then
260335
console.debug.error(err)
261336
return
262337
end
263338

264339
self:render(function()
265-
local has_staged = false
266-
self.status_list_view:each_status(function(status)
267-
if status:is_staged() then
268-
has_staged = true
340+
if next_staged_filename then
341+
-- Go to the next staged file
342+
self:move_to(function(status, entry_type)
343+
return status.filename == next_staged_filename and entry_type == 'staged'
344+
end)
345+
else
346+
-- No next staged file - try first staged, then unstaged version
347+
local found = self:move_to(function(_, entry_type)
348+
return entry_type == 'staged'
349+
end)
350+
if not found then
351+
self:move_to(function(status)
352+
return status.filename == filename
353+
end)
269354
end
270-
end)
271-
272-
self:move_to(function(status)
273-
if has_staged then return status:is_staged() == true end
274-
return status.filename == entry.status.filename
275-
end)
355+
end
276356
end)
277357
end
278358

0 commit comments

Comments
 (0)