mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-28 10:15:32 -05:00
CommitFileTreeViewModel embedded the low-level tree's SetTree, which rebuilds the node list without touching the cursor. So after a shrinking rebuild (e.g. moving a patch out into the index removes a file), the selection index could be left past the end of the tree. GetSelectedItems then indexes out of range and returns a nil node, which segfaults callers such as canEditFiles when the options map is rendered during layout. Override SetTree to ClampSelection after the rebuild. Unlike FileTreeViewModel we deliberately don't also re-find the selected node by path: that walk lands on the containing directory when a file is removed from a dir that then collapses, whereas keeping the clamped index lands on the sibling file (see discard_old_file_changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.2 KiB
Go
41 lines
1.2 KiB
Go
package filetree
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
"github.com/jesseduffield/lazygit/pkg/common"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// When the tree shrinks under the selection - e.g. moving a patch out into the
|
|
// index removes a file - SetTree must keep the selection in range. Otherwise
|
|
// GetSelectedItems returns a nil node, which crashes callers such as
|
|
// canEditFiles when the options map is rendered during layout.
|
|
func TestCommitFileTreeViewModelSetTreeClampsSelectionOnShrink(t *testing.T) {
|
|
files := []*models.CommitFile{
|
|
{Path: "file1"},
|
|
{Path: "file2"},
|
|
{Path: "file3"},
|
|
}
|
|
viewModel := NewCommitFileTreeViewModel(
|
|
func() []*models.CommitFile { return files },
|
|
common.NewDummyCommon(),
|
|
false, // flat list
|
|
)
|
|
viewModel.SetTree()
|
|
viewModel.SetSelectedLineIdx(viewModel.Len() - 1)
|
|
|
|
// The file under the cursor goes away and the tree shrinks.
|
|
files = []*models.CommitFile{{Path: "file1"}}
|
|
viewModel.SetTree()
|
|
|
|
assert.Less(t, viewModel.GetSelectedLineIdx(), viewModel.Len())
|
|
assert.NotNil(t, viewModel.GetSelected())
|
|
items, _, _ := viewModel.GetSelectedItems()
|
|
assert.NotEmpty(t, items)
|
|
for _, item := range items {
|
|
assert.NotNil(t, item)
|
|
}
|
|
}
|