@@ -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
131144end
132145
133146function 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
174200end
175201
176202function 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
221260end
222261
223262function 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 )
249309end
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 )
277357end
278358
0 commit comments