mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-28 10:15:32 -05:00
Pressing the left button on the current selection now starts a drag that moves the selected commits, both in the normal commits view and for todos during an interactive rebase. A press anywhere else falls through to the usual click handling, so dragging from an unselected line still creates a range selection, and releasing without having moved collapses the selection to the pressed commit like a plain click would. While dragging, the insertion point follows the pointer: rows below the dragged block insert after the pointed-at commit, rows above it insert before it, and during a rebase the destination is limited to the contiguous block of movable todos around the selection. gocui moves the view cursor along with the pointer, so each drag event moves it back to keep the original selection highlighted. The move happens on release. The model may have been refreshed during the drag, so the dragged commits are located again by their identity (hash, subject, todo action); if they no longer form a unique contiguous block, the drop is ignored rather than guessing.
134 lines
3.1 KiB
Go
134 lines
3.1 KiB
Go
package controllers
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestFindCommitDragBlock(t *testing.T) {
|
|
commit := func(hash string) *models.Commit {
|
|
return models.NewCommit(&utils.StringPool{}, models.NewCommitOpts{Hash: hash})
|
|
}
|
|
identities := []commitDragIdentity{
|
|
commitDragIdentityForCommit(commit("b")),
|
|
commitDragIdentityForCommit(commit("c")),
|
|
}
|
|
|
|
t.Run("finds the original block after selection changes", func(t *testing.T) {
|
|
commits := []*models.Commit{commit("a"), commit("b"), commit("c"), commit("d")}
|
|
|
|
actual, startIndex, endIndex, found := findCommitDragBlock(commits, identities)
|
|
|
|
assert.True(t, found)
|
|
assert.Equal(t, commits[1:3], actual)
|
|
assert.Equal(t, 1, startIndex)
|
|
assert.Equal(t, 2, endIndex)
|
|
})
|
|
|
|
t.Run("rejects a block that is no longer contiguous", func(t *testing.T) {
|
|
_, _, _, found := findCommitDragBlock(
|
|
[]*models.Commit{commit("a"), commit("b"), commit("d"), commit("c")}, identities,
|
|
)
|
|
|
|
assert.False(t, found)
|
|
})
|
|
|
|
t.Run("rejects an ambiguous block", func(t *testing.T) {
|
|
_, _, _, found := findCommitDragBlock(
|
|
[]*models.Commit{commit("b"), commit("c"), commit("b"), commit("c")}, identities,
|
|
)
|
|
|
|
assert.False(t, found)
|
|
})
|
|
}
|
|
|
|
func Test_countSquashableCommitsAbove(t *testing.T) {
|
|
scenarios := []struct {
|
|
name string
|
|
commits []*models.Commit
|
|
selectedIdx int
|
|
rebaseStartIdx int
|
|
expectedResult int
|
|
}{
|
|
{
|
|
name: "no squashable commits",
|
|
commits: []*models.Commit{
|
|
{Name: "abc"},
|
|
{Name: "def"},
|
|
{Name: "ghi"},
|
|
},
|
|
selectedIdx: 2,
|
|
rebaseStartIdx: 2,
|
|
expectedResult: 0,
|
|
},
|
|
{
|
|
name: "some squashable commits, including for the selected commit",
|
|
commits: []*models.Commit{
|
|
{Name: "fixup! def"},
|
|
{Name: "fixup! ghi"},
|
|
{Name: "abc"},
|
|
{Name: "def"},
|
|
{Name: "ghi"},
|
|
},
|
|
selectedIdx: 4,
|
|
rebaseStartIdx: 4,
|
|
expectedResult: 2,
|
|
},
|
|
{
|
|
name: "base commit is below rebase start",
|
|
commits: []*models.Commit{
|
|
{Name: "fixup! def"},
|
|
{Name: "abc"},
|
|
{Name: "def"},
|
|
},
|
|
selectedIdx: 1,
|
|
rebaseStartIdx: 1,
|
|
expectedResult: 0,
|
|
},
|
|
{
|
|
name: "base commit does not exist at all",
|
|
commits: []*models.Commit{
|
|
{Name: "fixup! xyz"},
|
|
{Name: "abc"},
|
|
{Name: "def"},
|
|
},
|
|
selectedIdx: 2,
|
|
rebaseStartIdx: 2,
|
|
expectedResult: 0,
|
|
},
|
|
{
|
|
name: "selected commit is in the middle of fixups",
|
|
commits: []*models.Commit{
|
|
{Name: "fixup! def"},
|
|
{Name: "abc"},
|
|
{Name: "fixup! ghi"},
|
|
{Name: "def"},
|
|
{Name: "ghi"},
|
|
},
|
|
selectedIdx: 1,
|
|
rebaseStartIdx: 4,
|
|
expectedResult: 1,
|
|
},
|
|
{
|
|
name: "selected commit is after rebase start",
|
|
commits: []*models.Commit{
|
|
{Name: "fixup! def"},
|
|
{Name: "abc"},
|
|
{Name: "def"},
|
|
{Name: "ghi"},
|
|
},
|
|
selectedIdx: 3,
|
|
rebaseStartIdx: 2,
|
|
expectedResult: 1,
|
|
},
|
|
}
|
|
for _, s := range scenarios {
|
|
t.Run(s.name, func(t *testing.T) {
|
|
assert.Equal(t, s.expectedResult, countSquashableCommitsAbove(s.commits, s.selectedIdx, s.rebaseStartIdx))
|
|
})
|
|
}
|
|
}
|