From ed22322ec84019c32772d95577de8049ae3f1653 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Thu, 6 Aug 2026 21:28:33 +0200 Subject: [PATCH] Collapse the stash range selection from the refresh's Then Collapsing the range before kicking off the refresh paints the new selection against the list as it was before the drop, so for a frame the entries that were just dropped are still on screen (and, with gui.shrinkSidePanelsToContent, the panel is still at its old size). Co-Authored-By: Claude Opus 5 (1M context) --- pkg/gui/controllers/stash_controller.go | 32 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/pkg/gui/controllers/stash_controller.go b/pkg/gui/controllers/stash_controller.go index 65de7f243..5d78a84ca 100644 --- a/pkg/gui/controllers/stash_controller.go +++ b/pkg/gui/controllers/stash_controller.go @@ -163,19 +163,33 @@ func (self *StashController) handleStashDrop(stashEntries []*models.StashEntry) // iteration lets the workers race and an earlier, stale result can // land last. The indices are captured up front and we drop // highest-first, so the remaining lower indices stay valid without - // an intervening refresh. Block input until the refresh has - // landed, so that dropping the next entry in quick succession - // (confirming and pressing the key again right away) sees the - // refreshed list and not the stale, pre-drop indices. - defer self.c.RefreshBlockingInput(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}}) + // an intervening refresh. + var dropErr error for i := len(stashEntries) - 1; i >= 0; i-- { self.c.LogCommand(fmt.Sprintf(self.c.Tr.Log.DroppingStash, stashEntries[i].Hash), false) - if err := self.c.Git().Stash.Drop(stashEntries[i].Index); err != nil { - return err + if dropErr = self.c.Git().Stash.Drop(stashEntries[i].Index); dropErr != nil { + break } } - self.context().CollapseRangeSelectionToTop() - return nil + // Block input until the refresh has landed, so that dropping the + // next entry in quick succession (confirming and pressing the key + // again right away) sees the refreshed list and not the stale, + // pre-drop indices. + self.c.RefreshBlockingInput(types.RefreshOptions{ + Scope: []types.RefreshableView{types.STASH}, + Then: func() error { + // Collapse the range selection from here, so that it lands + // in the same frame as the shortened list. The refresh has + // painted the list by the time Then runs, so the new + // selection needs a focus update of its own. + if dropErr == nil { + self.context().CollapseRangeSelectionToTop() + self.context().HandleFocus(types.OnFocusOpts{}) + } + return nil + }, + }) + return dropErr }, })